7
7
8
8
9
9
10
+ // expected frequency on DPLL, since we don't configure it ourselves. Typically this is the CPU frequency.
11
+ // for custom boards or overclockers you can override it using this define.
12
+ #ifndef SIMPLEFOC_SAMD51_DPLL_FREQ
13
+ #define SIMPLEFOC_SAMD51_DPLL_FREQ 120000000
14
+ #endif
15
+
16
+
17
+
18
+
19
+
10
20
// TCC# Channels WO_NUM Counter size Fault Dithering Output matrix DTI SWAP Pattern generation
11
21
// 0 6 8 24-bit Yes Yes Yes Yes Yes Yes
12
22
// 1 4 8 24-bit Yes Yes Yes Yes Yes Yes
17
27
18
28
#define NUM_WO_ASSOCIATIONS 72
19
29
20
-
21
30
struct wo_association WO_associations[] = {
22
31
23
32
{ PORTB, 9 , TC4_CH1, 1 , NOT_ON_TIMER, 0 , NOT_ON_TIMER, 0 },
@@ -112,7 +121,7 @@ struct wo_association& getWOAssociation(EPortType port, uint32_t pin) {
112
121
113
122
114
123
EPioType getPeripheralOfPermutation (int permutation, int pin_position) {
115
- return ((permutation>>pin_position)&0x01 )==0x1 ?PIO_TIMER_ALT:PIO_TIMER ;
124
+ return ((permutation>>pin_position)&0x01 )==0x1 ?PIO_TCC_PDEC:PIO_TIMER_ALT ;
116
125
}
117
126
118
127
@@ -124,24 +133,17 @@ void syncTCC(Tcc* TCCx) {
124
133
125
134
126
135
127
- void writeSAMDDutyCycle (int chaninfo , float dc) {
128
- uint8_t tccn = GetTCNumber (chaninfo);
129
- uint8_t chan = GetTCChannelNumber (chaninfo);
136
+ void writeSAMDDutyCycle (tccConfiguration* info , float dc) {
137
+ uint8_t tccn = GetTCNumber (info-> tcc . chaninfo );
138
+ uint8_t chan = GetTCChannelNumber (info-> tcc . chaninfo );
130
139
if (tccn<TCC_INST_NUM) {
131
- Tcc* tcc = (Tcc*)GetTC (chaninfo);
140
+ Tcc* tcc = (Tcc*)GetTC (info-> tcc . chaninfo );
132
141
// set via CCBUF
133
- while ( (tcc->SYNCBUSY .vec .CC & (0x1 <<chan)) > 0 );
134
- tcc->CCBUF [chan].reg = (uint32_t )((SIMPLEFOC_SAMD_PWM_RESOLUTION-1 ) * dc); // TODO pwm frequency!
135
- // tcc->STATUS.vec.CCBUFV |= (0x1<<chan);
136
- // while ( tcc->SYNCBUSY.bit.STATUS > 0 );
137
- // tcc->CTRLBSET.reg |= TCC_CTRLBSET_CMD(TCC_CTRLBSET_CMD_UPDATE_Val);
138
- // while ( tcc->SYNCBUSY.bit.CTRLB > 0 );
142
+ // while ( (tcc->SYNCBUSY.vec.CC & (0x1<<chan)) > 0 );
143
+ tcc->CCBUF [chan].reg = (uint32_t )((info->pwm_res -1 ) * dc); // TODO pwm frequency!
139
144
}
140
- else {
141
- // Tc* tc = (Tc*)GetTC(chaninfo);
142
- // //tc->COUNT16.CC[chan].reg = (uint32_t)((SIMPLEFOC_SAMD_PWM_RESOLUTION-1) * dc);
143
- // tc->COUNT8.CC[chan].reg = (uint8_t)((SIMPLEFOC_SAMD_PWM_TC_RESOLUTION-1) * dc);
144
- // while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
145
+ else {
146
+ // we don't support the TC channels on SAMD51, isn't worth it.
145
147
}
146
148
}
147
149
@@ -183,8 +185,8 @@ void configureSAMDClock() {
183
185
while (GCLK->SYNCBUSY .vec .GENCTRL &(0x1 <<PWM_CLOCK_NUM));
184
186
185
187
GCLK->GENCTRL [PWM_CLOCK_NUM].reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV (1 ) | GCLK_GENCTRL_IDC
186
- | GCLK_GENCTRL_SRC (GCLK_GENCTRL_SRC_DFLL_Val);
187
- // | GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DPLL0_Val);
188
+ // | GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL_Val);
189
+ | GCLK_GENCTRL_SRC (GCLK_GENCTRL_SRC_DPLL0_Val);
188
190
while (GCLK->SYNCBUSY .vec .GENCTRL &(0x1 <<PWM_CLOCK_NUM));
189
191
190
192
#ifdef SIMPLEFOC_SAMD_DEBUG
@@ -221,18 +223,27 @@ void configureTCC(tccConfiguration& tccConfig, long pwm_frequency, bool negate,
221
223
tcc->DRVCTRL .vec .INVEN = (tcc->DRVCTRL .vec .INVEN &invenMask)|invenVal;
222
224
syncTCC (tcc); // wait for sync
223
225
226
+ // work out pwm resolution for desired frequency and constrain to max/min values
227
+ long pwm_resolution = (SIMPLEFOC_SAMD51_DPLL_FREQ/2 ) / pwm_frequency;
228
+ if (pwm_resolution>SIMPLEFOC_SAMD_MAX_PWM_RESOLUTION)
229
+ pwm_resolution = SIMPLEFOC_SAMD_MAX_PWM_RESOLUTION;
230
+ if (pwm_resolution<SIMPLEFOC_SAMD_MIN_PWM_RESOLUTION)
231
+ pwm_resolution = SIMPLEFOC_SAMD_MIN_PWM_RESOLUTION;
232
+ // store for later use
233
+ tccConfig.pwm_res = pwm_resolution;
234
+
224
235
if (hw6pwm>0.0 ) {
225
236
tcc->WEXCTRL .vec .DTIEN |= (1 <<tccConfig.tcc .chan );
226
- tcc->WEXCTRL .bit .DTLS = hw6pwm*(SIMPLEFOC_SAMD_PWM_RESOLUTION -1 );
227
- tcc->WEXCTRL .bit .DTHS = hw6pwm*(SIMPLEFOC_SAMD_PWM_RESOLUTION -1 );
237
+ tcc->WEXCTRL .bit .DTLS = hw6pwm*(pwm_resolution -1 );
238
+ tcc->WEXCTRL .bit .DTHS = hw6pwm*(pwm_resolution -1 );
228
239
syncTCC (tcc); // wait for sync
229
240
}
230
241
231
242
if (!tccConfigured[tccConfig.tcc .tccn ]) {
232
243
tcc->WAVE .reg |= TCC_WAVE_POL (0xF )|TCC_WAVE_WAVEGEN_DSTOP; // Set wave form configuration - TODO check this... why set like this?
233
244
while ( tcc->SYNCBUSY .bit .WAVE == 1 ); // wait for sync
234
245
235
- tcc->PER .reg = SIMPLEFOC_SAMD_PWM_RESOLUTION - 1 ; // Set counter Top using the PER register
246
+ tcc->PER .reg = pwm_resolution - 1 ; // Set counter Top using the PER register
236
247
while ( tcc->SYNCBUSY .bit .PER == 1 ); // wait for sync
237
248
238
249
// set all channels to 0%
@@ -254,11 +265,12 @@ void configureTCC(tccConfiguration& tccConfig, long pwm_frequency, bool negate,
254
265
SIMPLEFOC_SAMD_DEBUG_SERIAL.print (tccConfig.tcc .chan );
255
266
SIMPLEFOC_SAMD_DEBUG_SERIAL.print (" [" );
256
267
SIMPLEFOC_SAMD_DEBUG_SERIAL.print (tccConfig.wo );
257
- SIMPLEFOC_SAMD_DEBUG_SERIAL.println (" ]" );
268
+ SIMPLEFOC_SAMD_DEBUG_SERIAL.print (" ] pwm res " );
269
+ SIMPLEFOC_SAMD_DEBUG_SERIAL.println (pwm_resolution);
258
270
#endif
259
271
}
260
272
else if (tccConfig.tcc .tccn >=TCC_INST_NUM) {
261
- Tc* tc = (Tc*)GetTC (tccConfig.tcc .chaninfo );
273
+ // Tc* tc = (Tc*)GetTC(tccConfig.tcc.chaninfo);
262
274
263
275
// disable
264
276
// tc->COUNT8.CTRLA.bit.ENABLE = 0;
@@ -280,8 +292,9 @@ void configureTCC(tccConfiguration& tccConfig, long pwm_frequency, bool negate,
280
292
// while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
281
293
282
294
#ifdef SIMPLEFOC_SAMD_DEBUG
283
- SIMPLEFOC_SAMD_DEBUG_SERIAL.print (" Initialized TC " );
295
+ SIMPLEFOC_SAMD_DEBUG_SERIAL.print (" Not initialized: TC " );
284
296
SIMPLEFOC_SAMD_DEBUG_SERIAL.println (tccConfig.tcc .tccn );
297
+ SIMPLEFOC_SAMD_DEBUG_SERIAL.print (" TC units not supported on SAMD51" );
285
298
#endif
286
299
}
287
300
0 commit comments