6#if defined(_SAMD51_)||defined(_SAME51_)
10#pragma message("SimpleFOC: compiling for SAMD51/SAME51")
17#ifndef SIMPLEFOC_SAMD51_DPLL_FREQ
18#define SIMPLEFOC_SAMD51_DPLL_FREQ 120000000
23#define TCC3_CH0 NOT_ON_TIMER
24#define TCC3_CH1 NOT_ON_TIMER
28#define TCC4_CH0 NOT_ON_TIMER
29#define TCC4_CH1 NOT_ON_TIMER
34#define TC4_CH0 NOT_ON_TIMER
35#define TC4_CH1 NOT_ON_TIMER
39#define TC5_CH0 NOT_ON_TIMER
40#define TC5_CH1 NOT_ON_TIMER
44#define TC6_CH0 NOT_ON_TIMER
45#define TC6_CH1 NOT_ON_TIMER
49#define TC7_CH0 NOT_ON_TIMER
50#define TC7_CH1 NOT_ON_TIMER
63#define NUM_WO_ASSOCIATIONS 72
65struct wo_association WO_associations[] = {
67 { PORTB, 9, TC4_CH1, 1, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
68 { PORTA, 4, TC0_CH0, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
69 { PORTA, 5, TC0_CH1, 1, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
70 { PORTA, 6, TC1_CH0, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
71 { PORTA, 7, TC1_CH1, 1, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
72 { PORTC, 4, NOT_ON_TIMER, 0, TCC0_CH0, 0, NOT_ON_TIMER, 0},
74 { PORTA, 8, TC0_CH0, 0, TCC0_CH0, 0, TCC1_CH0, 4},
75 { PORTA, 9, TC0_CH1, 1, TCC0_CH1, 1, TCC1_CH1, 5},
76 { PORTA, 10, TC1_CH0, 0, TCC0_CH2, 2, TCC1_CH2, 6},
77 { PORTA, 11, TC1_CH1, 1, TCC0_CH3, 3, TCC1_CH3, 7},
78 { PORTB, 10, TC5_CH0, 0, TCC0_CH4, 4, TCC1_CH0, 0},
79 { PORTB, 11, TC5_CH1, 1, TCC0_CH5, 5, TCC1_CH1, 1},
80 { PORTB, 12, TC4_CH0, 0, TCC3_CH0, 0, TCC0_CH0, 0},
81 { PORTB, 13, TC4_CH1, 1, TCC3_CH1, 1, TCC0_CH1, 1},
82 { PORTB, 14, TC5_CH0, 0, TCC4_CH0, 0, TCC0_CH2, 2},
83 { PORTB, 15, TC5_CH1, 1, TCC4_CH1, 1, TCC0_CH3, 3},
84 { PORTD, 8, NOT_ON_TIMER, 0, TCC0_CH1, 1, NOT_ON_TIMER, 0},
85 { PORTD, 9, NOT_ON_TIMER, 0, TCC0_CH2, 2, NOT_ON_TIMER, 0},
86 { PORTD, 10, NOT_ON_TIMER, 0, TCC0_CH3, 3, NOT_ON_TIMER, 0},
87 { PORTD, 11, NOT_ON_TIMER, 0, TCC0_CH4, 4, NOT_ON_TIMER, 0},
88 { PORTD, 12, NOT_ON_TIMER, 0, TCC0_CH5, 5, NOT_ON_TIMER, 0},
89 { PORTC, 10, NOT_ON_TIMER, 0, TCC0_CH0, 0, TCC1_CH0, 4},
90 { PORTC, 11, NOT_ON_TIMER, 0, TCC0_CH1, 1, TCC1_CH1, 5},
91 { PORTC, 12, NOT_ON_TIMER, 0, TCC0_CH2, 2, TCC1_CH2, 6},
92 { PORTC, 13, NOT_ON_TIMER, 0, TCC0_CH3, 3, TCC1_CH3, 7},
93 { PORTC, 14, NOT_ON_TIMER, 0, TCC0_CH4, 4, TCC1_CH0, 0},
94 { PORTC, 15, NOT_ON_TIMER, 0, TCC0_CH5, 5, TCC1_CH1, 1},
95 { PORTA, 12, TC2_CH0, 0, TCC0_CH0, 6, TCC1_CH2, 2},
96 { PORTA, 13, TC2_CH1, 1, TCC0_CH1, 7, TCC1_CH3, 3},
97 { PORTA, 14, TC3_CH0, 0, TCC2_CH0, 0, TCC1_CH2, 2},
98 { PORTA, 15, TC3_CH1, 1, TCC2_CH1, 1, TCC1_CH3, 3},
99 { PORTA, 16, TC2_CH0, 0, TCC1_CH0, 0, TCC0_CH4, 4},
100 { PORTA, 17, TC2_CH1, 1, TCC1_CH1, 1, TCC0_CH5, 5},
101 { PORTA, 18, TC3_CH0, 0, TCC1_CH2, 2, TCC0_CH0, 6},
102 { PORTA, 19, TC3_CH1, 1, TCC1_CH3, 3, TCC0_CH1, 7},
103 { PORTC, 16, NOT_ON_TIMER, 0, TCC0_CH0, 0, NOT_ON_TIMER, 0},
104 { PORTC, 17, NOT_ON_TIMER, 0, TCC0_CH1, 1, NOT_ON_TIMER, 0},
105 { PORTC, 18, NOT_ON_TIMER, 0, TCC0_CH2, 2, NOT_ON_TIMER, 0},
106 { PORTC, 19, NOT_ON_TIMER, 0, TCC0_CH3, 3, NOT_ON_TIMER, 0},
107 { PORTC, 20, NOT_ON_TIMER, 0, TCC0_CH4, 4, NOT_ON_TIMER, 0},
108 { PORTC, 21, NOT_ON_TIMER, 0, TCC0_CH5, 5, NOT_ON_TIMER, 0},
109 { PORTC, 22, NOT_ON_TIMER, 0, TCC0_CH0, 6, NOT_ON_TIMER, 0},
110 { PORTC, 23, NOT_ON_TIMER, 0, TCC0_CH1, 7, NOT_ON_TIMER, 0},
111 { PORTD, 20, NOT_ON_TIMER, 0, TCC1_CH0, 0, NOT_ON_TIMER, 0},
112 { PORTD, 21, NOT_ON_TIMER, 0, TCC1_CH1, 1, NOT_ON_TIMER, 0},
113 { PORTB, 16, TC6_CH0, 0, TCC3_CH0, 0, TCC0_CH4, 4},
114 { PORTB, 17, TC6_CH1, 1, TCC3_CH1, 1, TCC0_CH5, 5},
115 { PORTB, 18, NOT_ON_TIMER, 0, TCC1_CH0, 0, NOT_ON_TIMER, 0},
116 { PORTB, 19, NOT_ON_TIMER, 0, TCC1_CH1, 1, NOT_ON_TIMER, 0},
117 { PORTB, 20, NOT_ON_TIMER, 0, TCC1_CH2, 2, NOT_ON_TIMER, 0},
118 { PORTB, 21, NOT_ON_TIMER, 0, TCC1_CH3, 3, NOT_ON_TIMER, 0},
119 { PORTA, 20, TC7_CH0, 0, TCC1_CH0, 4, TCC0_CH0, 0},
120 { PORTA, 21, TC7_CH1, 1, TCC1_CH1, 5, TCC0_CH1, 1},
121 { PORTA, 22, TC4_CH0, 0, TCC1_CH2, 6, TCC0_CH2, 2},
122 { PORTA, 23, TC4_CH1, 1, TCC1_CH3, 7, TCC0_CH3, 3},
123 { PORTA, 24, TC5_CH0, 0, TCC2_CH2, 2, NOT_ON_TIMER, 0},
124 { PORTA, 25, TC5_CH1, 1, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
125 { PORTB, 22, TC7_CH0, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
126 { PORTB, 23, TC7_CH1, 1, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
127 { PORTB, 24, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
128 { PORTB, 25, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
129 { PORTB, 26, NOT_ON_TIMER, 0, TCC1_CH2, 2, NOT_ON_TIMER, 0},
130 { PORTB, 27, NOT_ON_TIMER, 0, TCC1_CH3, 3, NOT_ON_TIMER, 0},
131 { PORTB, 28, NOT_ON_TIMER, 0, TCC1_CH0, 4, NOT_ON_TIMER, 0},
132 { PORTB, 29, NOT_ON_TIMER, 0, TCC1_CH1, 5, NOT_ON_TIMER, 0},
134 { PORTA, 30, TC6_CH0, 0, TCC2_CH0, 0, NOT_ON_TIMER, 0},
135 { PORTA, 31, TC6_CH1, 1, TCC2_CH1, 1, NOT_ON_TIMER, 0},
136 { PORTB, 30, TC0_CH0, 0, TCC4_CH0, 0, TCC0_CH0, 6},
137 { PORTB, 31, TC0_CH1, 1, TCC4_CH1, 1, TCC0_CH1, 7},
139 { PORTB, 0, TC7_CH0, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
140 { PORTB, 1, TC7_CH1, 1, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0},
141 { PORTB, 2, TC6_CH0, 0, TCC2_CH2, 2, NOT_ON_TIMER, 0},
145wo_association ASSOCIATION_NOT_FOUND = { NOT_A_PORT, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0, NOT_ON_TIMER, 0};
148uint8_t TCC_CHANNEL_COUNT[] = { TCC0_CC_NUM, TCC1_CC_NUM, TCC2_CC_NUM };
150uint8_t TCC_CHANNEL_COUNT[] = { TCC0_CC_NUM, TCC1_CC_NUM, TCC2_CC_NUM, TCC3_CC_NUM, TCC4_CC_NUM };
154struct wo_association& getWOAssociation(EPortType port, uint32_t pin) {
155 for (
int i=0;i<NUM_WO_ASSOCIATIONS;i++) {
156 if (WO_associations[i].port==port && WO_associations[i].pin==pin)
157 return WO_associations[i];
159 return ASSOCIATION_NOT_FOUND;
163EPioType getPeripheralOfPermutation(
int permutation,
int pin_position) {
164 return ((permutation>>pin_position)&0x01)==0x1?PIO_TCC_PDEC:PIO_TIMER_ALT;
169void syncTCC(Tcc* TCCx) {
170 while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK);
176void writeSAMDDutyCycle(tccConfiguration* info,
float dc) {
177 uint8_t tccn = GetTCNumber(info->tcc.chaninfo);
178 uint8_t chan = GetTCChannelNumber(info->tcc.chaninfo);
179 if (tccn<TCC_INST_NUM) {
180 Tcc* tcc = (Tcc*)GetTC(info->tcc.chaninfo);
183 tcc->CCBUF[chan].reg = (uint32_t)((info->pwm_res-1) * dc);
191#define DPLL_CLOCK_NUM 2
192#define PWM_CLOCK_NUM 3
200void configureSAMDClock() {
201 if (!SAMDClockConfigured) {
202 SAMDClockConfigured =
true;
203 for (
int i=0;i<TCC_INST_NUM;i++)
204 tccConfigured[i] =
false;
224 GCLK->GENCTRL[PWM_CLOCK_NUM].bit.GENEN = 0;
225 while (GCLK->SYNCBUSY.vec.GENCTRL&(0x1<<PWM_CLOCK_NUM));
227 GCLK->GENCTRL[PWM_CLOCK_NUM].reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_IDC
229 | GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DPLL0_Val);
230 while (GCLK->SYNCBUSY.vec.GENCTRL&(0x1<<PWM_CLOCK_NUM));
232#ifdef SIMPLEFOC_SAMD_DEBUG
247void configureTCC(tccConfiguration& tccConfig,
long pwm_frequency,
bool negate,
float hw6pwm) {
249 if (!tccConfigured[tccConfig.tcc.tccn]) {
250 uint32_t GCLK_CLKCTRL_ID_ofthistcc = GCLK_CLKCTRL_IDs[tccConfig.tcc.tccn];
251 GCLK->PCHCTRL[GCLK_CLKCTRL_ID_ofthistcc].reg = GCLK_PCHCTRL_GEN(PWM_CLOCK_NUM)|GCLK_PCHCTRL_CHEN;
252 while (GCLK->SYNCBUSY.vec.GENCTRL&(0x1<<PWM_CLOCK_NUM));
255 if (tccConfig.tcc.tccn<TCC_INST_NUM) {
256 Tcc* tcc = (Tcc*)GetTC(tccConfig.tcc.chaninfo);
258 tcc->CTRLA.bit.ENABLE = 0;
259 while ( tcc->SYNCBUSY.bit.ENABLE == 1 );
261 uint8_t invenMask = ~(1<<tccConfig.tcc.chan);
262 uint8_t invenVal = negate?(1<<tccConfig.tcc.chan):0;
263 tcc->DRVCTRL.vec.INVEN = (tcc->DRVCTRL.vec.INVEN&invenMask)|invenVal;
267 long pwm_resolution = (SIMPLEFOC_SAMD51_DPLL_FREQ/2) / pwm_frequency;
268 if (pwm_resolution>SIMPLEFOC_SAMD_MAX_PWM_RESOLUTION)
269 pwm_resolution = SIMPLEFOC_SAMD_MAX_PWM_RESOLUTION;
270 if (pwm_resolution<SIMPLEFOC_SAMD_MIN_PWM_RESOLUTION)
271 pwm_resolution = SIMPLEFOC_SAMD_MIN_PWM_RESOLUTION;
273 tccConfig.pwm_res = pwm_resolution;
276 tcc->WEXCTRL.vec.DTIEN |= (1<<tccConfig.tcc.chan);
277 tcc->WEXCTRL.bit.DTLS = hw6pwm*(pwm_resolution-1);
278 tcc->WEXCTRL.bit.DTHS = hw6pwm*(pwm_resolution-1);
282 if (!tccConfigured[tccConfig.tcc.tccn]) {
283 tcc->WAVE.reg |= TCC_WAVE_POL(0xF)|TCC_WAVE_WAVEGEN_DSTOP;
284 while ( tcc->SYNCBUSY.bit.WAVE == 1 );
286 tcc->PER.reg = pwm_resolution - 1;
287 while ( tcc->SYNCBUSY.bit.PER == 1 );
290 for (
int i=0;i<TCC_CHANNEL_COUNT[tccConfig.tcc.tccn];i++) {
292 uint32_t chanbit = 0x1<<(TCC_SYNCBUSY_CC0_Pos+i);
293 while ( (tcc->SYNCBUSY.reg & chanbit) > 0 );
298 tcc->CTRLA.reg |= TCC_CTRLA_ENABLE | TCC_CTRLA_PRESCALER_DIV1;
299 while ( tcc->SYNCBUSY.bit.ENABLE == 1 );
301#if defined(SIMPLEFOC_SAMD_DEBUG) && !defined(SIMPLEFOC_DISABLE_DEBUG)
313 else if (tccConfig.tcc.tccn>=TCC_INST_NUM) {
335 #ifdef SIMPLEFOC_SAMD_DEBUG
342 tccConfigured[tccConfig.tcc.tccn] =
true;
#define SIMPLEFOC_DEBUG(msg,...)
static void print(const char *msg)