diff --git a/src/current_sense/hardware_specific/stm32/stm32_adc_hal.h b/src/current_sense/hardware_specific/stm32/stm32_adc_hal.h new file mode 100644 index 00000000..9b1bb3ee --- /dev/null +++ b/src/current_sense/hardware_specific/stm32/stm32_adc_hal.h @@ -0,0 +1,23 @@ +#ifndef STM32_ADC_INCLUDE_HAL + +#include "Arduino.h" + +#if defined(_STM32_DEF_) + +#include "stm32_mcu.h" + +// for searching the best ADCs, we need to know the number of ADCs +// it might be better to use some HAL variable for example ADC_COUNT +// here I've assumed the maximum number of ADCs is 5 +#define ADC_COUNT 5 + +// pointer to the ADC handles used in the project +ADC_HandleTypeDef* _get_adc_handles(); + +int _adc_init_regular(ADC_TypeDef* adc_instance); +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); +int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); + +#endif + +#endif \ No newline at end of file diff --git a/src/current_sense/hardware_specific/stm32/stm32_adc_utils.cpp b/src/current_sense/hardware_specific/stm32/stm32_adc_utils.cpp index bf9a210d..c8bc7d4a 100644 --- a/src/current_sense/hardware_specific/stm32/stm32_adc_utils.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32_adc_utils.cpp @@ -1,10 +1,19 @@ #include "stm32_adc_utils.h" #include "stm32_mcu.h" +#include "stm32_adc_hal.h" #if defined(_STM32_DEF_) +#ifdef STM32F1xx +#include "stm32f1xx_ll_adc.h" +#endif +#ifdef STM32F7xx +#include "stm32f7xx_ll_adc.h" +#endif +extern ADC_HandleTypeDef hadc[]; + int _adcToIndex(ADC_TypeDef *AdcHandle){ if(AdcHandle == ADC1) return 0; #ifdef ADC2 // if ADC2 exists @@ -110,12 +119,37 @@ int _findIndexOfLastPinMapADCEntry(int pin) { return _findIndexOfLastEntry(pinName); } +// find the best ADC for the given pin +// returns the ADC_TypeDef pointer or nullptr if not found +// It returns already configured ADC if possible +// otherwise it returns the first available unconfigured ADC +ADC_TypeDef* _findBestADCForRegularPin(int pin, ADC_HandleTypeDef adc_handles[]) { + PinName pinName = digitalPinToPinName(pin); + int index = _findIndexOfFirstPinMapADCEntry(pin); + int last_index = _findIndexOfLastPinMapADCEntry(pin); + if (index == -1) { + return nullptr; + } + for (int j = index; j <= last_index; j++) { + if (PinMap_ADC[j].pin == NC) { + break; + } + int adcIndex = _adcToIndex((ADC_TypeDef*)PinMap_ADC[j].peripheral); + if (adc_handles[adcIndex].Instance != NP) { + // if ADC is already configured, return it + return (ADC_TypeDef*)PinMap_ADC[j].peripheral; + } + } + // return the first available ADC + return (ADC_TypeDef*)PinMap_ADC[index].peripheral; +} + // find the best ADC combination for the given pins // returns the index of the best ADC // each pin can be connected to multiple ADCs // the function will try to find a single ADC that can be used for all pins // if not possible it will return nullptr -ADC_TypeDef* _findBestADCForPins(int numPins, int pins[], ADC_HandleTypeDef adc_handles[]) { +ADC_TypeDef* _findBestADCForInjectedPins(int numPins, int pins[], ADC_HandleTypeDef adc_handles[]) { // assuning that there is at most 5 ADCs uint8_t pins_at_adc[ADC_COUNT] = {0}; @@ -153,9 +187,12 @@ ADC_TypeDef* _findBestADCForPins(int numPins, int pins[], ADC_HandleTypeDef adc_ SimpleFOCDebug::print(" pins: "); SimpleFOCDebug::println(pins_at_adc[i]); if (adc_handles[i].Instance != NP) { - SimpleFOCDebug::print("STM32-CS: ADC"); - SimpleFOCDebug::print(i+1); - SimpleFOCDebug::println(" already in use!"); + // check if ADC injeted is already in use + if(!LL_ADC_INJ_IsTriggerSourceSWStart(adc_handles[i].Instance)) { + SimpleFOCDebug::print("STM32-CS: ADC"); + SimpleFOCDebug::print(i+1); + SimpleFOCDebug::println(" already in use for injected channels!"); + } } } #endif @@ -163,7 +200,8 @@ ADC_TypeDef* _findBestADCForPins(int numPins, int pins[], ADC_HandleTypeDef adc_ // now take the first ADC that has all pins connected for (int i = 0; i < ADC_COUNT; i++) { if (adc_handles[i].Instance != NP) { - continue; // ADC already in use + if (!LL_ADC_INJ_IsTriggerSourceSWStart(adc_handles[i].Instance)) + continue; // ADC already in use for injected } if (pins_at_adc[i] == no_pins) { return _indexToADC(i); @@ -371,7 +409,6 @@ uint32_t _getADCChannel(PinName pin, ADC_TypeDef *AdcHandle ) for (int i = first_ind; i <= last_ind; i++) { if (PinMap_ADC[i].peripheral == AdcHandle) { channel =_getADCChannelFromPinMap(PinMap_ADC[i].pin); - SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); break; } } @@ -502,4 +539,134 @@ float _readADCInjectedChannelVoltage(int pin, void* cs_params, Stm32AdcInterrupt #endif } + + +int last_pin[ADC_COUNT] = {-1,-1,-1,-1,-1}; +uint32_t last_channel[ADC_COUNT] = {0,0,0,0,0}; + +/** + * Read a regular ADC channel while injected channels are running for current sensing. + * + * This function performs a one-shot regular conversion on the same ADC that is being + * used for injected current sensing. Injected conversions have hardware priority and + * will pre-empt regular conversions, so this function may experience some latency. + * + * The function will retry a few times if the ADC returns HAL_BUSY, making it suitable + * for reading auxiliary sensors (temperature, voltage, potentiometers, etc.) while + * motor control is active. + * + * @param pin - Arduino pin number to read (must be on the same ADC as current sensing) + * @return float - Voltage reading in volts, or -1.0f on error + */ +float _readRegularADCVoltage(const int pin){ + + ADC_HandleTypeDef* hadc = _get_adc_handles(); + + int adc_index = NOT_SET; + for(int i = 0; i < ADC_COUNT; i++){ + if(last_pin[i] == pin){ + adc_index = i; + break; + } + } + // avoid re-configuring the channel if reading the same pin as last time + if(!_isset(adc_index)){ + ADC_TypeDef* adc_instance = _findBestADCForRegularPin(pin, hadc); + if(adc_instance == NP){ + #ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Pin does not belong to any ADC!"); + #endif + return -1.0f; + } + adc_index = _adcToIndex(adc_instance); + + ADC_HandleTypeDef adc_handle = hadc[adc_index]; + if (adc_handle.Instance == NP) { + #ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: WARN: ADC not configured, need to configure it: ADC", adc_index+1); + #endif + if(_adc_init_regular(adc_instance) != 0){ + #ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Failed to initialize ADC for pin ", pin); + #endif + return -1.0f; + } + } + + + last_pin[adc_index] = pin; + // Configure the regular channel for this pin + PinName pinName = analogInputToPinName(pin); + uint32_t channel = _getADCChannel(pinName, adc_instance); + + last_channel[adc_index] = channel; + } + + + ADC_ChannelConfTypeDef sConfig = {0}; + sConfig.Channel = last_channel[adc_index]; + // the shortes possible sampling time + // this seems to be a constant in HAL - the shortest time enum is equal to 0 + // G4 - 2.5 cycles + // F1, H7 - 1.5 cycles + // L4 - 2.5 cycles + // F4, F7 - 3 cycles + sConfig.SamplingTime = 0; + +#ifdef ADC_REGULAR_RANK_1 + sConfig.Rank = ADC_REGULAR_RANK_1; +#else + sConfig.Rank = 1; +#endif +#ifdef ADC_SINGLE_ENDED + sConfig.SingleDiff = ADC_SINGLE_ENDED; +#endif +#ifdef ADC_OFFSET_NONE + sConfig.OffsetNumber = ADC_OFFSET_NONE; +#endif +#ifndef STM32F1xx + sConfig.Offset = 0; +#endif + + if (HAL_ADC_ConfigChannel(&hadc[adc_index], &sConfig) != HAL_OK) { +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Failed to configure regular channel"); +#endif + return -1.0f; + } + + // Try to start conversion, with retries for HAL_BUSY + // (ADC may be busy with injected conversion) + HAL_StatusTypeDef status; + int retries = 5; + + do { + status = HAL_ADC_Start(&hadc[adc_index]); + if (status == HAL_BUSY) { + // Wait a bit for injected conversion to complete + delayMicroseconds(1); + retries--; + } + } while (status == HAL_BUSY && retries > 0); + + if (status != HAL_OK) { +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: ADC busy or failed to start"); +#endif + return -1.0f; + } + + // Wait for conversion to complete + // Timeout of 1ms should be more than enough + if (HAL_ADC_PollForConversion(&hadc[adc_index], 1) == HAL_OK) { + uint32_t raw = HAL_ADC_GetValue(&hadc[adc_index]); + return raw * 3.3f / 4096.0f; // assuming 12-bit ADC and 3.3V reference + } + +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Regular conversion timeout"); +#endif + return -1.0f; +} + #endif \ No newline at end of file diff --git a/src/current_sense/hardware_specific/stm32/stm32_adc_utils.h b/src/current_sense/hardware_specific/stm32/stm32_adc_utils.h index 3e15976e..71d836c4 100644 --- a/src/current_sense/hardware_specific/stm32/stm32_adc_utils.h +++ b/src/current_sense/hardware_specific/stm32/stm32_adc_utils.h @@ -7,11 +7,6 @@ #define _TRGO_NOT_AVAILABLE 12345 -// for searching the best ADCs, we need to know the number of ADCs -// it might be better to use some HAL variable for example ADC_COUNT -// here I've assumed the maximum number of ADCs is 5 -#define ADC_COUNT 5 - #include "../../../common/foc_utils.h" #include "../../../communication/SimpleFOCDebug.h" @@ -41,8 +36,8 @@ int _adcToIndex(ADC_TypeDef *AdcHandle); // functions helping to find the best ADC channel int _findIndexOfFirstPinMapADCEntry(int pin); int _findIndexOfLastPinMapADCEntry(int pin); -ADC_TypeDef* _findBestADCForPins(int num_pins, int pins[], ADC_HandleTypeDef adc_handles[]); - +ADC_TypeDef* _findBestADCForInjectedPins(int num_pins, int pins[], ADC_HandleTypeDef adc_handles[]); +ADC_TypeDef* _findBestADCForRegularPin(int pin, ADC_HandleTypeDef adc_handles[]); // Structure to hold ADC interrupt configuration per ADC instance struct Stm32AdcInterruptConfig { @@ -59,5 +54,7 @@ uint8_t _handleInjectedConvCpltCallback(ADC_HandleTypeDef *AdcHandle, Stm32AdcIn // returns the voltage // if the pin is not found in the current sense parameters, returns 0 float _readADCInjectedChannelVoltage(int pin, void* cs_params, Stm32AdcInterruptConfig& adc_interrupt_config, uint32_t adc_val[4]); + + #endif #endif diff --git a/src/current_sense/hardware_specific/stm32/stm32_mcu.cpp b/src/current_sense/hardware_specific/stm32/stm32_mcu.cpp index efc55733..39ae8dcc 100644 --- a/src/current_sense/hardware_specific/stm32/stm32_mcu.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32_mcu.cpp @@ -8,6 +8,8 @@ #define _ADC_VOLTAGE 3.3f #define _ADC_RESOLUTION 1024.0f +extern ADC_HandleTypeDef hadc[]; + // function reading an ADC value and returning the read voltage void* _configureADCInline(const void* driver_params, const int pinA,const int pinB,const int pinC){ _UNUSED(driver_params); @@ -30,5 +32,4 @@ __attribute__((weak)) float _readADCVoltageInline(const int pinA, const void* c return raw_adc * ((Stm32CurrentSenseParams*)cs_params)->adc_voltage_conv; } - #endif \ No newline at end of file diff --git a/src/current_sense/hardware_specific/stm32/stm32_mcu.h b/src/current_sense/hardware_specific/stm32/stm32_mcu.h index 564598d3..2af33a6c 100644 --- a/src/current_sense/hardware_specific/stm32/stm32_mcu.h +++ b/src/current_sense/hardware_specific/stm32/stm32_mcu.h @@ -20,5 +20,26 @@ typedef struct Stm32CurrentSenseParams { } Stm32CurrentSenseParams; +/** + * Read a regular ADC channel while injected channels are running for current sensing. + * Injected conversions have hardware priority and will pre-empt regular conversions. + * + * This funciton performs a one-shot regular conversion on either on the same ADC as the one + * used for injected current sensing, or on another ADC if the pin belongs to a different ADC. + * The funciton will initialize the ADC for regular conversion if not already initialized. + * + * NOTE: + * The low-side current sensing code already initializes the ADC for injected conversions and regullar conversions + * so if the same ADC is used for regular reading, no re-configuration is needed. + * + * NOTE: + * This function will be relatively slow >10us in comparision to the injected reading. + * But it is much better than analogRead though. + * + * @param pin - the Arduino pin to be read (must be an ADC pin on the same ADC) + * @return float - the voltage read from the pin, or -1.0f on error + */ +float _readRegularADCVoltage(const int pin); + #endif #endif \ No newline at end of file diff --git a/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.cpp b/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.cpp index e65c99e5..ced24e0e 100644 --- a/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.cpp @@ -8,21 +8,21 @@ // pointer to the ADC handles used in the project ADC_HandleTypeDef hadc[ADC_COUNT] = {0}; +ADC_HandleTypeDef* _get_adc_handles(){ + return hadc; +} + + + /** - * Function initializing the ADC and the injected channels for the low-side current sensing + * Function initializing the ADC for the regular channels for the low-side current sensing * - * @param cs_params - current sense parameters - * @param driver_params - driver parameters + * @param adc_instance - ADC instance to initialize * * @return int - 0 if success */ -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +int _adc_init_regular(ADC_TypeDef* adc_instance) { - ADC_InjectionConfTypeDef sConfigInjected; - - /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) - */ - auto adc_instance = _findBestADCForPins(3, cs_params->pins, hadc); if(adc_instance == ADC1) __HAL_RCC_ADC1_CLK_ENABLE(); #ifdef ADC2 // if defined ADC2 @@ -47,6 +47,46 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive hadc[adc_num].Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc[adc_num].Init.NbrOfConversion = 1; HAL_ADC_Init(&hadc[adc_num]); + +return 0; +} + +/** + * Function initializing the ADC and the injected channels for the low-side current sensing + * + * @param cs_params - current sense parameters + * @param driver_params - driver parameters + * + * @return int - 0 if success + */ +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +{ + ADC_InjectionConfTypeDef sConfigInjected; + + /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) + */ + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); + + if(adc_instance == NP){ +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Pin does not belong to any ADC!"); +#endif + return -1; // error not a valid ADC instance + } + + if( _adc_init_regular(adc_instance) != 0){ + return -1; + } + + auto adc_num = _adcToIndex(adc_instance); + hadc[adc_num].Instance = adc_instance; + hadc[adc_num].Init.ScanConvMode = ADC_SCAN_ENABLE; + hadc[adc_num].Init.ContinuousConvMode = DISABLE; + hadc[adc_num].Init.DiscontinuousConvMode = DISABLE; + hadc[adc_num].Init.ExternalTrigConv = ADC_SOFTWARE_START; + hadc[adc_num].Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc[adc_num].Init.NbrOfConversion = 1; + HAL_ADC_Init(&hadc[adc_num]); /**Configure for the selected ADC regular channel to be converted. */ @@ -105,7 +145,10 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive sConfigInjected.InjectedRank = _getADCInjectedRank(channel_no++); sConfigInjected.InjectedChannel = _getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance); - if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); +#endif + if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ #ifdef SIMPLEFOC_STM32_DEBUG SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)_getADCChannel(analogInputToPinName(cs_params->pins[i]) , hadc[adc_num].Instance)); #endif diff --git a/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.h b/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.h index fbcf4e99..1f32f692 100644 --- a/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.h +++ b/src/current_sense/hardware_specific/stm32/stm32f1/stm32f1_hal.h @@ -6,9 +6,8 @@ #if defined(STM32F1xx) #include "stm32f1xx_hal.h" #include "../stm32_mcu.h" - -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); -int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); +#include "../stm32_adc_hal.h" +#include "stm32f1xx_ll_adc.h" #endif diff --git a/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.cpp b/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.cpp index b8c3bf33..216819db 100644 --- a/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.cpp @@ -9,22 +9,23 @@ // pointer to the ADC handles used in the project ADC_HandleTypeDef hadc[ADC_COUNT] = {0}; +ADC_HandleTypeDef* _get_adc_handles(){ + return hadc; +} + + /** - * Function initializing the ADC and the injected channels for the low-side current sensing + * Function initializing the ADC for the regular channels for the low-side current sensing * - * @param cs_params - current sense parameters - * @param driver_params - driver parameters + * @param adc_instance - ADC instance to initialize * * @return int - 0 if success */ -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) -{ +int _adc_init_regular(ADC_TypeDef* adc_instance){ ADC_InjectionConfTypeDef sConfigInjected; /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ - auto adc_instance = _findBestADCForPins(3, cs_params->pins, hadc); - if(adc_instance == ADC1) __HAL_RCC_ADC1_CLK_ENABLE(); #ifdef ADC2 // if defined ADC2 else if(adc_instance == ADC2) __HAL_RCC_ADC2_CLK_ENABLE(); @@ -50,7 +51,7 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive hadc[adc_num].Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc[adc_num].Init.Resolution = ADC_RESOLUTION_12B; hadc[adc_num].Init.ScanConvMode = ENABLE; - hadc[adc_num].Init.ContinuousConvMode = ENABLE; + hadc[adc_num].Init.ContinuousConvMode = DISABLE; hadc[adc_num].Init.DiscontinuousConvMode = DISABLE; hadc[adc_num].Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc[adc_num].Init.ExternalTrigConv = ADC_SOFTWARE_START; // for now @@ -64,6 +65,35 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive #endif return -1; } + return 0; +} + + +/** + * Function initializing the ADC and the injected channels for the low-side current sensing + * + * @param cs_params - current sense parameters + * @param driver_params - driver parameters + * + * @return int - 0 if success + */ +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +{ + ADC_InjectionConfTypeDef sConfigInjected; + + /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) + */ + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); + if(adc_instance == NP){ +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Pin does not belong to any ADC!"); +#endif + return -1; // error not a valid ADC instance + } + if( _adc_init_regular(adc_instance) != 0){ + return -1; + } + auto adc_num = _adcToIndex(adc_instance); /**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time */ @@ -120,9 +150,12 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive sConfigInjected.InjectedRank = _getADCInjectedRank(channel_no++); sConfigInjected.InjectedChannel = _getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance); +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)sConfigInjected.InjectedChannel); +#endif if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ #ifdef SIMPLEFOC_STM32_DEBUG - SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)_getADCChannel(analogInputToPinName(cs_params->pins[i]) , hadc[adc_num].Instance)); + SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)sConfigInjected.InjectedChannel); #endif return -1; } diff --git a/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.h b/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.h index f0f9a03d..679cc323 100644 --- a/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.h +++ b/src/current_sense/hardware_specific/stm32/stm32f4/stm32f4_hal.h @@ -5,12 +5,10 @@ #if defined(STM32F4xx) #include "stm32f4xx_hal.h" +#include "../stm32_adc_hal.h" #include "../stm32_mcu.h" #include "../stm32_adc_utils.h" -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); -int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); - #endif #endif \ No newline at end of file diff --git a/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.cpp b/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.cpp index 6fa45be7..494dd2e7 100644 --- a/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.cpp @@ -9,21 +9,21 @@ // pointer to the ADC handles used in the project ADC_HandleTypeDef hadc[ADC_COUNT] = {0}; +ADC_HandleTypeDef* _get_adc_handles(){ + return hadc; +} + + + /** - * Function initializing the ADC and the injected channels for the low-side current sensing + * Function initializing the ADC for the regular channels for the low-side current sensing * - * @param cs_params - current sense parameters - * @param driver_params - driver parameters + * @param adc_instance - ADC instance to initialize * * @return int - 0 if success */ -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +int _adc_init_regular(ADC_TypeDef* adc_instance) { - ADC_InjectionConfTypeDef sConfigInjected; - - /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) - */ - auto adc_instance = _findBestADCForPins(3, cs_params->pins, hadc); if(adc_instance == ADC1) __HAL_RCC_ADC1_CLK_ENABLE(); #ifdef ADC2 // if defined ADC2 @@ -63,6 +63,40 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive #endif return -1; } + return 0; +} + +/** + * Function initializing the ADC and the injected channels for the low-side current sensing + * + * @param cs_params - current sense parameters + * @param driver_params - driver parameters + * + * @return int - 0 if success + */ +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +{ + + /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) + */ + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); + if(adc_instance == NP){ +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Pin does not belong to any ADC!"); +#endif + return -1; // error not a valid ADC instance + } + if( _adc_init_regular(adc_instance) != 0){ + return -1; + } + int adc_num = _adcToIndex(adc_instance); + +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: Using ADC: ", adc_num+1); +#endif + + + ADC_InjectionConfTypeDef sConfigInjected; /**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time */ @@ -127,6 +161,9 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive sConfigInjected.InjectedRank = _getADCInjectedRank(channel_no++); sConfigInjected.InjectedChannel = _getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance); +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); +#endif if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ #ifdef SIMPLEFOC_STM32_DEBUG SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)_getADCChannel(analogInputToPinName(cs_params->pins[i]) , hadc[adc_num].Instance)); diff --git a/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.h b/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.h index 391b3fb5..c7eb192b 100644 --- a/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.h +++ b/src/current_sense/hardware_specific/stm32/stm32f7/stm32f7_hal.h @@ -8,9 +8,7 @@ #include "stm32f7xx_hal.h" #include "../stm32_mcu.h" #include "../stm32_adc_utils.h" - -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); -int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); +#include "../stm32_adc_hal.h" #endif diff --git a/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.cpp b/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.cpp index b8b8226e..7879f145 100644 --- a/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.cpp @@ -10,21 +10,20 @@ // pointer to the ADC handles used in the project ADC_HandleTypeDef hadc[ADC_COUNT] = {0}; +ADC_HandleTypeDef* _get_adc_handles(){ + return hadc; +} + /** - * Function initializing the ADC and the injected channels for the low-side current sensing + * Function initializing the ADC for the regular channels for the low-side current sensing * - * @param cs_params - current sense parameters - * @param driver_params - driver parameters + * @param adc_instance - ADC instance to initialize * * @return int - 0 if success */ -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) -{ +int _adc_init_regular(ADC_TypeDef* adc_instance){ ADC_InjectionConfTypeDef sConfigInjected; - - /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) - */ - auto adc_instance = _findBestADCForPins(3, cs_params->pins, hadc); + if(adc_instance == ADC1) { #ifdef __HAL_RCC_ADC1_CLK_ENABLE @@ -112,9 +111,38 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive #endif return -1; } - + + return 0; +} + +/** + * Function initializing the ADC and the injected channels for the low-side current sensing + * + * @param cs_params - current sense parameters + * @param driver_params - driver parameters + * + * @return int - 0 if success + */ +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +{ + + /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) + */ + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); + if(adc_instance == NP){ +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: No ADCs available!"); +#endif + return -1; // error not a valid ADC instance + } + if( _adc_init_regular(adc_instance) != 0){ + return -1; + } + int adc_num = _adcToIndex(adc_instance); + /**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time */ + ADC_InjectionConfTypeDef sConfigInjected; sConfigInjected.InjectedNbrOfConversion = 0; for(int pin_no=0; pin_no<3; pin_no++){ if(_isset(cs_params->pins[pin_no])){ @@ -172,9 +200,12 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive sConfigInjected.InjectedRank = _getADCInjectedRank(channel_no++); sConfigInjected.InjectedChannel = _getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance); +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); +#endif if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ #ifdef SIMPLEFOC_STM32_DEBUG - SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)_getADCChannel(analogInputToPinName(cs_params->pins[i]) , hadc[adc_num].Instance)); + SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); #endif return -1; } @@ -248,5 +279,4 @@ extern "C" { } #endif } - #endif \ No newline at end of file diff --git a/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.h b/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.h index 81faf26b..f2ae6622 100644 --- a/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.h +++ b/src/current_sense/hardware_specific/stm32/stm32g4/stm32g4_hal.h @@ -8,9 +8,8 @@ #include "stm32g4xx_hal.h" #include "../stm32_mcu.h" #include "../stm32_adc_utils.h" +#include "../stm32_adc_hal.h" -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); -int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); #endif diff --git a/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.cpp b/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.cpp index 8259f960..dc627b1b 100644 --- a/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.cpp @@ -9,22 +9,25 @@ // pointer to the ADC handles used in the project ADC_HandleTypeDef hadc[ADC_COUNT] = {0}; +ADC_HandleTypeDef* _get_adc_handles(){ + return hadc; +} + + /** - * Function initializing the ADC and the injected channels for the low-side current sensing + * Function initializing the ADC for the regular channels for the low-side current sensing * - * @param cs_params - current sense parameters - * @param driver_params - driver parameters + * @param adc_instance - ADC instance to initialize * * @return int - 0 if success */ -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +int _adc_init_regular(ADC_TypeDef* adc_instance) { - ADC_InjectionConfTypeDef sConfigInjected; /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ - auto adc_instance = _findBestADCForPins(3, cs_params->pins, hadc); + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); if(adc_instance == ADC1) __HAL_RCC_ADC12_CLK_ENABLE(); #ifdef ADC2 // if defined ADC2 @@ -78,9 +81,38 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive #endif return -1; } - + return 0; +} + +/** + * Function initializing the ADC and the injected channels for the low-side current sensing + * + * @param cs_params - current sense parameters + * @param driver_params - driver parameters + * + * @return int - 0 if success + */ +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +{ + + + /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) + */ + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); + if(adc_instance == NP){ +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ERR: Pin does not belong to any ADC!"); +#endif + return -1; // error not a valid ADC instance + } + if( _adc_init_regular(adc_instance) != 0){ + return -1; + } + int adc_num = _adcToIndex(adc_instance); + /**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time */ + ADC_InjectionConfTypeDef sConfigInjected; sConfigInjected.InjectedNbrOfConversion = 0; for(int pin_no=0; pin_no<3; pin_no++){ if(_isset(cs_params->pins[pin_no])){ @@ -149,6 +181,9 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive sConfigInjected.InjectedRank = _getADCInjectedRank(channel_no++); sConfigInjected.InjectedChannel = _getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance); +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); +#endif if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ #ifdef SIMPLEFOC_STM32_DEBUG SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)_getADCChannel(analogInputToPinName(cs_params->pins[i]) , hadc[adc_num].Instance)); diff --git a/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.h b/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.h index 70a4b762..3dd8d97a 100644 --- a/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.h +++ b/src/current_sense/hardware_specific/stm32/stm32h7/stm32h7_hal.h @@ -6,8 +6,6 @@ #include "stm32h7xx_hal.h" #include "../stm32_adc_utils.h" #include "../stm32_mcu.h" - -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); -int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); +#include "../stm32_adc_hal.h" #endif diff --git a/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.cpp b/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.cpp index 48fa866f..3a9639b4 100644 --- a/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.cpp +++ b/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.cpp @@ -9,21 +9,25 @@ // pointer to the ADC handles used in the project ADC_HandleTypeDef hadc[ADC_COUNT] = {0}; +ADC_HandleTypeDef* _get_adc_handles(){ + return hadc; +} + + + /** - * Function initializing the ADC and the injected channels for the low-side current sensing + * Function initializing the ADC for the regular channels for the low-side current sensing * - * @param cs_params - current sense parameters - * @param driver_params - driver parameters + * @param adc_instance - ADC instance to initialize * * @return int - 0 if success */ -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +int _adc_init_regular(ADC_TypeDef* adc_instance) { - ADC_InjectionConfTypeDef sConfigInjected; /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ - auto adc_instance = _findBestADCForPins(3, cs_params->pins, hadc); + int adc_num = _adcToIndex(adc_instance); if (hadc[adc_num].Instance != NP) { SIMPLEFOC_DEBUG("STM32-CS: ERR: ADC already in use: ADC", adc_num + 1); @@ -112,7 +116,34 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive #endif return -1; } - + return 0; +} + + +/** + * Function initializing the ADC and the injected channels for the low-side current sensing + * + * @param cs_params - current sense parameters + * @param driver_params - driver parameters + * + * @return int - 0 if success + */ +int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params) +{ + + /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) + */ + auto adc_instance = _findBestADCForInjectedPins(3, cs_params->pins, hadc); + int adc_num = _adcToIndex(adc_instance); + if (hadc[adc_num].Instance != NP) { + SIMPLEFOC_DEBUG("STM32-CS: ERR: ADC already in use: ADC", adc_num + 1); + return -1; + } + if(_adc_init_regular(adc_instance) != 0){ + return -1; + } + + ADC_InjectionConfTypeDef sConfigInjected; /**Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time */ sConfigInjected.InjectedNbrOfConversion = _isset(cs_params->pins[2]) ? 3 : 2; @@ -168,6 +199,9 @@ int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* drive sConfigInjected.InjectedRank = _getADCInjectedRank(channel_no++); sConfigInjected.InjectedChannel = _getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance); +#ifdef SIMPLEFOC_STM32_DEBUG + SIMPLEFOC_DEBUG("STM32-CS: ADC channel: ", (int)STM_PIN_CHANNEL(pinmap_function(PinMap_ADC[i].pin, PinMap_ADC))); +#endif if (HAL_ADCEx_InjectedConfigChannel(&hadc[adc_num], &sConfigInjected) != HAL_OK){ #ifdef SIMPLEFOC_STM32_DEBUG SIMPLEFOC_DEBUG("STM32-CS: ERR: cannot init injected channel: ", (int)_getADCChannel(analogInputToPinName(cs_params->pins[i]), hadc[adc_num].Instance)); diff --git a/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.h b/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.h index fa49d593..d9385680 100644 --- a/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.h +++ b/src/current_sense/hardware_specific/stm32/stm32l4/stm32l4_hal.h @@ -8,9 +8,7 @@ #include "stm32l4xx_hal.h" #include "../stm32_mcu.h" #include "../stm32_adc_utils.h" - -int _adc_init(Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params); -int _adc_gpio_init(Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC); +#include "../stm32_adc_hal.h" #endif