SimpleFOClibrary 2.4.0
Loading...
Searching...
No Matches
drivers/hardware_specific/stm32/stm32_mcu.cpp
Go to the documentation of this file.
1
2#include "../../hardware_api.h"
3#include "./stm32_mcu.h"
6
7#if defined(_STM32_DEF_) || defined(TARGET_STM32H7) // if stm32duino or portenta
8
9#pragma message("")
10#pragma message("SimpleFOC: compiling for STM32")
11#pragma message("")
12
13
14/*
15 * Timer management
16 * SimpleFOC manages the timers using only STM32 HAL and LL APIs, and does not use the HardwareTimer API.
17 * This is because the HardwareTimer API is not available on all STM32 boards, and does not provide all
18 * the functionality that SimpleFOC requires anyway.
19 * By using the HAL and LL APIs directly, we can ensure that SimpleFOC works on all STM32 boards, specifically
20 * also those that use MBED with Arduino (Portenta H7, Giga, Nicla).
21 *
22 * When using stm32duino, the HardwareTimer API is available, and can be used in parallel with SimpleFOC,
23 * provided you don't use the same timers for both.
24 */
25
26// track timers initialized via SimpleFOC
27int numTimersUsed = 0;
28TIM_HandleTypeDef* timersUsed[SIMPLEFOC_STM32_MAX_TIMERSUSED];
29
30// reserve timers for other uses, so SimpleFOC doesn't use them for motors
31int numTimersReserved = 0;
32TIM_TypeDef* reservedTimers[SIMPLEFOC_STM32_MAX_TIMERSRESERVED];
33
34// track drivers initialized via SimpleFOC - used to know which timer channels are used
35int numMotorsUsed = 0;
36STM32DriverParams* motorsUsed[SIMPLEFOC_STM32_MAX_MOTORSUSED];
37
38// query functions to check which timers are used
39int stm32_getNumTimersUsed() {
40 return numTimersUsed;
41}
42int stm32_getNumMotorsUsed() {
43 return numMotorsUsed;
44}
45int stm32_getNumTimersReserved() {
46 return numTimersReserved;
47}
48bool stm32_isTimerReserved(TIM_TypeDef* timer) {
49 for (int i=0; i<numTimersReserved; i++) {
50 if (reservedTimers[i] == timer)
51 return true;
52 }
53 return false;
54}
55bool stm32_isTimerUsed(TIM_HandleTypeDef* timer) {
56 for (int i=0; i<numTimersUsed; i++) {
57 if (timersUsed[i] == timer)
58 return true;
59 }
60 return false;
61}
62STM32DriverParams* stm32_getMotorUsed(int index) {
63 return motorsUsed[index];
64}
65bool stm32_isChannelUsed(PinMap* pin) {
66 if (stm32_isTimerReserved((TIM_TypeDef*)pin->peripheral)) {
67 return true;
68 }
69 for (int i=0; i<numMotorsUsed; i++) {
70 for (int j=0; j<6; j++) {
71 if (motorsUsed[i]->timers_handle[j] == NULL) break;
72 if (motorsUsed[i]->channels[j] == STM_PIN_CHANNEL(pin->function) && ((TIM_TypeDef*)pin->peripheral) == motorsUsed[i]->timers_handle[j]->Instance)
73 return true;
74 }
75 }
76 return false;
77}
78TIM_HandleTypeDef* stm32_getTimer(PinMap* timer) {
79 for (int i=0; i<numTimersUsed; i++) {
80 if (timersUsed[i]->Instance == (TIM_TypeDef*)timer->peripheral)
81 return timersUsed[i];
82 }
83 return NULL;
84}
85bool stm32_reserveTimer(TIM_TypeDef* timer) {
86 if (numTimersReserved >= SIMPLEFOC_STM32_MAX_TIMERSRESERVED) {
87 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many timers reserved");
88 return false;
89 }
90 reservedTimers[numTimersReserved++] = timer;
91 return true;
92}
93// function to get a timer handle given the pinmap entry of the pin you want to use
94// after calling this function, the timer is marked as used by SimpleFOC
95TIM_HandleTypeDef* stm32_useTimer(PinMap* timer) {
96 TIM_HandleTypeDef* handle = stm32_getTimer(timer);
97 if (handle != NULL) return handle;
98 if (numTimersUsed >= SIMPLEFOC_STM32_MAX_TIMERSUSED) {
99 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many timers used");
100 return NULL;
101 }
102 if (stm32_isTimerReserved((TIM_TypeDef*)timer->peripheral)) {
103 SIMPLEFOC_DEBUG("STM32-DRV: ERR: timer reserved");
104 return NULL;
105 }
106 handle = new TIM_HandleTypeDef();
107 handle->Instance = (TIM_TypeDef*)timer->peripheral;
108 handle->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
109 handle->Lock = HAL_UNLOCKED;
110 handle->State = HAL_TIM_STATE_RESET;
111 handle->hdma[0] = NULL;
112 handle->hdma[1] = NULL;
113 handle->hdma[2] = NULL;
114 handle->hdma[3] = NULL;
115 handle->hdma[4] = NULL;
116 handle->hdma[5] = NULL;
117 handle->hdma[6] = NULL;
118 handle->Init.Prescaler = 0;
119 handle->Init.Period = ((1 << 16) - 1);
120 handle->Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED2;
121 handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
122 handle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
123 #if defined(TIM_RCR_REP)
124 handle->Init.RepetitionCounter = 1;
125 #endif
126 enableTimerClock(handle);
127 HAL_TIM_Base_Init(handle);
128 stm32_pauseTimer(handle);
129 timersUsed[numTimersUsed++] = handle;
130 return handle;
131}
132
133
134
135
136bool _getPwmState(void* params) {
137 // assume timers are synchronized and that there's at least one timer
138 bool dir = __HAL_TIM_IS_TIM_COUNTING_DOWN(((STM32DriverParams*)params)->timers_handle[0]);
139 return dir;
140}
141
142
143
144
145void stm32_pause(STM32DriverParams* params) {
146 if (params->master_timer != NULL) {
147 stm32_pauseTimer(params->master_timer);
148 }
149 else {
150 for (int i=0; i<params->num_timers; i++) {
151 stm32_pauseTimer(params->timers_handle[i]);
152 }
153 }
154}
155
156
157
158void stm32_resume(STM32DriverParams* params) {
159 if (params->master_timer != NULL) {
160 stm32_resumeTimer(params->master_timer);
161 }
162 else {
163 for (int i=0; i<params->num_timers; i++) {
164 stm32_resumeTimer(params->timers_handle[i]);
165 }
166 }
167}
168
169
170
171// init pin pwm
172TIM_HandleTypeDef* stm32_initPinPWM(uint32_t PWM_freq, PinMap* timer, uint32_t mode = TIM_OCMODE_PWM1, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t Npolarity = TIM_OCNPOLARITY_HIGH) {
173 // sanity check
174 if (timer==NULL)
175 return NULL;
176 TIM_HandleTypeDef* handle = stm32_getTimer(timer);
177 uint32_t channel = STM_PIN_CHANNEL(timer->function);
178 if (handle==NULL) {
179 handle = stm32_useTimer(timer);
180 #if defined(SIMPLEFOC_STM32_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
181 SIMPLEFOC_DEBUG("STM32-DRV: Initializing TIM", (int)stm32_getTimerNumber(handle->Instance));
182 #endif
183 uint32_t arr = stm32_setClockAndARR(handle, PWM_freq);
184 if (arr<SIMPLEFOC_STM32_MIN_RESOLUTION) {
185 SIMPLEFOC_DEBUG("STM32-DRV: WARN timer resolution too low (<8bit): ", (int)arr+1);
186 }
187 else {
188 #if defined(SIMPLEFOC_STM32_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
189 SIMPLEFOC_DEBUG("STM32-DRV: Timer resolution set to: ", (int)arr+1);
190 #endif
191 }
192 }
193 TIM_OC_InitTypeDef channelOC;
194 channelOC.OCMode = mode;
195 channelOC.Pulse = 0; //__HAL_TIM_GET_COMPARE(handle, channel);
196 channelOC.OCPolarity = polarity;
197 channelOC.OCFastMode = TIM_OCFAST_DISABLE;
198#if defined(TIM_CR2_OIS1)
199 channelOC.OCIdleState = TIM_OCIDLESTATE_RESET; //(polarity==TIM_OCPOLARITY_HIGH)?TIM_OCIDLESTATE_RESET:TIM_OCIDLESTATE_SET;
200#endif
201#if defined(TIM_CCER_CC1NE)
202 channelOC.OCNPolarity = Npolarity;
203#if defined(TIM_CR2_OIS1)
204 channelOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; //(Npolarity==TIM_OCNPOLARITY_HIGH)?TIM_OCNIDLESTATE_RESET:TIM_OCNIDLESTATE_SET;
205#endif
206#endif
207 HAL_TIM_PWM_ConfigChannel(handle, &channelOC, stm32_getHALChannel(channel));
208 pinmap_pinout(timer->pin, PinMap_TIM);
209 LL_TIM_CC_EnableChannel(handle->Instance, stm32_getLLChannel(timer));
210 if (IS_TIM_BREAK_INSTANCE(handle->Instance)) {
211 __HAL_TIM_MOE_ENABLE(handle);
212 }
213 #if defined(SIMPLEFOC_STM32_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
214 SimpleFOCDebug::print("STM32-DRV: Configured TIM");
215 SimpleFOCDebug::print((int)stm32_getTimerNumber(handle->Instance));
216 SIMPLEFOC_DEBUG("_CH", (int)channel);
217 #endif
218 return handle;
219}
220
221
222
223
224
225
226/**
2270110: PWM mode 1 - In upcounting, channel 1 is active as long as TIMx_CNT<TIMx_CCR1
228else inactive. In downcounting, channel 1 is inactive (OC1REF=‘0’) as long as
229TIMx_CNT>TIMx_CCR1 else active (OC1REF=’1’).
2300111: PWM mode 2 - In upcounting, channel 1 is inactive as long as
231TIMx_CNT<TIMx_CCR1 else active. In downcounting, channel 1 is active as long as
232TIMx_CNT>TIMx_CCR1 else inactive
233 */
234// init high side pin
235TIM_HandleTypeDef* _stm32_initPinPWMHigh(uint32_t PWM_freq, PinMap* timer) {
236 uint32_t polarity = SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH ? TIM_OCPOLARITY_HIGH : TIM_OCPOLARITY_LOW ;
237 TIM_HandleTypeDef* handle = stm32_initPinPWM(PWM_freq, timer, TIM_OCMODE_PWM1, polarity);
238 LL_TIM_OC_EnablePreload(handle->Instance, stm32_getLLChannel(timer));
239 return handle;
240}
241
242// init low side pin
243TIM_HandleTypeDef* _stm32_initPinPWMLow(uint32_t PWM_freq, PinMap* timer) {
244 uint32_t polarity = SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH ? TIM_OCPOLARITY_HIGH : TIM_OCPOLARITY_LOW;
245 TIM_HandleTypeDef* handle = stm32_initPinPWM(PWM_freq, timer, TIM_OCMODE_PWM2, polarity);
246 LL_TIM_OC_EnablePreload(handle->Instance, stm32_getLLChannel(timer));
247 return handle;
248}
249
250
251
252
253
254
255// // align the timers to end the init
256// void _startTimers(TIM_HandleTypeDef *timers_to_start[], int timer_num) {
257// stm32_alignTimers(timers_to_start, timer_num);
258// }
259
260// void _stopTimers(TIM_HandleTypeDef **timers_to_stop, int timer_num) {
261// TIM_HandleTypeDef* timers_distinct[6];
262// timer_num = stm32_distinctTimers(timers_to_stop, timer_num, timers_distinct);
263// for (int i=0; i < timer_num; i++) {
264// if(timers_distinct[i] == NULL) return;
265// stm32_pauseTimer(timers_distinct[i]);
266// stm32_refreshTimer(timers_distinct[i]);
267// #ifdef SIMPLEFOC_STM32_DEBUG
268// SIMPLEFOC_DEBUG("STM32-DRV: Stopping timer ", stm32_getTimerNumber(timers_distinct[i]->Instance));
269// #endif
270// }
271// }
272
273
274
275
276
277
278// Basically a sanity check to avoid complex scenarios where the user is using the same timers for multiple purposes.
279int stm32_checkTimerFrequency(long pwm_frequency, TIM_HandleTypeDef *timers[], uint8_t num_timers){
280 TIM_HandleTypeDef* timers_distinct[6];
281 uint8_t timer_num = stm32_distinctTimers(timers, num_timers, timers_distinct);
282 float common_pwm_freq = 0.0f;
283 for (int i=0; i<timer_num; i++) {
284 uint32_t freq = stm32_getTimerClockFreq(timers_distinct[i]);
285 uint32_t arr = timers_distinct[i]->Instance->ARR;
286 uint32_t prescaler = timers_distinct[i]->Instance->PSC;
287 float pwm_freq = (float)freq/(prescaler+1.0f)/(arr+1.0f)/2.0f;
288 if (i==0) {
289 common_pwm_freq = pwm_freq;
290 } else {
291 if (pwm_freq != common_pwm_freq) {
292 #if defined(SIMPLEFOC_STM32_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
293 SimpleFOCDebug::print("STM32-DRV: ERR: Timer frequency different: TIM");
294 SimpleFOCDebug::print(stm32_getTimerNumber(timers_distinct[0]->Instance));
295 SimpleFOCDebug::print(" freq: ");
296 SimpleFOCDebug::print(common_pwm_freq);
297 SimpleFOCDebug::print(" != TIM");
298 SimpleFOCDebug::print(stm32_getTimerNumber(timers_distinct[i]->Instance));
299 SimpleFOCDebug::println(" freq: ", pwm_freq);
300 #endif
301 return -1;
302 }
303 }
304 }
305 if ( (common_pwm_freq - (float)pwm_frequency) > 1.0f) {
306 #if defined(SIMPLEFOC_STM32_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
307 SIMPLEFOC_DEBUG("STM32-DRV: ERR: Common timer frequency unexpected: ", common_pwm_freq);
308 #endif
309 return -1;
310 }
311 return 0;
312}
313
314
315// configure hardware 6pwm for a complementary pair of channels
316STM32DriverParams* _stm32_initHardware6PWMPair(long PWM_freq, float dead_zone, PinMap* pinH, PinMap* pinL, STM32DriverParams* params, int paramsPos) {
317 // sanity check
318 if (pinH==NULL || pinL==NULL)
319 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
320#if defined(STM32L0xx) // L0 boards dont have hardware 6pwm interface
321 return SIMPLEFOC_DRIVER_INIT_FAILED; // return nothing
322#endif
323
324 uint32_t channel1 = STM_PIN_CHANNEL(pinH->function);
325 uint32_t channel2 = STM_PIN_CHANNEL(pinL->function);
326
327 // more sanity check
328 if (channel1!=channel2 || pinH->peripheral!=pinL->peripheral)
329 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
330
331 uint32_t polarity = SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH ? TIM_OCPOLARITY_HIGH : TIM_OCPOLARITY_LOW;
332 uint32_t Npolarity = SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH ? TIM_OCNPOLARITY_HIGH : TIM_OCNPOLARITY_LOW;
333 TIM_HandleTypeDef* handle = stm32_initPinPWM(PWM_freq, pinH, TIM_OCMODE_PWM1, polarity, Npolarity);
334 pinmap_pinout(pinL->pin, PinMap_TIM); // also init the low side pin
335
336 // dead time is set in nanoseconds
337 uint32_t dead_time_ns = (float)(1e9f/PWM_freq)*dead_zone;
338 uint32_t dead_time = __LL_TIM_CALC_DEADTIME(stm32_getTimerClockFreq(handle), LL_TIM_GetClockDivision(handle->Instance), dead_time_ns);
339 if (dead_time>255) dead_time = 255;
340 if (dead_time==0 && dead_zone>0) {
341 dead_time = 255; // LL_TIM_CALC_DEADTIME returns 0 if dead_time_ns is too large
342 SIMPLEFOC_DEBUG("STM32-DRV: WARN: dead time too large, setting to max");
343 }
344 // make sure timer output goes to LOW when timer channels are temporarily disabled
345 // TODO why init this here, and not generally in the initPWM or init timer functions?
346 // or, since its a rather specialized and hardware-speific setting, why not move it to
347 // another function?
348 LL_TIM_SetOffStates(handle->Instance, LL_TIM_OSSI_DISABLE, LL_TIM_OSSR_ENABLE);
349 LL_TIM_OC_SetDeadTime(handle->Instance, dead_time); // deadtime is non linear!
350 LL_TIM_CC_EnableChannel(handle->Instance, stm32_getLLChannel(pinH) | stm32_getLLChannel(pinL));
351 params->timers_handle[paramsPos] = handle;
352 params->timers_handle[paramsPos+1] = handle;
353 params->channels[paramsPos] = channel1;
354 params->channels[paramsPos+1] = channel2;
355 params->llchannels[paramsPos] = stm32_getLLChannel(pinH);
356 params->llchannels[paramsPos+1] = stm32_getLLChannel(pinL);
357 return params;
358}
359
360
361
362
363STM32DriverParams* _stm32_initHardware6PWMInterface(long PWM_freq, float dead_zone, PinMap* pinA_h, PinMap* pinA_l, PinMap* pinB_h, PinMap* pinB_l, PinMap* pinC_h, PinMap* pinC_l) {
364 STM32DriverParams* params = new STM32DriverParams {
365 .timers_handle = { NULL, NULL, NULL, NULL, NULL, NULL },
366 .channels = { 0, 0, 0, 0, 0, 0 },
367 .llchannels = { 0, 0, 0, 0, 0, 0 },
368 .pwm_frequency = PWM_freq,
369 .num_timers = 0,
370 .master_timer = NULL,
371 .dead_zone = dead_zone,
372 .interface_type = _HARDWARE_6PWM
373 };
374 if (_stm32_initHardware6PWMPair(PWM_freq, dead_zone, pinA_h, pinA_l, params, 0) == SIMPLEFOC_DRIVER_INIT_FAILED)
375 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
376 if(_stm32_initHardware6PWMPair(PWM_freq, dead_zone, pinB_h, pinB_l, params, 2) == SIMPLEFOC_DRIVER_INIT_FAILED)
377 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
378 if (_stm32_initHardware6PWMPair(PWM_freq, dead_zone, pinC_h, pinC_l, params, 4) == SIMPLEFOC_DRIVER_INIT_FAILED)
379 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
380 params->num_timers = stm32_countTimers(params->timers_handle, 6);
381 return params;
382}
383
384
385
386
387
388
389void* _configure1PWM(long pwm_frequency, const int pinA) {
390 if (numMotorsUsed+1 > SIMPLEFOC_STM32_MAX_MOTORSUSED) {
391 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many drivers used");
392 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
393 }
394
395 if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = SIMPLEFOC_STM32_PWM_FREQUENCY; // default frequency 25khz
396
397 int pins[1] = { pinA };
398 PinMap* pinTimers[1] = { NULL };
399 if (stm32_findBestTimerCombination(1, pins, pinTimers)<0)
400 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
401
402 TIM_HandleTypeDef* HT1 = stm32_initPinPWM(pwm_frequency, pinTimers[0], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
403 uint32_t channel1 = STM_PIN_CHANNEL(pinTimers[0]->function);
404
405 STM32DriverParams* params = new STM32DriverParams {
406 .timers_handle = { HT1 },
407 .channels = { channel1 },
408 .llchannels = { stm32_getLLChannel(pinTimers[0]) },
409 .pwm_frequency = pwm_frequency,
410 .num_timers = 1,
411 .master_timer = NULL
412 };
413 // align the timers (in this case, just start them)
414 params->master_timer = stm32_alignTimers(params->timers_handle, 1);
415 motorsUsed[numMotorsUsed++] = params;
416 return params;
417}
418
419
420
421
422
423// function setting the high pwm frequency to the supplied pins
424// - Stepper motor - 2PWM setting
425// - hardware speciffic
426void* _configure2PWM(long pwm_frequency, const int pinA, const int pinB) {
427 if (numMotorsUsed+1 > SIMPLEFOC_STM32_MAX_MOTORSUSED) {
428 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many drivers used");
429 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
430 }
431
432 if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = SIMPLEFOC_STM32_PWM_FREQUENCY; // default frequency 25khz
433
434 int pins[2] = { pinA, pinB };
435 PinMap* pinTimers[2] = { NULL, NULL };
436 if (stm32_findBestTimerCombination(2, pins, pinTimers)<0)
437 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
438
439 TIM_HandleTypeDef* HT1 = stm32_initPinPWM(pwm_frequency, pinTimers[0], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
440 TIM_HandleTypeDef* HT2 = stm32_initPinPWM(pwm_frequency, pinTimers[1], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
441 TIM_HandleTypeDef *timers[2] = {HT1, HT2};
442 stm32_checkTimerFrequency(pwm_frequency, timers, 2);
443
444 uint32_t channel1 = STM_PIN_CHANNEL(pinTimers[0]->function);
445 uint32_t channel2 = STM_PIN_CHANNEL(pinTimers[1]->function);
446
447 STM32DriverParams* params = new STM32DriverParams {
448 .timers_handle = { HT1, HT2 },
449 .channels = { channel1, channel2 },
450 .llchannels = { stm32_getLLChannel(pinTimers[0]), stm32_getLLChannel(pinTimers[1]) },
451 .pwm_frequency = pwm_frequency, // TODO set to actual frequency
452 .num_timers = stm32_countTimers(timers, 2),
453 .master_timer = NULL
454 };
455 // align the timers
456 params->master_timer = stm32_alignTimers(timers, 2);
457 motorsUsed[numMotorsUsed++] = params;
458 return params;
459}
460
461
462
463
464// function setting the high pwm frequency to the supplied pins
465// - BLDC motor - 3PWM setting
466// - hardware speciffic
467void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC) {
468 if (numMotorsUsed+1 > SIMPLEFOC_STM32_MAX_MOTORSUSED) {
469 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many drivers used");
470 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
471 }
472 if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = SIMPLEFOC_STM32_PWM_FREQUENCY; // default frequency 25khz
473
474 int pins[3] = { pinA, pinB, pinC };
475 PinMap* pinTimers[3] = { NULL, NULL, NULL };
476 if (stm32_findBestTimerCombination(3, pins, pinTimers)<0)
477 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
478
479 TIM_HandleTypeDef* HT1 = stm32_initPinPWM(pwm_frequency, pinTimers[0], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
480 TIM_HandleTypeDef* HT2 = stm32_initPinPWM(pwm_frequency, pinTimers[1], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
481 TIM_HandleTypeDef* HT3 = stm32_initPinPWM(pwm_frequency, pinTimers[2], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
482
483 TIM_HandleTypeDef *timers[3] = {HT1, HT2, HT3};
484 stm32_checkTimerFrequency(pwm_frequency, timers, 3);
485
486 uint32_t channel1 = STM_PIN_CHANNEL(pinTimers[0]->function);
487 uint32_t channel2 = STM_PIN_CHANNEL(pinTimers[1]->function);
488 uint32_t channel3 = STM_PIN_CHANNEL(pinTimers[2]->function);
489
490 STM32DriverParams* params = new STM32DriverParams {
491 .timers_handle = { HT1, HT2, HT3 },
492 .channels = { channel1, channel2, channel3 },
493 .llchannels = { stm32_getLLChannel(pinTimers[0]), stm32_getLLChannel(pinTimers[1]), stm32_getLLChannel(pinTimers[2]) },
494 .pwm_frequency = pwm_frequency,
495 .num_timers = stm32_countTimers(timers, 3),
496 .master_timer = NULL
497 };
498 params->master_timer = stm32_alignTimers(timers, 3);
499 motorsUsed[numMotorsUsed++] = params;
500 return params;
501}
502
503
504
505// function setting the high pwm frequency to the supplied pins
506// - Stepper motor - 4PWM setting
507// - hardware speciffic
508void* _configure4PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC, const int pinD) {
509 if (numMotorsUsed+1 > SIMPLEFOC_STM32_MAX_MOTORSUSED) {
510 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many drivers used");
511 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
512 }
513 if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = SIMPLEFOC_STM32_PWM_FREQUENCY; // default frequency 25khz
514
515 int pins[4] = { pinA, pinB, pinC, pinD };
516 PinMap* pinTimers[4] = { NULL, NULL, NULL, NULL };
517 if (stm32_findBestTimerCombination(4, pins, pinTimers)<0)
518 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
519
520 TIM_HandleTypeDef* HT1 = stm32_initPinPWM(pwm_frequency, pinTimers[0], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
521 TIM_HandleTypeDef* HT2 = stm32_initPinPWM(pwm_frequency, pinTimers[1], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
522 TIM_HandleTypeDef* HT3 = stm32_initPinPWM(pwm_frequency, pinTimers[2], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
523 TIM_HandleTypeDef* HT4 = stm32_initPinPWM(pwm_frequency, pinTimers[3], TIM_OCMODE_PWM1, (SIMPLEFOC_PWM_ACTIVE_HIGH)?TIM_OCPOLARITY_HIGH:TIM_OCPOLARITY_LOW);
524 TIM_HandleTypeDef *timers[4] = {HT1, HT2, HT3, HT4};
525 stm32_checkTimerFrequency(pwm_frequency, timers, 4);
526
527 uint32_t channel1 = STM_PIN_CHANNEL(pinTimers[0]->function);
528 uint32_t channel2 = STM_PIN_CHANNEL(pinTimers[1]->function);
529 uint32_t channel3 = STM_PIN_CHANNEL(pinTimers[2]->function);
530 uint32_t channel4 = STM_PIN_CHANNEL(pinTimers[3]->function);
531
532 STM32DriverParams* params = new STM32DriverParams {
533 .timers_handle = { HT1, HT2, HT3, HT4 },
534 .channels = { channel1, channel2, channel3, channel4 },
535 .llchannels = { stm32_getLLChannel(pinTimers[0]), stm32_getLLChannel(pinTimers[1]), stm32_getLLChannel(pinTimers[2]), stm32_getLLChannel(pinTimers[3]) },
536 .pwm_frequency = pwm_frequency,
537 .num_timers = stm32_countTimers(timers, 4),
538 .master_timer = NULL
539 };
540 params->master_timer = stm32_alignTimers(timers, 4);
541 motorsUsed[numMotorsUsed++] = params;
542 return params;
543}
544
545
546
547// function setting the pwm duty cycle to the hardware
548// - DC motor - 1PWM setting
549// - hardware specific
550void _writeDutyCycle1PWM(float dc_a, void* params){
551 uint32_t duty = dc_a*(((STM32DriverParams*)params)->timers_handle[0]->Instance->ARR+1);
552 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], duty);
553}
554
555
556
557// function setting the pwm duty cycle to the hardware
558// - Stepper motor - 2PWM setting
559//- hardware specific
560void _writeDutyCycle2PWM(float dc_a, float dc_b, void* params){
561 uint32_t duty1 = dc_a*(((STM32DriverParams*)params)->timers_handle[0]->Instance->ARR+1);
562 uint32_t duty2 = dc_b*(((STM32DriverParams*)params)->timers_handle[1]->Instance->ARR+1);
563 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
564 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], duty1);
565 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[1], ((STM32DriverParams*)params)->channels[1], duty2);
566 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
567}
568
569// function setting the pwm duty cycle to the hardware
570// - BLDC motor - 3PWM setting
571//- hardware specific
572void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* params){
573 uint32_t duty1 = dc_a*(((STM32DriverParams*)params)->timers_handle[0]->Instance->ARR+1);
574 uint32_t duty2 = dc_b*(((STM32DriverParams*)params)->timers_handle[1]->Instance->ARR+1);
575 uint32_t duty3 = dc_c*(((STM32DriverParams*)params)->timers_handle[2]->Instance->ARR+1);
576 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
577 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], duty1);
578 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[1], ((STM32DriverParams*)params)->channels[1], duty2);
579 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[2], ((STM32DriverParams*)params)->channels[2], duty3);
580 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
581}
582
583
584// function setting the pwm duty cycle to the hardware
585// - Stepper motor - 4PWM setting
586//- hardware specific
587void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, void* params){
588 uint32_t duty1 = dc_1a*(((STM32DriverParams*)params)->timers_handle[0]->Instance->ARR+1);
589 uint32_t duty2 = dc_1b*(((STM32DriverParams*)params)->timers_handle[1]->Instance->ARR+1);
590 uint32_t duty3 = dc_2a*(((STM32DriverParams*)params)->timers_handle[2]->Instance->ARR+1);
591 uint32_t duty4 = dc_2b*(((STM32DriverParams*)params)->timers_handle[3]->Instance->ARR+1);
592 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
593 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], duty1);
594 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[1], ((STM32DriverParams*)params)->channels[1], duty2);
595 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[2], ((STM32DriverParams*)params)->channels[2], duty3);
596 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[3], ((STM32DriverParams*)params)->channels[3], duty4);
597 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
598}
599
600
601
602
603// Configuring PWM frequency, resolution and alignment
604// - BLDC driver - 6PWM setting
605// - hardware specific
606void* _configure6PWM(long pwm_frequency, float dead_zone, const int pinA_h, const int pinA_l, const int pinB_h, const int pinB_l, const int pinC_h, const int pinC_l){
607 if (numMotorsUsed+1 > SIMPLEFOC_STM32_MAX_MOTORSUSED) {
608 SIMPLEFOC_DEBUG("STM32-DRV: ERR: too many drivers used");
609 return (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
610 }
611 if( !pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = SIMPLEFOC_STM32_PWM_FREQUENCY; // default frequency 25khz
612
613 // find configuration
614 int pins[6] = { pinA_h, pinA_l, pinB_h, pinB_l, pinC_h, pinC_l };
615 PinMap* pinTimers[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
616 int score = stm32_findBestTimerCombination(6, pins, pinTimers);
617
618 STM32DriverParams* params;
619 // configure accordingly
620 if (score<0)
621 params = (STM32DriverParams*)SIMPLEFOC_DRIVER_INIT_FAILED;
622 else if (score<10) // hardware pwm
623 params = _stm32_initHardware6PWMInterface(pwm_frequency, dead_zone, pinTimers[0], pinTimers[1], pinTimers[2], pinTimers[3], pinTimers[4], pinTimers[5]);
624 else { // software pwm
625 TIM_HandleTypeDef* HT1 = _stm32_initPinPWMHigh(pwm_frequency, pinTimers[0]);
626 TIM_HandleTypeDef* HT2 = _stm32_initPinPWMLow(pwm_frequency, pinTimers[1]);
627 TIM_HandleTypeDef* HT3 = _stm32_initPinPWMHigh(pwm_frequency, pinTimers[2]);
628 TIM_HandleTypeDef* HT4 = _stm32_initPinPWMLow(pwm_frequency, pinTimers[3]);
629 TIM_HandleTypeDef* HT5 = _stm32_initPinPWMHigh(pwm_frequency, pinTimers[4]);
630 TIM_HandleTypeDef* HT6 = _stm32_initPinPWMLow(pwm_frequency, pinTimers[5]);
631 TIM_HandleTypeDef *timers[6] = {HT1, HT2, HT3, HT4, HT5, HT6};
632 stm32_checkTimerFrequency(pwm_frequency, timers, 6);
633 uint32_t channel1 = STM_PIN_CHANNEL(pinTimers[0]->function);
634 uint32_t channel2 = STM_PIN_CHANNEL(pinTimers[1]->function);
635 uint32_t channel3 = STM_PIN_CHANNEL(pinTimers[2]->function);
636 uint32_t channel4 = STM_PIN_CHANNEL(pinTimers[3]->function);
637 uint32_t channel5 = STM_PIN_CHANNEL(pinTimers[4]->function);
638 uint32_t channel6 = STM_PIN_CHANNEL(pinTimers[5]->function);
639 params = new STM32DriverParams {
640 .timers_handle = { HT1, HT2, HT3, HT4, HT5, HT6 },
641 .channels = { channel1, channel2, channel3, channel4, channel5, channel6 },
642 .llchannels = { stm32_getLLChannel(pinTimers[0]), stm32_getLLChannel(pinTimers[1]), stm32_getLLChannel(pinTimers[2]), stm32_getLLChannel(pinTimers[3]), stm32_getLLChannel(pinTimers[4]), stm32_getLLChannel(pinTimers[5]) },
643 .pwm_frequency = pwm_frequency,
644 .num_timers = stm32_countTimers(timers, 6),
645 .master_timer = NULL,
646 .dead_zone = dead_zone,
647 .interface_type = _SOFTWARE_6PWM
648 };
649 }
650 if (score>=0) {
651 params->master_timer = stm32_alignTimers(params->timers_handle, 6);
652 motorsUsed[numMotorsUsed++] = params;
653 }
654 return params; // success
655}
656
657
658
659void _setSinglePhaseState(PhaseState state, TIM_HandleTypeDef *HT, int llchannel_hi, int llchannel_lo) {
660 switch (state) {
662 stm32_pauseChannel(HT, llchannel_hi | llchannel_lo);
663 break;
665 stm32_pauseChannel(HT, llchannel_lo);
666 stm32_resumeChannel(HT, llchannel_hi);
667 break;
669 stm32_pauseChannel(HT, llchannel_hi);
670 stm32_resumeChannel(HT, llchannel_lo);
671 break;
673 default:
674 stm32_resumeChannel(HT, llchannel_hi | llchannel_lo);
675 break;
676 }
677}
678
679
680// Function setting the duty cycle to the pwm pin (ex. analogWrite())
681// - BLDC driver - 6PWM setting
682// - hardware specific
683void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState* phase_state, void* params){
684 uint32_t duty1;
685 uint32_t duty2;
686 uint32_t duty3;
687 switch(((STM32DriverParams*)params)->interface_type){
688 case _HARDWARE_6PWM:
689 duty1 = dc_a*(((STM32DriverParams*)params)->timers_handle[0]->Instance->ARR+1);
690 duty2 = dc_b*(((STM32DriverParams*)params)->timers_handle[2]->Instance->ARR+1);
691 duty3 = dc_c*(((STM32DriverParams*)params)->timers_handle[4]->Instance->ARR+1);
692 if(phase_state[0] == PhaseState::PHASE_OFF) duty1 = 0;
693 if(phase_state[1] == PhaseState::PHASE_OFF) duty2 = 0;
694 if(phase_state[2] == PhaseState::PHASE_OFF) duty3 = 0;
695 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
696 _setSinglePhaseState(phase_state[0], ((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->llchannels[0], ((STM32DriverParams*)params)->llchannels[1]);
697 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], duty1);
698 _setSinglePhaseState(phase_state[1], ((STM32DriverParams*)params)->timers_handle[2], ((STM32DriverParams*)params)->llchannels[2], ((STM32DriverParams*)params)->llchannels[3]);
699 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[2], ((STM32DriverParams*)params)->channels[2], duty2);
700 _setSinglePhaseState(phase_state[2], ((STM32DriverParams*)params)->timers_handle[4], ((STM32DriverParams*)params)->llchannels[4], ((STM32DriverParams*)params)->llchannels[5]);
701 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[4], ((STM32DriverParams*)params)->channels[4], duty3);
702 if (((STM32DriverParams*)params)->num_timers == 1) LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
703 break;
704 case _SOFTWARE_6PWM:
705 float dead_zone = ((STM32DriverParams*)params)->dead_zone / 2.0f;
706 duty1 = _constrain(dc_a - dead_zone, 0.0f, 1.0f)*(((STM32DriverParams*)params)->timers_handle[0]->Instance->ARR+1);
707 duty2 = _constrain(dc_b - dead_zone, 0.0f, 1.0f)*(((STM32DriverParams*)params)->timers_handle[2]->Instance->ARR+1);
708 duty3 = _constrain(dc_c - dead_zone, 0.0f, 1.0f)*(((STM32DriverParams*)params)->timers_handle[4]->Instance->ARR+1);
709 uint32_t duty1N = _constrain(dc_a + dead_zone, 0.0f, 1.0f)*(((STM32DriverParams*)params)->timers_handle[1]->Instance->ARR+1);
710 uint32_t duty2N = _constrain(dc_b + dead_zone, 0.0f, 1.0f)*(((STM32DriverParams*)params)->timers_handle[3]->Instance->ARR+1);
711 uint32_t duty3N = _constrain(dc_c + dead_zone, 0.0f, 1.0f)*(((STM32DriverParams*)params)->timers_handle[5]->Instance->ARR+1);
712
713 LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance); // timers for high and low side assumed to be the same timer
715 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], duty1);
716 else
717 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[0], ((STM32DriverParams*)params)->channels[0], 0);
719 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[1], ((STM32DriverParams*)params)->channels[1], duty1N);
720 else
721 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[1], ((STM32DriverParams*)params)->channels[1], 0);
722
723 LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[2]->Instance); // timers for high and low side assumed to be the same timer
725 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[2], ((STM32DriverParams*)params)->channels[2], duty2);
726 else
727 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[2], ((STM32DriverParams*)params)->channels[2], 0);
729 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[3], ((STM32DriverParams*)params)->channels[3], duty2N);
730 else
731 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[3], ((STM32DriverParams*)params)->channels[3], 0);
732
733 LL_TIM_DisableUpdateEvent(((STM32DriverParams*)params)->timers_handle[4]->Instance); // timers for high and low side assumed to be the same timer
735 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[4], ((STM32DriverParams*)params)->channels[4], duty3);
736 else
737 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[4], ((STM32DriverParams*)params)->channels[4], 0);
739 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[5], ((STM32DriverParams*)params)->channels[5], duty3N);
740 else
741 stm32_setPwm(((STM32DriverParams*)params)->timers_handle[5], ((STM32DriverParams*)params)->channels[5], 0);
742
743 LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[0]->Instance);
744 LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[2]->Instance);
745 LL_TIM_EnableUpdateEvent(((STM32DriverParams*)params)->timers_handle[4]->Instance);
746 break;
747 }
748}
749
750
751
752#endif
PhaseState
Definition FOCDriver.h:7
@ PHASE_HI
Definition FOCDriver.h:10
@ PHASE_ON
Definition FOCDriver.h:9
@ PHASE_LO
Definition FOCDriver.h:11
@ PHASE_OFF
Definition FOCDriver.h:8
#define SIMPLEFOC_DEBUG(msg,...)
static void print(const char *msg)
static void println()
const int const int const int pinC
GenericCurrentSenseParams * params
#define SIMPLEFOC_PWM_ACTIVE_HIGH
void * _configure4PWM(long pwm_frequency, const int pin1A, const int pin1B, const int pin2A, const int pin2B)
void * _configure6PWM(long pwm_frequency, float dead_zone, const int pinA_h, const int pinA_l, const int pinB_h, const int pinB_l, const int pinC_h, const int pinC_l)
void * _configure2PWM(long pwm_frequency, const int pinA, const int pinB)
void _writeDutyCycle2PWM(float dc_a, float dc_b, void *params)
void _writeDutyCycle1PWM(float dc_a, void *params)
#define SIMPLEFOC_DRIVER_INIT_FAILED
void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, void *params)
void * _configure3PWM(long pwm_frequency, const int pinA, const int pinB, const int pinC)
#define SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH
void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void *params)
void * _configure1PWM(long pwm_frequency, const int pinA)
#define SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH
void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void *params)
float const int const int const int pinB_h
float const int const int const int const int pinB_l
float const int const int const int const int const int pinC_h
float float float dc_2b
float float PhaseState * phase_state
float const int const int const int const int const int const int pinC_l
float const int const int pinA_l
#define _isset(a)
Definition foc_utils.h:13
#define _constrain(amt, low, high)
Definition foc_utils.h:11