@@ -41,71 +41,68 @@ static void syncTCC(Tcc* TCCx) {
41
41
}
42
42
#endif
43
43
44
- extern uint32_t toneMaxFrequency;
45
-
46
44
#if defined(__SAMD51__)
47
- #define PER_COUNTER 0xFF
45
+ #define MAX_PERIOD 0xFF
48
46
#else
49
- #define PER_COUNTER 0xFFFF
47
+ #define MAX_PERIOD 0xFFFF
50
48
#endif
51
49
52
- static inline uint32_t calcPrescaler (uint32_t frequency)
50
+ static inline unsigned long calcPrescaler (uint32_t frequency, uint32_t &period )
53
51
{
54
52
// if it's a rest, set to 1Hz (below audio range)
55
53
frequency = (frequency > 0 ? frequency : 1 );
56
54
//
57
55
// Calculate best prescaler divider and comparator value for a 16 bit TC peripheral
58
- uint32_t prescalerConfigBits;
59
- uint32_t ccValue;
56
+ unsigned long prescalerConfigVal;
60
57
61
- ccValue = toneMaxFrequency / frequency - 1 ;
62
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1 ;
58
+ period = F_CPU / frequency - 1 ;
59
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV1_Val ;
63
60
64
61
uint8_t i = 0 ;
65
62
66
- while (ccValue > PER_COUNTER )
63
+ while (period > MAX_PERIOD )
67
64
{
68
- ccValue = toneMaxFrequency / frequency / (2 << i) - 1 ;
69
- i++;
70
65
if (i == 4 || i == 6 || i == 8 ) // DIV32 DIV128 and DIV512 are not available
71
66
i++;
67
+ period = F_CPU / frequency / (2 << i) - 1 ;
68
+ i++;
72
69
}
73
70
74
71
switch (i - 1 )
75
72
{
76
73
case 0 :
77
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2 ;
74
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV2_Val ;
78
75
break ;
79
76
80
77
case 1 :
81
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4 ;
78
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV4_Val ;
82
79
break ;
83
80
84
81
case 2 :
85
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8 ;
82
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV8_Val ;
86
83
break ;
87
84
88
85
case 3 :
89
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16 ;
86
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV16_Val ;
90
87
break ;
91
88
92
89
case 5 :
93
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64 ;
90
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV64_Val ;
94
91
break ;
95
92
96
93
case 7 :
97
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256 ;
94
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV256_Val ;
98
95
break ;
99
96
100
97
case 9 :
101
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024 ;
98
+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV1024_Val ;
102
99
break ;
103
100
104
101
default :
105
102
break ;
106
103
}
107
104
108
- return prescalerConfigBits ;
105
+ return prescalerConfigVal ;
109
106
}
110
107
111
108
void pwm (uint32_t outputPin, uint32_t frequency, uint32_t duty)
@@ -116,10 +113,11 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
116
113
#if defined(__SAMD51__)
117
114
if (attr & (PIN_ATTR_PWM_E | PIN_ATTR_PWM_F | PIN_ATTR_PWM_G))
118
115
{
119
- duty = mapResolution (duty, 10 , 8 ) ;
120
- uint32_t prescalerConfigBits ;
116
+ unsigned long prescalerConfigVal ;
117
+ uint32_t period ;
121
118
122
- prescalerConfigBits = calcPrescaler (frequency);
119
+ prescalerConfigVal = calcPrescaler (frequency, period);
120
+ duty = map (duty, 0 , 1024 , 0 , period);
123
121
124
122
uint32_t tcNum = GetTCNumber (pinDesc.ulPWMChannel );
125
123
uint8_t tcChannel = GetTCChannelNumber (pinDesc.ulPWMChannel );
@@ -149,7 +147,7 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
149
147
while (TCx->COUNT8 .SYNCBUSY .bit .ENABLE )
150
148
;
151
149
// Set Timer counter Mode to 8 bits, normal PWM,
152
- TCx->COUNT8 .CTRLA .reg = TC_CTRLA_MODE_COUNT8 | prescalerConfigBits ;
150
+ TCx->COUNT8 .CTRLA .reg = TC_CTRLA_MODE_COUNT8 | TC_CTRLA_PRESCALER (prescalerConfigVal) ;
153
151
TCx->COUNT8 .WAVE .reg = TC_WAVE_WAVEGEN_NPWM;
154
152
155
153
while (TCx->COUNT8 .SYNCBUSY .bit .CC0 )
@@ -158,8 +156,8 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
158
156
TCx->COUNT8 .CC [tcChannel].reg = (uint8_t )duty;
159
157
while (TCx->COUNT8 .SYNCBUSY .bit .CC0 )
160
158
;
161
- // Set PER to maximum counter value (resolution : 0xFF)
162
- TCx->COUNT8 .PER .reg = 0xFF ;
159
+ // Set PER to calculated period
160
+ TCx->COUNT8 .PER .reg = period ;
163
161
while (TCx->COUNT8 .SYNCBUSY .bit .PER )
164
162
;
165
163
// Enable TCx
@@ -181,7 +179,7 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
181
179
while (TCCx->SYNCBUSY .bit .ENABLE )
182
180
;
183
181
// Set prescaler
184
- TCCx->CTRLA .reg = prescalerConfigBits | TCC_CTRLA_PRESCSYNC_GCLK;
182
+ TCCx->CTRLA .reg = TC_CTRLA_PRESCALER (prescalerConfigVal) | TCC_CTRLA_PRESCSYNC_GCLK;
185
183
186
184
// Set TCx as normal PWM
187
185
TCCx->WAVE .reg = TCC_WAVE_WAVEGEN_NPWM;
@@ -194,8 +192,8 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
194
192
TCCx->CC [tcChannel].reg = (uint32_t )duty;
195
193
while (TCCx->SYNCBUSY .bit .CC0 || TCCx->SYNCBUSY .bit .CC1 )
196
194
;
197
- // Set PER to maximum counter value (resolution : 0xFF)
198
- TCCx->PER .reg = 0xFF ;
195
+ // Set PER to calculated period
196
+ TCCx->PER .reg = period ;
199
197
while (TCCx->SYNCBUSY .bit .PER )
200
198
;
201
199
// Enable TCCx
@@ -210,10 +208,10 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
210
208
211
209
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
212
210
{
213
- duty = mapResolution (duty, 10 , 16 ) ;
214
- uint32_t prescalerConfigBits ;
211
+ uint32_t prescalerConfigVal ;
212
+ uint32_t period ;
215
213
216
- prescalerConfigBits = calcPrescaler (frequency);
214
+ prescalerConfigVal = calcPrescaler (frequency, period );
217
215
218
216
uint32_t tcNum = GetTCNumber (pinDesc.ulPWMChannel );
219
217
uint8_t tcChannel = GetTCChannelNumber (pinDesc.ulPWMChannel );
@@ -259,13 +257,14 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
259
257
// Set PORT
260
258
if (tcNum >= TCC_INST_NUM)
261
259
{
260
+ duty = mapResolution (duty, 10 , 16 );
262
261
// -- Configure TC
263
262
Tc *TCx = (Tc *)GetTC (pinDesc.ulPWMChannel );
264
263
// Disable TCx
265
264
TCx->COUNT16 .CTRLA .bit .ENABLE = 0 ;
266
265
syncTC_16 (TCx);
267
266
// Set Timer counter Mode to 16 bits, normal PWM
268
- TCx->COUNT16 .CTRLA .reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_NPWM | prescalerConfigBits ;
267
+ TCx->COUNT16 .CTRLA .reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_NPWM | TC_CTRLA_PRESCALER (prescalerConfigVal) ;
269
268
syncTC_16 (TCx);
270
269
// Set the initial value
271
270
TCx->COUNT16 .CC [tcChannel].reg = (uint32_t )duty;
@@ -276,19 +275,23 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
276
275
}
277
276
else
278
277
{
278
+ duty = map (duty, 0 , 1024 , 0 , period);
279
279
// -- Configure TCC
280
280
Tcc *TCCx = (Tcc *)GetTC (pinDesc.ulPWMChannel );
281
281
// Disable TCCx
282
282
TCCx->CTRLA .bit .ENABLE = 0 ;
283
283
syncTCC (TCCx);
284
+ // Set prescaler
285
+ TCCx->CTRLA .bit .PRESCALER = prescalerConfigVal;
286
+ syncTCC (TCCx);
284
287
// Set TCCx as normal PWM
285
288
TCCx->WAVE .reg |= TCC_WAVE_WAVEGEN_NPWM;
286
289
syncTCC (TCCx);
287
290
// Set the initial value
288
291
TCCx->CC [tcChannel].reg = (uint32_t )duty;
289
292
syncTCC (TCCx);
290
- // Set PER to maximum counter value (resolution : 0xFFFF)
291
- TCCx->PER .reg = 0xFFFF ;
293
+ // Set PER to calculated period
294
+ TCCx->PER .reg = period ;
292
295
syncTCC (TCCx);
293
296
// Enable TCCx
294
297
TCCx->CTRLA .bit .ENABLE = 1 ;
0 commit comments