Skip to content

Commit 8ab5336

Browse files
committed
refactored the injected channel config
1 parent 311dfe7 commit 8ab5336

File tree

9 files changed

+289
-492
lines changed

9 files changed

+289
-492
lines changed

src/current_sense/hardware_specific/stm32/stm32_adc_utils.cpp

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
#include "stm32_adc_utils.h"
2+
#include "stm32_mcu.h"
23

34
#if defined(_STM32_DEF_)
45

5-
// for searching the best ADCs, we need to know the number of ADCs
6-
// it might be better to use some HAL variable for example ADC_COUNT
7-
// here I've assumed the maximum number of ADCs is 5
8-
#define ADC_COUNT 5
9-
106

117

128
int _adcToIndex(ADC_TypeDef *AdcHandle){
@@ -344,4 +340,91 @@ uint32_t _getADCInjectedRank(uint8_t ind){
344340
}
345341
}
346342

343+
// returns 0 if no interrupt is needed, 1 if interrupt is needed
344+
uint32_t _initTimerInterruptDownsampling(Stm32CurrentSenseParams* cs_params, STM32DriverParams* driver_params, Stm32AdcInterruptConfig& adc_interrupt_config){
345+
346+
// If DIR is 0 (upcounting), the next event is high-side active (PWM rising edge)
347+
// If DIR is 1 (downcounting), the next event is low-side active (PWM falling edge)
348+
bool next_event_high_side = (cs_params->timer_handle->Instance->CR1 & TIM_CR1_DIR) == 0;
349+
350+
// if timer has repetition counter - it will downsample using it
351+
// and it does not need the software downsample
352+
if( IS_TIM_REPETITION_COUNTER_INSTANCE(cs_params->timer_handle->Instance) ){
353+
// adjust the initial timer state such that the trigger
354+
// - only necessary for the timers that have repetition counters
355+
// - basically make sure that the next trigger event is the one that is expected (high-side first then low-side)
356+
357+
// set the direction and the
358+
for(int i=0; i< 6; i++){
359+
if(driver_params->timers_handle[i] == NP) continue; // skip if not set
360+
if(next_event_high_side){
361+
// Set DIR bit to 0 (downcounting)
362+
driver_params->timers_handle[i]->Instance->CR1 |= TIM_CR1_DIR;
363+
// Set CNT to ARR so it starts upcounting from the top
364+
driver_params->timers_handle[i]->Instance->CNT = driver_params->timers_handle[i]->Instance->ARR;
365+
}else{
366+
// Set DIR bit to 0 (upcounting)
367+
driver_params->timers_handle[i]->Instance->CR1 &= ~TIM_CR1_DIR;
368+
// Set CNT to ARR so it starts upcounting from zero
369+
driver_params->timers_handle[i]->Instance->CNT = 0;// driver_params->timers_handle[i]->Instance->ARR;
370+
}
371+
}
372+
return 0; // no interrupt is needed, the timer will handle the downsampling
373+
}else{
374+
if(!adc_interrupt_config.use_adc_interrupt){
375+
// If the timer has no repetition counter, it needs to use the interrupt to downsample for low side sensing
376+
adc_interrupt_config.use_adc_interrupt = 1;
377+
// remember that this timer does not have the repetition counter - need to downasmple
378+
adc_interrupt_config.needs_downsample = 1;
379+
380+
if(next_event_high_side) // Next event is high-side active
381+
adc_interrupt_config.tim_downsample = 0; // skip the next interrupt (and every second one)
382+
else // Next event is low-side active
383+
adc_interrupt_config.tim_downsample = 1; // read the next one (and every second one after)
384+
385+
return 1; // interrupt is needed
386+
}
387+
}
388+
return 1; // interrupt is needed
389+
}
390+
391+
// returns 0 if no downsampling is needed, 1 if downsampling is needed, 2 if error
392+
uint8_t _handleInjectedConvCpltCallback(ADC_HandleTypeDef *AdcHandle, Stm32AdcInterruptConfig& adc_interrupt_config, uint32_t adc_val[4]) {
393+
394+
// if the timer han't repetition counter - downsample two times
395+
if( adc_interrupt_config.needs_downsample && adc_interrupt_config.tim_downsample++ > 0) {
396+
adc_interrupt_config.tim_downsample = 0;
397+
return 1;
398+
}
399+
400+
adc_val[0]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_1);
401+
adc_val[1]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_2);
402+
adc_val[2]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_3);
403+
adc_val[3]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_4);
404+
405+
return 0; // no downsampling needed
406+
}
407+
408+
// reads the ADC injected voltage for the given pin
409+
// returns the voltage
410+
// if the pin is not found in the current sense parameters, returns 0
411+
float _readADCInjectedChannelVoltage(int pin, void* cs_params, Stm32AdcInterruptConfig& adc_interrupt_config, uint32_t adc_val[4]) {
412+
Stm32CurrentSenseParams* cs_p = (Stm32CurrentSenseParams*)cs_params;
413+
uint8_t channel_no = 0;
414+
uint8_t adc_index = (uint8_t)_adcToIndex(cs_p->adc_handle);
415+
for(int i=0; i < 3; i++){
416+
if( pin == cs_p->pins[i]){ // found in the buffer
417+
if (adc_interrupt_config.use_adc_interrupt){
418+
return adc_val[channel_no] * cs_p->adc_voltage_conv;
419+
}else{
420+
// an optimized way to go from i to the channel i=0 -> channel 1, i=1 -> channel 2, i=2 -> channel 3
421+
uint32_t channel = _getADCInjectedRank(channel_no);
422+
return HAL_ADCEx_InjectedGetValue(cs_p->adc_handle, channel) * cs_p->adc_voltage_conv;
423+
}
424+
}
425+
if(_isset(cs_p->pins[i])) channel_no++;
426+
}
427+
return 0; // pin not found
428+
}
429+
347430
#endif

