Skip to content

Commit 9b22622

Browse files
Roy, Elizabethfacchinm
authored andcommitted
Removed possibility to use TCA0 for safety
1 parent 73689a3 commit 9b22622

File tree

1 file changed

+61
-186
lines changed

1 file changed

+61
-186
lines changed

cores/arduino/Tone.cpp

Lines changed: 61 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -45,26 +45,19 @@
4545
/*
4646
#define USE_TIMERB2 // interferes with PWM on pin 11
4747
#define USE_TIMERB0 // interferes with PWM on pin 6
48-
#define USE_TIMERA0 // interferes with PWM on pins 5,9,10 NOT RECOMMENDED
4948
*/
5049

5150
// Can't use TIMERB3 -- used for application time tracking
52-
// Using TIMERA0 NOT RECOMMENDED -- leave to last -- all other timers use its clock!
53-
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { TIMERB1 /*, TIMERB2, TIMERB0, TIMERA0 */ };
54-
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { NOT_A_PIN /*, NOT_A_PIN, NOT_A_PIN, NOT_A_PIN */ };
51+
// Using TIMERA0 NOT RECOMMENDED -- all other timers use its clock!
52+
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { TIMERB1 /*, TIMERB2, TIMERB0 */ };
53+
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { NOT_A_PIN /*, NOT_A_PIN, NOT_A_PIN */ };
5554

5655

5756
// timerx_toggle_count:
5857
// > 0 - duration specified
5958
// = 0 - stopped
6059
// < 0 - infinitely (until stop() method called, or new play() called)
6160

62-
#if defined(USE_TIMERA0)
63-
volatile long timera0_toggle_count;
64-
volatile uint8_t *timera0_outtgl_reg;
65-
volatile uint8_t timera0_bit_mask;
66-
#endif
67-
6861
#if defined(USE_TIMERB0)
6962
volatile long timerb0_toggle_count;
7063
volatile uint8_t *timerb0_outtgl_reg;
@@ -147,101 +140,50 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
147140
toggle_count = -1;
148141
}
149142

