use TC1 for servo, TC0 for tone for samd51

- make Tone_Handler() a strong symbol
This commit is contained in:
hathach 2020-08-28 14:41:48 +07:00
parent 1e92424a50
commit aa5fa81bb7
2 changed files with 80 additions and 67 deletions

View file

@ -20,12 +20,6 @@
#include "Tone.h"
#include "variant.h"
#if defined(__SAMD51__)
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
#else
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
#endif
uint32_t toneMaxFrequency = F_CPU / 2;
uint32_t lastOutputPin = 0xFFFFFFFF;
@ -37,22 +31,24 @@ volatile bool toneIsActive = false;
volatile bool firstTimeRunning = false;
#if defined(__SAMD51__)
#define TONE_TC TC0
#define TONE_TC_IRQn TC0_IRQn
#define TONE_TC_GCLK_ID TC0_GCLK_ID
#define TONE_TC TC0
#define TONE_TC_IRQn TC0_IRQn
#define TONE_TC_GCLK_ID TC0_GCLK_ID
#define Tone_Handler TC0_Handler
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
#else
#define TONE_TC TC5
#define TONE_TC_IRQn TC5_IRQn
#define TONE_TC TC5
#define TONE_TC_IRQn TC5_IRQn
#define Tone_Handler TC5_Handler
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
#endif
#define TONE_TC_TOP 0xFFFF
#define TONE_TC_CHANNEL 0
#if defined(__SAMD51__)
void TC0_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
#else
void TC5_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
#endif
static inline void resetTC (Tc* TCx)
{
// Disable TCx
@ -72,6 +68,14 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
// Avoid divide by zero error by calling 'noTone' instead
if (frequency == 0)
{
noTone(outputPin);
return;
}
// Configure interrupt request
NVIC_DisableIRQ(TONE_TC_IRQn);
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
@ -90,9 +94,6 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
while (GCLK->STATUS.bit.SYNCBUSY);
#endif
}
//if it's a rest, set to 1Hz (below audio range)
frequency = (frequency > 0 ? frequency : 1);
if (toneIsActive && (outputPin != lastOutputPin))
noTone(lastOutputPin);
@ -167,8 +168,8 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
lastOutputPin = outputPin;
digitalWrite(outputPin, LOW);
pinMode(outputPin, OUTPUT);
toneIsActive = true;
}
toneIsActive = true;
// Enable TONE_TC
TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
@ -179,9 +180,19 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
void noTone (uint32_t outputPin)
{
resetTC(TONE_TC);
digitalWrite(outputPin, LOW);
toneIsActive = false;
/* 'tone' need to run at least once in order to enable GCLK for
* the timers used for the tone-functionality. If 'noTone' is called
* without ever calling 'tone' before then 'WAIT_TC16_REGS_SYNC(TCx)'
* will wait infinitely. The variable 'firstTimeRunning' is set the
* 1st time 'tone' is set so it can be used to detect wether or not
* 'tone' has been called before.
*/
if(firstTimeRunning)
{
resetTC(TONE_TC);
digitalWrite(outputPin, LOW);
toneIsActive = false;
}
}
#ifdef __cplusplus

View file

@ -38,50 +38,52 @@
// to manage more than one channel per timer on the SAMD architecture
#if defined(__SAMD51__)
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC0
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC0
#define IRQn_FOR_TIMER1 TC0_IRQn
#define HANDLER_FOR_TIMER1 TC0_Handler
#define GCM_FOR_TIMER_1 9 // GCLK_TC0
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC0
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define INTFLAG_BIT_FOR_TIMER_2 TC_INTFLAG_MC1
#define ID_TC_FOR_TIMER2 ID_TC0
#define IRQn_FOR_TIMER2 TC0_IRQn
#define HANDLER_FOR_TIMER2 TC0_Handler
#define GCM_FOR_TIMER_2 9 // GCLK_TC0
#endif
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC1
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC1
#define IRQn_FOR_TIMER1 TC1_IRQn
#define HANDLER_FOR_TIMER1 TC1_Handler
#define GCM_FOR_TIMER_1 TC1_GCLK_ID
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC1
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define INTFLAG_BIT_FOR_TIMER_2 TC_INTFLAG_MC1
#define ID_TC_FOR_TIMER2 ID_TC1
#define IRQn_FOR_TIMER2 TC1_IRQn
#define HANDLER_FOR_TIMER2 TC1_Handler
#define GCM_FOR_TIMER_2 TC1_GCLK_ID
#endif
#else
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC4
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC4
#define IRQn_FOR_TIMER1 TC4_IRQn
#define HANDLER_FOR_TIMER1 TC4_Handler
#define GCM_FOR_TIMER_1 GCM_TC4_TC5
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC4
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#define GCM_FOR_TIMER_2 GCM_TC4_TC5
#endif
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC4
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC4
#define IRQn_FOR_TIMER1 TC4_IRQn
#define HANDLER_FOR_TIMER1 TC4_Handler
#define GCM_FOR_TIMER_1 GCM_TC4_TC5
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC4
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#define GCM_FOR_TIMER_2 GCM_TC4_TC5
#endif
#endif
typedef enum {