11#pragma message("SimpleFOC: compiling for SAMD21")
16#define TCC3_CH0 NOT_ON_TIMER
19#define TCC3_CH1 NOT_ON_TIMER
22#define TCC3_CH2 NOT_ON_TIMER
25#define TCC3_CH3 NOT_ON_TIMER
28#define TCC3_CH4 NOT_ON_TIMER
31#define TCC3_CH5 NOT_ON_TIMER
34#define TCC3_CH6 NOT_ON_TIMER
37#define TCC3_CH7 NOT_ON_TIMER
40#define TC6_CH0 NOT_ON_TIMER
43#define TC6_CH1 NOT_ON_TIMER
46#define TC7_CH0 NOT_ON_TIMER
49#define TC7_CH1 NOT_ON_TIMER
54#define NUM_WO_ASSOCIATIONS 48
65struct wo_association WO_associations[] = {
67 { PORTA, 0, TCC2_CH0, 0, NOT_ON_TIMER, 0},
68 { PORTA, 1, TCC2_CH1, 1, NOT_ON_TIMER, 0},
69 { PORTA, 2, NOT_ON_TIMER, 0, TCC3_CH0, 0},
70 { PORTA, 3, NOT_ON_TIMER, 0, TCC3_CH1, 1},
72 { PORTB, 8, TC4_CH0, 0, TCC3_CH6, 6},
73 { PORTB, 9, TC4_CH1, 1, TCC3_CH7, 7},
74 { PORTA, 4, TCC0_CH0, 0, TCC3_CH2, 2},
75 { PORTA, 5, TCC0_CH1, 1, TCC3_CH3, 3},
76 { PORTA, 6, TCC1_CH0, 0, TCC3_CH4, 4},
77 { PORTA, 7, TCC1_CH1, 1, TCC3_CH5, 5},
78 { PORTA, 8, TCC0_CH0, 0, TCC1_CH2, 2},
79 { PORTA, 9, TCC0_CH1, 1, TCC1_CH3, 3},
80 { PORTA, 10, TCC1_CH0, 0, TCC0_CH2, 2},
81 { PORTA, 11, TCC1_CH1, 1, TCC0_CH3, 3},
82 { PORTB, 10, TC5_CH0, 0, TCC0_CH4, 4},
83 { PORTB, 11, TC5_CH1, 1, TCC0_CH5, 5},
84 { PORTB, 12, TC4_CH0, 0, TCC0_CH6, 6},
85 { PORTB, 13, TC4_CH1, 1, TCC0_CH7, 7},
86 { PORTB, 14, TC5_CH0, 0, NOT_ON_TIMER, 0},
87 { PORTB, 15, TC5_CH1, 1, NOT_ON_TIMER, 0},
88 { PORTA, 12, TCC2_CH0, 0, TCC0_CH6, 6},
89 { PORTA, 13, TCC2_CH1, 1, TCC0_CH7, 7},
90 { PORTA, 14, TC3_CH0, 0, TCC0_CH4, 4},
91 { PORTA, 15, TC3_CH1, 1, TCC0_CH5, 5},
92 { PORTA, 16, TCC2_CH0, 0, TCC0_CH6, 6},
93 { PORTA, 17, TCC2_CH1, 1, TCC0_CH7, 7},
94 { PORTA, 18, TC3_CH0, 0, TCC0_CH2, 2},
95 { PORTA, 19, TC3_CH1, 1, TCC0_CH3, 3},
96 { PORTB, 16, TC6_CH0, 0, TCC0_CH4, 4},
97 { PORTB, 17, TC6_CH1, 1, TCC0_CH5, 5},
98 { PORTA, 20, TC7_CH0, 0, TCC0_CH6, 6},
99 { PORTA, 21, TC7_CH1, 1, TCC0_CH7, 7},
100 { PORTA, 22, TC4_CH0, 0, TCC0_CH4, 4},
101 { PORTA, 23, TC4_CH1, 1, TCC0_CH5, 5},
102 { PORTA, 24, TC5_CH0, 0, TCC1_CH2, 2},
103 { PORTA, 25, TC5_CH1, 1, TCC1_CH3, 3},
104 { PORTB, 22, TC7_CH0, 0, TCC3_CH0, 0},
105 { PORTB, 23, TC7_CH1, 1, TCC3_CH1, 1},
106 { PORTA, 27, NOT_ON_TIMER, 0, TCC3_CH6, 6},
107 { PORTA, 28, NOT_ON_TIMER, 0, TCC3_CH7, 7},
108 { PORTA, 30, TCC1_CH0, 0, TCC3_CH4, 4},
109 { PORTA, 31, TCC1_CH1, 1, TCC3_CH5, 5},
110 { PORTB, 30, TCC0_CH0, 0, TCC1_CH2, 2},
111 { PORTB, 31, TCC0_CH1, 1, TCC1_CH3, 3},
112 { PORTB, 0, TC7_CH0, 0, NOT_ON_TIMER, 0},
113 { PORTB, 1, TC7_CH1, 1, NOT_ON_TIMER, 0},
114 { PORTB, 2, TC6_CH0, 0, TCC3_CH2, 2},
115 { PORTB, 3, TC6_CH1, 1, TCC3_CH3, 3}
117wo_association ASSOCIATION_NOT_FOUND = { NOT_A_PORT, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0};
121struct wo_association& getWOAssociation(EPortType port, uint32_t pin) {
122 for (
int i=0;i<NUM_WO_ASSOCIATIONS;i++) {
123 if (WO_associations[i].port==port && WO_associations[i].pin==pin)
124 return WO_associations[i];
126 return ASSOCIATION_NOT_FOUND;
131EPioType getPeripheralOfPermutation(
int permutation,
int pin_position) {
132 return ((permutation>>pin_position)&0x01)==0x1?PIO_TIMER_ALT:PIO_TIMER;
139void syncTCC(Tcc* TCCx) {
140 while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK);
150void configureSAMDClock() {
155 if (!SAMDClockConfigured) {
156 SAMDClockConfigured =
true;
157 for (
int i=0;i<TCC_INST_NUM;i++)
158 tccConfigured[i] =
false;
159 REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |
161 while (GCLK->STATUS.bit.SYNCBUSY);
163 REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |
165 GCLK_GENCTRL_SRC_DFLL48M |
168 while (GCLK->STATUS.bit.SYNCBUSY);
170#ifdef SIMPLEFOC_SAMD_DEBUG
184void configureTCC(tccConfiguration& tccConfig,
long pwm_frequency,
bool negate,
float hw6pwm) {
186 long pwm_resolution = (24000000) / pwm_frequency;
187 if (pwm_resolution>SIMPLEFOC_SAMD_MAX_PWM_RESOLUTION)
188 pwm_resolution = SIMPLEFOC_SAMD_MAX_PWM_RESOLUTION;
189 if (pwm_resolution<SIMPLEFOC_SAMD_MIN_PWM_RESOLUTION)
190 pwm_resolution = SIMPLEFOC_SAMD_MIN_PWM_RESOLUTION;
192 tccConfig.pwm_res = pwm_resolution;
195 if (!tccConfigured[tccConfig.tcc.tccn]) {
196 uint32_t GCLK_CLKCTRL_ID_ofthistcc = -1;
197 switch (tccConfig.tcc.tccn>>1) {
198 case 0: GCLK_CLKCTRL_ID_ofthistcc = GCLK_CLKCTRL_ID(GCM_TCC0_TCC1);
break;
199 case 1: GCLK_CLKCTRL_ID_ofthistcc = GCLK_CLKCTRL_ID(GCM_TCC2_TC3);
break;
200 case 2: GCLK_CLKCTRL_ID_ofthistcc = GCLK_CLKCTRL_ID(GCM_TC4_TC5);
break;
201 case 3: GCLK_CLKCTRL_ID_ofthistcc = GCLK_CLKCTRL_ID(GCM_TC6_TC7);
break;
206 REG_GCLK_CLKCTRL = (uint16_t) GCLK_CLKCTRL_CLKEN |
207 GCLK_CLKCTRL_GEN_GCLK4 |
208 GCLK_CLKCTRL_ID_ofthistcc;
209 while (GCLK->STATUS.bit.SYNCBUSY);
211 tccConfigured[tccConfig.tcc.tccn] =
true;
213 if (tccConfig.tcc.tccn>=TCC_INST_NUM) {
214 Tc* tc = (Tc*)GetTC(tccConfig.tcc.chaninfo);
216 tc->COUNT8.CTRLA.bit.ENABLE = 0;
217 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
219 tc->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8 | TC_CTRLA_WAVEGEN_NPWM ;
220 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
222 tc->COUNT8.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV8_Val ;
223 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
225 tc->COUNT8.PER.reg = SIMPLEFOC_SAMD_PWM_TC_RESOLUTION-1;
226 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
228 tc->COUNT8.CC[tccConfig.tcc.chan].reg = 0;
229 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
231 tc->COUNT8.CTRLA.bit.ENABLE = 1;
232 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
233#ifdef SIMPLEFOC_SAMD_DEBUG
238 Tcc* tcc = (Tcc*)GetTC(tccConfig.tcc.chaninfo);
240 uint8_t invenMask = ~(1<<tccConfig.tcc.chan);
241 uint8_t invenVal = negate?(1<<tccConfig.tcc.chan):0;
242 tcc->DRVCTRL.vec.INVEN = (tcc->DRVCTRL.vec.INVEN&invenMask)|invenVal;
245 tcc->WAVE.reg |= TCC_WAVE_POL(0xF)|TCC_WAVEB_WAVEGENB_DSBOTH;
246 while ( tcc->SYNCBUSY.bit.WAVE == 1 );
249 tcc->WEXCTRL.vec.DTIEN |= (1<<tccConfig.tcc.chan);
250 tcc->WEXCTRL.bit.DTLS = hw6pwm*(pwm_resolution-1);
251 tcc->WEXCTRL.bit.DTHS = hw6pwm*(pwm_resolution-1);
255 tcc->PER.reg = pwm_resolution - 1;
256 while ( tcc->SYNCBUSY.bit.PER == 1 );
259 uint8_t chanCount = (tccConfig.tcc.tccn==1||tccConfig.tcc.tccn==2)?2:4;
260 for (
int i=0;i<chanCount;i++) {
262 uint32_t chanbit = 0x1<<(TCC_SYNCBUSY_CC0_Pos+i);
263 while ( (tcc->SYNCBUSY.reg & chanbit) > 0 );
267 tcc->CTRLA.reg |= TCC_CTRLA_ENABLE | TCC_CTRLA_PRESCALER_DIV1;
268 while ( tcc->SYNCBUSY.bit.ENABLE == 1 );
270#if defined(SIMPLEFOC_SAMD_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
283 else if (tccConfig.tcc.tccn<TCC_INST_NUM) {
285 Tcc* tcc = (Tcc*)GetTC(tccConfig.tcc.chaninfo);
287 tcc->CTRLA.bit.ENABLE = 0;
288 while ( tcc->SYNCBUSY.bit.ENABLE == 1 );
290 uint8_t invenMask = ~(1<<tccConfig.tcc.chan);
291 uint8_t invenVal = negate?(1<<tccConfig.tcc.chan):0;
292 tcc->DRVCTRL.vec.INVEN = (tcc->DRVCTRL.vec.INVEN&invenMask)|invenVal;
296 tcc->WEXCTRL.vec.DTIEN |= (1<<tccConfig.tcc.chan);
297 tcc->WEXCTRL.bit.DTLS = hw6pwm*(pwm_resolution-1);
298 tcc->WEXCTRL.bit.DTHS = hw6pwm*(pwm_resolution-1);
302 tcc->CTRLA.bit.ENABLE = 1;
303 while ( tcc->SYNCBUSY.bit.ENABLE == 1 );
305#if defined(SIMPLEFOC_SAMD_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
325void writeSAMDDutyCycle(tccConfiguration* info,
float dc) {
326 uint8_t tccn = GetTCNumber(info->tcc.chaninfo);
327 uint8_t chan = GetTCChannelNumber(info->tcc.chaninfo);
328 if (tccn<TCC_INST_NUM) {
329 Tcc* tcc = (Tcc*)GetTC(info->tcc.chaninfo);
336 tcc->CCB[chan].reg = (uint32_t)((info->pwm_res-1) * dc);
344 Tc* tc = (Tc*)GetTC(info->tcc.chaninfo);
345 tc->COUNT8.CC[chan].reg = (uint8_t)((SIMPLEFOC_SAMD_PWM_TC_RESOLUTION-1) * dc);
346 while ( tc->COUNT8.STATUS.bit.SYNCBUSY == 1 );
#define SIMPLEFOC_DEBUG(msg,...)
static void print(const char *msg)