11#include " stm32_adc_utils.h"
22#include " stm32_mcu.h"
3+ #include " stm32_adc_hal.h"
34
45#if defined(_STM32_DEF_)
56
7+ #ifdef STM32F1xx
8+ #include " stm32f1xx_ll_adc.h"
9+ #endif
10+ #ifdef STM32F7xx
11+ #include " stm32f7xx_ll_adc.h"
12+ #endif
613
714
15+ extern ADC_HandleTypeDef hadc[];
16+
817int _adcToIndex (ADC_TypeDef *AdcHandle){
918 if (AdcHandle == ADC1) return 0 ;
1019#ifdef ADC2 // if ADC2 exists
@@ -110,14 +119,39 @@ int _findIndexOfLastPinMapADCEntry(int pin) {
110119 return _findIndexOfLastEntry (pinName);
111120}
112121
122+ // find the best ADC for the given pin
123+ // returns the ADC_TypeDef pointer or nullptr if not found
124+ // It returns already configured ADC if possible
125+ // otherwise it returns the first available unconfigured ADC
126+ ADC_TypeDef* _findBestADCForRegularPin (int pin, ADC_HandleTypeDef adc_handles[]) {
127+ PinName pinName = digitalPinToPinName (pin);
128+ int index = _findIndexOfFirstPinMapADCEntry (pin);
129+ int last_index = _findIndexOfLastPinMapADCEntry (pin);
130+ if (index == -1 ) {
131+ return nullptr ;
132+ }
133+ for (int j = index; j <= last_index; j++) {
134+ if (PinMap_ADC[j].pin == NC) {
135+ break ;
136+ }
137+ int adcIndex = _adcToIndex ((ADC_TypeDef*)PinMap_ADC[j].peripheral );
138+ if (adc_handles[adcIndex].Instance != NP) {
139+ // if ADC is already configured, return it
140+ return (ADC_TypeDef*)PinMap_ADC[j].peripheral ;
141+ }
142+ }
143+ // return the first available ADC
144+ return (ADC_TypeDef*)PinMap_ADC[index].peripheral ;
145+ }
146+
113147// find the best ADC combination for the given pins
114148// returns the index of the best ADC
115149// each pin can be connected to multiple ADCs
116150// the function will try to find a single ADC that can be used for all pins
117151// if not possible it will return nullptr
118- ADC_TypeDef* _findBestADCForPins (int numPins, int pins[]) {
152+ ADC_TypeDef* _findBestADCForInjectedPins (int numPins, int pins[], ADC_HandleTypeDef adc_handles []) {
119153
120- // assuning that there is less than 8 ADCs
154+ // assuning that there is at most 5 ADCs
121155 uint8_t pins_at_adc[ADC_COUNT] = {0 };
122156
123157 // check how many pins are there and are not set
@@ -152,11 +186,23 @@ ADC_TypeDef* _findBestADCForPins(int numPins, int pins[]) {
152186 SimpleFOCDebug::print (i+1 );
153187 SimpleFOCDebug::print (" pins: " );
154188 SimpleFOCDebug::println (pins_at_adc[i]);
189+ if (adc_handles[i].Instance != NP) {
190+ // check if ADC injeted is already in use
191+ if (!LL_ADC_INJ_IsTriggerSourceSWStart (adc_handles[i].Instance )) {
192+ SimpleFOCDebug::print (" STM32-CS: ADC" );
193+ SimpleFOCDebug::print (i+1 );
194+ SimpleFOCDebug::println (" already in use for injected channels!" );
195+ }
196+ }
155197 }
156198#endif
157199
158200 // now take the first ADC that has all pins connected
159201 for (int i = 0 ; i < ADC_COUNT; i++) {
202+ if (adc_handles[i].Instance != NP) {
203+ if (!LL_ADC_INJ_IsTriggerSourceSWStart (adc_handles[i].Instance ))
204+ continue ; // ADC already in use for injected
205+ }
160206 if (pins_at_adc[i] == no_pins) {
161207 return _indexToADC (i);
162208 }
@@ -363,7 +409,6 @@ uint32_t _getADCChannel(PinName pin, ADC_TypeDef *AdcHandle )
363409 for (int i = first_ind; i <= last_ind; i++) {
364410 if (PinMap_ADC[i].peripheral == AdcHandle) {
365411 channel =_getADCChannelFromPinMap (PinMap_ADC[i].pin );
366- SIMPLEFOC_DEBUG (" STM32-CS: ADC channel: " , (int )STM_PIN_CHANNEL (pinmap_function (PinMap_ADC[i].pin , PinMap_ADC)));
367412 break ;
368413 }
369414 }
@@ -494,4 +539,134 @@ float _readADCInjectedChannelVoltage(int pin, void* cs_params, Stm32AdcInterrupt
494539 #endif
495540}
496541
542+
543+
544+ int last_pin[ADC_COUNT] = {-1 ,-1 ,-1 ,-1 ,-1 };
545+ uint32_t last_channel[ADC_COUNT] = {0 ,0 ,0 ,0 ,0 };
546+
547+ /* *
548+ * Read a regular ADC channel while injected channels are running for current sensing.
549+ *
550+ * This function performs a one-shot regular conversion on the same ADC that is being
551+ * used for injected current sensing. Injected conversions have hardware priority and
552+ * will pre-empt regular conversions, so this function may experience some latency.
553+ *
554+ * The function will retry a few times if the ADC returns HAL_BUSY, making it suitable
555+ * for reading auxiliary sensors (temperature, voltage, potentiometers, etc.) while
556+ * motor control is active.
557+ *
558+ * @param pin - Arduino pin number to read (must be on the same ADC as current sensing)
559+ * @return float - Voltage reading in volts, or -1.0f on error
560+ */
561+ float _readRegularADCVoltage (const int pin){
562+
563+ ADC_HandleTypeDef* hadc = _get_adc_handles ();
564+
565+ int adc_index = NOT_SET;
566+ for (int i = 0 ; i < ADC_COUNT; i++){
567+ if (last_pin[i] == pin){
568+ adc_index = i;
569+ break ;
570+ }
571+ }
572+ // avoid re-configuring the channel if reading the same pin as last time
573+ if (!_isset (adc_index)){
574+ ADC_TypeDef* adc_instance = _findBestADCForRegularPin (pin, hadc);
575+ if (adc_instance == NP){
576+ #ifdef SIMPLEFOC_STM32_DEBUG
577+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: Pin does not belong to any ADC!" );
578+ #endif
579+ return -1 .0f ;
580+ }
581+ adc_index = _adcToIndex (adc_instance);
582+
583+ ADC_HandleTypeDef adc_handle = hadc[adc_index];
584+ if (adc_handle.Instance == NP) {
585+ #ifdef SIMPLEFOC_STM32_DEBUG
586+ SIMPLEFOC_DEBUG (" STM32-CS: WARN: ADC not configured, need to configure it: ADC" , adc_index+1 );
587+ #endif
588+ if (_adc_init_regular (adc_instance) != 0 ){
589+ #ifdef SIMPLEFOC_STM32_DEBUG
590+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: Failed to initialize ADC for pin " , pin);
591+ #endif
592+ return -1 .0f ;
593+ }
594+ }
595+
596+
597+ last_pin[adc_index] = pin;
598+ // Configure the regular channel for this pin
599+ PinName pinName = analogInputToPinName (pin);
600+ uint32_t channel = _getADCChannel (pinName, adc_instance);
601+
602+ last_channel[adc_index] = channel;
603+ }
604+
605+
606+ ADC_ChannelConfTypeDef sConfig = {0 };
607+ sConfig .Channel = last_channel[adc_index];
608+ // the shortes possible sampling time
609+ // this seems to be a constant in HAL - the shortest time enum is equal to 0
610+ // G4 - 2.5 cycles
611+ // F1, H7 - 1.5 cycles
612+ // L4 - 2.5 cycles
613+ // F4, F7 - 3 cycles
614+ sConfig .SamplingTime = 0 ;
615+
616+ #ifdef ADC_REGULAR_RANK_1
617+ sConfig .Rank = ADC_REGULAR_RANK_1;
618+ #else
619+ sConfig .Rank = 1 ;
620+ #endif
621+ #ifdef ADC_SINGLE_ENDED
622+ sConfig .SingleDiff = ADC_SINGLE_ENDED;
623+ #endif
624+ #ifdef ADC_OFFSET_NONE
625+ sConfig .OffsetNumber = ADC_OFFSET_NONE;
626+ #endif
627+ #ifndef STM32F1xx
628+ sConfig .Offset = 0 ;
629+ #endif
630+
631+ if (HAL_ADC_ConfigChannel (&hadc[adc_index], &sConfig ) != HAL_OK) {
632+ #ifdef SIMPLEFOC_STM32_DEBUG
633+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: Failed to configure regular channel" );
634+ #endif
635+ return -1 .0f ;
636+ }
637+
638+ // Try to start conversion, with retries for HAL_BUSY
639+ // (ADC may be busy with injected conversion)
640+ HAL_StatusTypeDef status;
641+ int retries = 5 ;
642+
643+ do {
644+ status = HAL_ADC_Start (&hadc[adc_index]);
645+ if (status == HAL_BUSY) {
646+ // Wait a bit for injected conversion to complete
647+ delayMicroseconds (1 );
648+ retries--;
649+ }
650+ } while (status == HAL_BUSY && retries > 0 );
651+
652+ if (status != HAL_OK) {
653+ #ifdef SIMPLEFOC_STM32_DEBUG
654+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: ADC busy or failed to start" );
655+ #endif
656+ return -1 .0f ;
657+ }
658+
659+ // Wait for conversion to complete
660+ // Timeout of 1ms should be more than enough
661+ if (HAL_ADC_PollForConversion (&hadc[adc_index], 1 ) == HAL_OK) {
662+ uint32_t raw = HAL_ADC_GetValue (&hadc[adc_index]);
663+ return raw * 3 .3f / 4096 .0f ; // assuming 12-bit ADC and 3.3V reference
664+ }
665+
666+ #ifdef SIMPLEFOC_STM32_DEBUG
667+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: Regular conversion timeout" );
668+ #endif
669+ return -1 .0f ;
670+ }
671+
497672#endif
0 commit comments