1+ #include " stm32h7_hal.h"
2+
3+ #if defined(STM32H7xx)
4+
5+ // #define SIMPLEFOC_STM32_DEBUG
6+
7+ #include " ../../../../communication/SimpleFOCDebug.h"
8+ #define _TRGO_NOT_AVAILABLE 12345
9+
10+ ADC_HandleTypeDef hadc;
11+
12+ /* *
13+ * Function initializing the ADC and the injected channels for the low-side current sensing
14+ *
15+ * @param cs_params - current sense parameters
16+ * @param driver_params - driver parameters
17+ *
18+ * @return int - 0 if success
19+ */
20+ int _adc_init (Stm32CurrentSenseParams* cs_params, const STM32DriverParams* driver_params)
21+ {
22+ ADC_InjectionConfTypeDef sConfigInjected ;
23+
24+ // check if all pins belong to the same ADC
25+ ADC_TypeDef* adc_pin1 = _isset (cs_params->pins [0 ]) ? (ADC_TypeDef*)pinmap_peripheral (analogInputToPinName (cs_params->pins [0 ]), PinMap_ADC) : nullptr ;
26+ ADC_TypeDef* adc_pin2 = _isset (cs_params->pins [1 ]) ? (ADC_TypeDef*)pinmap_peripheral (analogInputToPinName (cs_params->pins [1 ]), PinMap_ADC) : nullptr ;
27+ ADC_TypeDef* adc_pin3 = _isset (cs_params->pins [2 ]) ? (ADC_TypeDef*)pinmap_peripheral (analogInputToPinName (cs_params->pins [2 ]), PinMap_ADC) : nullptr ;
28+ if ( ((adc_pin1 != adc_pin2) && (adc_pin1 && adc_pin2)) ||
29+ ((adc_pin2 != adc_pin3) && (adc_pin2 && adc_pin3)) ||
30+ ((adc_pin1 != adc_pin3) && (adc_pin1 && adc_pin3))
31+ ){
32+ #ifdef SIMPLEFOC_STM32_DEBUG
33+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: Analog pins dont belong to the same ADC!" );
34+ #endif
35+ return -1 ;
36+ }
37+
38+ /* *Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
39+ */
40+ hadc.Instance = (ADC_TypeDef *)pinmap_peripheral (analogInputToPinName (cs_params->pins [0 ]), PinMap_ADC);
41+
42+ if (hadc.Instance == ADC1) __HAL_RCC_ADC12_CLK_ENABLE ();
43+ #ifdef ADC2 // if defined ADC2
44+ else if (hadc.Instance == ADC2) __HAL_RCC_ADC12_CLK_ENABLE ();
45+ #endif
46+ #ifdef ADC3 // if defined ADC3
47+ else if (hadc.Instance == ADC3) __HAL_RCC_ADC3_CLK_ENABLE ();
48+ #endif
49+ else {
50+ #ifdef SIMPLEFOC_STM32_DEBUG
51+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: Pin does not belong to any ADC!" );
52+ #endif
53+ return -1 ; // error not a valid ADC instance
54+ }
55+
56+ #ifdef SIMPLEFOC_STM32_DEBUG
57+ SIMPLEFOC_DEBUG (" STM32-CS: Using ADC: " , _adcToIndex (&hadc)+1 );
58+ #endif
59+
60+ hadc.Init .ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
61+ hadc.Init .Resolution = ADC_RESOLUTION_12B;
62+ hadc.Init .ScanConvMode = ENABLE;
63+ hadc.Init .ContinuousConvMode = DISABLE;
64+ hadc.Init .DiscontinuousConvMode = DISABLE;
65+ hadc.Init .ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
66+ hadc.Init .ExternalTrigConv = ADC_SOFTWARE_START; // for now
67+ #if defined(ADC_VER_V5_V90)
68+ // only for ADC3
69+ if (hadc.Instance == ADC3){
70+ hadc.Init .DataAlign = ADC3_DATAALIGN_RIGHT;
71+ }
72+ // more info here
73+ // https://github.com/stm32duino/Arduino_Core_STM32/blob/e156c32db24d69cb4818208ccc28894e2f427cfa/system/Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_adc.h#L170C13-L170C27
74+ hadc.Init .DMAContinuousRequests = DISABLE;
75+ // not sure about this one!!! maybe use: ADC_SAMPLING_MODE_NORMAL
76+ hadc.Init .SamplingMode = ADC_SAMPLING_MODE_BULB;
77+ #endif
78+ hadc.Init .NbrOfConversion = 1 ;
79+ hadc.Init .NbrOfDiscConversion = 0 ;
80+ hadc.Init .EOCSelection = ADC_EOC_SINGLE_CONV;
81+
82+ hadc.Init .LowPowerAutoWait = DISABLE;
83+
84+
85+ if ( HAL_ADC_Init (&hadc) != HAL_OK){
86+ #ifdef SIMPLEFOC_STM32_DEBUG
87+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: cannot init ADC!" );
88+ #endif
89+ return -1 ;
90+ }
91+
92+ /* *Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
93+ */
94+ sConfigInjected .InjectedNbrOfConversion = _isset (cs_params->pins [2 ]) ? 3 : 2 ;
95+ // if ADC1 or ADC2
96+ if (hadc.Instance == ADC1 || hadc.Instance == ADC2){
97+ // more info here: https://github.com/stm32duino/Arduino_Core_STM32/blob/e156c32db24d69cb4818208ccc28894e2f427cfa/system/Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_adc.h#L658
98+ sConfigInjected .InjectedSamplingTime = ADC_SAMPLETIME_2CYCLE_5;
99+ }else {
100+ // adc3
101+ // https://github.com/stm32duino/Arduino_Core_STM32/blob/e156c32db24d69cb4818208ccc28894e2f427cfa/system/Drivers/STM32H7xx_HAL_Driver/Inc/stm32h7xx_hal_adc.h#L673
102+ sConfigInjected .InjectedSamplingTime = ADC3_SAMPLETIME_2CYCLES_5;
103+ }
104+ sConfigInjected .ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONV_EDGE_RISINGFALLING;
105+ sConfigInjected .AutoInjectedConv = DISABLE;
106+ sConfigInjected .InjectedDiscontinuousConvMode = DISABLE;
107+ sConfigInjected .InjectedOffset = 0 ;
108+ sConfigInjected .InjectedSingleDiff = ADC_SINGLE_ENDED;
109+ sConfigInjected .InjectedOffsetNumber = ADC_OFFSET_NONE;
110+ sConfigInjected .QueueInjectedContext = DISABLE;
111+ sConfigInjected .InjecOversamplingMode = DISABLE;
112+
113+ // automating TRGO flag finding - hardware specific
114+ uint8_t tim_num = 0 ;
115+ for (size_t i=0 ; i<6 ; i++) {
116+ TIM_HandleTypeDef *timer_to_check = driver_params->timers_handle [tim_num++];
117+ TIM_TypeDef *instance_to_check = timer_to_check->Instance ;
118+
119+ uint32_t trigger_flag = _timerToInjectedTRGO (timer_to_check);
120+ if (trigger_flag == _TRGO_NOT_AVAILABLE) continue ; // timer does not have valid trgo for injected channels
121+
122+ // check if TRGO used already - if yes use the next timer
123+ if ((timer_to_check->Instance ->CR2 & LL_TIM_TRGO_ENABLE) || // if used for timer sync
124+ (timer_to_check->Instance ->CR2 & LL_TIM_TRGO_UPDATE)) // if used for ADC sync
125+ {
126+ continue ;
127+ }
128+
129+ // if the code comes here, it has found the timer available
130+ // timer does have trgo flag for injected channels
131+ sConfigInjected .ExternalTrigInjecConv = trigger_flag;
132+
133+ // this will be the timer with which the ADC will sync
134+ cs_params->timer_handle = timer_to_check;
135+ // done
136+ break ;
137+ }
138+ if ( cs_params->timer_handle == NP ){
139+ // not possible to use these timers for low-side current sense
140+ #ifdef SIMPLEFOC_STM32_DEBUG
141+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: cannot sync any timer to injected channels!" );
142+ #endif
143+ return -1 ;
144+ }else {
145+ #ifdef SIMPLEFOC_STM32_DEBUG
146+ SIMPLEFOC_DEBUG (" STM32-CS: Using timer: " , stm32_getTimerNumber (cs_params->timer_handle ->Instance ));
147+ #endif
148+ }
149+
150+ uint32_t ranks[4 ] = {ADC_INJECTED_RANK_1, ADC_INJECTED_RANK_2, ADC_INJECTED_RANK_3, ADC_INJECTED_RANK_4};
151+ for (int i=0 ; i<3 ; i++){
152+ // skip if not set
153+ if (!_isset (cs_params->pins [i])) continue ;
154+ sConfigInjected .InjectedRank = ranks[i];
155+ sConfigInjected .InjectedChannel = _getADCChannel (analogInputToPinName (cs_params->pins [i]));
156+ if (HAL_ADCEx_InjectedConfigChannel (&hadc, &sConfigInjected ) != HAL_OK){
157+ #ifdef SIMPLEFOC_STM32_DEBUG
158+ SIMPLEFOC_DEBUG (" STM32-CS: ERR: cannot init injected channel: " , (int )_getADCChannel (analogInputToPinName (cs_params->pins [i])) );
159+ #endif
160+ return -1 ;
161+ }
162+ }
163+
164+
165+ delay (1000 );
166+ #ifdef SIMPLEFOC_STM32_ADC_INTERRUPT
167+ // enable interrupt
168+ HAL_NVIC_SetPriority (ADC_IRQn, 0 , 0 );
169+ HAL_NVIC_EnableIRQ (ADC_IRQn);
170+ #endif
171+
172+ cs_params->adc_handle = &hadc;
173+ return 0 ;
174+ }
175+
176+
177+ /* *
178+ * Function to initialize the ADC GPIO pins
179+ *
180+ * @param cs_params current sense parameters
181+ * @param pinA pin number for phase A
182+ * @param pinB pin number for phase B
183+ * @param pinC pin number for phase C
184+ * @return int 0 if success, -1 if error
185+ */
186+ int _adc_gpio_init (Stm32CurrentSenseParams* cs_params, const int pinA, const int pinB, const int pinC)
187+ {
188+ int pins[3 ] = {pinA, pinB, pinC};
189+ const char * port_names[3 ] = {" A" , " B" , " C" };
190+ for (int i=0 ; i<3 ; i++){
191+ if (_isset (pins[i])){
192+ // check if pin is an analog pin
193+ if (pinmap_peripheral (analogInputToPinName (pins[i]), PinMap_ADC) == NP){
194+ #ifdef SIMPLEFOC_STM32_DEBUG
195+ SimpleFOCDebug::print (" STM32-CS: ERR: Pin " );
196+ SimpleFOCDebug::print (port_names[i]);
197+ SimpleFOCDebug::println (" does not belong to any ADC!" );
198+ #endif
199+ return -1 ;
200+ }
201+ pinmap_pinout (analogInputToPinName (pins[i]), PinMap_ADC);
202+ cs_params->pins [i] = pins[i];
203+ }
204+ }
205+ return 0 ;
206+ }
207+
208+ #ifdef SIMPLEFOC_STM32_ADC_INTERRUPT
209+ extern " C" {
210+ void ADC_IRQHandler (void )
211+ {
212+ HAL_ADC_IRQHandler (&hadc);
213+ }
214+ }
215+ #endif
216+
217+ #endif
0 commit comments