Skip to content

Commit 533d7cc

Browse files
committed
Fixed PWM frequency glitch
2 parents 94d6f56 + c9f315b commit 533d7cc

File tree

2 files changed

+132
-152
lines changed

2 files changed

+132
-152
lines changed

CHANGELOG

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ SAMD CORE
1010
* Fixed digitalWrite() unnecessarily activating the pull-up resistor
1111
* Wire: Slave writes now use TX buffer
1212
* Added getTimeout() method to Stream.
13+
* Fixed glitch in PWM generation that may happen when calling analogWrite()
14+
* PWM frequency is now 732.4Hz (before it was 187500.0Hz)
1315

1416
SAMD CORE 1.6.6 2016.05.19
1517

cores/arduino/wiring_analog.c

+130-152
Original file line numberDiff line numberDiff line change
@@ -53,47 +53,36 @@ static void syncTCC(Tcc* TCCx) {
5353
while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK);
5454
}
5555

56-
void analogReadResolution( int res )
56+
void analogReadResolution(int res)
5757
{
58-
_readResolution = res ;
59-
if (res > 10)
60-
{
58+
_readResolution = res;
59+
if (res > 10) {
6160
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
6261
_ADCResolution = 12;
63-
}
64-
else if (res > 8)
65-
{
62+
} else if (res > 8) {
6663
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
6764
_ADCResolution = 10;
68-
}
69-
else
70-
{
65+
} else {
7166
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
7267
_ADCResolution = 8;
7368
}
7469
syncADC();
7570
}
7671

77-
void analogWriteResolution( int res )
72+
void analogWriteResolution(int res)
7873
{
79-
_writeResolution = res ;
74+
_writeResolution = res;
8075
}
8176

82-
static inline uint32_t mapResolution( uint32_t value, uint32_t from, uint32_t to )
77+
static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to)
8378
{
84-
if ( from == to )
85-
{
86-
return value ;
79+
if (from == to) {
80+
return value;
8781
}
88-
89-
if ( from > to )
90-
{
91-
return value >> (from-to) ;
92-
}
93-
else
94-
{
95-
return value << (to-from) ;
82+
if (from > to) {
83+
return value >> (from-to);
9684
}
85+
return value << (to-from);
9786
}
9887

9988
/*
@@ -102,10 +91,10 @@ static inline uint32_t mapResolution( uint32_t value, uint32_t from, uint32_t to
10291
*
10392
* Warning : On Arduino Zero board the input/output voltage for SAMD21G18 is 3.3 volts maximum
10493
*/
105-
void analogReference( eAnalogReference ulMode )
94+
void analogReference(eAnalogReference mode)
10695
{
10796
syncADC();
108-
switch ( ulMode )
97+
switch (mode)
10998
{
11099
case AR_INTERNAL:
111100
case AR_INTERNAL2V23:
@@ -136,27 +125,25 @@ void analogReference( eAnalogReference ulMode )
136125
}
137126
}
138127

139-
uint32_t analogRead( uint32_t ulPin )
128+
uint32_t analogRead(uint32_t pin)
140129
{
141130
uint32_t valueRead = 0;
142131

143-
if ( ulPin < A0 )
144-
{
145-
ulPin += A0 ;
132+
if (pin < A0) {
133+
pin += A0;
146134
}
147135

148-
pinPeripheral(ulPin, PIO_ANALOG);
136+
pinPeripheral(pin, PIO_ANALOG);
149137

150-
if (ulPin == A0) // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
151-
{
138+
if (pin == A0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
152139
syncDAC();
153140
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
154141
//DAC->CTRLB.bit.EOEN = 0x00; // The DAC output is turned off.
155142
syncDAC();
156143
}
157144

158145
syncADC();
159-
ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ulPin].ulADCChannelNumber; // Selection for the positive ADC input
146+
ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[pin].ulADCChannelNumber; // Selection for the positive ADC input
160147

161148
// Control A
162149
/*
@@ -185,7 +172,7 @@ uint32_t analogRead( uint32_t ulPin )
185172
ADC->SWTRIG.bit.START = 1;
186173

187174
// Store the value
188-
while ( ADC->INTFLAG.bit.RESRDY == 0 ); // Waiting for conversion to complete
175+
while (ADC->INTFLAG.bit.RESRDY == 0); // Waiting for conversion to complete
189176
valueRead = ADC->RESULT.reg;
190177

191178
syncADC();
@@ -200,143 +187,134 @@ uint32_t analogRead( uint32_t ulPin )
200187
// hardware support. These are defined in the appropriate
201188
// pins_*.c file. For the rest of the pins, we default
202189
// to digital output.
203-
void analogWrite( uint32_t ulPin, uint32_t ulValue )
190+
void analogWrite(uint32_t pin, uint32_t value)
204191
{
205-
uint32_t attr = g_APinDescription[ulPin].ulPinAttribute ;
192+
PinDescription pinDesc = g_APinDescription[pin];
193+
uint32_t attr = pinDesc.ulPinAttribute;
206194

207-
if ( (attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG )
195+
if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
208196
{
209-
if ( ulPin != PIN_A0 ) // Only 1 DAC on A0 (PA02)
210-
{
197+
// DAC handling code
198+
199+
if (pin != PIN_A0) { // Only 1 DAC on A0 (PA02)
211200
return;
212201
}
213202

214-
ulValue = mapResolution(ulValue, _writeResolution, 10);
203+
value = mapResolution(value, _writeResolution, 10);
215204

216205
syncDAC();
217-
DAC->DATA.reg = ulValue & 0x3FF; // DAC on 10 bits.
206+
DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits.
218207
syncDAC();
219208
DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC
220209
syncDAC();
221-
return ;
210+
return;
222211
}
223212

224-
if ( (attr & PIN_ATTR_PWM) == PIN_ATTR_PWM )
213+
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM)
225214
{
226-
if (attr & PIN_ATTR_TIMER) {
227-
#if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
228-
// Compatibility for cores based on SAMD core <=1.6.2
229-
if (g_APinDescription[ulPin].ulPinType == PIO_TIMER_ALT) {
230-
pinPeripheral(ulPin, PIO_TIMER_ALT);
231-
} else
232-
#endif
233-
{
234-
pinPeripheral(ulPin, PIO_TIMER);
215+
value = mapResolution(value, _writeResolution, 8);
216+
217+
uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel);
218+
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
219+
static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM];
220+
221+
if (!tcEnabled[tcNum]) {
222+
tcEnabled[tcNum] = true;
223+
224+
if (attr & PIN_ATTR_TIMER) {
225+
#if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603)
226+
// Compatibility for cores based on SAMD core <=1.6.2
227+
if (pinDesc.ulPinType == PIO_TIMER_ALT) {
228+
pinPeripheral(pin, PIO_TIMER_ALT);
229+
} else
230+
#endif
231+
{
232+
pinPeripheral(pin, PIO_TIMER);
233+
}
234+
} else {
235+
// We suppose that attr has PIN_ATTR_TIMER_ALT bit set...
236+
pinPeripheral(pin, PIO_TIMER_ALT);
235237
}
236-
} else {
237-
// We suppose that attr has PIN_ATTR_TIMER_ALT bit set...
238-
pinPeripheral(ulPin, PIO_TIMER_ALT);
239-
}
240238

241-
Tc* TCx = 0 ;
242-
Tcc* TCCx = 0 ;
243-
uint8_t Channelx = GetTCChannelNumber( g_APinDescription[ulPin].ulPWMChannel ) ;
244-
if ( GetTCNumber( g_APinDescription[ulPin].ulPWMChannel ) >= TCC_INST_NUM )
245-
{
246-
TCx = (Tc*) GetTC( g_APinDescription[ulPin].ulPWMChannel ) ;
247-
}
248-
else
249-
{
250-
TCCx = (Tcc*) GetTC( g_APinDescription[ulPin].ulPWMChannel ) ;
251-
}
252-
253-
// Enable clocks according to TCCx instance to use
254-
switch ( GetTCNumber( g_APinDescription[ulPin].ulPWMChannel ) )
255-
{
256-
case 0: // TCC0
257-
case 1: // TCC1
258-
// Enable GCLK for TCC0 and TCC1 (timer counter input clock)
259-
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ;
260-
break ;
261-
262-
case 2: // TCC2
263-
case 3: // TC3
264-
// Enable GCLK for TCC2 and TC3 (timer counter input clock)
265-
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 )) ;
266-
break ;
267-
268-
case 4: // TC4
269-
case 5: // TC5
270-
// Enable GCLK for TC4 and TC5 (timer counter input clock)
271-
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 ));
272-
break ;
273-
274-
case 6: // TC6 (not available on Zero)
275-
case 7: // TC7 (not available on Zero)
276-
// Enable GCLK for TC6 and TC7 (timer counter input clock)
277-
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TC6_TC7 ));
278-
break ;
279-
}
280-
281-
while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ;
282-
283-
ulValue = mapResolution(ulValue, _writeResolution, 8);
284-
285-
// Set PORT
286-
if ( TCx )
287-
{
288-
// -- Configure TC
289-
290-
// Disable TCx
291-
TCx->COUNT8.CTRLA.reg &= ~TC_CTRLA_ENABLE;
292-
syncTC_8(TCx);
293-
// Set Timer counter Mode to 8 bits
294-
TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8;
295-
// Set TCx as normal PWM
296-
TCx->COUNT8.CTRLA.reg |= TC_CTRLA_WAVEGEN_NPWM;
297-
// Set TCx in waveform mode Normal PWM
298-
TCx->COUNT8.CC[Channelx].reg = (uint8_t) ulValue;
299-
syncTC_8(TCx);
300-
// Set PER to maximum counter value (resolution : 0xFF)
301-
TCx->COUNT8.PER.reg = 0xFF;
302-
syncTC_8(TCx);
303-
// Enable TCx
304-
TCx->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE;
305-
syncTC_8(TCx);
306-
}
307-
else
308-
{
309-
// -- Configure TCC
310-
// Disable TCCx
311-
TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE;
312-
syncTCC(TCCx);
313-
// Set TCx as normal PWM
314-
TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
315-
syncTCC(TCCx);
316-
// Set TCx in waveform mode Normal PWM
317-
TCCx->CC[Channelx].reg = (uint32_t)ulValue;
318-
syncTCC(TCCx);
319-
// Set PER to maximum counter value (resolution : 0xFF)
320-
TCCx->PER.reg = 0xFF;
321-
syncTCC(TCCx);
322-
// Enable TCCx
323-
TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ;
324-
syncTCC(TCCx);
239+
uint16_t GCLK_CLKCTRL_IDs[] = {
240+
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0
241+
GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1
242+
GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TCC2
243+
GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TC3
244+
GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC4
245+
GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC5
246+
GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC6
247+
GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC7
248+
};
249+
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_IDs[tcNum]);
250+
while (GCLK->STATUS.bit.SYNCBUSY == 1);
251+
252+
// Set PORT
253+
if (tcNum >= TCC_INST_NUM) {
254+
// -- Configure TC
255+
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
256+
// Disable TCx
257+
TCx->COUNT8.CTRLA.bit.ENABLE = 0;
258+
syncTC_8(TCx);
259+
// Set Timer counter Mode to 8 bits, normal PWM, prescaler 1/256
260+
TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8 | TC_CTRLA_WAVEGEN_NPWM | TC_CTRLA_PRESCALER_DIV256;
261+
syncTC_8(TCx);
262+
// Set the initial value
263+
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
264+
syncTC_8(TCx);
265+
// Set PER to maximum counter value (resolution : 0xFF)
266+
TCx->COUNT8.PER.reg = 0xFF;
267+
syncTC_8(TCx);
268+
// Enable TCx
269+
TCx->COUNT8.CTRLA.bit.ENABLE = 1;
270+
syncTC_8(TCx);
271+
} else {
272+
// -- Configure TCC
273+
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
274+
// Disable TCCx
275+
TCCx->CTRLA.bit.ENABLE = 0;
276+
syncTCC(TCCx);
277+
// Set prescaler to 1/256
278+
TCCx->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV256;
279+
syncTCC(TCCx);
280+
// Set TCx as normal PWM
281+
TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
282+
syncTCC(TCCx);
283+
// Set the initial value
284+
TCCx->CC[tcChannel].reg = (uint32_t) value;
285+
syncTCC(TCCx);
286+
// Set PER to maximum counter value (resolution : 0xFF)
287+
TCCx->PER.reg = 0xFF;
288+
syncTCC(TCCx);
289+
// Enable TCCx
290+
TCCx->CTRLA.bit.ENABLE = 1;
291+
syncTCC(TCCx);
292+
}
293+
} else {
294+
if (tcNum >= TCC_INST_NUM) {
295+
Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel);
296+
TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value;
297+
syncTC_8(TCx);
298+
} else {
299+
Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);
300+
TCCx->CTRLBSET.bit.LUPD = 1;
301+
syncTCC(TCCx);
302+
TCCx->CCB[tcChannel].reg = (uint32_t) value;
303+
syncTCC(TCCx);
304+
TCCx->CTRLBCLR.bit.LUPD = 1;
305+
syncTCC(TCCx);
306+
}
325307
}
326-
327-
return ;
308+
return;
328309
}
329310

330311
// -- Defaults to digital write
331-
pinMode( ulPin, OUTPUT ) ;
332-
ulValue = mapResolution(ulValue, _writeResolution, 8);
333-
if ( ulValue < 128 )
334-
{
335-
digitalWrite( ulPin, LOW ) ;
336-
}
337-
else
338-
{
339-
digitalWrite( ulPin, HIGH ) ;
312+
pinMode(pin, OUTPUT);
313+
value = mapResolution(value, _writeResolution, 8);
314+
if (value < 128) {
315+
digitalWrite(pin, LOW);
316+
} else {
317+
digitalWrite(pin, HIGH);
340318
}
341319
}
342320

0 commit comments

Comments
 (0)