Este microcontrolador posee 3 o 5 timers de 8 o 16 bits, con la posibilidad de unirlos de a dos para hacer timers de 32 bits, y cada uno de ellos con dos canales. Esto significa que podemos usarlos casi como 6 o 10 timers de 16 bits, o 2 timer de 16 bits y 2 o 4 de 32 bits, teniendo en cuenta que en cada grupo de 2 el prescaler ha de ser el mismo.
Prescalers
Cada Timer tiene 8 opciones de prescaler: directo, 2, 4, 8, 16, 64, 256 y 1024
Para referirnos a ellos usaremos las siguientes definiciones: TC_CMR_TCCLKS_TIMER_CLOCK1, TC_CMR_TCCLKS_TIMER_CLOCK2, TC_CMR_TCCLKS_TIMER_CLOCK3 y TC_CMR_TCCLKS_TIMER_CLOCK4 respectivamente.
Si usamos como ejemplo un Arduino Due, que funciona a 84MHz, los ticks por segundo quedarían:
Base | Define | Prescaler | Frecuencia | Intervalo base | Intervalo overflow |
---|---|---|---|---|---|
48MHz | GCLK_TC | 1 | 48MHz | 0,020833333us | 1365,333333333us; 1,365333333333ms |
48MHz | GCLK_TC/2 | 2 | 24MHz | 0,041666667us | 2730,666666667us; 2,730666666667ms |
48MHz | GCLK_TC/4 | 4 | 12MHz | 0,083333333us | 5461,333333333us; 5,461333333333ms |
48MHz | GCLK_TC/8 | 8 | 6MHz | 0,166666667us | 10922,666666667us; 10,922666666667ms |
48MHz | GCLK_TC/16 | 16 | 3MHz | 0,333333333us | 21845,333333333us; 21,845333333333ms |
48MHz | GCLK_TC/64 | 64 | 750KHz | 1,333333333us | 87381,333311488us; 87,381333311488ms |
48MHz | GCLK_TC/256 | 256 | 187,5KHz | 5,333333333us | 349525,333311488us; 349,525333311488ms |
48MHz | GCLK_TC/1024 | 1024 | 46.875Hz | 21,333333333us | 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s |
Pasos y código para programar un Timer en un microcontrolador SAMD21:
La arquitectura SAMD21 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.
Aquí tenéis un ejemplo, usando el TC3 y ambos canales:
Código: Seleccionar todo
// Change the 16 on TcCount16 for 8 or 32, as you need. Also change TC to fit your needs.
TcCount16* _TC = (TcCount16*) TC3;
// Enable clock for TC
REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3)) ;
while (GCLK->STATUS.bit.SYNCBUSY == 1); // sync
// Disable TC
_TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
// Set Timer counter Mode to 16 bits (TC_CTRLA_MODE_COUNT16) + Set TC as normal Normal Frq + Prescaler: GCLK_TC/16 (TC_CTRLA_PRESCALER_DIV16; chgange as you need)
_TC->CTRLA.reg |= (TC_CTRLA_MODE_COUNT16 + TC_CTRLA_WAVEGEN_NFRQ + TC_CTRLA_PRESCALER_DIV16);
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
_TC->CC[0].reg = 12345; // Change the CC for your desired count - channel 0
_TC->CC[2].reg = 23456; // Change the CC for your desired count - channel 1
_TC->INTENSET.reg = 0; // disable all interrupts
_TC->INTENSET.bit.OVF = 1; // enable/disable overfollow interrupt
_TC->INTENSET.bit.MC0 = 1; // enable/disable compare match to CC0 (channel 0) interrupt
_TC->INTENSET.bit.MC1 = 1; // enable/disable compare match to CC1 (channel 1) interrupt
while (_TC->STATUS.bit.SYNCBUSY == 1); // sync
_TC->COUNT.reg = 0; // Reset to 0
NVIC_EnableIRQ(TC3_IRQn);
// Enable TC
_TC->CTRLA.reg |= TC_CTRLA_ENABLE;
// [...]
// Y en el programa, como instrucción global, definiremos la función a adjuntar a la interrupción:
void TC3_Handler() {
/*
Si no es una variable global necesitaremos redefinir _TC:
// Change the 16 on TcCount16 for 8 or 32, as you need. Also change TC to fit your needs.
TcCount16* _TC = (TcCount16*) TC3;
*/
// Overflow
if (_TC->INTFLAG.bit.OVF == 1) {
_TC->INTFLAG.bit.OVF = 1; // Clear flag
// NUESTRO CÓDIGO
}
// Compare channel 0
if (_TC->INTFLAG.bit.MC0 == 1) {
_TC->INTFLAG.bit.MC0 = 1; // Clear flag
// NUESTRO CÓDIGO
}
// Compare channel 1
if (_TC->INTFLAG.bit.MC1 == 1) {
_TC->INTFLAG.bit.MC1 = 1; // Clear flag
// NUESTRO CÓDIGO
}
}