Pasos y código para programar un Timer en un microcontrolador SAM:
La arquitectura SAM es bastante peculiar comparada con los sencillos AVR. Debido a su potencia, por defecto la mayoría de partes de este microcontrolador están apagadas, de manera que así se reduce muchísimo su consumo. Pero por ello mismo debemos activarlas para poder usarlas.
Por ello, antes de usar el Timer en sí debemos activar dichas partes:
En este código usaré diversos 'comodines' cuyos nombres corresponderán a los nombres de las tablas anteriores:
- _TC_TIMER_ - Corresponde a la columna "Timer".
- _TC_NAME_ - Corresponde a la columna "Nombre".
- _TC_CHANNEL_ - Corresponde a la columna "Canal".
- _PRESCALER_ - Corresponderá a la columna "DEFINE".
- _ID_TC_TIMER_ - No es una columna, sino un #define que usamos y que corresponde a "ID_" con el _TC_TIMER_ que usamos; así, para TC3 será ID_TC3.
- _TC_IRQn_ - Tampoco es una columna, es un #define que corresponde al _TC_TIMER_ con "_IRQn" detrás; así, para TC3 será TC3_IRQn.
- __COUNT__ - Es el número de 32 bits cuando deseamos que salte la interrupción
- _HANDLER_ - Es el nombre de la función que hace de manejador para la interrupción; se compone por el _TC_NAME_ con el texto "_Handler".
Código: Seleccionar todo
pmc_set_writeprotect(false); // Permite la reprogramación
pmc_enable_periph_clk(_ID_TC_TIMER_); // Activar el periférico
TC_Configure(_TC_TIMER_, _TC_CHANNEL_, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | _PRESCALER_); // Configuramos el timer
TC_SetRC(_TC_TIMER_, _TC_CHANNEL_, __COUNT__); // Int on last number
//TC_SetRA(_TC_TIMER_, _TC_CHANNEL_, __COUNT__); // EXTRA: Si deseas usar PWM, este es el número donde el pin de salida pasará a estado low. Así, podríamos definir que la señal PWM esté baja del tick 12 al 40000 y el resto a alta. Si no vas a usar PWM no hace falta ponerlo.
TC_Start(_TC_TIMER_, _TC_CHANNEL_); // Iniciamos la cuenta
// Cuidado aquí, TC_CHANNEL (sin los "_") NO es un texto a substituir; la substitución está entre los corchetes:
_TC_TIMER_->TC_CHANNEL[_TC_CHANNEL_].TC_IER = TC_IER_CPCS; // Habilitamos las interrupciones ligadas al registro C
_TC_TIMER_->TC_CHANNEL[_TC_CHANNEL_].TC_IDR = ~TC_IER_CPCS; // Y quitamos el flag de deshabilitar interrupciones (sí, dos pasos, habilitar y quitar bloqueo)
NVIC_EnableIRQ(_TC_IRQn_); // Finalmente habilitamos la interrupción del Timer en el dispositivo de interrupciones anidadas
// [...]
// Y en el programa, como instrucción global, definiremos la función a adjuntar a la interrupción:
void TC3_Handler() {
TC_GetStatus(_TC_TIMER_, TC_CHANNEL); // Reseteamos la interrupción; de no hacerse no se volverá a llamar.
// Nuestro código
}
Y aquí tenéis un ejemplo completo, usando El timer TC3, es decir, Timer 1 y canal 0, con un prescaler de 32
Código: Seleccionar todo
pmc_set_writeprotect(false); // Permite la reprogramación
pmc_enable_periph_clk(ID_TC3); // Activar el periférico
TC_Configure(TC1, 0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK3); // Configuramos el timer (prescaler 32)
TC_SetRC(TC1, 0,30000); // Lo he puesto a boleo, ni idea....
TC_Start(TC1, 0); // Iniciamos la cuenta
TC1->TC_CHANNEL[0].TC_IER = TC_IER_CPCS; // Habilitamos las interrupciones ligadas al registro C
TC1->TC_CHANNEL[0].TC_IDR = ~TC_IER_CPCS; // Y quitamos el flag de deshabilitar interrupciones (sí, dos pasos, habilitar y quitar bloqueo)
NVIC_EnableIRQ(TC3_IRQn); // Finalmente habilitamos la interrupción del Timer en el dispositivo de interrupciones anidadas
// [...]
// Y en el programa, como instrucción global, definiremos la función a adjuntar a la interrupción:
void TC3_Handler() {
TC_GetStatus(TC1, 0); // Reseteamos la interrupción; de no hacerse no se volverá a llamar.
// Nuestro código
}