Nos artigos anteriores foram apresentados os principais módulos do DSP, registradores e os módulos GPIO. Neste artigo serão apresentados o timers do DSP e as configurações necessárias para gerar interrupções periódicas. É importante lembrar que o DSP possui timers de propósito geral nos módulos EVA e EVB que podem ser utilizados para gerar sinais PWM, contador de pulsos, entre outras aplicações.
Operação dos Timers do DSP TMS320F2812
O DSP possui três timers de 32 bits. Os timers 1 e 2 são geralmente utilizados pela Texas para aplicações de tempo real. Já o timer 0 pode ser utilizado para propósitos gerais. Na Figura 1 é mostrado o diagrama de registradores e sinais utilizados nesses módulos.
É importante destacar que os timers são habilitados após o reset. Esses módulos têm como clock o sinal SYSCLKOUT, isto é, o clock da CPU. A cada pulso de clock o registrador contador é decrementado. Além dos contadores de 32 bits, é possível, via configuração, dividir o clock de entrada, alterando o comportamento do módulo em função dos pulsos de clock. Outra função é o carregamento automático do registrador contador após um estouro.
Interrupções
Os três timers podem gerar sinais de interrupção. O timer 0 tem o sinal de interrupção conectado ao bloco PIE, enquanto os outros 2 são conectados aos canais INT13 e INT14. Isso é ilustrado na Figura 2.

