1
\$\begingroup\$

Setup: ATMEL Studio 7, ASF3.47.0, SAME70 XPlained eval board.

In the minimum working example shown below, I use the onboard LED for visualizing if the timer and interrupt enabling have executed. PIO_PD20 is used to check if the interrupt is working. For that I simply connected my oscilloscope probe to MISO on the six-pin header near the center of the board. The code below works as expected up to frequencies of 2287 Hz. Once I choose frequencies higher than that, the interrupt doesn't seem to get triggered. What am I doing wrong? I need this to clock at 100 kHz.

I've also used the debugger to step through the individual lines of code. A breakpoint in the TC0 handler gets trigger at frequencies at or below 2287 Hz. Higher frequencies do not trigger the breakpoint, reconfirming that the interrupt routine doesn't fire.

#include <asf.h>

void TC0_Handler(void) {
    volatile uint32_t ul_dummy;

    pio_set_output(PIOD, PIO_PD20, HIGH, DISABLE, DISABLE);

    ul_dummy=TC0->TC_CHANNEL[0].TC_SR;  // read status register to clear interrupt flag.
    UNUSED(ul_dummy);

    pio_set_output(PIOD, PIO_PD20, LOW, DISABLE, DISABLE);
}


int main (void) {
    static uint32_t ul_sysclk, ul_div, ul_tcclks;
    uint32_t interrupt_frequency=2287; // in Hz

    sysclk_init();
    board_init();
    pmc_enable_periph_clk(ID_PIOC);
    pmc_enable_periph_clk(ID_PIOD);

    // Turn onboard LED off
    pio_set_output(PIOC, PIO_PC8, HIGH, DISABLE, DISABLE);

    // Timer and interrupt configuration
    ul_sysclk=sysclk_get_cpu_hz();
    pmc_enable_periph_clk(ID_TC0);
    tc_find_mck_divisor(interrupt_frequency, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
    tc_init(TC0, 0, ul_tcclks | TC_CMR_CPCTRG);
    tc_write_rc(TC0, 0, (ul_sysclk/ul_div)/interrupt_frequency);
    NVIC_EnableIRQ((IRQn_Type) ID_TC0);
    tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
    tc_start(TC0, 0);

    // Turn onboard LED on
    pio_set_output(PIOC, PIO_PC8, LOW, DISABLE, DISABLE);

    while(true){};
}
\$\endgroup\$
7
  • \$\begingroup\$ What is the clock divisor? With a limited timer counter range you use a prescaler to tick the timer at slower rate than at CPU sysclock speed. If the divisor is high then the timer ticks at slow rate so 100 kHz interrupts are not possible unless you make the timer to tick faster by changing the prescaler divisor to be smaller. Another thing is, what on earth would you do with 100kHz interrupts anyway? Sounds like either you are just testing or trying to do something in a way that is not good. \$\endgroup\$
    – Justme
    Apr 11, 2020 at 9:00
  • \$\begingroup\$ Based on debugging, in case I choose an interrupt frequency of 2287 Hz, the result of (ul_sysclk/ul_div)/interrupt_frequency is 16397 (ul_sysclk is 300000000 and ul_div is 8). If I choose 2288 Hz as interrupt frequency, (ul_sysclk/ul_div)/interrupt_frequency is 65588 (ul_div is 2). \$\endgroup\$
    – Hansel
    Apr 11, 2020 at 9:08
  • \$\begingroup\$ I need an interrupt frequency of 100 kHz for audio processing. \$\endgroup\$
    – Hansel
    Apr 11, 2020 at 9:09
  • \$\begingroup\$ You have a so called X-Y problem. It makes no sense to have a 100 kHz interrupt for audio processing. You would for example use DMA transfers and process the audio in small chunks of many samples, not a single sample at a time. If the MCU has no other way than a 100kHz timer interrupts to do it then it is a wrong MCU for the job. \$\endgroup\$
    – Justme
    Apr 11, 2020 at 9:26
  • \$\begingroup\$ You are making assumptions without really knowing what sort of processing I am planning. It's besides my question. I am still trying to get to 100 kHz. As far as I stand the scaling is calculated using tc_find_mck_divisor. \$\endgroup\$
    – Hansel
    Apr 11, 2020 at 9:36

1 Answer 1

1
\$\begingroup\$

Thanks to @Justme, I've managed to configure the interrupt for 100 kHz. The problem was that the timer wasn't set to a width of 32 bits and the function tc_find_mck_divisor doesn't 'know' that. The following code is a solution that still works with a 16-b timer register (provided the master clock runs at 150 MHz):

int main (void) {

    sysclk_init();
    board_init();

    pmc_enable_periph_clk(ID_PIOC);
    pmc_enable_periph_clk(ID_PIOD);

    // Turn onboard LED off
    pio_set_output(PIOC, PIO_PC8, HIGH, DISABLE, DISABLE);

    // Timer and interrupt configuration for 100 kHz interrupt frequency
    pmc_enable_periph_clk(ID_TC0);
    tc_init(TC0, 0, 1 | TC_CMR_CPCTRG); // set prescaler to 8 (TCCLKS = 1)
    tc_write_rc(TC0, 0, 187);   // 150 MHz (MCK) divided by 8 (prescaler) divided by 100 kHz - 1.
    NVIC_EnableIRQ((IRQn_Type) ID_TC0);
    tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
    tc_start(TC0, 0);

    // Turn onboard LED on
    pio_set_output(PIOC, PIO_PC8, LOW, DISABLE, DISABLE);

    while(true){};
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.