Skip to content

Commit 83b63b1

Browse files
authored
Merge pull request arduino#257 from adafruit/fix-tone
Fix tone on SAMD51
2 parents 1e92424 + aa5fa81 commit 83b63b1

File tree

2 files changed

+80
-67
lines changed

2 files changed

+80
-67
lines changed

cores/arduino/Tone.cpp

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@
2020
#include "Tone.h"
2121
#include "variant.h"
2222

23-
#if defined(__SAMD51__)
24-
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
25-
#else
26-
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
27-
#endif
28-
2923
uint32_t toneMaxFrequency = F_CPU / 2;
3024
uint32_t lastOutputPin = 0xFFFFFFFF;
3125

@@ -37,22 +31,24 @@ volatile bool toneIsActive = false;
3731
volatile bool firstTimeRunning = false;
3832

3933
#if defined(__SAMD51__)
40-
#define TONE_TC TC0
41-
#define TONE_TC_IRQn TC0_IRQn
42-
#define TONE_TC_GCLK_ID TC0_GCLK_ID
34+
#define TONE_TC TC0
35+
#define TONE_TC_IRQn TC0_IRQn
36+
#define TONE_TC_GCLK_ID TC0_GCLK_ID
37+
#define Tone_Handler TC0_Handler
38+
39+
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
40+
4341
#else
44-
#define TONE_TC TC5
45-
#define TONE_TC_IRQn TC5_IRQn
42+
#define TONE_TC TC5
43+
#define TONE_TC_IRQn TC5_IRQn
44+
#define Tone_Handler TC5_Handler
45+
46+
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
4647
#endif
48+
4749
#define TONE_TC_TOP 0xFFFF
4850
#define TONE_TC_CHANNEL 0
4951

50-
#if defined(__SAMD51__)
51-
void TC0_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
52-
#else
53-
void TC5_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
54-
#endif
55-
5652
static inline void resetTC (Tc* TCx)
5753
{
5854
// Disable TCx
@@ -72,6 +68,14 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
7268

7369
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
7470
{
71+
72+
// Avoid divide by zero error by calling 'noTone' instead
73+
if (frequency == 0)
74+
{
75+
noTone(outputPin);
76+
return;
77+
}
78+
7579
// Configure interrupt request
7680
NVIC_DisableIRQ(TONE_TC_IRQn);
7781
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
@@ -90,9 +94,6 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
9094
while (GCLK->STATUS.bit.SYNCBUSY);
9195
#endif
9296
}
93-
94-
//if it's a rest, set to 1Hz (below audio range)
95-
frequency = (frequency > 0 ? frequency : 1);
9697

9798
if (toneIsActive && (outputPin != lastOutputPin))
9899
noTone(lastOutputPin);
@@ -167,8 +168,8 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
167168
lastOutputPin = outputPin;
168169
digitalWrite(outputPin, LOW);
169170
pinMode(outputPin, OUTPUT);
171+
toneIsActive = true;
170172
}
171-
toneIsActive = true;
172173

173174
// Enable TONE_TC
174175
TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
@@ -179,9 +180,19 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
179180

180181
void noTone (uint32_t outputPin)
181182
{
182-
resetTC(TONE_TC);
183-
digitalWrite(outputPin, LOW);
184-
toneIsActive = false;
183+
/* 'tone' need to run at least once in order to enable GCLK for
184+
* the timers used for the tone-functionality. If 'noTone' is called
185+
* without ever calling 'tone' before then 'WAIT_TC16_REGS_SYNC(TCx)'
186+
* will wait infinitely. The variable 'firstTimeRunning' is set the
187+
* 1st time 'tone' is set so it can be used to detect wether or not
188+
* 'tone' has been called before.
189+
*/
190+
if(firstTimeRunning)
191+
{
192+
resetTC(TONE_TC);
193+
digitalWrite(outputPin, LOW);
194+
toneIsActive = false;
195+
}
185196
}
186197

187198
#ifdef __cplusplus

libraries/Servo/src/samd/ServoTimers.h

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,50 +38,52 @@
3838
// to manage more than one channel per timer on the SAMD architecture
3939