Para o timer 0 é necessário especificar a fonte de interrupção selecionada para o sinal INT1. Isso é realizado no registrador PIEIER1. Como mostrado na Figura 3, o Timer 0 corresponde à fonte de interrupção 7 (bit 6) de INT1.
Registradores de controle
A operação do timer é controlada pelo registrador TIMERxTCR (Figura 4). Para desativar o timer é necessário alterar o bit TSS, definindo seu valor igual a 1. O bit TRB é responsável por ativar o recarregamento automático do registrador TIMERxTPR e TIMERxPRD. Além disso, o bit TIE habilita a geração de sinal de interrupção quando o contador é decrementado até zero. A flag que indica a ocorrência desse evento é denominada TIF. Os bits FREE e SOFT determinam o comportamento do timer quando o mesmo está em depuração.
O registrador TIMERxTPR é dividido em duas partes: PSC (bits 15~8, CPU-Timer Prescale Counter) e TDDR (bits 7~0, CPU-Timer Divide-Down). O TDDR contém a quantidade de pulsos de clock necessários para que o contador seja decrementado. Assim, o PSC é decrementado a cada pulso de SYSCLKOUT, quando é igual a zero, um pulso é gerado para decrementar o contador de 32 bits (TIMERxTIM/TIMH). Os registradores de controle de todos os timers são mostrados na Figura 5.
Exemplo de aplicação
O exemplo a seguir configura o timer 0 para gerar interrupções a cada 1 ms. Para isso, os registradores TIMER0PRD/PRDH foram configurados com a quantidade de pulsos necessários para atender o período especificado. Assim, considerando clock de 150MHz e o timer0 sem divisor de clock, são necessários 150MHz/1000Hz pulsos para contabilizar 1 ms. Quando o contador chega a zero, uma interrupção é gerada. Para tal, o vetor de interrupção do timer zero (localizado no endereço 0xD4C) foi configurado com o endereço da rotina de interrupção INT1_ISR. Além dessas configurações, o canal INT1 foi configurado para selecionar a fonte de interrupção INT1.7. Isso foi configurado no registrador PIEIER1.
Obs: Programa criado no CCSv7 (CCS Project – Empty ), usando o compilador TI v17.3.0.STS.
/*Registrador de controle do watchdog timer*/
#define WDCR (*(volatile unsigned int *)0x007029)
/*Reigstrador de */
#define PLLCR (*(volatile unsigned int *)0x007021)
/*Registrador que define a direção dos pinos do GPIOA*/
#define GPADIR (*(volatile unsigned int *)0x0070C1)
/*Registrador de estados do GPIOA*/
#define GPADAT (*(volatile unsigned int *)0x0070E0)
/*Reigistrador do controlador de interrupções*/
#define PIECRTL (*(volatile unsigned int *)0x00000CE0)
/*Registrador de ACK das interrupções*/
#define PIEACK (*(volatile unsigned int *)0x00000CE1)
/*Registrador de controle da fonte de interrupção INT1*/
#define PIEIER1 (*(volatile unsigned int *)0x00000CE2)
#define TIMER0TIM (*(volatile unsigned int *)0x00000C00) /*Timer 0, Counter Register Low*/
#define TIMER0TIMH (*(volatile unsigned int *)0x00000C01) /*Timer 0, Counter Register High*/
#define TIMER0PRD (*(volatile unsigned int *)0x00000C02) /*Timer 0, Period Register Low*/
#define TIMER0PRDH (*(volatile unsigned int *)0x00000C03) /*Timer 0, Period Register High*/
#define TIMER0TCR (*(volatile unsigned int *)0x00000C04) /*Timer 0, Control Register*/
#define TIMER0TPR (*(volatile unsigned int *)0x00000C06) /*Timer 0, Prescaler Register*/
#define TIMER0TPRH (*(volatile unsigned int *)0x00000C07) /**/
/*Endereço do vetor de interrupção XINT1 do PIE*/
#define INT1_ADDR (*(volatile unsigned long *)0x00000D4C)
/*Rotina de interrupção*/
interrupt void INT1_ISR(void);
#define F_IN 150000000 //150 MHz
#define F_OUT 1000 //1kHz
#define PRD ((long)(F_IN / F_OUT))
int main(void) {
/*Habilita acesso aos registradores e ao vetor de interrupção do PIE*/
asm(" EALLOW");
/*bit 3~0: seleção de clock -> valor 10, CLKIN = (OSCCLK * 10.0)/2 = 150MHz*/
PLLCR = 10;
/* Desativa o watchdog timer
* WDDIS: bit 6: bit de enable
* WDCHK: bit 5~3: necessário escrever o valor 5*/
WDCR = (1 << 6) | (5 << 3);
/*Configura os GPIOAL como saída*/
GPADIR = 0x00FF;
/*Preenche o vetor de interrupção XINT1 com o endereço da rotina que será utilizada*/
INT1_ADDR = (unsigned long)INT1_ISR;
/*Ativa região protegida*/
asm(" EDIS");
/*Seleciona canal de interrupção INT1.7*/
PIEIER1 = (1 << 6);
/*Define que os vetores de interrupção são definidos no bloco PIE*/
PIECRTL = 1;
/*Habilita fonte de interrupção INT1*/
asm(" OR IER,#1");
/*Habilita interrupções*/
asm(" CLRC INTM");
/*TIE: bit 4 - pausa o timer
*/
TIMER0TCR = (1 << 4);
/*zera os contadores*/
TIMER0TIM = 0;
TIMER0TPR = 0;
TIMER0TPRH = 0;
/*configura o registrador que determina a quantidade de pulsos contados*/
TIMER0PRD = (unsigned int)PRD;
TIMER0PRDH = (unsigned int)(PRD >> 16);
/* TIF: bit 15 - flag de interrupção (necessário escrever 1 para zerar a flag)
* TIE: bit 14 - habilita a interrupção do timer
* SOFT-FREE: bit 11~10 - modo free-run
* TRB: bit 5: carregamento automático
* */
TIMER0TCR |= (1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 5);
/*ativa o timer*/
TIMER0TCR &= ~(1 << 4);
while(1)
{
}
}
interrupt void INT1_ISR(void)
{
static int cont = 0;
/*zera flag de interrupção*/
TIMER0TCR |= (1 << 15);
/*Determina que a interrupção foi atendida*/
PIEACK = 1;
if(cont == 0)
cont = 1;
else
cont = 0;
/*escreve o valor do contador no GPIOA*/
GPADAT = cont;
}
Referências









