156 lines
No EOL
5.3 KiB
C++
156 lines
No EOL
5.3 KiB
C++
#include "bsp_timer.h"
|
|
#include "PinMap.h"
|
|
#include "SeesawConfig.h"
|
|
|
|
#if CONFIG_TIMER
|
|
_PWM g_pwms[]=
|
|
{
|
|
#ifdef USE_TCC_TIMERS
|
|
{ CONFIG_TIMER_PWM_OUT0_TC, CONFIG_TIMER_PWM_OUT0_TCC, CONFIG_TIMER_PWM_OUT0_WO, CONFIG_TIMER_PWM_OUT0_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT1_TC, CONFIG_TIMER_PWM_OUT1_TCC, CONFIG_TIMER_PWM_OUT1_WO, CONFIG_TIMER_PWM_OUT1_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT2_TC, CONFIG_TIMER_PWM_OUT2_TCC, CONFIG_TIMER_PWM_OUT2_WO, CONFIG_TIMER_PWM_OUT2_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT3_TC, CONFIG_TIMER_PWM_OUT3_TCC, CONFIG_TIMER_PWM_OUT3_WO, CONFIG_TIMER_PWM_OUT3_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT4_TC, CONFIG_TIMER_PWM_OUT4_TCC, CONFIG_TIMER_PWM_OUT4_WO, CONFIG_TIMER_PWM_OUT4_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT5_TC, CONFIG_TIMER_PWM_OUT5_TCC, CONFIG_TIMER_PWM_OUT5_WO, CONFIG_TIMER_PWM_OUT5_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT6_TC, CONFIG_TIMER_PWM_OUT6_TCC, CONFIG_TIMER_PWM_OUT6_WO, CONFIG_TIMER_PWM_OUT6_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT7_TC, CONFIG_TIMER_PWM_OUT7_TCC, CONFIG_TIMER_PWM_OUT7_WO, CONFIG_TIMER_PWM_OUT7_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT8_TC, CONFIG_TIMER_PWM_OUT8_TCC, CONFIG_TIMER_PWM_OUT8_WO, CONFIG_TIMER_PWM_OUT8_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT9_TC, CONFIG_TIMER_PWM_OUT6_TCC, CONFIG_TIMER_PWM_OUT9_WO, CONFIG_TIMER_PWM_OUT9_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT10_TC, CONFIG_TIMER_PWM_OUT10_TCC, CONFIG_TIMER_PWM_OUT10_WO, CONFIG_TIMER_PWM_OUT10_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT11_TC, CONFIG_TIMER_PWM_OUT11_TCC, CONFIG_TIMER_PWM_OUT11_WO, CONFIG_TIMER_PWM_OUT11_PIN },
|
|
|
|
#else
|
|
{ CONFIG_TIMER_PWM_OUT0_TC, CONFIG_TIMER_PWM_OUT0_WO, CONFIG_TIMER_PWM_OUT0_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT1_TC, CONFIG_TIMER_PWM_OUT1_WO, CONFIG_TIMER_PWM_OUT1_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT2_TC, CONFIG_TIMER_PWM_OUT2_WO, CONFIG_TIMER_PWM_OUT2_PIN },
|
|
{ CONFIG_TIMER_PWM_OUT3_TC, CONFIG_TIMER_PWM_OUT3_WO, CONFIG_TIMER_PWM_OUT3_PIN },
|
|
#endif //USE_TCC_TIMERS
|
|
};
|
|
#endif
|
|
|
|
//TODO: this will probably change based on the use of the timer
|
|
void initTimerPWM( Tc *TCx )
|
|
{
|
|
initTimerClocks();
|
|
|
|
#ifdef GCLK_CLKCTRL_ID_TC4_TC5
|
|
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCLK_CLKCTRL_ID_TC4_TC5_Val));
|
|
while (GCLK->STATUS.bit.SYNCBUSY == 1);
|
|
#endif
|
|
|
|
// Disable TCx
|
|
TCx->COUNT16.CTRLA.bit.ENABLE = 0;
|
|
syncTC_16(TCx);
|
|
// Set Timer counter Mode to 16 bits, normal PWM, prescaler 1/16
|
|
TCx->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_NPWM | TC_CTRLA_PRESCALER_DIV1;
|
|
syncTC_16(TCx);
|
|
|
|
// Set the initial values
|
|
TCx->COUNT16.CC[0].reg = 0x00;
|
|
TCx->COUNT16.CC[1].reg = 0x00;
|
|
syncTC_16(TCx);
|
|
|
|
enableTimer(TCx);
|
|
}
|
|
|
|
#ifdef USE_TCC_TIMERS
|
|
void initTimerPWM( Tcc *TCCx )
|
|
{
|
|
initTimerClocks();
|
|
// Disable TCCx
|
|
TCCx->CTRLA.bit.ENABLE = 0;
|
|
syncTCC(TCCx);
|
|
// Set prescaler to 1/16
|
|
TCCx->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16;
|
|
syncTCC(TCCx);
|
|
// Set TCx as normal PWM
|
|
TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM;
|
|
syncTCC(TCCx);
|
|
|
|
// Set the initial value
|
|
TCCx->CC[0].reg = (uint32_t) 0;
|
|
while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
|
|
|
|
TCCx->PER.reg = (48000000/(16 * 2000)) - 1; //2khz default
|
|
syncTCC(TCCx);
|
|
|
|
enableTimer(TCCx);
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_TIMER
|
|
void PWMWrite( uint8_t pwm, uint16_t value)
|
|
{
|
|
_PWM p = g_pwms[pwm];
|
|
#ifdef USE_TCC_TIMERS
|
|
if(p.tc != NOT_ON_TC){
|
|
#endif
|
|
p.tc->COUNT16.CC[p.wo].reg = value;
|
|
syncTC_16(p.tc);
|
|
#ifdef USE_TCC_TIMERS
|
|
}
|
|
else{
|
|
uint32_t top = p.tcc->PER.reg + 1;
|
|
uint32_t val = (uint32_t)value * top / 65535UL; //map to current top value
|
|
while (p.tcc->SYNCBUSY.bit.CTRLB);
|
|
while (p.tcc->SYNCBUSY.bit.CC0 || p.tcc->SYNCBUSY.bit.CC1);
|
|
p.tcc->CCB[p.wo].reg = val;
|
|
while (p.tcc->SYNCBUSY.bit.CC0 || p.tcc->SYNCBUSY.bit.CC1);
|
|
p.tcc->CTRLBCLR.bit.LUPD = 1;
|
|
while (p.tcc->SYNCBUSY.bit.CTRLB);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void setFreq( uint8_t pwm, uint16_t freq )
|
|
{
|
|
_PWM p = g_pwms[pwm];
|
|
#ifdef USE_TCC_TIMERS
|
|
if(p.tc != NOT_ON_TC){
|
|
#endif
|
|
uint8_t prescale = TC_CTRLA_PRESCALER_DIV256_Val;
|
|
if( freq > 500) prescale = TC_CTRLA_PRESCALER_DIV1_Val;
|
|
else if( freq > 250 ) prescale = TC_CTRLA_PRESCALER_DIV2_Val;
|
|
else if( freq > 140 ) prescale = TC_CTRLA_PRESCALER_DIV4_Val;
|
|
else if( freq > 75 ) prescale = TC_CTRLA_PRESCALER_DIV8_Val;
|
|
else if( freq > 25 ) prescale = TC_CTRLA_PRESCALER_DIV16_Val;
|
|
else if( freq > 7 ) prescale = TC_CTRLA_PRESCALER_DIV64_Val;
|
|
|
|
p.tc->COUNT16.CTRLA.bit.ENABLE = 0;
|
|
syncTC_16(p.tc);
|
|
p.tc->COUNT16.CTRLA.bit.PRESCALER = prescale;
|
|
enableTimer(p.tc);
|
|
#ifdef USE_TCC_TIMERS
|
|
}
|
|
else{
|
|
//fpwm = 48000000/prescale * (PER + 1)
|
|
syncTCC(p.tcc);
|
|
p.tcc->PER.reg = (48000000/(16 * freq)) - 1;
|
|
syncTCC(p.tcc);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void initTimer(Tc *TCx, uint16_t frequency)
|
|
{
|
|
initTimerClocks();
|
|
|
|
syncTC_16(TCx);
|
|
TCx->COUNT8.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV2;
|
|
|
|
/* Clear old ctrlb configuration */
|
|
syncTC_16(TCx);
|
|
TCx->COUNT8.CTRLBCLR.reg = 0xFF;
|
|
|
|
TCx->COUNT8.CTRLC.reg = 0;
|
|
syncTC_16(TCx);
|
|
|
|
TCx->COUNT16.COUNT.reg = 0;
|
|
|
|
syncTC_16(TCx);
|
|
|
|
TCx->COUNT16.CC[0].reg = (uint16_t)( (SystemCoreClock >> 1) / frequency);
|
|
|
|
TCx->COUNT8.INTENSET.reg = TC_INTFLAG_MC0;
|
|
} |