SimpleFOClibrary 2.4.0
Loading...
Searching...
No Matches
drivers/hardware_specific/due_mcu.cpp
Go to the documentation of this file.
1#include "../hardware_api.h"
2
3#if defined(__arm__) && defined(__SAM3X8E__)
4
5
6#pragma message("")
7#pragma message("SimpleFOC: compiling for Arduino/Due")
8#pragma message("")
9
10
11#define _PWM_FREQUENCY 25000 // 25khz
12#define _PWM_FREQUENCY_MAX 50000 // 50khz
13
14#define _PWM_RES_MIN 255 // 50khz
15
16// pwm frequency and max duty cycle
17static unsigned long _pwm_frequency;
18static int _max_pwm_value = 1023;
19
20// array mapping the timer values to the interrupt handlers
21static IRQn_Type irq_type[] = {TC0_IRQn, TC0_IRQn, TC1_IRQn, TC1_IRQn, TC2_IRQn, TC2_IRQn, TC3_IRQn, TC3_IRQn, TC4_IRQn, TC4_IRQn, TC5_IRQn, TC5_IRQn, TC6_IRQn, TC6_IRQn, TC7_IRQn, TC7_IRQn, TC8_IRQn, TC8_IRQn};
22// current counter values
23static volatile uint32_t pwm_counter_vals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
24
25
26// variables copied from wiring_analog.cpp for arduino due
27static uint8_t PWMEnabled = 0;
28static uint8_t TCChanEnabled[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
29static const uint32_t channelToChNo[] = { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2 };
30static const uint32_t channelToAB[] = { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 };
31static Tc *channelToTC[] = {
32 TC0, TC0, TC0, TC0, TC0, TC0,
33 TC1, TC1, TC1, TC1, TC1, TC1,
34 TC2, TC2, TC2, TC2, TC2, TC2 };
35static const uint32_t channelToId[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8 };
36
37
38// function setting the CMR register
39static void TC_SetCMR_ChannelA(Tc *tc, uint32_t chan, uint32_t v){ tc->TC_CHANNEL[chan].TC_CMR = (tc->TC_CHANNEL[chan].TC_CMR & 0xFFF0FFFF) | v;}
40static void TC_SetCMR_ChannelB(Tc *tc, uint32_t chan, uint32_t v){ tc->TC_CHANNEL[chan].TC_CMR = (tc->TC_CHANNEL[chan].TC_CMR & 0xF0FFFFFF) | v; }
41
42
43// function which starts and syncs the timers
44// if the pin is the true PWM pin this function does not do anything
45void syncTimers(uint32_t ulPin1,uint32_t ulPin2, uint32_t ulPin3 = -1, uint32_t ulPin4 = -1){
46 uint32_t chNo1,chNo2,chNo3,chNo4;
47 Tc *chTC1 = nullptr,*chTC2 = nullptr,*chTC3 = nullptr,*chTC4 = nullptr;
48
49 // configure timer channel for the first pin if it is a timer pin
50 uint32_t attr = g_APinDescription[ulPin1].ulPinAttribute;
51 if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) {
52 ETCChannel channel1 = g_APinDescription[ulPin1].ulTCChannel;
53 chNo1 = channelToChNo[channel1];
54 chTC1 = channelToTC[channel1];
55 TCChanEnabled[channelToId[channel1]] = 1;
56 }
57
58 // configure timer channel for the first pin if it is a timer pin
59 attr = g_APinDescription[ulPin2].ulPinAttribute;
60 if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) {
61 ETCChannel channel2 = g_APinDescription[ulPin2].ulTCChannel;
62 chNo2 = channelToChNo[channel2];
63 chTC2 = channelToTC[channel2];
64 TCChanEnabled[channelToId[channel2]] = 1;
65 }
66 if(ulPin3 > 0 ){
67 // configure timer channel for the first pin if it is a timer pin
68 attr = g_APinDescription[ulPin3].ulPinAttribute;
69 if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) {
70 ETCChannel channel3 = g_APinDescription[ulPin3].ulTCChannel;
71 chNo3 = channelToChNo[channel3];
72 chTC3 = channelToTC[channel3];
73 TCChanEnabled[channelToId[channel3]] = 1;
74 }
75 }
76 if(ulPin4 > 0 ){
77 // configure timer channel for the first pin if it is a timer pin
78 attr = g_APinDescription[ulPin4].ulPinAttribute;
79 if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) {
80 ETCChannel channel4 = g_APinDescription[ulPin4].ulTCChannel;
81 chNo4 = channelToChNo[channel4];
82 chTC4 = channelToTC[channel4];
83 TCChanEnabled[channelToId[channel4]] = 1;
84 }
85 }
86 // start timers and make them synced
87 if(chTC1){
88 TC_Start(chTC1, chNo1);
89 chTC1->TC_BCR = TC_BCR_SYNC;
90 }
91 if(chTC2){
92 TC_Start(chTC2, chNo2);
93 chTC2->TC_BCR = TC_BCR_SYNC;
94 }
95 if(chTC3 && ulPin3){
96 TC_Start(chTC3, chNo3);
97 chTC3->TC_BCR = TC_BCR_SYNC;
98 }
99 if(chTC4 && ulPin4){
100 TC_Start(chTC4, chNo4);
101 chTC4->TC_BCR = TC_BCR_SYNC;
102 }
103}
104
105// function configuring the pwm frequency for given pin
106// possible to supply the pwm pin and the timer pin
107void initPWM(uint32_t ulPin, uint32_t pwm_freq){
108 // check which pin type
109 uint32_t attr = g_APinDescription[ulPin].ulPinAttribute;
110 if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM) { // if pwm pin
111
112 if (!PWMEnabled) {
113 // PWM Startup code
114 pmc_enable_periph_clk(PWM_INTERFACE_ID);
115 // this function does not work too well - I'll rewrite it
116 // PWMC_ConfigureClocks(PWM_FREQUENCY * _max_pwm_value, 0, VARIANT_MCK);
117
118 // finding the divisors an prescalers form FindClockConfiguration function
119 uint32_t divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
120 uint8_t divisor = 0;
121 uint32_t prescaler;
122
123 /* Find prescaler and divisor values */
124 prescaler = (VARIANT_MCK / divisors[divisor]) / (pwm_freq*_max_pwm_value);
125 while ((prescaler > 255) && (divisor < 11)) {
126 divisor++;
127 prescaler = (VARIANT_MCK / divisors[divisor]) / (pwm_freq*_max_pwm_value);
128 }
129 // update the divisor*prescaler value
130 prescaler = prescaler | (divisor << 8);
131
132 // now calculate the real resolution timer period necessary (pwm resolution)
133 // pwm_res = bus_freq / (pwm_freq * (prescaler))
134 _max_pwm_value = (double)VARIANT_MCK / (double)pwm_freq / (double)(prescaler);
135 // set the prescaler value
136 PWM->PWM_CLK = prescaler;
137
138 PWMEnabled = 1;
139 }
140
141 uint32_t chan = g_APinDescription[ulPin].ulPWMChannel;
142 if ((g_pinStatus[ulPin] & 0xF) != PIN_STATUS_PWM) {
143 // Setup PWM for this pin
144 PIO_Configure(g_APinDescription[ulPin].pPort,
145 g_APinDescription[ulPin].ulPinType,
146 g_APinDescription[ulPin].ulPin,
147 g_APinDescription[ulPin].ulPinConfiguration);
148 // PWM_CMR_CALG - center align
149 // PWMC_ConfigureChannel(PWM_INTERFACE, chan, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0);
150 PWMC_ConfigureChannel(PWM_INTERFACE, chan, PWM_CMR_CPRE_CLKA, 0, 0);
151 PWMC_SetPeriod(PWM_INTERFACE, chan, _max_pwm_value);
152 PWMC_SetDutyCycle(PWM_INTERFACE, chan, 0);
153 PWMC_EnableChannel(PWM_INTERFACE, chan);
154 g_pinStatus[ulPin] = (g_pinStatus[ulPin] & 0xF0) | PIN_STATUS_PWM;
155 }
156 return;
157 }
158
159 if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) { // if timer pin
160 // We use MCLK/2 as clock.
161 const uint32_t TC = VARIANT_MCK / 2 / pwm_freq ;
162 // Setup Timer for this pin
163 ETCChannel channel = g_APinDescription[ulPin].ulTCChannel;
164 uint32_t chNo = channelToChNo[channel];
165 uint32_t chA = channelToAB[channel];
166 Tc *chTC = channelToTC[channel];
167 uint32_t interfaceID = channelToId[channel];
168
169 if (!TCChanEnabled[interfaceID]) {
170 pmc_enable_periph_clk(TC_INTERFACE_ID + interfaceID);
171 TC_Configure(chTC, chNo,
172 TC_CMR_TCCLKS_TIMER_CLOCK1 |
173 TC_CMR_WAVE | // Waveform mode
174 TC_CMR_WAVSEL_UP_RC | // Counter running up and reset when equals to RC
175 TC_CMR_EEVT_XC0 | // Set external events from XC0 (this setup TIOB as output)
176 TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
177 TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR);
178 TC_SetRC(chTC, chNo, TC);
179 }
180
181 // disable the counter on start
182 if (chA){
183 TC_SetCMR_ChannelA(chTC, chNo, TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);
184 }else{
185 TC_SetCMR_ChannelB(chTC, chNo, TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_SET);
186 }
187 // configure input-ouput structure
188 if ((g_pinStatus[ulPin] & 0xF) != PIN_STATUS_PWM) {
189 PIO_Configure(g_APinDescription[ulPin].pPort,
190 g_APinDescription[ulPin].ulPinType,
191 g_APinDescription[ulPin].ulPin,
192 g_APinDescription[ulPin].ulPinConfiguration);
193 g_pinStatus[ulPin] = (g_pinStatus[ulPin] & 0xF0) | PIN_STATUS_PWM;
194 }
195 // enable interrupts
196 chTC->TC_CHANNEL[chNo].TC_IER = TC_IER_CPAS // interrupt on RA compare match
197 | TC_IER_CPBS // interrupt on RB compare match
198 | TC_IER_CPCS; // interrupt on RC compare match
199 chTC->TC_CHANNEL[chNo].TC_IDR = ~TC_IER_CPAS // interrupt on RA compare match
200 & ~TC_IER_CPBS // interrupt on RB compare match
201 & ~ TC_IER_CPCS; // interrupt on RC compare match
202 // enable interrupts for this timer
203 NVIC_EnableIRQ(irq_type[channel]);
204 return;
205 }
206}
207
208// pwm setting function
209// it sets the duty cycle for pwm pin or timer pin
210void setPwm(uint32_t ulPin, uint32_t ulValue) {
211 // check pin type
212 uint32_t attr = g_APinDescription[ulPin].ulPinAttribute;
213 if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM) { // if pwm
214 uint32_t chan = g_APinDescription[ulPin].ulPWMChannel;
215 PWMC_SetDutyCycle(PWM_INTERFACE, chan, ulValue);
216 return;
217 }
218
219 if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) { // if timer pin
220 // get the timer variables
221 ETCChannel channel = g_APinDescription[ulPin].ulTCChannel;
222 Tc *chTC = channelToTC[channel];
223 uint32_t chNo = channelToChNo[channel];
224 if(!ulValue) {
225 // if the value 0 disable counter
226 if (channelToAB[channel])
227 TC_SetCMR_ChannelA(chTC, chNo, TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR);
228 else
229 TC_SetCMR_ChannelB(chTC, chNo, TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR);
230 }else{
231 // if the value not zero
232 // calculate clock
233 const uint32_t TC = VARIANT_MCK / 2 / _pwm_frequency;
234 // Map value to Timer ranges 0..max_duty_cycle => 0..TC
235 // Setup Timer for this pin
236 ulValue = ulValue * TC ;
237 pwm_counter_vals[channel] = ulValue / _max_pwm_value;
238 // enable counter
239 if (channelToAB[channel])
240 TC_SetCMR_ChannelA(chTC, chNo, TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);
241 else
242 TC_SetCMR_ChannelB(chTC, chNo, TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_SET);
243 }
244
245 return;
246 }
247}
248
249// interrupt handlers for seamless pwm duty-cycle setting
250void TC0_Handler()
251{
252 // read/clear interrupt status
253 TC_GetStatus(TC0, 0);
254 // update the counters
255 if(pwm_counter_vals[0]) TC_SetRA(TC0, 0, pwm_counter_vals[0]);
256 if(pwm_counter_vals[1]) TC_SetRB(TC0, 0, pwm_counter_vals[1]);
257}
258
259void TC1_Handler()
260{
261 // read/clear interrupt status
262 TC_GetStatus(TC0, 1);
263 // update the counters
264 if(pwm_counter_vals[2]) TC_SetRA(TC0, 1, pwm_counter_vals[2]);
265 if(pwm_counter_vals[3]) TC_SetRB(TC0, 1, pwm_counter_vals[3]);
266}
267
268void TC2_Handler()
269{
270 // read/clear interrupt status
271 TC_GetStatus(TC0, 2);
272 // update the counters
273 if(pwm_counter_vals[4]) TC_SetRA(TC0, 2, pwm_counter_vals[4]);
274 if(pwm_counter_vals[5]) TC_SetRB(TC0, 2, pwm_counter_vals[5]);
275}
276void TC3_Handler()
277{
278 // read/clear interrupt status
279 TC_GetStatus(TC1, 0);
280 // update the counters
281 if(pwm_counter_vals[6]) TC_SetRA(TC1, 0, pwm_counter_vals[6]);
282 if(pwm_counter_vals[7]) TC_SetRB(TC1, 0, pwm_counter_vals[7]);
283}
284
285void TC4_Handler()
286{
287 // read/clear interrupt status
288 TC_GetStatus(TC1, 1);
289 // update the counters
290 if(pwm_counter_vals[8]) TC_SetRA(TC1, 1, pwm_counter_vals[8]);
291 if(pwm_counter_vals[9]) TC_SetRB(TC1, 1, pwm_counter_vals[9]);
292}
293
294void TC5_Handler()
295{
296 // read/clear interrupt status
297 TC_GetStatus(TC1, 2);
298 // update the counters
299 if(pwm_counter_vals[10]) TC_SetRA(TC1, 2, pwm_counter_vals[10]);
300 if(pwm_counter_vals[11]) TC_SetRB(TC1, 2, pwm_counter_vals[11]);
301}
302void TC6_Handler()
303{
304 // read/clear interrupt status
305 TC_GetStatus(TC2, 0);
306 // update the counters
307 if(pwm_counter_vals[12]) TC_SetRA(TC2, 0, pwm_counter_vals[12]);
308 if(pwm_counter_vals[13]) TC_SetRB(TC2, 0, pwm_counter_vals[13]);
309}
310
311void TC7_Handler()
312{
313 // read/clear interrupt status
314 TC_GetStatus(TC2, 1);
315 // update the counters
316 if(pwm_counter_vals[14]) TC_SetRA(TC2, 1, pwm_counter_vals[14]);
317 if(pwm_counter_vals[15]) TC_SetRB(TC2, 1, pwm_counter_vals[15]);
318}
319
320void TC8_Handler()
321{
322 // read/clear interrupt status
323 TC_GetStatus(TC2, 2);
324 // update the counters
325 if(pwm_counter_vals[16]) TC_SetRA(TC2, 2, pwm_counter_vals[16]);
326 if(pwm_counter_vals[17]) TC_SetRB(TC2, 2, pwm_counter_vals[17]);
327}
328
329
330
331
332
333// implementation of the hardware_api.cpp
334// ---------------------------------------------------------------------------------------------------------------------------------
335
336// function setting the high pwm frequency to the supplied pins
337// - BLDC motor - 3PWM setting
338// - hardware specific
339void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC) {
340 if(!pwm_frequency || !_isset(pwm_frequency) ) pwm_frequency = _PWM_FREQUENCY; // default frequency 50khz
341 else pwm_frequency = _constrain(pwm_frequency, 0, _PWM_FREQUENCY_MAX); // constrain to 50kHz max
342 // save the pwm frequency
343 _pwm_frequency = pwm_frequency;
344 // cinfigure pwm pins
345 initPWM(pinA, _pwm_frequency);
346 initPWM(pinB, _pwm_frequency);
347 initPWM(pinC, _pwm_frequency);
348 // sync the timers if possible
349 syncTimers(pinA, pinB, pinC);
350
352 .pins = { pinA, pinB, pinC },
353 .pwm_frequency = pwm_frequency
354 };
355 return params;
356}
357
358
359
360
361// Configuring PWM frequency, resolution and alignment
362//- Stepper driver - 2PWM setting
363// - hardware specific
364void* _configure2PWM(long pwm_frequency, const int pinA, const int pinB) {
365 if(!pwm_frequency || !_isset(pwm_frequency)) pwm_frequency = _PWM_FREQUENCY; // default frequency 50khz
366 else pwm_frequency = _constrain(pwm_frequency, 0, _PWM_FREQUENCY_MAX); // constrain to 50kHz max
367 // save the pwm frequency
368 _pwm_frequency = pwm_frequency;
369 // cinfigure pwm pins
370 initPWM(pinA, _pwm_frequency);
371 initPWM(pinB, _pwm_frequency);
372 // sync the timers if possible
373 syncTimers(pinA, pinB);
374
376 .pins = { pinA, pinB },
377 .pwm_frequency = pwm_frequency
378 };
379 return params;
380}
381
382
383
384
385// function setting the high pwm frequency to the supplied pins
386// - Stepper motor - 4PWM setting
387// - hardware speciffic
388void* _configure4PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC, const int pinD) {
389 if(!pwm_frequency || !_isset(pwm_frequency)) pwm_frequency = _PWM_FREQUENCY; // default frequency 50khz
390 else pwm_frequency = _constrain(pwm_frequency, 0, _PWM_FREQUENCY_MAX); // constrain to 50kHz max
391 // save the pwm frequency
392 _pwm_frequency = pwm_frequency;
393 // cinfigure pwm pins
394 initPWM(pinA, _pwm_frequency);
395 initPWM(pinB, _pwm_frequency);
396 initPWM(pinC, _pwm_frequency);
397 initPWM(pinD, _pwm_frequency);
398 // sync the timers if possible
399 syncTimers(pinA, pinB, pinC, pinD);
400
402 .pins = { pinA, pinB, pinC, pinD },
403 .pwm_frequency = pwm_frequency
404 };
405 return params;
406}
407
408
409
410
411// function setting the pwm duty cycle to the hardware
412// - BLDC motor - 3PWM setting
413// - hardware speciffic
414void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* param){
415 // transform duty cycle from [0,1] to [0,_max_pwm_value]
417 setPwm(p->pins[0], _max_pwm_value*dc_a);
418 setPwm(p->pins[1], _max_pwm_value*dc_b);
419 setPwm(p->pins[2], _max_pwm_value*dc_c);
420}
421
422
423
424// function setting the pwm duty cycle to the hardware
425// - Stepper motor - 4PWM setting
426// - hardware speciffic
427void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, void* param){
428 // transform duty cycle from [0,1] to [0,_max_pwm_value]
430 setPwm(p->pins[0], _max_pwm_value*dc_1a);
431 setPwm(p->pins[1], _max_pwm_value*dc_1b);
432 setPwm(p->pins[2], _max_pwm_value*dc_2a);
433 setPwm(p->pins[3], _max_pwm_value*dc_2b);
434}
435
436
437
438// Function setting the duty cycle to the pwm pin (ex. analogWrite())
439// - Stepper driver - 2PWM setting
440// - hardware specific
441void _writeDutyCycle2PWM(float dc_a, float dc_b, void* param){
442 // transform duty cycle from [0,1] to [0,_max_pwm_value]
444 setPwm(p->pins[0], _max_pwm_value*dc_a);
445 setPwm(p->pins[1], _max_pwm_value*dc_b);
446}
447
448
449#endif
const int const int const int pinC
GenericCurrentSenseParams * params
void * _configure4PWM(long pwm_frequency, const int pin1A, const int pin1B, const int pin2A, const int pin2B)
void * _configure2PWM(long pwm_frequency, const int pinA, const int pinB)
void _writeDutyCycle2PWM(float dc_a, float dc_b, void *params)
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)
void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void *params)
float float float dc_2b
#define _isset(a)
Definition foc_utils.h:13
#define _constrain(amt, low, high)
Definition foc_utils.h:11