src/current_sense/hardware_specific/stm32/stm32_adc_utils.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@
77

88
#define _TRGO_NOT_AVAILABLE 12345
99

10+
// for searching the best ADCs, we need to know the number of ADCs
11+
// it might be better to use some HAL variable for example ADC_COUNT
12+
// here I've assumed the maximum number of ADCs is 5
13+
#define ADC_COUNT 5
14+
15+
1016
#include "../../../common/foc_utils.h"
1117
#include "../../../communication/SimpleFOCDebug.h"
18+
#include "../../../drivers/hardware_specific/stm32/stm32_mcu.h"
19+
#include "stm32_mcu.h"
20+
21+
1222

1323
/* Exported Functions */
1424
/**
@@ -34,5 +44,22 @@ int _adcToIndex(ADC_TypeDef *AdcHandle);
3444
int _findIndexOfFirstPinMapADCEntry(int pin);
3545
int _findIndexOfLastPinMapADCEntry(int pin);
3646
ADC_TypeDef* _findBestADCForPins(int num_pins, int pins[]);
47+
48+
49+
// Structure to hold ADC interrupt configuration per ADC instance
50+
struct Stm32AdcInterruptConfig {
51+
bool needs_downsample = 0;
52+
uint8_t tim_downsample = 0;
53+
bool use_adc_interrupt = 0;
54+
};
55+
56+
// returns 0 if no interrupt is needed, 1 if interrupt is needed
57+
uint32_t _initTimerInterruptDownsampling(Stm32CurrentSenseParams* cs_params, STM32DriverParams* driver_params, Stm32AdcInterruptConfig& adc_interrupt_config);
58+
// returns 0 if no downsampling is needed, 1 if downsampling is needed, 2 if error
59+
uint8_t _handleInjectedConvCpltCallback(ADC_HandleTypeDef *AdcHandle, Stm32AdcInterruptConfig& adc_interrupt_config, uint32_t adc_val[4]);
60+
// reads the ADC injected voltage for the given pin
61+
// returns the voltage
62+
// if the pin is not found in the current sense parameters, returns 0
63+
float _readADCInjectedChannelVoltage(int pin, void* cs_params, Stm32AdcInterruptConfig& adc_interrupt_config, uint32_t adc_val[4]);
3764
#endif
3865
#endif

src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_mcu.cpp

Lines changed: 27 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,25 @@
1313
#define _ADC_VOLTAGE_F1 3.3f
1414
#define _ADC_RESOLUTION_F1 4096.0f
1515

16-
// array of values of 4 injected channels per adc instance (3)
17-
uint32_t adc_val[3][4]={0};
18-
// does adc interrupt need a downsample - per adc (3)
19-
bool needs_downsample[3] = {0};
20-
// downsampling variable - per adc (3)
21-
uint8_t tim_downsample[3] = {0};
16+
// array of values of 4 injected channels per adc instance (5)
17+
uint32_t adc_val[5][4]={0};
2218

2319
#ifdef SIMPLEFOC_STM32_ADC_INTERRUPT
24-
uint8_t use_adc_interrupt = 1;
20+
#define USE_ADC_INTERRUPT 1
2521
#else
26-
uint8_t use_adc_interrupt = 0;
22+
#define USE_ADC_INTERRUPT 0
2723
#endif
2824

25+
// structure containing the configuration of the adc interrupt
26+
Stm32AdcInterruptConfig adc_interrupt_config[5] = {
27+
{0, 0, USE_ADC_INTERRUPT}, // ADC1
28+
{0, 0, USE_ADC_INTERRUPT}, // ADC2
29+
{0, 0, USE_ADC_INTERRUPT}, // ADC3
30+
{0, 0, USE_ADC_INTERRUPT}, // ADC4
31+
{0, 0, USE_ADC_INTERRUPT} // ADC5
32+
};
33+
34+
2935
void* _configureADCLowSide(const void* driver_params, const int pinA, const int pinB, const int pinC){
3036

3137
Stm32CurrentSenseParams* cs_params= new Stm32CurrentSenseParams {
@@ -48,47 +54,13 @@ void* _driverSyncLowSide(void* _driver_params, void* _cs_params){
4854
// stop all the timers for the driver
4955
stm32_pause(driver_params);
5056

51-
// If DIR is 0 (upcounting), the next event is high-side active (PWM rising edge)
52-
// If DIR is 1 (downcounting), the next event is low-side active (PWM falling edge)
53-
bool next_event_high_side = (cs_params->timer_handle->Instance->CR1 & TIM_CR1_DIR) == 0;
54-
55-
// if timer has repetition counter - it will downsample using it
56-
// and it does not need the software downsample
57-
if( IS_TIM_REPETITION_COUNTER_INSTANCE(cs_params->timer_handle->Instance) ){
58-
// adjust the initial timer state such that the trigger
59-
// - only necessary for the timers that have repetition counters
60-
// - basically make sure that the next trigger event is the one that is expected (high-side first then low-side)
61-
62-
// set the direction and the
63-
for(int i=0; i< 6; i++){
64-
if(driver_params->timers_handle[i] == NP) continue; // skip if not set
65-
if(next_event_high_side){
66-
// Set DIR bit to 0 (downcounting)
67-
driver_params->timers_handle[i]->Instance->CR1 |= TIM_CR1_DIR;
68-
// Set CNT to ARR so it starts upcounting from the top
69-
driver_params->timers_handle[i]->Instance->CNT = driver_params->timers_handle[i]->Instance->ARR;
70-
}else{
71-
// Set DIR bit to 0 (upcounting)
72-
driver_params->timers_handle[i]->Instance->CR1 &= ~TIM_CR1_DIR;
73-
// Set CNT to ARR so it starts upcounting from zero
74-
driver_params->timers_handle[i]->Instance->CNT = 0;// driver_params->timers_handle[i]->Instance->ARR;
75-
}
76-
}
77-
}else{
78-
if(!use_adc_interrupt){
79-
// If the timer has no repetition counter, it needs to use the interrupt to downsample for low side sensing
80-
use_adc_interrupt = 1;
81-
uint8_t adc_index = _adcToIndex(cs_params->adc_handle);
82-
// remember that this timer does not have the repetition counter - need to downasmple
83-
needs_downsample[adc_index] = 1;
84-
85-
if(next_event_high_side) // Next event is high-side active
86-
tim_downsample[adc_index] = 0; // skip the next interrupt (and every second one)
87-
else // Next event is low-side active
88-
tim_downsample[adc_index] = 1; // read the next one (and every second one after)
89-
90-
SIMPLEFOC_DEBUG("STM32-CS: timer has no repetition counter, ADC interrupt has to be used");
91-
}
57+
// get the index of the adc
58+
int adc_index = _adcToIndex(cs_params->adc_handle);
59+
60+
bool tim_interrupt = _initTimerInterruptDownsampling(cs_params, driver_params, adc_interrupt_config[adc_index]);
61+
if(tim_interrupt) {
62+
// error in the timer interrupt initialization
63+
SIMPLEFOC_DEBUG("STM32-CS: timer has no repetition counter, ADC interrupt has to be used");
9264
}
9365

9466
// set the trigger output event
@@ -98,7 +70,7 @@ void* _driverSyncLowSide(void* _driver_params, void* _cs_params){
9870
HAL_ADCEx_Calibration_Start(cs_params->adc_handle);
9971

10072
// start the adc
101-
if(use_adc_interrupt){
73+
if(adc_interrupt_config[adc_index].use_adc_interrupt){
10274
HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
10375
HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
10476

@@ -120,38 +92,16 @@ void* _driverSyncLowSide(void* _driver_params, void* _cs_params){
12092

12193
// function reading an ADC value and returning the read voltage
12294
float _readADCVoltageLowSide(const int pin, const void* cs_params){
123-
uint8_t channel_no = 0;
124-
for(int i=0; i < 3; i++){
125-
if( pin == ((Stm32CurrentSenseParams*)cs_params)->pins[i]){ // found in the buffer
126-
if (use_adc_interrupt){
127-
return adc_val[_adcToIndex(((Stm32CurrentSenseParams*)cs_params)->adc_handle)][channel_no] * ((Stm32CurrentSenseParams*)cs_params)->adc_voltage_conv;
128-
}else{
129-
// an optimized way to go from i to the channel i=0 -> channel 1, i=1 -> channel 2, i=2 -> channel 3
130-
uint32_t channel = _getADCInjectedRank(channel_no);
131-
return HAL_ADCEx_InjectedGetValue(((Stm32CurrentSenseParams*)cs_params)->adc_handle, channel) * ((Stm32CurrentSenseParams*)cs_params)->adc_voltage_conv;
132-
}
133-
}
134-
if(_isset(((Stm32CurrentSenseParams*)cs_params)->pins[i])) channel_no++;
135-
}
136-
return 0;
95+
uint8_t adc_index = (uint8_t)_adcToIndex(((Stm32CurrentSenseParams*)cs_params)->adc_handle);
96+
return _readADCInjectedChannelVoltage(pin, (void*)cs_params, adc_interrupt_config[adc_index], adc_val[adc_index]);
13797
}
13898

13999
extern "C" {
140100
void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef *AdcHandle){
141-
// calculate the instance
142-
int adc_index = _adcToIndex(AdcHandle);
143-
144-
// if the timer han't repetition counter - downsample two times
145-
if( needs_downsample[adc_index] && tim_downsample[adc_index]++ > 0) {
146-
tim_downsample[adc_index] = 0;
147-
return;
148-
}
149-
150-
adc_val[adc_index][0]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_1);
151-
adc_val[adc_index][1]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_2);
152-
adc_val[adc_index][2]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_3);
153-
adc_val[adc_index][3]=HAL_ADCEx_InjectedGetValue(AdcHandle, ADC_INJECTED_RANK_4);
101+
uint8_t adc_index = (uint8_t)_adcToIndex(AdcHandle);
102+
_handleInjectedConvCpltCallback(AdcHandle, adc_interrupt_config[adc_index], adc_val[adc_index]);
154103
}
155104
}
156105

106+
157107
#endif

0 commit comments

Comments
 (0)