4040
#if defined(__SAMD51__)
41-
#if defined (_useTimer1)
42-
#define TC_FOR_TIMER1 TC0
43-
#define CHANNEL_FOR_TIMER1 0
44-
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
45-
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
46-
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
47-
#define ID_TC_FOR_TIMER1 ID_TC0
48-
#define IRQn_FOR_TIMER1 TC0_IRQn
49-
#define HANDLER_FOR_TIMER1 TC0_Handler
50-
#define GCM_FOR_TIMER_1 9 // GCLK_TC0
51-
#endif
52-
#if defined (_useTimer2)
53-
#define TC_FOR_TIMER2 TC0
54-
#define CHANNEL_FOR_TIMER2 1
55-
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
56-
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
57-
#define INTFLAG_BIT_FOR_TIMER_2 TC_INTFLAG_MC1
58-
#define ID_TC_FOR_TIMER2 ID_TC0
59-
#define IRQn_FOR_TIMER2 TC0_IRQn
60-
#define HANDLER_FOR_TIMER2 TC0_Handler
61-
#define GCM_FOR_TIMER_2 9 // GCLK_TC0
62-
#endif
41+
#if defined (_useTimer1)
42+
#define TC_FOR_TIMER1 TC1
43+
#define CHANNEL_FOR_TIMER1 0
44+
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
45+
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
46+
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
47+
#define ID_TC_FOR_TIMER1 ID_TC1
48+
#define IRQn_FOR_TIMER1 TC1_IRQn
49+
#define HANDLER_FOR_TIMER1 TC1_Handler
50+
#define GCM_FOR_TIMER_1 TC1_GCLK_ID
51+
#endif
52+
53+
#if defined (_useTimer2)
54+
#define TC_FOR_TIMER2 TC1
55+
#define CHANNEL_FOR_TIMER2 1
56+
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
57+
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
58+
#define INTFLAG_BIT_FOR_TIMER_2 TC_INTFLAG_MC1
59+
#define ID_TC_FOR_TIMER2 ID_TC1
60+
#define IRQn_FOR_TIMER2 TC1_IRQn
61+
#define HANDLER_FOR_TIMER2 TC1_Handler
62+
#define GCM_FOR_TIMER_2 TC1_GCLK_ID
63+
#endif
6364
#else
64-
#if defined (_useTimer1)
65-
#define TC_FOR_TIMER1 TC4
66-
#define CHANNEL_FOR_TIMER1 0
67-
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
68-
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
69-
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
70-
#define ID_TC_FOR_TIMER1 ID_TC4
71-
#define IRQn_FOR_TIMER1 TC4_IRQn
72-
#define HANDLER_FOR_TIMER1 TC4_Handler
73-
#define GCM_FOR_TIMER_1 GCM_TC4_TC5
74-
#endif
75-
#if defined (_useTimer2)
76-
#define TC_FOR_TIMER2 TC4
77-
#define CHANNEL_FOR_TIMER2 1
78-
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
79-
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
80-
#define ID_TC_FOR_TIMER2 ID_TC4
81-
#define IRQn_FOR_TIMER2 TC4_IRQn
82-
#define HANDLER_FOR_TIMER2 TC4_Handler
83-
#define GCM_FOR_TIMER_2 GCM_TC4_TC5
84-
#endif
65+
#if defined (_useTimer1)
66+
#define TC_FOR_TIMER1 TC4
67+
#define CHANNEL_FOR_TIMER1 0
68+
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
69+
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
70+
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
71+
#define ID_TC_FOR_TIMER1 ID_TC4
72+
#define IRQn_FOR_TIMER1 TC4_IRQn
73+
#define HANDLER_FOR_TIMER1 TC4_Handler
74+
#define GCM_FOR_TIMER_1 GCM_TC4_TC5
75+
#endif
76+
77+
#if defined (_useTimer2)
78+
#define TC_FOR_TIMER2 TC4
79+
#define CHANNEL_FOR_TIMER2 1
80+
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
81+
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
82+
#define ID_TC_FOR_TIMER2 ID_TC4
83+
#define IRQn_FOR_TIMER2 TC4_IRQn
84+
#define HANDLER_FOR_TIMER2 TC4_Handler
85+
#define GCM_FOR_TIMER_2 GCM_TC4_TC5
86+
#endif
8587
#endif
8688

8789
typedef enum {

0 commit comments

Comments
 (0)