150-
// Timer settings
151-
switch (_timer){
143+
// Timer settings -- will be type B
152144

153-
case TIMERB0:{
154-
case TIMERB1:{
155-
case TIMERB2:{
156-
157-
// Get timer struct
158-
TCB_t *timer_B = ((TCB_t *)&TCB0 + (_timer - TIMERB0));
145+
// Get timer struct
146+
TCB_t *timer_B = ((TCB_t *)&TCB0 + (_timer - TIMERB0));
159147

160-
// Disable for now, set clk according to 'prescaler_needed'
161-
// (Prescaled clock will come from TCA --
162-
// by default it should have a prescaler of 64 (250kHz clock)
163-
// TCA default initialization is in wiring.c -- init() )
164-
if(prescaler_needed){
165-
timer_B->CTRLA = TCB_CLKSEL_CLKTCA_gc;
166-
} else {
167-
timer_B->CTRLA = TCB_CLKSEL_CLKDIV1_gc;
168-
}
148+
// Disable for now, set clk according to 'prescaler_needed'
149+
// (Prescaled clock will come from TCA --
150+
// by default it should have a prescaler of 64 (250kHz clock)
151+
// TCA default initialization is in wiring.c -- init() )
152+
if(prescaler_needed){
153+
timer_B->CTRLA = TCB_CLKSEL_CLKTCA_gc;
154+
} else {
155+
timer_B->CTRLA = TCB_CLKSEL_CLKDIV1_gc;
156+
}
169157

170-
// Timer to Periodic interrupt mode
171-
// This write will also disable any active PWM outputs
172-
timer_B->CTRLB = TCB_CNTMODE_INT_gc;
158+
// Timer to Periodic interrupt mode
159+
// This write will also disable any active PWM outputs
160+
timer_B->CTRLB = TCB_CNTMODE_INT_gc;
173161

174-
// Write compare register
175-
timer_B->CCMP = compare_val;
162+
// Write compare register
163+
timer_B->CCMP = compare_val;
176164

177-
// Enable interrupt
178-
timer_B->INTCTRL = TCB_CAPTEI_bm;
165+
// Enable interrupt
166+
timer_B->INTCTRL = TCB_CAPTEI_bm;
179167

180-
// Populate variables needed in interrupt
181-
if(_timer == TIMERB1){
182-
timerb1_outtgl_reg = port_outtgl;
183-
timerb1_bit_mask = bit_mask;
184-
timerb1_toggle_count = toggle_count;
168+
// Populate variables needed in interrupt
169+
if(_timer == TIMERB1){
170+
timerb1_outtgl_reg = port_outtgl;
171+
timerb1_bit_mask = bit_mask;
172+
timerb1_toggle_count = toggle_count;
185173

186-
} else if(_timer == TIMERB2){
187-
timerb2_outtgl_reg = port_outtgl;
188-
timerb2_bit_mask = bit_mask;
189-
timerb2_toggle_count = toggle_count;
174+
} else if(_timer == TIMERB2){
175+
timerb2_outtgl_reg = port_outtgl;
176+
timerb2_bit_mask = bit_mask;
177+
timerb2_toggle_count = toggle_count;
190178

191-
} else { // _timer == TIMERB0
192-
timerb0_outtgl_reg = port_outtgl;
193-
timerb0_bit_mask = bit_mask;
194-
timerb0_toggle_count = toggle_count;
195-
}
196-
197-
// Enable timer
198-
timer_B->CTRLA |= TCB_ENABLE_bm;
199-
200-
break;
201-
}
202-
}
203-
}
204-
205-
/* Keep in mind this is NOT RECOMMENDED since other timers
206-
rely on the clock of TCA0 */
207-
#if defined(USE_TIMERA0)
208-
case TIMERA0:{
209-
210-
// Disable for now, assign clock according to prescaler_needed
211-
if(prescaler_needed){
212-
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV64_gc;
213-
} else {
214-
// WARNING: THIS MIGHT AFFECT TCB OPERATION
215-
// -- THEY MAY BE USING TCA CLOCK!!!!
216-
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc;
217-
}
218-
219-
// Timer to Normal mode
220-
// This write will also disable any active PWM outputs
221-
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
222-
223-
// Write compare register
224-
TCA0.SINGLE.PERBUF = compare_val;
225-
226-
// Enable interrupt
227-
TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
228-
229-
// Populate variables needed in interrupt
230-
timera0_outtgl_reg = port_outtgl;
231-
timera0_bit_mask = bit_mask;
232-
timera0_toggle_count = toggle_count;
233-
234-
// Enable timer
235-
TCA0.SINGLE.CTRLA |= TCA_SINGLE_ENABLE_bm;
236-
237-
break;
238-
}
239-
#endif
179+
} else { // _timer == TIMERB0
180+
timerb0_outtgl_reg = port_outtgl;
181+
timerb0_bit_mask = bit_mask;
182+
timerb0_toggle_count = toggle_count;
183+
}
240184

241-
default:{
242-
243-
break;
244-
}
185+
// Enable timer
186+
timer_B->CTRLA |= TCB_ENABLE_bm;
245187

246188
}
247189
}
@@ -251,80 +193,38 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
251193
configuration it had to output PWM for analogWrite() */
252194
void disableTimer(uint8_t _timer)
253195
{
254-
switch (_timer){
255-
case TIMERB0:{
256-
case TIMERB1:{
257-
case TIMERB2:{
196+
// Reinit back to producing PWM -- timer will be type B
258197

259-
// Get timer struct
260-
TCB_t *timer_B = ((TCB_t *)&TCB0 + (_timer - TIMERB0));
261-
262-
// Disable interrupt
263-
timer_B->INTCTRL = 0;
198+
// Get timer struct
199+
TCB_t *timer_B = ((TCB_t *)&TCB0 + (_timer - TIMERB0));
264200

265-
// Disable timer
266-
timer_B->CTRLA = 0;
201+
// Disable interrupt
202+
timer_B->INTCTRL = 0;
267203

268-
// RESTORE PWM FUNCTIONALITY:
204+
// Disable timer
205+
timer_B->CTRLA = 0;
269206

270-
/* 8 bit PWM mode, but do not enable output yet, will do in analogWrite() */
271-
timer_B->CTRLB = (TCB_CNTMODE_PWM8_gc);
272-
273-
/* Assign 8-bit period */
274-
timer_B->CCMPL = PWM_TIMER_PERIOD;
275-
276-
/* default duty 50%, set when output enabled */
277-
timer_B->CCMPH = PWM_TIMER_COMPARE;
278-
279-
/* Use TCA clock (250kHz) and enable */
280-
/* (sync update commented out, might try to synchronize later */
281-
timer_B->CTRLA = (TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);
282-
283-
break;
284-
}
285-
}
286-
}
287-
288-
#if defined(USE_TIMERA0)
289-
case TIMERA0:{
290-
291-
// Disable interrupt
292-
TCA0.SINGLE.INTCTRL = 0;
293-
294-
// Disable timer
295-
TCA0.SINGLE.CTRLA = 0;
207+
// RESTORE PWM FUNCTIONALITY:
296208

297-
// RESTORE PWM FUNCTIONALITY:
298-
299-
/* Setup timers for single slope PWM, but do not enable, will do in analogWrite() */
300-
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc;
209+
/* 8 bit PWM mode, but do not enable output yet, will do in analogWrite() */
210+
timer_B->CTRLB = (TCB_CNTMODE_PWM8_gc);
301211

302-
/* Period setting, 16 bit register but val resolution is 8 bit */
303-
TCA0.SINGLE.PER = PWM_TIMER_PERIOD;
212+
/* Assign 8-bit period */
213+
timer_B->CCMPL = PWM_TIMER_PERIOD;
304214

305-
/* Default duty 50%, will re-assign in analogWrite() */
306-
TCA0.SINGLE.CMP0BUF = PWM_TIMER_COMPARE;
307-
TCA0.SINGLE.CMP1BUF = PWM_TIMER_COMPARE;
308-
TCA0.SINGLE.CMP2BUF = PWM_TIMER_COMPARE;
215+
/* default duty 50%, set when output enabled */
216+
timer_B->CCMPH = PWM_TIMER_COMPARE;
309217

310-
/* Use DIV64 prescaler (giving 250kHz clock), enable TCA timer */
311-
TCA0.SINGLE.CTRLA = (TCA_SINGLE_CLKSEL_DIV64_gc) | (TCA_SINGLE_ENABLE_bm);
312-
313-
break;
314-
}
315-
#endif
218+
/* Use TCA clock (250kHz) and enable */
219+
/* (sync update commented out, might try to synchronize later */
220+
timer_B->CTRLA = (TCB_CLKSEL_CLKTCA_gc) | (TCB_ENABLE_bm);
316221

317-
default:{
318-
319-
break;
320-
}
321-
}
322222
}
323223

