- I need to count the number of pulses in a moving window (e.g. last 60 seconds) using as less CPU time as possible.
- The first step is to use TCC to capture pulse period.
- The pulses arrive randomly at PB02 and the average frequency is about 20-100 counts per minute.
Attempt
According to datasheet TCC has Period and Pulse-Width (PPW) Capture Action
External pulse(PB02)-->EIC-->Event channel-->Event user(TC)
volatile uint32_t T;
volatile uint32_t count;
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("init");
md_setup();
// put your setup code here, to run once:
}
void loop() {
Serial.println(T);
Serial.println(count);
}
void md_setup() {
//PM
REG_PM_APBCMASK |= PM_APBCMASK_EVSYS;
REG_PM_APBCMASK |= PM_APBCMASK_TCC0;
Serial.println("PM done");
//GLCK
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(8) |
GCLK_GENDIV_ID(5);
while (GCLK->STATUS.bit.SYNCBUSY);
REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK 5
GCLK_GENCTRL_SRC_OSCULP32K | // Set the clock source to 32K
GCLK_GENCTRL_ID(5); // Set clock source on GCLK 5
while (GCLK->STATUS.bit.SYNCBUSY);
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |
GCLK_CLKCTRL_GEN_GCLK5 |
GCLK_CLKCTRL_ID_TCC0_TCC1;
while (GCLK->STATUS.bit.SYNCBUSY);
Serial.println("GCLK done");
//PORT
//REG_PORT_PMUX1 |= PORT_PMUX_PMUXEN;
//REG_PORT_PINCFG1 |= PORT_PINCFG_PMUXEN;
REG_PORT_WRCONFIG1 = PORT_WRCONFIG_PINMASK(2) | //select pin PB02 (EIC02)
PORT_WRCONFIG_PMUXEN | //enable peripheral function
PORT_WRCONFIG_INEN | //input mode
PORT_WRCONFIG_PMUX(0) | //select peripheral function A
PORT_WRCONFIG_WRPMUX | //Write to PMUX register
PORT_WRCONFIG_WRPINCFG | //Write to PINCFG register
(0 << 31); //Select lower pins
Serial.println("PORT done");
//EIC
REG_EIC_EVCTRL |= EIC_EVCTRL_EXTINTEO2; // Enable event output on external interrupt 2
REG_EIC_CONFIG0 |= EIC_CONFIG_SENSE2_RISE; // Set event detecting rise
REG_EIC_INTENCLR = EIC_INTENCLR_EXTINT2; // Clear the interrupt flag on channel 2
REG_EIC_CTRL |= EIC_CTRL_ENABLE; // Enable EIC peripheral
//while (EIC->STATUS.bit.SYNCBUSY);
Serial.println("EIC done");
//EVSYS
REG_EVSYS_CHANNEL |= EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT | //no output
EVSYS_CHANNEL_PATH_ASYNCHRONOUS | //async path
EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_2) | // Select EIC2
EVSYS_CHANNEL_CHANNEL(1); //Channel 1
REG_EVSYS_USER |= EVSYS_USER_USER(EVSYS_ID_USER_TCC0_EV_1) | //Select USER = TCC0
EVSYS_USER_CHANNEL(2); //Select Channel 1 (N+1)
//REG_EVSYS_CTRL |= CTRL_SWRST;
Serial.println("EVSYS done");
//TCC0
REG_TCC0_CTRLA &= ~TCC_CTRLA_ENABLE; // Disable TCC0 peripheral
REG_TCC0_CTRLBCLR |= TCC_CTRLBCLR_DIR; // Clear DIR bit to count up
while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for (write) synchronization
REG_TCC0_EVCTRL |= TCC_EVCTRL_TCEI0 | // Enable the TCC event 0 input
//TCC_EVCTRL_TCEI1 | // Enable the TCC event 1 input
TCC_EVCTRL_MCEI1 | // Enable the match or capture channel 1 event input
TCC_EVCTRL_MCEI0 | // Enable the match or capture channel 0 event input
TCC_EVCTRL_EVACT1_PPW; // Select PPW
REG_TCC0_CTRLA |= TCC_CTRLA_CPTEN1 | // Enable capture on CC1
TCC_CTRLA_CPTEN0 | // Enable capture on CC0
TCC_CTRLA_PRESCALER_DIV1;
REG_TCC0_INTENSET = TCC_INTENSET_MC1 | // Enable compare channel 1 (CC1) interrupts
TCC_INTENSET_MC0; // Enable compare channel 0 (CC0) interrupts
REG_TCC0_CTRLA |= TCC_CTRLA_ENABLE; // Enable TCC0
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
NVIC_SetPriority(TCC0_IRQn, 0);
NVIC_EnableIRQ(TCC0_IRQn);
Serial.println("TCC done");
}
void TCC0_Handler()
{
count++;
if (TCC0->INTFLAG.bit.MC0)
{
T = TCC0->CC[0].reg;
}
if (TCC0->INTFLAG.bit.MC1);
}
Problem
- The result (T,count) is always zero.
- if while (EIC->STATUS.bit.SYNCBUSY); is uncommitted, the execution will lock up there.