Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions src/current_sense/phoque/Phoque_CurrentSense.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ void Phoque_CurrentSense::DMA_Init()
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();

#ifdef DMA_USE_INTERRUPT
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
#endif

// Enable external clock for ADC
RCC_PeriphCLKInitTypeDef PeriphClkInit;
Expand Down Expand Up @@ -171,7 +173,6 @@ void* Phoque_CurrentSense::SyncLowSide(void* _driver_params, void* _cs_params)
SIMPLEFOC_DEBUG("STM32-CS: timer has no repetition counter, ADC interrupt not supported for this Phoque");
return SIMPLEFOC_CURRENT_SENSE_INIT_FAILED;
}

// set the trigger output event
LL_TIM_SetTriggerOutput(cs_params->timer_handle->Instance, LL_TIM_TRGO_UPDATE);

Expand Down Expand Up @@ -202,7 +203,7 @@ void* Phoque_CurrentSense::ConfigureADC(const void* driver_params, const int pin
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);

DMA1_Init(&hadc1, &hdma_adc1, DMA1_Channel1, DMA_REQUEST_ADC1);
DMA1_Init(&hadc2, &hdma_adc2, DMA1_Channel2, DMA_REQUEST_ADC2);
DMA1_Init(&hadc2, &hdma_adc2, DMA2_Channel1, DMA_REQUEST_ADC2);

if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc1_buffer, adc1_len) != HAL_OK)
{
Expand Down Expand Up @@ -276,6 +277,7 @@ int Phoque_CurrentSense::init()
void Phoque_CurrentSense::calibrateOffsets(){
const int calibration_rounds = 2000;


// find adc offset = zero current voltage
uint32_t accA = 0, accB = 0, accC = 0;
// read the adc voltage 1000 times ( arbitrary number )
Expand All @@ -287,7 +289,11 @@ void Phoque_CurrentSense::calibrateOffsets(){
//no new data: this iteration didn't happen
i--;
//wait for interrupt (dma irq should do it)
#ifdef DMA_USE_INTERRUPT
__WFI();
#else
delayMicroseconds(100);
#endif
continue;
}
//invalidate current data
Expand All @@ -296,27 +302,31 @@ void Phoque_CurrentSense::calibrateOffsets(){
accB += currv;
accC += currw;
}

// calculate the mean offsets
offset_ia = accA * ((Stm32CurrentSenseParams*)params)->adc_voltage_conv / calibration_rounds;
offset_ib = accB * ((Stm32CurrentSenseParams*)params)->adc_voltage_conv / calibration_rounds;
offset_ic = accC * ((Stm32CurrentSenseParams*)params)->adc_voltage_conv / calibration_rounds;
SimpleFOCDebug::printf("PHOQUE-CS: Calibrated centers at %f, %f, %f\r\n", offset_ia, offset_ib, offset_ic);
}

int Phoque_CurrentSense::driverAlign(float align_voltage, bool modulation_centered)
{
_UNUSED(align_voltage);
_UNUSED(modulation_centered);
return 0;
return 1;
}

#ifdef DMA_USE_INTERRUPT
extern "C" {
void DMA1_Channel1_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_adc1);
}

void DMA1_Channel2_IRQHandler(void) {
void DMA2_Channel1_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_adc2);
}
}
#endif

#endif
219 changes: 219 additions & 0 deletions src/current_sense/phoque1/Phoque1_CurrentSense.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
#if defined(ARDUINO_PHOQUE1)

#include "Phoque1_CurrentSense.hpp"
#include "communication/SimpleFOCDebug.h"
#include "current_sense/hardware_specific/stm32/stm32_adc_utils.h"

static OPAMP_HandleTypeDef hopamp1;
static OPAMP_HandleTypeDef hopamp2;
static OPAMP_HandleTypeDef hopamp3;

Phoque1_CurrentSense::Phoque1_CurrentSense(float _shunt_resistor, float _gain, bool _read_bemf)
:Phoque_CurrentSense(_shunt_resistor, _gain, _read_bemf)
{
pinA = A_CURRU_H;
pinB = A_CURRV_H;
pinC = A_CURRW_H;
}

Phoque1_CurrentSense::Phoque1_CurrentSense(float mVpA, bool _read_bemf)
:Phoque_CurrentSense(mVpA, _read_bemf)
{
pinA = A_CURRU_H;
pinB = A_CURRV_H;
pinC = A_CURRW_H;
}

Phoque1_CurrentSense::~Phoque1_CurrentSense()
{
}

void Phoque1_CurrentSense::Opamp_Init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_3 | GPIO_PIN_5|GPIO_PIN_7; //Opamp 1 | Opamp 2
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2; // Opamp 3
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

OPAMP_HandleTypeDef *opamp_handles[] = {&hopamp1, &hopamp2, &hopamp3};
OPAMP_TypeDef *opamp_instances[] = {OPAMP1, OPAMP2, OPAMP3};
static_assert(sizeof(opamp_handles)/sizeof(opamp_handles[0]) == sizeof(opamp_instances)/sizeof(opamp_instances[0]));

