The toneBegin() manages the relation of pin and timer which is used by tone(), and sets ther timer. In the current implementation, timer2_pin port is used to set timer output port and timer2_pin_mask is used to set timer output bit. These variables are used in an intterrupt handler.
Source Code
The toneBegin() is defined in hardware/arduino/avr/cores/arduino/Tone.cpp as below. Only the souce code for Arduino UNO is quoted. The original source code supports many tips using #if’s.
volatileuint8_t*timer0_pin_port;volatileuint8_ttimer0_pin_mask;volatileuint8_t*timer1_pin_port;volatileuint8_ttimer1_pin_mask;volatileuint8_t*timer2_pin_port;volatileuint8_ttimer2_pin_mask;#define AVAILABLE_TONE_PINS 1
// Leave timer 0 to last.
constuint8_tPROGMEMtone_pin_to_timer_PGM[]={2/*, 1, 0 */};staticuint8_ttone_pins[AVAILABLE_TONE_PINS]={255/*, 255, 255 */};staticint8_ttoneBegin(uint8_t_pin){int8_t_timer=-1;// if we're already using the pin, the timer should be configured.
for(inti=0;i<AVAILABLE_TONE_PINS;i++){if(tone_pins[i]==_pin){returnpgm_read_byte(tone_pin_to_timer_PGM+i);}}// search for an unused timer.
for(inti=0;i<AVAILABLE_TONE_PINS;i++){if(tone_pins[i]==255){tone_pins[i]=_pin;_timer=pgm_read_byte(tone_pin_to_timer_PGM+i);break;}}if(_timer!=-1){// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch(_timer){case0:// 8 bit timer
TCCR0A=0;TCCR0B=0;bitWrite(TCCR0A,WGM01,1);bitWrite(TCCR0B,CS00,1);timer0_pin_port=portOutputRegister(digitalPinToPort(_pin));timer0_pin_mask=digitalPinToBitMask(_pin);break;case1:// 16 bit timer
TCCR1A=0;TCCR1B=0;bitWrite(TCCR1B,WGM12,1);bitWrite(TCCR1B,CS10,1);timer1_pin_port=portOutputRegister(digitalPinToPort(_pin));timer1_pin_mask=digitalPinToBitMask(_pin);break;case2:// 8 bit timer
TCCR2A=0;TCCR2B=0;bitWrite(TCCR2A,WGM21,1);bitWrite(TCCR2B,CS20,1);timer2_pin_port=portOutputRegister(digitalPinToPort(_pin));timer2_pin_mask=digitalPinToBitMask(_pin);break;}}return_timer;}
The AVAILABLE_TONE_PINS is set to 1. This is the number of pins that can be used at the same time.
The tone_pin_to_timer_PGM[] is an array that holds timer/counter. Currently only “2” is defined.
The tone_pins[] shows pins which is used by timer/counter, which is related to tone_pin_to_timer_PGM[]. 255 means unused.
8
9
10
11
12
#define AVAILABLE_TONE_PINS 1
// Leave timer 0 to last.
constuint8_tPROGMEMtone_pin_to_timer_PGM[]={2/*, 1, 0 */};staticuint8_ttone_pins[AVAILABLE_TONE_PINS]={255/*, 255, 255 */};
The input is _pin and its type is int8_t. The return type is int8_t.
If the tone() is already executed, it returns the current timer/counter. This means it changes the current pin settings.
14
15
16
17
18
19
20
21
22
23
staticint8_ttoneBegin(uint8_t_pin){int8_t_timer=-1;// if we're already using the pin, the timer should be configured.
for(inti=0;i<AVAILABLE_TONE_PINS;i++){if(tone_pins[i]==_pin){returnpgm_read_byte(tone_pin_to_timer_PGM+i);}}
The pgm_read_byte() is a macro to read one byte from PROGMEM. As the tone_pin_to_timer_PGM is an array, tone_pin_to_timer_PGM+i means the i-th element of the array.
If the tone() is not executed on the specified pin, it searchs unused timer/counter.
25
26
27
28
29
30
31
32
// search for an unused timer.
for(inti=0;i<AVAILABLE_TONE_PINS;i++){if(tone_pins[i]==255){tone_pins[i]=_pin;_timer=pgm_read_byte(tone_pin_to_timer_PGM+i);break;}}
If one of the element of the tone_pins[] is 255, sets the pin number to tone_pins[] and sets the tone_pin_to_timer_PGM+i to _timer. Currently the value is fixed to 2.
If the _timer is not -1, timerX_pin_port and timerX_pin_mask are set.
if(_timer!=-1){// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch(_timer){case0:// 8 bit timer
TCCR0A=0;TCCR0B=0;bitWrite(TCCR0A,WGM01,1);bitWrite(TCCR0B,CS00,1);timer0_pin_port=portOutputRegister(digitalPinToPort(_pin));timer0_pin_mask=digitalPinToBitMask(_pin);break;case1:// 16 bit timer
TCCR1A=0;TCCR1B=0;bitWrite(TCCR1B,WGM12,1);bitWrite(TCCR1B,CS10,1);timer1_pin_port=portOutputRegister(digitalPinToPort(_pin));timer1_pin_mask=digitalPinToBitMask(_pin);break;case2:// 8 bit timer
TCCR2A=0;TCCR2B=0;bitWrite(TCCR2A,WGM21,1);bitWrite(TCCR2B,CS20,1);timer2_pin_port=portOutputRegister(digitalPinToPort(_pin));timer2_pin_mask=digitalPinToBitMask(_pin);break;}}
The TCCR is a register to control timer/counter. In this case, CTC mode is set.