Move SAMD51 Temperature timer to RTC (#16868)

This commit is contained in:
Giuliano Zaro 2020-02-16 05:45:52 +01:00 committed by GitHub
parent 4360142bd1
commit 199a1ba0e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 97 additions and 47 deletions

View File

@ -37,15 +37,16 @@
// Private Variables
// --------------------------------------------------------------------------
const tTimerConfig TimerConfig[NUM_HARDWARE_TIMERS] = {
{ TC0, TC0_IRQn, TC_PRIORITY(0) },
{ TC1, TC1_IRQn, TC_PRIORITY(1) },
{ TC2, TC2_IRQn, TC_PRIORITY(2) }, // Reserved by framework tone function
{ TC3, TC3_IRQn, TC_PRIORITY(3) }, // Reserved by servo library
{ TC4, TC4_IRQn, TC_PRIORITY(4) },
{ TC5, TC5_IRQn, TC_PRIORITY(5) },
{ TC6, TC6_IRQn, TC_PRIORITY(6) },
{ TC7, TC7_IRQn, TC_PRIORITY(7) }
const tTimerConfig TimerConfig[NUM_HARDWARE_TIMERS+1] = {
{ {.pTc=TC0}, TC0_IRQn, TC_PRIORITY(0) }, // 0 - stepper
{ {.pTc=TC1}, TC1_IRQn, TC_PRIORITY(1) }, // 1 - stepper (needed by 32 bit timers)
{ {.pTc=TC2}, TC2_IRQn, TC_PRIORITY(2) }, // 2 - tone (framework)
{ {.pTc=TC3}, TC3_IRQn, TC_PRIORITY(3) }, // 3 - servo
{ {.pTc=TC4}, TC4_IRQn, TC_PRIORITY(4) },
{ {.pTc=TC5}, TC5_IRQn, TC_PRIORITY(5) },
{ {.pTc=TC6}, TC6_IRQn, TC_PRIORITY(6) },
{ {.pTc=TC7}, TC7_IRQn, TC_PRIORITY(7) },
{ {.pRtc=RTC}, RTC_IRQn, TC_PRIORITY(8) } // 8 - temperature
};
// --------------------------------------------------------------------------
@ -66,49 +67,80 @@ FORCE_INLINE void Disable_Irq(IRQn_Type irq) {
// --------------------------------------------------------------------------
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
Tc * const tc = TimerConfig[timer_num].pTimer;
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
// Disable interrupt, just in case it was already enabled
Disable_Irq(irq);
// Disable timer interrupt
tc->COUNT32.INTENCLR.reg = TC_INTENCLR_OVF; // disable overflow interrupt
if (timer_num == RTC_TIMER_NUM) {
Rtc * const rtc = TimerConfig[timer_num].pRtc;
// TCn clock setup
const uint8_t clockID = GCLK_CLKCTRL_IDs[TCC_INST_NUM + timer_num];
GCLK->PCHCTRL[clockID].bit.CHEN = false;
SYNC(GCLK->PCHCTRL[clockID].bit.CHEN);
GCLK->PCHCTRL[clockID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
SYNC(!GCLK->PCHCTRL[clockID].bit.CHEN);
// Disable timer interrupt
rtc->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
// Stop timer, just in case, to be able to reconfigure it
tc->COUNT32.CTRLA.bit.ENABLE = false;
SYNC(tc->COUNT32.SYNCBUSY.bit.ENABLE);
// RTC clock setup
OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K; // External 32.768KHz oscillator
// Reset timer
tc->COUNT32.CTRLA.bit.SWRST = true;
SYNC(tc->COUNT32.SYNCBUSY.bit.SWRST);
// Stop timer, just in case, to be able to reconfigure it
rtc->MODE0.CTRLA.bit.ENABLE = false;
SYNC(rtc->MODE0.SYNCBUSY.bit.ENABLE);
NVIC_SetPriority(irq, TimerConfig[timer_num].priority);
// Mode, reset counter on match
rtc->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_MODE_COUNT32 | RTC_MODE0_CTRLA_MATCHCLR;
// Wave mode, reset counter on overflow on 0 (I use count down to prevent double buffer use)
tc->COUNT32.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
tc->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_PRESCALER_DIV1;
tc->COUNT32.CTRLBSET.reg = TC_CTRLBCLR_DIR;
SYNC(tc->COUNT32.SYNCBUSY.bit.CTRLB);
// Set compare value
rtc->MODE0.COMP[0].reg = (32768 + frequency / 2) / frequency;
SYNC(rtc->MODE0.SYNCBUSY.bit.COMP0);
// Set compare value
tc->COUNT32.COUNT.reg = tc->COUNT32.CC[0].reg = (HAL_TIMER_RATE) / frequency;
// Enable interrupt on compare
rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; // reset pending interrupt
rtc->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; // enable compare 0 interrupt
// And start timer
tc->COUNT32.CTRLA.bit.ENABLE = true;
SYNC(tc->COUNT32.SYNCBUSY.bit.ENABLE);
// And start timer
rtc->MODE0.CTRLA.bit.ENABLE = true;
SYNC(rtc->MODE0.SYNCBUSY.bit.ENABLE);
}
else {
Tc * const tc = TimerConfig[timer_num].pTc;
// Enable interrupt on RC compare
tc->COUNT32.INTENSET.reg = TC_INTENCLR_OVF; // enable overflow interrupt
// Disable timer interrupt
tc->COUNT32.INTENCLR.reg = TC_INTENCLR_OVF; // disable overflow interrupt
// TCn clock setup
const uint8_t clockID = GCLK_CLKCTRL_IDs[TCC_INST_NUM + timer_num]; // TC clock are preceeded by TCC ones
GCLK->PCHCTRL[clockID].bit.CHEN = false;
SYNC(GCLK->PCHCTRL[clockID].bit.CHEN);
GCLK->PCHCTRL[clockID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
SYNC(!GCLK->PCHCTRL[clockID].bit.CHEN);
// Stop timer, just in case, to be able to reconfigure it
tc->COUNT32.CTRLA.bit.ENABLE = false;
SYNC(tc->COUNT32.SYNCBUSY.bit.ENABLE);
// Reset timer
tc->COUNT32.CTRLA.bit.SWRST = true;
SYNC(tc->COUNT32.SYNCBUSY.bit.SWRST);
// Wave mode, reset counter on overflow on 0 (I use count down to prevent double buffer use)
tc->COUNT32.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
tc->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_PRESCALER_DIV1;
tc->COUNT32.CTRLBSET.reg = TC_CTRLBCLR_DIR;
SYNC(tc->COUNT32.SYNCBUSY.bit.CTRLB);
// Set compare value
tc->COUNT32.COUNT.reg = tc->COUNT32.CC[0].reg = (HAL_TIMER_RATE) / frequency;
// Enable interrupt on compare
tc->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF; // reset pending interrupt
tc->COUNT32.INTENSET.reg = TC_INTENSET_OVF; // enable overflow interrupt
// And start timer
tc->COUNT32.CTRLA.bit.ENABLE = true;
SYNC(tc->COUNT32.SYNCBUSY.bit.ENABLE);
}
// Finally, enable IRQ
NVIC_SetPriority(irq, TimerConfig[timer_num].priority);
NVIC_EnableIRQ(irq);
}

View File

@ -25,6 +25,7 @@
// --------------------------------------------------------------------------
// Defines
// --------------------------------------------------------------------------
#define RTC_TIMER_NUM 8 // This is not a TC but a RTC
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
@ -33,12 +34,12 @@ typedef uint32_t hal_timer_t;
#define STEP_TIMER_NUM 0 // index of timer to use for stepper (also +1 for 32bits counter)
#define PULSE_TIMER_NUM STEP_TIMER_NUM
#define TEMP_TIMER_NUM 4 // index of timer to use for temperature (also +1 for 32bits counter)
#define TEMP_TIMER_NUM RTC_TIMER_NUM // index of timer to use for temperature
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE
@ -62,14 +63,21 @@ typedef uint32_t hal_timer_t;
#if STEP_TIMER_NUM != PULSE_TIMER_NUM
#define HAL_PULSE_TIMER_ISR() TC_HANDLER(PULSE_TIMER_NUM)
#endif
#define HAL_TEMP_TIMER_ISR() TC_HANDLER(TEMP_TIMER_NUM)
#if TEMP_TIMER_NUM == RTC_TIMER_NUM
#define HAL_TEMP_TIMER_ISR() void RTC_Handler()
#else
#define HAL_TEMP_TIMER_ISR() TC_HANDLER(TEMP_TIMER_NUM)
#endif
// --------------------------------------------------------------------------
// Types
// --------------------------------------------------------------------------
typedef struct {
Tc *pTimer;
union {
Tc *pTc;
Rtc *pRtc;
};
IRQn_Type IRQ_Id;
uint8_t priority;
} tTimerConfig;
@ -87,17 +95,20 @@ extern const tTimerConfig TimerConfig[];
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
Tc * const tc = TimerConfig[timer_num].pTimer;
// Should never be called with timer RTC_TIMER_NUM
Tc * const tc = TimerConfig[timer_num].pTc;
tc->COUNT32.CC[0].reg = HAL_TIMER_TYPE_MAX - compare;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
Tc * const tc = TimerConfig[timer_num].pTimer;
// Should never be called with timer RTC_TIMER_NUM
Tc * const tc = TimerConfig[timer_num].pTc;
return (hal_timer_t)(HAL_TIMER_TYPE_MAX - tc->COUNT32.CC[0].reg);
}
FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
Tc * const tc = TimerConfig[timer_num].pTimer;
// Should never be called with timer RTC_TIMER_NUM
Tc * const tc = TimerConfig[timer_num].pTc;
tc->COUNT32.CTRLBSET.reg = TC_CTRLBCLR_CMD_READSYNC;
SYNC(tc->COUNT32.SYNCBUSY.bit.CTRLB || tc->COUNT32.SYNCBUSY.bit.COUNT);
return HAL_TIMER_TYPE_MAX - tc->COUNT32.COUNT.reg;
@ -108,9 +119,16 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
Tc * const tc = TimerConfig[timer_num].pTimer;
// Clear interrupt flag
tc->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF;
if (timer_num == RTC_TIMER_NUM) {
Rtc * const rtc = TimerConfig[timer_num].pRtc;
// Clear interrupt flag
rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
}
else {
Tc * const tc = TimerConfig[timer_num].pTc;
// Clear interrupt flag
tc->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF;
}
}
#define HAL_timer_isr_epilogue(timer_num)