for (size_t i = 0; i < sizeof(opamp_handles)/sizeof(opamp_handles[0]); i++)
{
auto hopamp = opamp_handles[i];
hopamp->Instance = opamp_instances[i];
hopamp->Init.PowerMode = OPAMP_POWERMODE_HIGHSPEED;
hopamp->Init.Mode = OPAMP_PGA_MODE;
hopamp->Init.NonInvertingInput = OPAMP_NONINVERTINGINPUT_IO0;
hopamp->Init.InternalOutput = ENABLE;
hopamp->Init.TimerControlledMuxmode = OPAMP_TIMERCONTROLLEDMUXMODE_DISABLE;
hopamp->Init.PgaConnect = OPAMP_PGA_CONNECT_INVERTINGINPUT_IO0_BIAS;
hopamp->Init.PgaGain = OPAMP_PGA_GAIN_16_OR_MINUS_15;
hopamp->Init.UserTrimming = OPAMP_TRIMMING_FACTORY;
if (HAL_OPAMP_Init(hopamp) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_OPAMP_Init failed!");
}
HAL_OPAMP_Start(hopamp);
}
}

int Phoque1_CurrentSense::ADC1_Init(ADC_HandleTypeDef* hadc1)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;

hadc1->Init.NbrOfConversion += 3 + read_bemf * 2;
Phoque_CurrentSense::ADC1_Init(hadc1);

/** Configure Regular Channel (Opamp 1 / phase W current)
*/
sConfig.Channel = ADC_CHANNEL_13; // OP1_OUT is ADC1_IN13 for internal channel
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc1, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}

if(read_bemf)
{
/* Configure Regular Channel (PA0 / BEMFU / Phase U)
*/
sConfig.Channel = _getADCChannel(analogInputToPinName(A_BEMFU), ADC1);
sConfig.Rank = ADC_REGULAR_RANK_2;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc1, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}

/* Configure Regular Channel (PC4 / BEMFV / Phase V)
*/
sConfig.Channel = _getADCChannel(analogInputToPinName(A_BEMFV), ADC1);
sConfig.Rank = ADC_REGULAR_RANK_3;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc1, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}
}

//******************************************************************
// Aux analog readings
/* Configure Regular Channel (PC1, supply voltage)
*/
sConfig.Channel = _getADCChannel(analogInputToPinName(A_VBUS), ADC1);
sConfig.Rank = read_bemf ? ADC_REGULAR_RANK_4 : ADC_REGULAR_RANK_2;
sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc1, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}

/** Configure Regular Channel (PC0, Potentiometer)
*/
sConfig.Channel = _getADCChannel(analogInputToPinName(A_POTENTIOMETER), ADC1);
sConfig.Rank = read_bemf ? ADC_REGULAR_RANK_5 : ADC_REGULAR_RANK_3;
sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc1, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}
return hadc1->Init.NbrOfConversion;
}

int Phoque1_CurrentSense::ADC2_Init(ADC_HandleTypeDef* hadc2)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;

hadc2->Init.NbrOfConversion += 3 + read_bemf;
Phoque_CurrentSense::ADC2_Init(hadc2);

/** Configure Regular Channel (Opamp 2 / phase U current)
*/
sConfig.Channel = ADC_CHANNEL_16; // OP2_OUT is ADC2_IN16 for internal channel
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc2, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}
/** Configure Regular Channel (Opamp 3 / phase V current)
*/
sConfig.Channel = ADC_CHANNEL_18; // OP3_OUT is ADC2_IN18 for internal channel
sConfig.Rank = ADC_REGULAR_RANK_2;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc2, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}

if(read_bemf)
{
/** Configure Regular Channel (PA2 / BEMFW / Phase W)
*/
sConfig.Channel = _getADCChannel(analogInputToPinName(A_BEMFW), ADC2);
sConfig.Rank = ADC_REGULAR_RANK_3;
sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc2, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}
}

/** Configure Regular Channel (PF1 / Mosfet temperature)
*/
sConfig.Channel = _getADCChannel(analogInputToPinName(A_TEMPERATURE), ADC2);
sConfig.Rank = read_bemf ? ADC_REGULAR_RANK_4 : ADC_REGULAR_RANK_3;
sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5;
if (HAL_ADC_ConfigChannel(hadc2, &sConfig) != HAL_OK)
{
SIMPLEFOC_DEBUG("HAL_ADC_ConfigChannel failed!");
}
return hadc2->Init.NbrOfConversion;
}

uint16_t Phoque1_CurrentSense::readRaw(const int pin)
{
switch (pin)
{
case A_CURRU_H:
case -1:
return adc2_buffer[0];
case A_CURRV_H:
case -2:
return adc2_buffer[1];
case A_CURRW_H:
case -3:
return adc1_buffer[0];

case A_BEMFU:
return adc1_buffer[1];
case A_BEMFV:
return adc1_buffer[2];
case A_BEMFW:
return adc2_buffer[2];

case A_POTENTIOMETER:
return adc1_buffer[2+read_bemf*2];
case A_TEMPERATURE:
return adc2_buffer[2+read_bemf];
case A_VBUS:
return adc1_buffer[1+read_bemf*2];
default:
return 0;
}
}

#endif
22 changes: 22 additions & 0 deletions src/current_sense/phoque1/Phoque1_CurrentSense.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#if defined(ARDUINO_PHOQUE1)

#include "current_sense/phoque/Phoque_CurrentSense.hpp"

class Phoque1_CurrentSense : public Phoque_CurrentSense
{
public:
Phoque1_CurrentSense(float shunt_resistor, float gain, bool read_bemf=false);
Phoque1_CurrentSense(float mVpA, bool read_bemf=false);
~Phoque1_CurrentSense();

uint16_t readRaw(const int pin);

private:
void Opamp_Init();
int ADC1_Init(ADC_HandleTypeDef* hadc1);
int ADC2_Init(ADC_HandleTypeDef* hadc2);
};

#endif
Loading
Loading