Skip to content

Commit e1dbd13

Browse files
Claudio Indellicatibitron
authored andcommitted
Added first tone library implementation.
Interrupt based implementation that works on every pin.
1 parent b094035 commit e1dbd13

File tree

3 files changed

+185
-2
lines changed

3 files changed

+185
-2
lines changed

cores/arduino/Tone.cpp

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,176 @@
1515
License along with this library; if not, write to the Free Software
1616
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1717
*/
18+
19+
#include "Tone.h"
20+
#include "variant.h"
21+
22+
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
23+
24+
uint32_t toneMaxFrequency = SystemCoreClock / 2;
25+
uint32_t lastOutputPin = 0xFFFFFFFF;
26+
27+
volatile uint32_t *portToggleRegister;
28+
volatile uint32_t *portClearRegister;
29+
volatile uint32_t portBitMask;
30+
volatile int64_t toggleCount;
31+
volatile bool toneIsActive = false;
32+
33+
#define TONE_TC TC5
34+
#define TONE_TC_IRQn TC5_IRQn
35+
#define TONE_TC_TOP 0xFFFF
36+
#define TONE_TC_CHANNEL 0
37+
38+
static inline void resetTC (Tc* TCx)
39+
{
40+
// Disable TCx
41+
TCx->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
42+
WAIT_TC16_REGS_SYNC(TCx)
43+
44+
// Reset TCx
45+
TCx->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
46+
WAIT_TC16_REGS_SYNC(TCx)
47+
while (TCx->COUNT16.CTRLA.bit.SWRST);
48+
}
49+
50+
void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
51+
{
52+
toneMaxFrequency = accurateSystemCoreClockFrequency / 2;
53+
}
54+
55+
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
56+
{
57+
if (toneIsActive && (outputPin != lastOutputPin))
58+
noTone(lastOutputPin);
59+
60+
//
61+
// Calculate best prescaler divider and comparator value for a 16 bit TC peripheral
62+
//
63+
64+
uint32_t prescalerConfigBits;
65+
uint32_t ccValue;
66+
67+
ccValue = toneMaxFrequency / frequency - 1;
68+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1;
69+
70+
if (ccValue > TONE_TC_TOP)
71+
{
72+
ccValue = toneMaxFrequency / frequency / 2 - 1;
73+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2;
74+
75+
if (ccValue > TONE_TC_TOP)
76+
{
77+
ccValue = toneMaxFrequency / frequency / 4 - 1;
78+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4;
79+
80+
if (ccValue > TONE_TC_TOP)
81+
{
82+
ccValue = toneMaxFrequency / frequency / 8 - 1;
83+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8;
84+
85+
if (ccValue > TONE_TC_TOP)
86+
{
87+
ccValue = toneMaxFrequency / frequency / 16 - 1;
88+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16;
89+
90+
if (ccValue > TONE_TC_TOP)
91+
{
92+
ccValue = toneMaxFrequency / frequency / 64 - 1;
93+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64;
94+
95+
if (ccValue > TONE_TC_TOP)
96+
{
97+
ccValue = toneMaxFrequency / frequency / 256 - 1;
98+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256;
99+
100+
if (ccValue > TONE_TC_TOP)
101+
{
102+
ccValue = toneMaxFrequency / frequency / 1024 - 1;
103+
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024;
104+
}
105+
}
106+
}
107+
}
108+
}
109+
}
110+
}
111+
112+
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1);
113+
114+
// Enable GCLK for TC4 and TC5 (timer counter input clock)
115+
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5));
116+
while (GCLK->STATUS.bit.SYNCBUSY);
117+
118+
resetTC(TONE_TC);
119+
120+
// Set Timer counter Mode to 16 bits
121+
TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
122+
123+
// Set TONE_TC mode as match frequency
124+
TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
125+
126+
TONE_TC->COUNT16.CTRLA.reg |= prescalerConfigBits;
127+
128+
TONE_TC->COUNT16.CC[TONE_TC_CHANNEL].reg = (uint16_t) ccValue;
129+
WAIT_TC16_REGS_SYNC(TONE_TC)
130+
131+
// Configure interrupt request
132+
NVIC_DisableIRQ(TONE_TC_IRQn);
133+
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
134+
NVIC_SetPriority(TONE_TC_IRQn, 0);
135+
NVIC_EnableIRQ(TONE_TC_IRQn);
136+
137+
portToggleRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTTGL.reg);
138+
portClearRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTCLR.reg);
139+
portBitMask = (1ul << g_APinDescription[outputPin].ulPin);
140+
141+
// Enable the TONE_TC interrupt request
142+
TONE_TC->COUNT16.INTENSET.bit.MC0 = 1;
143+
144+
lastOutputPin = outputPin;
145+
digitalWrite(outputPin, LOW);
146+
pinMode(outputPin, OUTPUT);
147+
toneIsActive = true;
148+
149+
// Enable TONE_TC
150+
TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
151+
WAIT_TC16_REGS_SYNC(TONE_TC)
152+
}
153+
154+
void noTone (uint32_t outputPin)
155+
{
156+
resetTC(TONE_TC);
157+
digitalWrite(outputPin, LOW);
158+
toneIsActive = false;
159+
}
160+
161+
#ifdef __cplusplus
162+
extern "C" {
163+
#endif
164+
165+
void Tone_Handler (void)
166+
{
167+
if (toggleCount != 0)
168+
{
169+
// Toggle the ouput pin
170+
*portToggleRegister = portBitMask;
171+
172+
if (toggleCount > 0)
173+
--toggleCount;
174+
175+
// Clear the interrupt
176+
TONE_TC->COUNT16.INTFLAG.bit.MC0 = 1;
177+
}
178+
else
179+
{
180+
resetTC(TONE_TC);
181+
*portClearRegister = portBitMask;
182+
toneIsActive = false;
183+
}
184+
}
185+
186+
void TC5_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
187+
188+
#ifdef __cplusplus
189+
}
190+
#endif

cores/arduino/Tone.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2014 Arduino. All right reserved.
2+
Copyright (c) 2015 Arduino. All right reserved.
33
44
This library is free software; you can redistribute it and/or
55
modify it under the terms of the GNU Lesser General Public
@@ -19,5 +19,15 @@
1919
#ifndef _WIRING_TONE_
2020
#define _WIRING_TONE_
2121

22+
#ifdef __cplusplus
23+
24+
#include "Arduino.h"
25+
26+
void tone(uint32_t _pin, uint32_t frequency, uint32_t duration = 0);
27+
void noTone(uint32_t _pin);
28+
29+
void toneAccurateClock (uint32_t);
30+
31+
#endif /* __cplusplus */
2232

2333
#endif /* _WIRING_TONE_ */

cores/arduino/startup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void TCC1_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler
9393
void TCC2_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
9494
void TC3_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
9595
void TC4_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
96-
void TC5_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
96+
void TC5_Handler ( void ) __attribute__ ((weak));
9797
void TC6_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
9898
void TC7_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
9999
void ADC_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));

0 commit comments

Comments
 (0)