|
|
@@ -41,7 +41,8 @@ |
|
|
|
static uint32_t tone_toggle_count; |
|
|
|
static volatile uint8_t *tone_reg; |
|
|
|
static uint8_t tone_pin=255; |
|
|
|
static uint16_t tone_frequency=0; |
|
|
|
static float tone_usec=0.0; |
|
|
|
static uint32_t tone_new_count=0; |
|
|
|
IntervalTimer tone_timer; |
|
|
|
|
|
|
|
void tone_interrupt(void); |
|
|
@@ -68,8 +69,9 @@ void tone(uint8_t pin, uint16_t frequency, uint32_t duration) |
|
|
|
if (pin >= CORE_NUM_DIGITAL) return; |
|
|
|
if (duration) { |
|
|
|
count = (frequency * duration / 1000) * 2; |
|
|
|
if (!(count & 1)) count++; // always full waveform cycles |
|
|
|
} else { |
|
|
|
count = 0xFFFFFFFF; |
|
|
|
count = 0xFFFFFFFD; |
|
|
|
} |
|
|
|
usec = (float)500000.0 / (float)frequency; |
|
|
|
config = portConfigRegister(pin); |
|
|
@@ -78,22 +80,25 @@ void tone(uint8_t pin, uint16_t frequency, uint32_t duration) |
|
|
|
// the interrupt on a single timer. |
|
|
|
__disable_irq(); |
|
|
|
if (pin == tone_pin) { |
|
|
|
if (frequency == tone_frequency) { |
|
|
|
// same pin, same frequency, so just update the |
|
|
|
// duration. Users will call repetitively call |
|
|
|
// tone() with the same setting, expecting a |
|
|
|
// continuous output with no glitches or phase |
|
|
|
// changes or jitter at each call. |
|
|
|
tone_toggle_count = count; |
|
|
|
// changing a pin which is already playing a tone |
|
|
|
if (usec == tone_usec) { |
|
|
|
// same frequency, so just change the duration |
|
|
|
tone_toggle_count = (tone_toggle_count & 1) + count - 1; |
|
|
|
} else { |
|
|
|
// same pin, but a new frequency. |
|
|
|
TONE_CLEAR_PIN; // clear pin |
|
|
|
tone_timer.begin(tone_interrupt, usec); |
|
|
|
// different frequency, reduce duration to only the |
|
|
|
// remainder of its current cycle, and configure for |
|
|
|
// the transition to the new frequency when the |
|
|
|
// current cycle completes |
|
|
|
tone_usec = usec; |
|
|
|
tone_new_count = count; |
|
|
|
tone_toggle_count = (tone_toggle_count & 1); |
|
|
|
} |
|
|
|
} else { |
|
|
|
// if playing on a different pin, immediately stop, even mid-cycle :-( |
|
|
|
if (tone_pin < CORE_NUM_DIGITAL) { |
|
|
|
TONE_CLEAR_PIN; // clear pin |
|
|
|
} |
|
|
|
// configure the new tone to play |
|
|
|
tone_pin = pin; |
|
|
|
tone_reg = portClearRegister(pin); |
|
|
|
#if defined(KINETISL) |
|
|
@@ -103,6 +108,7 @@ void tone(uint8_t pin, uint16_t frequency, uint32_t duration) |
|
|
|
TONE_OUTPUT_PIN; // output mode; |
|
|
|
*config = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); |
|
|
|
tone_toggle_count = count; |
|
|
|
tone_usec = usec; |
|
|
|
tone_timer.begin(tone_interrupt, usec); |
|
|
|
} |
|
|
|
__enable_irq(); |
|
|
@@ -111,14 +117,24 @@ void tone(uint8_t pin, uint16_t frequency, uint32_t duration) |
|
|
|
|
|
|
|
void tone_interrupt(void) |
|
|
|
{ |
|
|
|
if (tone_toggle_count) { |
|
|
|
if (tone_toggle_count) { // odd = rising edge, even = falling edge |
|
|
|
// not the end |
|
|
|
TONE_TOGGLE_PIN; // toggle |
|
|
|
if (tone_toggle_count < 0xFFFFFFFF) tone_toggle_count--; |
|
|
|
tone_toggle_count--; |
|
|
|
if (tone_toggle_count == 0xFFFFFFFB) tone_toggle_count = 0xFFFFFFFD; |
|
|
|
} else { |
|
|
|
tone_timer.end(); |
|
|
|
// this transition completes the tone |
|
|
|
TONE_CLEAR_PIN; // clear |
|
|
|
tone_pin = 255; |
|
|
|
tone_frequency = 0; |
|
|
|
if (tone_new_count > 0) { |
|
|
|
// begin playing a new tone |
|
|
|
tone_timer.begin(tone_interrupt, tone_usec); |
|
|
|
tone_toggle_count = tone_new_count; |
|
|
|
tone_new_count = 0; |
|
|
|
} else { |
|
|
|
// finished playing |
|
|
|
tone_timer.end(); |
|
|
|
tone_pin = 255; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -130,7 +146,6 @@ void noTone(uint8_t pin) |
|
|
|
tone_timer.end(); |
|
|
|
TONE_CLEAR_PIN; // clear |
|
|
|
tone_pin = 255; |
|
|
|
tone_frequency = 0; |
|
|
|
} |
|
|
|
__enable_irq(); |
|
|
|
} |