1 votos

¿Cómo lograr una frecuencia de interrupción de 100 kHz en SAM E70?

Configuración: ATMEL Studio 7, ASF3.47.0, placa de evaluación SAME70 XPlained.

En el ejemplo de trabajo mínimo que se muestra a continuación, utilizo el LED integrado para visualizar si se han ejecutado la activación del temporizador y de la interrupción. Se utiliza PIO_PD20 para comprobar si la interrupción está funcionando. Para ello, simplemente conecté mi sonda de osciloscopio a MISO en el encabezado de seis pines cerca del centro de la placa. El código a continuación funciona como se espera hasta frecuencias de 2287 Hz. Una vez que elijo frecuencias más altas que eso, la interrupción parece no ser disparada. ¿Qué estoy haciendo mal? Necesito que esto funcione a 100 kHz.

También he utilizado el depurador para avanzar a través de las líneas individuales de código. Un breakpoint en el manejador de TC0 se activa en frecuencias de 2287 Hz o menos. Frecuencias más altas no activan el breakpoint, confirmando que la rutina de interrupción no se ejecuta.

#include 

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;  // leer el registro de estado para limpiar la bandera de interrupción.
    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; // en Hz

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

    // Apagar el LED integrado
    pio_set_output(PIOC, PIO_PC8, HIGH, DISABLE, DISABLE);

    // Configuración del temporizador y la interrupción
    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);

    // Encender el LED integrado
    pio_set_output(PIOC, PIO_PC8, LOW, DISABLE, DISABLE);

    while(true){};
}

1voto

William J Bagshaw Puntos 113

Gracias a @Justme, he logrado configurar la interrupción para 100 kHz. El problema era que el temporizador no estaba configurado con un ancho de 32 bits y la función tc_find_mck_divisor no 'sabía' eso. El siguiente código es una solución que aún funciona con un registro de temporizador de 16 bits (siempre que el reloj maestro funcione a 150 MHz):

int main (void) {

    sysclk_init();
    board_init();

    pmc_enable_periph_clk(ID_PIOC);
    pmc_enable_periph_clk(ID_PIOD);

    // Apagar el LED de la placa
    pio_set_output(PIOC, PIO_PC8, HIGH, DISABLE, DISABLE);

    // Configuración de temporizador e interrupción para una frecuencia de interrupción de 100 kHz
    pmc_enable_periph_clk(ID_TC0);
    tc_init(TC0, 0, 1 | TC_CMR_CPCTRG); // configurar prescaler a 8 (TCCLKS = 1)
    tc_write_rc(TC0, 0, 187);   // 150 MHz (MCK) dividido por 8 (prescaler) dividido por 100 kHz - 1.
    NVIC_EnableIRQ((IRQn_Type) ID_TC0);
    tc_enable_interrupt(TC0, 0, TC_IER_CPCS);
    tc_start(TC0, 0);

    // Encender el LED de la placa
    pio_set_output(PIOC, PIO_PC8, LOW, DISABLE, DISABLE);

    while(true){};
}

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X