Timers en Arduino SAMD21

Arduino, STM32 (Maple), ESP8266, ESP32, etc
Avatar de Usuario
Naguissa
Administrador del Sitio
Mensajes: 408
Registrado: 04 Jul 2016, 11:17
Agradecido: 84 veces
Agradecimiento recibido: 131 veces

Timers en Arduino SAMD21

Mensaje por Naguissa » 02 Ene 2019, 16:28

Mientras implementaba la compatibilidad de la librería uTimerLib con los microcontroladores SAMD21 he tenido que estudiar el complejo sistema de timers de dicho microcontrolador. Y, debido a que uTimerLib usa un timer definido, he querido explicar cómo implementar timers manualmente en este microcontrolador.

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
	}
}
Estos usuarios agradecierón al autor Naguissa por el mensaje:
Daniel
Valoración: 33%

Tags:

  • Similar Topics
    Respuestas
    Vistas
    Último mensaje