@@ -41,71 +41,68 @@ static void syncTCC(Tcc* TCCx) {
4141}
4242#endif
4343
44- extern uint32_t toneMaxFrequency;
45-
4644#if defined(__SAMD51__)
47- #define PER_COUNTER 0xFF
45+ #define MAX_PERIOD 0xFF
4846#else
49- #define PER_COUNTER 0xFFFF
47+ #define MAX_PERIOD 0xFFFF
5048#endif
5149
52- static inline uint32_t calcPrescaler (uint32_t frequency)
50+ static inline unsigned long calcPrescaler (uint32_t frequency, uint32_t &period )
5351{
5452 // if it's a rest, set to 1Hz (below audio range)
5553 frequency = (frequency > 0 ? frequency : 1 );
5654 //
5755 // 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;
6057
61- ccValue = toneMaxFrequency / frequency - 1 ;
62- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1 ;
58+ period = F_CPU / frequency - 1 ;
59+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV1_Val ;
6360
6461 uint8_t i = 0 ;
6562
66- while (ccValue > PER_COUNTER )
63+ while (period > MAX_PERIOD )
6764 {
68- ccValue = toneMaxFrequency / frequency / (2 << i) - 1 ;
69- i++;
7065 if (i == 4 || i == 6 || i == 8 ) // DIV32 DIV128 and DIV512 are not available
7166 i++;
67+ period = F_CPU / frequency / (2 << i) - 1 ;
68+ i++;
7269 }
7370
7471 switch (i - 1 )
7572 {
7673 case 0 :
77- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2 ;
74+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV2_Val ;
7875 break ;
7976
8077 case 1 :
81- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4 ;
78+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV4_Val ;
8279 break ;
8380
8481 case 2 :
85- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8 ;
82+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV8_Val ;
8683 break ;
8784
8885 case 3 :
89- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16 ;
86+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV16_Val ;
9087 break ;
9188
9289 case 5 :
93- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64 ;
90+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV64_Val ;
9491 break ;
9592
9693 case 7 :
97- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256 ;
94+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV256_Val ;
9895 break ;
9996
10097 case 9 :
101- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024 ;
98+ prescalerConfigVal = TC_CTRLA_PRESCALER_DIV1024_Val ;
10299 break ;
103100
104101 default :
105102 break ;
106103 }
107104
108- return prescalerConfigBits ;
105+ return prescalerConfigVal ;
109106}
110107
111108void 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)
116113#if defined(__SAMD51__)
117114 if (attr & (PIN_ATTR_PWM_E | PIN_ATTR_PWM_F | PIN_ATTR_PWM_G))
118115 {
119- duty = mapResolution (duty, 10 , 8 ) ;
120- uint32_t prescalerConfigBits ;
116+ unsigned long prescalerConfigVal ;
117+ uint32_t period ;
121118
122- prescalerConfigBits = calcPrescaler (frequency);
119+ prescalerConfigVal = calcPrescaler (frequency, period);
120+ duty = map (duty, 0 , 1024 , 0 , period);
123121
124122 uint32_t tcNum = GetTCNumber (pinDesc.ulPWMChannel );
125123 uint8_t tcChannel = GetTCChannelNumber (pinDesc.ulPWMChannel );
@@ -149,7 +147,7 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
149147 while (TCx->COUNT8 .SYNCBUSY .bit .ENABLE )
150148 ;
151149 // 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) ;
153151 TCx->COUNT8 .WAVE .reg = TC_WAVE_WAVEGEN_NPWM;
154152
155153 while (TCx->COUNT8 .SYNCBUSY .bit .CC0 )
@@ -158,8 +156,8 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
158156 TCx->COUNT8 .CC [tcChannel].reg = (uint8_t )duty;
159157 while (TCx->COUNT8 .SYNCBUSY .bit .CC0 )
160158 ;
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 ;
163161 while (TCx->COUNT8 .SYNCBUSY .bit .PER )
164162 ;
165163 // Enable TCx
@@ -181,7 +179,7 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
181179 while (TCCx->SYNCBUSY .bit .ENABLE )
182180 ;
183181 // Set prescaler
184- TCCx->CTRLA .reg = prescalerConfigBits | TCC_CTRLA_PRESCSYNC_GCLK;
182+ TCCx->CTRLA .reg = TC_CTRLA_PRESCALER (prescalerConfigVal) | TCC_CTRLA_PRESCSYNC_GCLK;
185183
186184 // Set TCx as normal PWM
187185 TCCx->WAVE .reg = TCC_WAVE_WAVEGEN_NPWM;
@@ -194,8 +192,8 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
194192 TCCx->CC [tcChannel].reg = (uint32_t )duty;
195193 while (TCCx->SYNCBUSY .bit .CC0 || TCCx->SYNCBUSY .bit .CC1 )
196194 ;
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 ;
199197 while (TCCx->SYNCBUSY .bit .PER )
200198 ;
201199 // Enable TCCx
@@ -210,10 +208,10 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
210208
211209 if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
212210 {
213- duty = mapResolution (duty, 10 , 16 ) ;
214- uint32_t prescalerConfigBits ;
211+ uint32_t prescalerConfigVal ;
212+ uint32_t period ;
215213
216- prescalerConfigBits = calcPrescaler (frequency);
214+ prescalerConfigVal = calcPrescaler (frequency, period );
217215
218216 uint32_t tcNum = GetTCNumber (pinDesc.ulPWMChannel );
219217 uint8_t tcChannel = GetTCChannelNumber (pinDesc.ulPWMChannel );
@@ -259,13 +257,14 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
259257 // Set PORT
260258 if (tcNum >= TCC_INST_NUM)
261259 {
260+ duty = mapResolution (duty, 10 , 16 );
262261 // -- Configure TC
263262 Tc *TCx = (Tc *)GetTC (pinDesc.ulPWMChannel );
264263 // Disable TCx
265264 TCx->COUNT16 .CTRLA .bit .ENABLE = 0 ;
266265 syncTC_16 (TCx);
267266 // 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) ;
269268 syncTC_16 (TCx);
270269 // Set the initial value
271270 TCx->COUNT16 .CC [tcChannel].reg = (uint32_t )duty;
@@ -276,19 +275,23 @@ void pwm(uint32_t outputPin, uint32_t frequency, uint32_t duty)
276275 }
277276 else
278277 {
278+ duty = map (duty, 0 , 1024 , 0 , period);
279279 // -- Configure TCC
280280 Tcc *TCCx = (Tcc *)GetTC (pinDesc.ulPWMChannel );
281281 // Disable TCCx
282282 TCCx->CTRLA .bit .ENABLE = 0 ;
283283 syncTCC (TCCx);
284+ // Set prescaler
285+ TCCx->CTRLA .bit .PRESCALER = prescalerConfigVal;
286+ syncTCC (TCCx);
284287 // Set TCCx as normal PWM
285288 TCCx->WAVE .reg |= TCC_WAVE_WAVEGEN_NPWM;
286289 syncTCC (TCCx);
287290 // Set the initial value
288291 TCCx->CC [tcChannel].reg = (uint32_t )duty;
289292 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 ;
292295 syncTCC (TCCx);
293296 // Enable TCCx
294297 TCCx->CTRLA .bit .ENABLE = 1 ;
0 commit comments