SimpleFOClibrary 2.4.0
Loading...
Searching...
No Matches
nrf52_mcu.cpp
Go to the documentation of this file.
1
2#include "../hardware_api.h"
3
4#if defined(NRF52_SERIES)
5
6#pragma message("")
7#pragma message("SimpleFOC: compiling for NRF52")
8#pragma message("")
9
10
11#define PWM_CLK (16000000)
12#define PWM_FREQ (40000)
13#define PWM_RESOLUTION (PWM_CLK/PWM_FREQ)
14#define PWM_MAX_FREQ (62500)
15#define DEAD_ZONE (250) // in ns
16#define DEAD_TIME (DEAD_ZONE / (PWM_RESOLUTION * 0.25 * 62.5)) // 62.5ns resolution of PWM
17
18#ifdef NRF_PWM3
19#define PWM_COUNT 4
20#else
21#define PWM_COUNT 3
22#endif
23
24// empty motor slot
25#define _EMPTY_SLOT (-0xAA)
26#define _TAKEN_SLOT (-0x55)
27
28int pwm_range;
29
30
31static NRF_PWM_Type* pwms[PWM_COUNT] = {
32 NRF_PWM0,
33 NRF_PWM1,
34 NRF_PWM2,
35 #ifdef NRF_PWM3
36 NRF_PWM3
37 #endif
38};
39
40typedef struct {
41 int pinA;
42 NRF_PWM_Type* mcpwm;
43 uint16_t mcpwm_channel_sequence[4];
44} bldc_3pwm_motor_slots_t;
45
46typedef struct {
47 int pin1A;
48 NRF_PWM_Type* mcpwm;
49 uint16_t mcpwm_channel_sequence[4];
50} stepper_motor_slots_t;
51
52typedef struct {
53 int pinAH;
54 NRF_PWM_Type* mcpwm1;
55 NRF_PWM_Type* mcpwm2;
56 uint16_t mcpwm_channel_sequence[8];
57} bldc_6pwm_motor_slots_t;
58
59// define bldc motor slots array
60bldc_3pwm_motor_slots_t nrf52_bldc_3pwm_motor_slots[4] = {
61 {_EMPTY_SLOT, pwms[0], {0,0,0,0}},// 1st motor will be PWM0
62 {_EMPTY_SLOT, pwms[1], {0,0,0,0}},// 2nd motor will be PWM1
63 {_EMPTY_SLOT, pwms[2], {0,0,0,0}},// 3rd motor will be PWM2
64 {_EMPTY_SLOT, pwms[3], {0,0,0,0}} // 4th motor will be PWM3
65 };
66
67// define stepper motor slots array
68stepper_motor_slots_t nrf52_stepper_motor_slots[4] = {
69 {_EMPTY_SLOT, pwms[0], {0,0,0,0}},// 1st motor will be on PWM0
70 {_EMPTY_SLOT, pwms[1], {0,0,0,0}},// 1st motor will be on PWM1
71 {_EMPTY_SLOT, pwms[2], {0,0,0,0}},// 1st motor will be on PWM2
72 {_EMPTY_SLOT, pwms[3], {0,0,0,0}} // 1st motor will be on PWM3
73 };
74
75// define BLDC motor slots array
76bldc_6pwm_motor_slots_t nrf52_bldc_6pwm_motor_slots[2] = {
77 {_EMPTY_SLOT, pwms[0], pwms[1], {0,0,0,0,0,0,0,0}},// 1st motor will be on PWM0 & PWM1
78 {_EMPTY_SLOT, pwms[2], pwms[3], {0,0,0,0,0,0,0,0}} // 2nd motor will be on PWM1 & PWM2
79 };
80
81
82
83typedef struct NRF52DriverParams {
84 union {
85 bldc_3pwm_motor_slots_t* slot3pwm;
86 bldc_6pwm_motor_slots_t* slot6pwm;
87 stepper_motor_slots_t* slotstep;
88 } slot;
89 long pwm_frequency;
90 float dead_time;
91} NRF52DriverParams;
92
93
94
95
96// configuring high frequency pwm timer
97void _configureHwPwm(NRF_PWM_Type* mcpwm1, NRF_PWM_Type* mcpwm2){
98
99 mcpwm1->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
100 mcpwm1->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos);
101 mcpwm1->MODE = (PWM_MODE_UPDOWN_UpAndDown << PWM_MODE_UPDOWN_Pos);
102 mcpwm1->COUNTERTOP = pwm_range; //pwm freq.
103 mcpwm1->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
104 mcpwm1->DECODER = ((uint32_t)PWM_DECODER_LOAD_Individual << PWM_DECODER_LOAD_Pos) | ((uint32_t)PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
105 mcpwm1->SEQ[0].REFRESH = 0;
106 mcpwm1->SEQ[0].ENDDELAY = 0;
107
108 if(mcpwm1 != mcpwm2){
109 mcpwm2->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
110 mcpwm2->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos);
111 mcpwm2->MODE = (PWM_MODE_UPDOWN_UpAndDown << PWM_MODE_UPDOWN_Pos);
112 mcpwm2->COUNTERTOP = pwm_range; //pwm freq.
113 mcpwm2->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
114 mcpwm2->DECODER = ((uint32_t)PWM_DECODER_LOAD_Individual << PWM_DECODER_LOAD_Pos) | ((uint32_t)PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
115 mcpwm2->SEQ[0].REFRESH = 0;
116 mcpwm2->SEQ[0].ENDDELAY = 0;
117 }else{
118 mcpwm1->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
119 }
120}
121
122
123
124// can we support it using the generic driver on this MCU? Commented out to fall back to generic driver for 2-pwm
125// void* _configure2PWM(long pwm_frequency, const int pinA, const int pinB) {
126// return SIMPLEFOC_DRIVER_INIT_FAILED; // not supported
127// }
128
129
130
131
132// function setting the high pwm frequency to the supplied pins
133// - BLDC motor - 3PWM setting
134// - hardware speciffic
135void* _configure3PWM(long pwm_frequency,const int pinA, const int pinB, const int pinC) {
136
137 if( !pwm_frequency || pwm_frequency == NOT_SET) pwm_frequency = PWM_FREQ; // default frequency 20khz for a resolution of 800
138 else pwm_frequency = _constrain(pwm_frequency, 0, PWM_MAX_FREQ); // constrain to 62.5kHz max for a resolution of 256
139
140 pwm_range = (PWM_CLK / pwm_frequency);
141
142 int pA = digitalPinToPinName(pinA); //g_ADigitalPinMap[pinA];
143 int pB = digitalPinToPinName(pinB); //g_ADigitalPinMap[pinB];
144 int pC = digitalPinToPinName(pinC); //g_ADigitalPinMap[pinC];
145
146 // determine which motor are we connecting
147 // and set the appropriate configuration parameters
148 int slot_num;
149 for(slot_num = 0; slot_num < 4; slot_num++){
150 if(nrf52_bldc_3pwm_motor_slots[slot_num].pinA == _EMPTY_SLOT){ // put the new motor in the first empty slot
151 nrf52_bldc_3pwm_motor_slots[slot_num].pinA = pinA;
152 break;
153 }
154 }
155 // if no slots available
156 if(slot_num >= 4) return SIMPLEFOC_DRIVER_INIT_FAILED;
157
158 // disable all the slots with the same MCPWM
159 if(slot_num < 2){
160 // slot 0 of the stepper
161 nrf52_stepper_motor_slots[slot_num].pin1A = _TAKEN_SLOT;
162 // slot 0 of the 6pwm bldc
163 nrf52_bldc_6pwm_motor_slots[0].pinAH = _TAKEN_SLOT;
164 //NRF_PPI->CHEN &= ~1UL;
165 }else{
166 // slot 1 of the stepper
167 nrf52_stepper_motor_slots[slot_num].pin1A = _TAKEN_SLOT;
168 // slot 0 of the 6pwm bldc
169 nrf52_bldc_6pwm_motor_slots[1].pinAH = _TAKEN_SLOT;
170 //NRF_PPI->CHEN &= ~2UL;
171 }
172
173 // configure pwm outputs
174
175 nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm->PSEL.OUT[0] = pA;
176 nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm->PSEL.OUT[1] = pB;
177 nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm->PSEL.OUT[2] = pC;
178
179 nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm->SEQ[0].PTR = (uint32_t)&nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm_channel_sequence[0];
180 nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm->SEQ[0].CNT = 4;
181
182 // configure the pwm
183 _configureHwPwm(nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm, nrf52_bldc_3pwm_motor_slots[slot_num].mcpwm);
184
185 NRF52DriverParams* params = new NRF52DriverParams();
186 params->slot.slot3pwm = &(nrf52_bldc_3pwm_motor_slots[slot_num]);
187 params->pwm_frequency = pwm_frequency;
188 return params;
189}
190
191
192
193
194// function setting the high pwm frequency to the supplied pins
195// - Stepper motor - 4PWM setting
196// - hardware speciffic
197void* _configure4PWM(long pwm_frequency, const int pinA, const int pinB, const int pinC, const int pinD) {
198
199 if( !pwm_frequency || pwm_frequency == NOT_SET) pwm_frequency = PWM_FREQ; // default frequency 20khz for a resolution of 800
200 else pwm_frequency = _constrain(pwm_frequency, 0, PWM_MAX_FREQ); // constrain to 62.5kHz max for a resolution of 256
201
202 pwm_range = (PWM_CLK / pwm_frequency);
203
204 int pA = digitalPinToPinName(pinA); //g_ADigitalPinMap[pinA];
205 int pB = digitalPinToPinName(pinB); //g_ADigitalPinMap[pinB];
206 int pC = digitalPinToPinName(pinC); //g_ADigitalPinMap[pinC];
207 int pD = digitalPinToPinName(pinD); //g_ADigitalPinMap[pinD];
208
209 // determine which motor are we connecting
210 // and set the appropriate configuration parameters
211 int slot_num;
212 for(slot_num = 0; slot_num < 4; slot_num++){
213 if(nrf52_stepper_motor_slots[slot_num].pin1A == _EMPTY_SLOT){ // put the new motor in the first empty slot
214 nrf52_stepper_motor_slots[slot_num].pin1A = pinA;
215 break;
216 }
217 }
218 // if no slots available
219 if (slot_num >= 4) return SIMPLEFOC_DRIVER_INIT_FAILED;
220
221 // disable all the slots with the same MCPWM
222 if (slot_num < 2){
223 // slots 0 and 1 of the 3pwm bldc
224 nrf52_bldc_3pwm_motor_slots[slot_num].pinA = _TAKEN_SLOT;
225 // slot 0 of the 6pwm bldc
226 nrf52_bldc_6pwm_motor_slots[0].pinAH = _TAKEN_SLOT;
227 //NRF_PPI->CHEN &= ~1UL;
228 }else{
229 // slots 2 and 3 of the 3pwm bldc
230 nrf52_bldc_3pwm_motor_slots[slot_num].pinA = _TAKEN_SLOT;
231 // slot 1 of the 6pwm bldc
232 nrf52_bldc_6pwm_motor_slots[1].pinAH = _TAKEN_SLOT;
233 //NRF_PPI->CHEN &= ~2UL;
234 }
235
236 // configure pwm outputs
237
238 nrf52_stepper_motor_slots[slot_num].mcpwm->PSEL.OUT[0] = pA;
239 nrf52_stepper_motor_slots[slot_num].mcpwm->PSEL.OUT[1] = pB;
240 nrf52_stepper_motor_slots[slot_num].mcpwm->PSEL.OUT[2] = pC;
241 nrf52_stepper_motor_slots[slot_num].mcpwm->PSEL.OUT[3] = pD;
242
243 nrf52_stepper_motor_slots[slot_num].mcpwm->SEQ[0].PTR = (uint32_t)&nrf52_stepper_motor_slots[slot_num].mcpwm_channel_sequence[0];
244 nrf52_stepper_motor_slots[slot_num].mcpwm->SEQ[0].CNT = 4;
245
246 // configure the pwm
247 _configureHwPwm(nrf52_stepper_motor_slots[slot_num].mcpwm, nrf52_stepper_motor_slots[slot_num].mcpwm);
248
249 NRF52DriverParams* params = new NRF52DriverParams();
250 params->slot.slotstep = &(nrf52_stepper_motor_slots[slot_num]);
251 params->pwm_frequency = pwm_frequency;
252 return params;
253}
254
255
256
257
258// function setting the pwm duty cycle to the hardware
259// - BLDC motor - 3PWM setting
260// - hardware speciffic
261void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c, void* params){
262 // transform duty cycle from [0,1] to [0,range]
263 bldc_3pwm_motor_slots_t* p = ((NRF52DriverParams*)params)->slot.slot3pwm;
264 p->mcpwm_channel_sequence[0] = (int)(dc_a * pwm_range) | 0x8000;
265 p->mcpwm_channel_sequence[1] = (int)(dc_b * pwm_range) | 0x8000;
266 p->mcpwm_channel_sequence[2] = (int)(dc_c * pwm_range) | 0x8000;
267
268 p->mcpwm->TASKS_SEQSTART[0] = 1;
269}
270
271
272
273
274// function setting the pwm duty cycle to the hardware
275// - Stepper motor - 4PWM setting
276// - hardware speciffic
277void _writeDutyCycle4PWM(float dc_1a, float dc_1b, float dc_2a, float dc_2b, void* params){
278
279 stepper_motor_slots_t* p = ((NRF52DriverParams*)params)->slot.slotstep;
280 p->mcpwm_channel_sequence[0] = (int)(dc_1a * pwm_range) | 0x8000;
281 p->mcpwm_channel_sequence[1] = (int)(dc_1b * pwm_range) | 0x8000;
282 p->mcpwm_channel_sequence[2] = (int)(dc_2a * pwm_range) | 0x8000;
283 p->mcpwm_channel_sequence[3] = (int)(dc_2b * pwm_range) | 0x8000;
284
285 p->mcpwm->TASKS_SEQSTART[0] = 1;
286}
287
288/* Configuring PWM frequency, resolution and alignment
289// - BLDC driver - 6PWM setting
290// - hardware specific
291*/
292void* _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){
293
294 if( !pwm_frequency || pwm_frequency == NOT_SET) pwm_frequency = PWM_FREQ; // default frequency 20khz - centered pwm has twice lower frequency for a resolution of 400
295 else pwm_frequency = _constrain(pwm_frequency*2, 0, PWM_MAX_FREQ); // constrain to 62.5kHz max => 31.25kHz for a resolution of 256
296
297 pwm_range = (PWM_CLK / pwm_frequency);
298 pwm_range /= 2; // scale the frequency (centered PWM)
299
300 float dead_time;
301 if (dead_zone != NOT_SET){
302 dead_time = dead_zone/2;
303 }else{
304 dead_time = DEAD_TIME/2;
305 }
306
307 int pA_l = digitalPinToPinName(pinA_l); //g_ADigitalPinMap[pinA_l];
308 int pA_h = digitalPinToPinName(pinA_h); //g_ADigitalPinMap[pinA_h];
309 int pB_l = digitalPinToPinName(pinB_l); //g_ADigitalPinMap[pinB_l];
310 int pB_h = digitalPinToPinName(pinB_h); //g_ADigitalPinMap[pinB_h];
311 int pC_l = digitalPinToPinName(pinC_l); //g_ADigitalPinMap[pinC_l];
312 int pC_h = digitalPinToPinName(pinC_h); //g_ADigitalPinMap[pinC_h];
313
314
315 // determine which motor are we connecting
316 // and set the appropriate configuration parameters
317 int slot_num;
318 for(slot_num = 0; slot_num < 2; slot_num++){
319 if(nrf52_bldc_6pwm_motor_slots[slot_num].pinAH == _EMPTY_SLOT){ // put the new motor in the first empty slot
320 nrf52_bldc_6pwm_motor_slots[slot_num].pinAH = pinA_h;
321 break;
322 }
323 }
324 // if no slots available
325 if(slot_num >= 2) return SIMPLEFOC_DRIVER_INIT_FAILED;
326
327 // disable all the slots with the same MCPWM
328 if( slot_num == 0 ){
329 // slots 0 and 1 of the 3pwm bldc
330 nrf52_bldc_3pwm_motor_slots[0].pinA = _TAKEN_SLOT;
331 nrf52_bldc_3pwm_motor_slots[1].pinA = _TAKEN_SLOT;
332 // slot 0 and 1 of the stepper
333 nrf52_stepper_motor_slots[0].pin1A = _TAKEN_SLOT;
334 nrf52_stepper_motor_slots[1].pin1A = _TAKEN_SLOT;
335 }else{
336 // slots 2 and 3 of the 3pwm bldc
337 nrf52_bldc_3pwm_motor_slots[2].pinA = _TAKEN_SLOT;
338 nrf52_bldc_3pwm_motor_slots[3].pinA = _TAKEN_SLOT;
339 // slot 1 of the stepper
340 nrf52_stepper_motor_slots[2].pin1A = _TAKEN_SLOT;
341 nrf52_stepper_motor_slots[3].pin1A = _TAKEN_SLOT;
342 }
343
344 // Configure pwm outputs
345
346 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->PSEL.OUT[0] = pA_h;
347 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->PSEL.OUT[1] = pA_l;
348 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->PSEL.OUT[2] = pB_h;
349 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->PSEL.OUT[3] = pB_l;
350 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->SEQ[0].PTR = (uint32_t)&nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm_channel_sequence[0];
351 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->SEQ[0].CNT = 4;
352
353 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm2->PSEL.OUT[0] = pC_h;
354 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm2->PSEL.OUT[1] = pC_l;
355 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm2->SEQ[0].PTR = (uint32_t)&nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm_channel_sequence[4];
356 nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm2->SEQ[0].CNT = 4;
357
358 // Initializing the PPI peripheral for sync the pwm slots
359
360 NRF_PPI->CH[slot_num].EEP = (uint32_t)&NRF_EGU0->EVENTS_TRIGGERED[0];
361 NRF_PPI->CH[slot_num].TEP = (uint32_t)&nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1->TASKS_SEQSTART[0];
362 NRF_PPI->FORK[slot_num].TEP = (uint32_t)&nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm2->TASKS_SEQSTART[0];
363 NRF_PPI->CHEN = 1UL << slot_num;
364
365 // configure the pwm type
366 _configureHwPwm(nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm1, nrf52_bldc_6pwm_motor_slots[slot_num].mcpwm2);
367
368 NRF52DriverParams* params = new NRF52DriverParams();
369 params->slot.slot6pwm = &(nrf52_bldc_6pwm_motor_slots[slot_num]);
370 params->pwm_frequency = pwm_frequency;
371 params->dead_time = dead_time;
372 return params;
373}
374
375
376
377
378/* Function setting the duty cycle to the pwm pin
379// - BLDC driver - 6PWM setting
380// - hardware specific
381*/
382void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void* params){
383 bldc_6pwm_motor_slots_t* p = ((NRF52DriverParams*)params)->slot.slot6pwm;
384 float dead_time = ((NRF52DriverParams*)params)->dead_time;
385 p->mcpwm_channel_sequence[0] = (int)(_constrain(dc_a-dead_time,0,1)*pwm_range) | 0x8000;
386 p->mcpwm_channel_sequence[1] = (int)(_constrain(dc_a+dead_time,0,1)*pwm_range);
387 p->mcpwm_channel_sequence[2] = (int)(_constrain(dc_b-dead_time,0,1)*pwm_range) | 0x8000;
388 p->mcpwm_channel_sequence[3] = (int)(_constrain(dc_b+dead_time,0,1)*pwm_range);
389 p->mcpwm_channel_sequence[4] = (int)(_constrain(dc_c-dead_time,0,1)*pwm_range) | 0x8000;
390 p->mcpwm_channel_sequence[5] = (int)(_constrain(dc_c+dead_time,0,1)*pwm_range);
391 NRF_EGU0->TASKS_TRIGGER[0] = 1;
392
394}
395
396
397#endif
PhaseState
Definition FOCDriver.h:7
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 * _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)
#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)
void _writeDutyCycle6PWM(float dc_a, float dc_b, float dc_c, PhaseState *phase_state, void *params)
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 NOT_SET
Definition foc_utils.h:34
#define _UNUSED(v)
Definition foc_utils.h:14
#define _constrain(amt, low, high)
Definition foc_utils.h:11