source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/cores/arduino/Tone.cpp @ 46

Last change on this file since 46 was 46, checked in by jrpelegrina, 4 years ago

First release to Xenial

File size: 14.7 KB
Line 
1/* Tone.cpp
2
3  A Tone Generator Library
4
5  Written by Brett Hagman
6
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  Lesser General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
21Version Modified By Date     Comments
22------- ----------- -------- --------
230001    B Hagman    09/08/02 Initial coding
240002    B Hagman    09/08/18 Multiple pins
250003    B Hagman    09/08/18 Moved initialization from constructor to begin()
260004    B Hagman    09/09/26 Fixed problems with ATmega8
270005    B Hagman    09/11/23 Scanned prescalars for best fit on 8 bit timers
28                    09/11/25 Changed pin toggle method to XOR
29                    09/11/25 Fixed timer0 from being excluded
300006    D Mellis    09/12/29 Replaced objects with functions
310007    M Sproul    10/08/29 Changed #ifdefs from cpu to register
320008    S Kanemoto  12/06/22 Fixed for Leonardo by @maris_HY
330009    J Reucker   15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62)
340010    jipp        15/04/13 added additional define check #2923
35*************************************************/
36
37#include <avr/interrupt.h>
38#include <avr/pgmspace.h>
39#include "Arduino.h"
40#include "pins_arduino.h"
41
42#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
43#define TCCR2A TCCR2
44#define TCCR2B TCCR2
45#define COM2A1 COM21
46#define COM2A0 COM20
47#define OCR2A OCR2
48#define TIMSK2 TIMSK
49#define OCIE2A OCIE2
50#define TIMER2_COMPA_vect TIMER2_COMP_vect
51#define TIMSK1 TIMSK
52#endif
53
54// timerx_toggle_count:
55//  > 0 - duration specified
56//  = 0 - stopped
57//  < 0 - infinitely (until stop() method called, or new play() called)
58
59#if !defined(__AVR_ATmega8__)
60volatile long timer0_toggle_count;
61volatile uint8_t *timer0_pin_port;
62volatile uint8_t timer0_pin_mask;
63#endif
64
65volatile long timer1_toggle_count;
66volatile uint8_t *timer1_pin_port;
67volatile uint8_t timer1_pin_mask;
68volatile long timer2_toggle_count;
69volatile uint8_t *timer2_pin_port;
70volatile uint8_t timer2_pin_mask;
71
72#if defined(TIMSK3)
73volatile long timer3_toggle_count;
74volatile uint8_t *timer3_pin_port;
75volatile uint8_t timer3_pin_mask;
76#endif
77
78#if defined(TIMSK4)
79volatile long timer4_toggle_count;
80volatile uint8_t *timer4_pin_port;
81volatile uint8_t timer4_pin_mask;
82#endif
83
84#if defined(TIMSK5)
85volatile long timer5_toggle_count;
86volatile uint8_t *timer5_pin_port;
87volatile uint8_t timer5_pin_mask;
88#endif
89
90
91#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
92
93#define AVAILABLE_TONE_PINS 1
94#define USE_TIMER2
95
96const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
97static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
98
99#elif defined(__AVR_ATmega8__)
100
101#define AVAILABLE_TONE_PINS 1
102#define USE_TIMER2
103
104const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
105static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
106
107#elif defined(__AVR_ATmega32U4__)
108 
109#define AVAILABLE_TONE_PINS 1
110#define USE_TIMER3
111 
112const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ };
113static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
114 
115#else
116
117#define AVAILABLE_TONE_PINS 1
118#define USE_TIMER2
119
120// Leave timer 0 to last.
121const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
122static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
123
124#endif
125
126
127
128static int8_t toneBegin(uint8_t _pin)
129{
130  int8_t _timer = -1;
131
132  // if we're already using the pin, the timer should be configured. 
133  for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
134    if (tone_pins[i] == _pin) {
135      return pgm_read_byte(tone_pin_to_timer_PGM + i);
136    }
137  }
138 
139  // search for an unused timer.
140  for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
141    if (tone_pins[i] == 255) {
142      tone_pins[i] = _pin;
143      _timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
144      break;
145    }
146  }
147 
148  if (_timer != -1)
149  {
150    // Set timer specific stuff
151    // All timers in CTC mode
152    // 8 bit timers will require changing prescalar values,
153    // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
154    switch (_timer)
155    {
156      #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01)
157      case 0:
158        // 8 bit timer
159        TCCR0A = 0;
160        TCCR0B = 0;
161        bitWrite(TCCR0A, WGM01, 1);
162        bitWrite(TCCR0B, CS00, 1);
163        timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
164        timer0_pin_mask = digitalPinToBitMask(_pin);
165        break;
166      #endif
167
168      #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
169      case 1:
170        // 16 bit timer
171        TCCR1A = 0;
172        TCCR1B = 0;
173        bitWrite(TCCR1B, WGM12, 1);
174        bitWrite(TCCR1B, CS10, 1);
175        timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
176        timer1_pin_mask = digitalPinToBitMask(_pin);
177        break;
178      #endif
179
180      #if defined(TCCR2A) && defined(TCCR2B)
181      case 2:
182        // 8 bit timer
183        TCCR2A = 0;
184        TCCR2B = 0;
185        bitWrite(TCCR2A, WGM21, 1);
186        bitWrite(TCCR2B, CS20, 1);
187        timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
188        timer2_pin_mask = digitalPinToBitMask(_pin);
189        break;
190      #endif
191
192      #if defined(TCCR3A) && defined(TCCR3B) &&  defined(TIMSK3)
193      case 3:
194        // 16 bit timer
195        TCCR3A = 0;
196        TCCR3B = 0;
197        bitWrite(TCCR3B, WGM32, 1);
198        bitWrite(TCCR3B, CS30, 1);
199        timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
200        timer3_pin_mask = digitalPinToBitMask(_pin);
201        break;
202      #endif
203
204      #if defined(TCCR4A) && defined(TCCR4B) &&  defined(TIMSK4)
205      case 4:
206        // 16 bit timer
207        TCCR4A = 0;
208        TCCR4B = 0;
209        #if defined(WGM42)
210          bitWrite(TCCR4B, WGM42, 1);
211        #elif defined(CS43)
212          // TODO this may not be correct
213          // atmega32u4
214          bitWrite(TCCR4B, CS43, 1);
215        #endif
216        bitWrite(TCCR4B, CS40, 1);
217        timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
218        timer4_pin_mask = digitalPinToBitMask(_pin);
219        break;
220      #endif
221
222      #if defined(TCCR5A) && defined(TCCR5B) &&  defined(TIMSK5)
223      case 5:
224        // 16 bit timer
225        TCCR5A = 0;
226        TCCR5B = 0;
227        bitWrite(TCCR5B, WGM52, 1);
228        bitWrite(TCCR5B, CS50, 1);
229        timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
230        timer5_pin_mask = digitalPinToBitMask(_pin);
231        break;
232      #endif
233    }
234  }
235
236  return _timer;
237}
238
239
240
241// frequency (in hertz) and duration (in milliseconds).
242
243void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
244{
245  uint8_t prescalarbits = 0b001;
246  long toggle_count = 0;
247  uint32_t ocr = 0;
248  int8_t _timer;
249
250  _timer = toneBegin(_pin);
251
252  if (_timer >= 0)
253  {
254    // Set the pinMode as OUTPUT
255    pinMode(_pin, OUTPUT);
256   
257    // if we are using an 8 bit timer, scan through prescalars to find the best fit
258    if (_timer == 0 || _timer == 2)
259    {
260      ocr = F_CPU / frequency / 2 - 1;
261      prescalarbits = 0b001;  // ck/1: same for both timers
262      if (ocr > 255)
263      {
264        ocr = F_CPU / frequency / 2 / 8 - 1;
265        prescalarbits = 0b010;  // ck/8: same for both timers
266
267        if (_timer == 2 && ocr > 255)
268        {
269          ocr = F_CPU / frequency / 2 / 32 - 1;
270          prescalarbits = 0b011;
271        }
272
273        if (ocr > 255)
274        {
275          ocr = F_CPU / frequency / 2 / 64 - 1;
276          prescalarbits = _timer == 0 ? 0b011 : 0b100;
277
278          if (_timer == 2 && ocr > 255)
279          {
280            ocr = F_CPU / frequency / 2 / 128 - 1;
281            prescalarbits = 0b101;
282          }
283
284          if (ocr > 255)
285          {
286            ocr = F_CPU / frequency / 2 / 256 - 1;
287            prescalarbits = _timer == 0 ? 0b100 : 0b110;
288            if (ocr > 255)
289            {
290              // can't do any better than /1024
291              ocr = F_CPU / frequency / 2 / 1024 - 1;
292              prescalarbits = _timer == 0 ? 0b101 : 0b111;
293            }
294          }
295        }
296      }
297
298#if defined(TCCR0B)
299      if (_timer == 0)
300      {
301        TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;
302      }
303      else
304#endif
305#if defined(TCCR2B)
306      {
307        TCCR2B = (TCCR2B & 0b11111000) | prescalarbits;
308      }
309#else
310      {
311        // dummy place holder to make the above ifdefs work
312      }
313#endif
314    }
315    else
316    {
317      // two choices for the 16 bit timers: ck/1 or ck/64
318      ocr = F_CPU / frequency / 2 - 1;
319
320      prescalarbits = 0b001;
321      if (ocr > 0xffff)
322      {
323        ocr = F_CPU / frequency / 2 / 64 - 1;
324        prescalarbits = 0b011;
325      }
326
327      if (_timer == 1)
328      {
329#if defined(TCCR1B)
330        TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
331#endif
332      }
333#if defined(TCCR3B)
334      else if (_timer == 3)
335        TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
336#endif
337#if defined(TCCR4B)
338      else if (_timer == 4)
339        TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
340#endif
341#if defined(TCCR5B)
342      else if (_timer == 5)
343        TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
344#endif
345
346    }
347   
348
349    // Calculate the toggle count
350    if (duration > 0)
351    {
352      toggle_count = 2 * frequency * duration / 1000;
353    }
354    else
355    {
356      toggle_count = -1;
357    }
358
359    // Set the OCR for the given timer,
360    // set the toggle count,
361    // then turn on the interrupts
362    switch (_timer)
363    {
364
365#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
366      case 0:
367        OCR0A = ocr;
368        timer0_toggle_count = toggle_count;
369        bitWrite(TIMSK0, OCIE0A, 1);
370        break;
371#endif
372
373      case 1:
374#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
375        OCR1A = ocr;
376        timer1_toggle_count = toggle_count;
377        bitWrite(TIMSK1, OCIE1A, 1);
378#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
379        // this combination is for at least the ATmega32
380        OCR1A = ocr;
381        timer1_toggle_count = toggle_count;
382        bitWrite(TIMSK, OCIE1A, 1);
383#endif
384        break;
385
386#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
387      case 2:
388        OCR2A = ocr;
389        timer2_toggle_count = toggle_count;
390        bitWrite(TIMSK2, OCIE2A, 1);
391        break;
392#endif
393
394#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
395      case 3:
396        OCR3A = ocr;
397        timer3_toggle_count = toggle_count;
398        bitWrite(TIMSK3, OCIE3A, 1);
399        break;
400#endif
401
402#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
403      case 4:
404        OCR4A = ocr;
405        timer4_toggle_count = toggle_count;
406        bitWrite(TIMSK4, OCIE4A, 1);
407        break;
408#endif
409
410#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
411      case 5:
412        OCR5A = ocr;
413        timer5_toggle_count = toggle_count;
414        bitWrite(TIMSK5, OCIE5A, 1);
415        break;
416#endif
417
418    }
419  }
420}
421
422
423// XXX: this function only works properly for timer 2 (the only one we use
424// currently).  for the others, it should end the tone, but won't restore
425// proper PWM functionality for the timer.
426void disableTimer(uint8_t _timer)
427{
428  switch (_timer)
429  {
430    case 0:
431      #if defined(TIMSK0)
432        TIMSK0 = 0;
433      #elif defined(TIMSK)
434        TIMSK = 0; // atmega32
435      #endif
436      break;
437
438#if defined(TIMSK1) && defined(OCIE1A)
439    case 1:
440      bitWrite(TIMSK1, OCIE1A, 0);
441      break;
442#endif
443
444    case 2:
445      #if defined(TIMSK2) && defined(OCIE2A)
446        bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
447      #endif
448      #if defined(TCCR2A) && defined(WGM20)
449        TCCR2A = (1 << WGM20);
450      #endif
451      #if defined(TCCR2B) && defined(CS22)
452        TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
453      #endif
454      #if defined(OCR2A)
455        OCR2A = 0;
456      #endif
457      break;
458
459#if defined(TIMSK3) && defined(OCIE3A)
460    case 3:
461      bitWrite(TIMSK3, OCIE3A, 0);
462      break;
463#endif
464
465#if defined(TIMSK4) && defined(OCIE4A)
466    case 4:
467      bitWrite(TIMSK4, OCIE4A, 0);
468      break;
469#endif
470
471#if defined(TIMSK5) && defined(OCIE5A)
472    case 5:
473      bitWrite(TIMSK5, OCIE5A, 0);
474      break;
475#endif
476  }
477}
478
479
480void noTone(uint8_t _pin)
481{
482  int8_t _timer = -1;
483 
484  for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
485    if (tone_pins[i] == _pin) {
486      _timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
487      tone_pins[i] = 255;
488      break;
489    }
490  }
491 
492  disableTimer(_timer);
493
494  digitalWrite(_pin, 0);
495}
496
497#ifdef USE_TIMER0
498ISR(TIMER0_COMPA_vect)
499{
500  if (timer0_toggle_count != 0)
501  {
502    // toggle the pin
503    *timer0_pin_port ^= timer0_pin_mask;
504
505    if (timer0_toggle_count > 0)
506      timer0_toggle_count--;
507  }
508  else
509  {
510    disableTimer(0);
511    *timer0_pin_port &= ~(timer0_pin_mask);  // keep pin low after stop
512  }
513}
514#endif
515
516
517#ifdef USE_TIMER1
518ISR(TIMER1_COMPA_vect)
519{
520  if (timer1_toggle_count != 0)
521  {
522    // toggle the pin
523    *timer1_pin_port ^= timer1_pin_mask;
524
525    if (timer1_toggle_count > 0)
526      timer1_toggle_count--;
527  }
528  else
529  {
530    disableTimer(1);
531    *timer1_pin_port &= ~(timer1_pin_mask);  // keep pin low after stop
532  }
533}
534#endif
535
536
537#ifdef USE_TIMER2
538ISR(TIMER2_COMPA_vect)
539{
540
541  if (timer2_toggle_count != 0)
542  {
543    // toggle the pin
544    *timer2_pin_port ^= timer2_pin_mask;
545
546    if (timer2_toggle_count > 0)
547      timer2_toggle_count--;
548  }
549  else
550  {
551    // need to call noTone() so that the tone_pins[] entry is reset, so the
552    // timer gets initialized next time we call tone().
553    // XXX: this assumes timer 2 is always the first one used.
554    noTone(tone_pins[0]);
555//    disableTimer(2);
556//    *timer2_pin_port &= ~(timer2_pin_mask);  // keep pin low after stop
557  }
558}
559#endif
560
561
562#ifdef USE_TIMER3
563ISR(TIMER3_COMPA_vect)
564{
565  if (timer3_toggle_count != 0)
566  {
567    // toggle the pin
568    *timer3_pin_port ^= timer3_pin_mask;
569
570    if (timer3_toggle_count > 0)
571      timer3_toggle_count--;
572  }
573  else
574  {
575    disableTimer(3);
576    *timer3_pin_port &= ~(timer3_pin_mask);  // keep pin low after stop
577  }
578}
579#endif
580
581
582#ifdef USE_TIMER4
583ISR(TIMER4_COMPA_vect)
584{
585  if (timer4_toggle_count != 0)
586  {
587    // toggle the pin
588    *timer4_pin_port ^= timer4_pin_mask;
589
590    if (timer4_toggle_count > 0)
591      timer4_toggle_count--;
592  }
593  else
594  {
595    disableTimer(4);
596    *timer4_pin_port &= ~(timer4_pin_mask);  // keep pin low after stop
597  }
598}
599#endif
600
601
602#ifdef USE_TIMER5
603ISR(TIMER5_COMPA_vect)
604{
605  if (timer5_toggle_count != 0)
606  {
607    // toggle the pin
608    *timer5_pin_port ^= timer5_pin_mask;
609
610    if (timer5_toggle_count > 0)
611      timer5_toggle_count--;
612  }
613  else
614  {
615    disableTimer(5);
616    *timer5_pin_port &= ~(timer5_pin_mask);  // keep pin low after stop
617  }
618}
619#endif
Note: See TracBrowser for help on using the repository browser.