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)
6962volatile long timerb0_toggle_count;
7063volatile 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() */
252194void 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
325225void 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