@@ -29,6 +29,7 @@ volatile uint32_t *portClearRegister;
29
29
volatile uint32_t portBitMask;
30
30
volatile int64_t toggleCount;
31
31
volatile bool toneIsActive = false ;
32
+ volatile bool firstTimeRunning = false ;
32
33
33
34
/* TC5 does not exist on the D11. Using TC2 instead. It will conflict with the 2 TC2 PWM pins */
34
35
#if defined(__SAMD11D14AM__) || defined(__SAMD11C14A__) || defined(__SAMD11D14AS__)
@@ -41,6 +42,7 @@ volatile bool toneIsActive = false;
41
42
42
43
#define TONE_TC_TOP 0xFFFF
43
44
#define TONE_TC_CHANNEL 0
45
+
44
46
void TC5_Handler (void ) __attribute__ ((weak, alias(" Tone_Handler" )));
45
47
46
48
static inline void resetTC (Tc* TCx)
@@ -62,6 +64,25 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
62
64
63
65
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
64
66
{
67
+ // Configure interrupt request
68
+ NVIC_DisableIRQ (TONE_TC_IRQn);
69
+ NVIC_ClearPendingIRQ (TONE_TC_IRQn);
70
+
71
+ if (!firstTimeRunning)
72
+ {
73
+ firstTimeRunning = true ;
74
+
75
+ NVIC_SetPriority (TONE_TC_IRQn, 0 );
76
+
77
+ // Enable GCLK for timer used
78
+ #if defined(__SAMD11D14AM__) || defined(__SAMD11C14A__) || defined(__SAMD11D14AS__)
79
+ GCLK->CLKCTRL .reg = (uint16_t ) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (GCM_TC1_TC2));
80
+ #else
81
+ GCLK->CLKCTRL .reg = (uint16_t ) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (GCM_TC4_TC5));
82
+ #endif
83
+ while (GCLK->STATUS .bit .SYNCBUSY );
84
+ }
85
+
65
86
if (toneIsActive && (outputPin != lastOutputPin))
66
87
noTone (lastOutputPin);
67
88
@@ -74,94 +95,70 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
74
95
75
96
ccValue = toneMaxFrequency / frequency - 1 ;
76
97
prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1;
77
-
78
- if (ccValue > TONE_TC_TOP)
98
+
99
+ uint8_t i = 0 ;
100
+
101
+ while (ccValue > TONE_TC_TOP)
102
+ {
103
+ ccValue = toneMaxFrequency / frequency / (2 <<i) - 1 ;
104
+ i++;
105
+ if (i == 4 || i == 6 || i == 8 ) // DIV32 DIV128 and DIV512 are not available
106
+ i++;
107
+ }
108
+
109
+ switch (i-1 )
79
110
{
80
- ccValue = toneMaxFrequency / frequency / 2 - 1 ;
81
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2;
82
-
83
- if (ccValue > TONE_TC_TOP)
84
- {
85
- ccValue = toneMaxFrequency / frequency / 4 - 1 ;
86
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4;
87
-
88
- if (ccValue > TONE_TC_TOP)
89
- {
90
- ccValue = toneMaxFrequency / frequency / 8 - 1 ;
91
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8;
92
-
93
- if (ccValue > TONE_TC_TOP)
94
- {
95
- ccValue = toneMaxFrequency / frequency / 16 - 1 ;
96
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16;
97
-
98
- if (ccValue > TONE_TC_TOP)
99
- {
100
- ccValue = toneMaxFrequency / frequency / 64 - 1 ;
101
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64;
102
-
103
- if (ccValue > TONE_TC_TOP)
104
- {
105
- ccValue = toneMaxFrequency / frequency / 256 - 1 ;
106
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256;
107
-
108
- if (ccValue > TONE_TC_TOP)
109
- {
110
- ccValue = toneMaxFrequency / frequency / 1024 - 1 ;
111
- prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024;
112
- }
113
- }
114
- }
115
- }
116
- }
117
- }
111
+ case 0 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2; break ;
112
+
113
+ case 1 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4; break ;
114
+
115
+ case 2 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8; break ;
116
+
117
+ case 3 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16; break ;
118
+
119
+ case 5 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64; break ;
120
+
121
+ case 7 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256; break ;
122
+
123
+ case 9 : prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024; break ;
124
+
125
+ default : break ;
118
126
}
119
127
120
128
toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1 );
121
129
122
- // Enable GCLK for timer used
123
- #if defined(__SAMD11D14AM__) || defined(__SAMD11C14A__) || defined(__SAMD11D14AS__)
124
- GCLK->CLKCTRL .reg = (uint16_t ) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (GCM_TC1_TC2));
125
- #else
126
- GCLK->CLKCTRL .reg = (uint16_t ) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (GCM_TC4_TC5));
127
- #endif
128
-
129
- while (GCLK->STATUS .bit .SYNCBUSY );
130
-
131
130
resetTC (TONE_TC);
132
131
133
- // Set Timer counter Mode to 16 bits
134
- TONE_TC->COUNT16 .CTRLA .reg |= TC_CTRLA_MODE_COUNT16;
135
-
136
- // Set TONE_TC mode as match frequency
137
- TONE_TC->COUNT16 .CTRLA .reg |= TC_CTRLA_WAVEGEN_MFRQ;
138
-
139
- TONE_TC->COUNT16 .CTRLA .reg |= prescalerConfigBits;
132
+ uint16_t tmpReg = 0 ;
133
+ tmpReg |= TC_CTRLA_MODE_COUNT16; // Set Timer counter Mode to 16 bits
134
+ tmpReg |= TC_CTRLA_WAVEGEN_MFRQ; // Set TONE_TC mode as match frequency
135
+ tmpReg |= prescalerConfigBits;
136
+ TONE_TC->COUNT16 .CTRLA .reg |= tmpReg;
137
+ WAIT_TC16_REGS_SYNC (TONE_TC)
140
138
141
139
TONE_TC->COUNT16 .CC [TONE_TC_CHANNEL].reg = (uint16_t ) ccValue;
142
140
WAIT_TC16_REGS_SYNC (TONE_TC)
143
141
144
- // Configure interrupt request
145
- NVIC_DisableIRQ (TONE_TC_IRQn);
146
- NVIC_ClearPendingIRQ (TONE_TC_IRQn);
147
- NVIC_SetPriority (TONE_TC_IRQn, 0 );
148
- NVIC_EnableIRQ (TONE_TC_IRQn);
149
-
150
142
portToggleRegister = &(PORT->Group [g_APinDescription[outputPin].ulPort ].OUTTGL .reg );
151
143
portClearRegister = &(PORT->Group [g_APinDescription[outputPin].ulPort ].OUTCLR .reg );
152
144
portBitMask = (1ul << g_APinDescription[outputPin].ulPin );
153
145
154
146
// Enable the TONE_TC interrupt request
155
147
TONE_TC->COUNT16 .INTENSET .bit .MC0 = 1 ;
156
-
157
- lastOutputPin = outputPin;
158
- digitalWrite (outputPin, LOW);
159
- pinMode (outputPin, OUTPUT);
160
- toneIsActive = true ;
148
+
149
+ if (outputPin != lastOutputPin)
150
+ {
151
+ lastOutputPin = outputPin;
152
+ digitalWrite (outputPin, LOW);
153
+ pinMode (outputPin, OUTPUT);
154
+ toneIsActive = true ;
155
+ }
161
156
162
157
// Enable TONE_TC
163
158
TONE_TC->COUNT16 .CTRLA .reg |= TC_CTRLA_ENABLE;
164
159
WAIT_TC16_REGS_SYNC (TONE_TC)
160
+
161
+ NVIC_EnableIRQ (TONE_TC_IRQn);
165
162
}
166
163
167
164
void noTone (uint32_t outputPin)
0 commit comments