324224

325225
void noTone(uint8_t _pin)
326226
{
327-
int8_t _timer = -1;
227+
int8_t _timer = NOT_ON_TIMER;
328228

329229
// Find timer associated with pin
330230
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
@@ -342,40 +242,15 @@ void noTone(uint8_t _pin)
342242
break;
343243
}
344244
}
345-
346-
disableTimer(_timer);
347-
348-
// Keep pin low after disabling of timer
349-
digitalWrite(_pin, LOW);
350-
}
351245

352-
#ifdef USE_TIMERA0
353-
ISR(TCA0_OVF_vect)
354-
{
355-
if (timera0_toggle_count != 0){
356-
357-
// toggle the pin
358-
*timera0_outtgl_reg = timera0_bit_mask;
359-
360-
// If duration was defined, decrement
361-
if (timera0_toggle_count > 0){
362-
timera0_toggle_count--;
363-
}
364-
365-
// If no duration (toggle count negative), go on until noTone() call
366-
367-
} else { // If toggle count = 0, stop
368-
369-
disableTimer(TIMERA0);
246+
if(_timer > NOT_ON_TIMER){
247+
disableTimer(_timer);
370248

371-
// keep pin low after stop (OUTCLR = OUTTGL - 1)
372-
*(timera0_outtgl_reg - 1) = timera0_bit_mask;
249+
// Keep pin low after disabling of timer
250+
digitalWrite(_pin, LOW);
373251
}
374-
375-
/* Clear flag */
376-
TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
252+
377253
}
378-
#endif
379254

380255

381256
#ifdef USE_TIMERB0

0 commit comments

Comments
 (0)