Contador incorrecto basado en el oscilador interno MCC de MCU de Atmel

1

Estoy programando un SAMC21 para un sistema de control y necesito un contador de milisegundos similar a la función de milis en arduino para hacer un seguimiento de las muestras, etc. Para hacer esto, primero configuro un canal de reloj para el oscilador interno (48MHz) cuya salida se divide por 48. Luego configuro un temporizador / contador de 8 bits con un período de 100. Cada vez que el TC alcanza los 100, se desborda y uso una devolución de llamada para llamar a una función que simplemente incrementa mi variable de contador de milis (uint32_t volátil) . Esto funciona bien, pero el contador es bastante más lento de lo que debería y demora entre 5 y 15 segundos por minuto. ¿Por qué es así y cómo podría hacerlo más preciso?

Nota: uso el controlador UART a través de Debug USB para leer el valor del contador.

Aquí está el código que se llama apropiadamente en main:

 void configure_gclock_generator(void) // Configuration of internal oscillator and channel
 {
     struct system_gclk_gen_config gclock_gen_conf;
     system_gclk_gen_get_config_defaults(&gclock_gen_conf);
     gclock_gen_conf.source_clock    = SYSTEM_CLOCK_SOURCE_OSC48M;
     gclock_gen_conf.division_factor = 48;
     system_gclk_gen_set_config(GCLK_GENERATOR_1, &gclock_gen_conf);
     system_gclk_gen_enable(GCLK_GENERATOR_1);
 }
 void configure_gclock_channel(void)
 {
     struct system_gclk_chan_config gclk_chan_conf;
     system_gclk_chan_get_config_defaults(&gclk_chan_conf);
     gclk_chan_conf.source_generator = GCLK_GENERATOR_1;
     system_gclk_chan_set_config(TC3_GCLK_ID, &gclk_chan_conf);
     system_gclk_chan_enable(TC3_GCLK_ID);
 }

void configure_tc(void) // COnfiguration of TC on internal oscillator
{
    struct tc_config config_tc;
    tc_get_config_defaults(&config_tc);
    config_tc.counter_size = TC_COUNTER_SIZE_8BIT;
    config_tc.clock_source = GCLK_GENERATOR_1;
    //config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
    config_tc.counter_8_bit.period = 100;
    //config_tc.counter_16_bit.compare_capture_channel[0] = 48;
    tc_init(&tc_instance, CONF_TC_MODULE, &config_tc);
    tc_enable(&tc_instance);
}

void millis_count(struct tc_module *const module_inst) { //millis increment function
    millis++;
    if (millis>=1000000000) {
        millis=millis-start;
        start=0;
    }
}

void configure_tc_callbacks(void) //Set up of Callback for millis function.
{
    tc_register_callback(&tc_instance, millis_count,TC_CALLBACK_OVERFLOW);
    //tc_register_callback(&tc_instance, millis_count,TC_CALLBACK_CC_CHANNEL0);
    tc_enable_callback(&tc_instance, TC_CALLBACK_OVERFLOW);
    //tc_enable_callback(&tc_instance, TC_CALLBACK_CC_CHANNEL0);
}
    
pregunta Eliott W

1 respuesta

2

En realidad, está tomando una interrupción cada 100 µs, no milisegundos como lo indica su nombre. Eso es un montón de interrupciones para un sistema de 48 MHz.

Además, el código sugiere una estructura de manejo de interrupciones bastante elaborada que existe "detrás de la escena", con devoluciones de llamada "registradas" y "habilitadas". Entonces, si bien su función de devolución de llamada real es breve y agradable, la sobrecarga general para tomar cualquier interrupción individual puede ser bastante alta.

También sugiere utilizar un UART para la comunicación, y supongo que su controlador también está basado en interrupciones.

Todo esto me lleva a sugerir que se está acercando al límite en la cantidad de interrupciones que este sistema puede manejar y que algunas de las interrupciones de su temporizador simplemente se están perdiendo. Esto sería especialmente cierto si las interrupciones de UART tienen una prioridad más alta que las interrupciones de temporizador, que es el caso habitual. Intente aumentar el período de interrupción del temporizador a 200 µs o 1000 µs. (En su devolución de llamada, incremente la variable millis en 2 o 10, respectivamente, entonces el resto del sistema no notará la diferencia).

    
respondido por el Dave Tweed

Lea otras preguntas en las etiquetas