![]() |
Programação do LPC2378 usando o arm-elf-gcc Parte 7: Interrupções |
![]() |
Anterior | Indice | Próximo |
Neste exemplo vamos fazer o programa a07_T0_FIQ para configurar o Kit de modo a usar a interrupção tipo FIQ para fazer piscar o LED de forma cadenciada usando o timer T0. Para configurar e testar o programa fazemos como de costume:
Configurar para gravar na memória Flash
Colocar o kit em modo de programação
Compilar e gravar a flash com o comando:
make ispTestar chamando o terminal ltser e iniciar a execução apertando no botão de RESET.
Configurar para gravar na memória RAM
Pode-se executar o programa na RAM. Até os vertores de interrupção podem rer remapeados para funcionar a partir da RAM a partir do endereço 0x40000000. Um registrador de configuração do LPC2378 chamado MEMMAP permite remapear os vetores de interrupção para a RAM.
O programa mon23 inclui um carregador de arquivos *.hex que pode colocar o programa na RAM usando o terminal ltser. Isto é feito automaticamente usando a diretiva make tser deste projeto. Antes de executar make tser é necessário que o monitor mon23 esteja gravado na Flash e sendo executado. Então basta fazer
make tserO programa será compilado com a configuração para executar na RAM e carregado na RAM usando o terminal ltser. Para executa-lo usa-se o comando P do monitor mon23.
Os registradores usados na configuração do timer são os seguintes:
T0CR 0xE0004004 |
Timer Control Register. Habilita ou Inicializa o Timer bit 0: Habilita o Timer. bit 1: Inicializa o timer com zero. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
T0TC 0xE0004008 |
T0 Timer Count. Neste registrador está o valor da contagem do timer. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
T0PR 0xE000400C |
T0 Prescale Register: Configura o divisor da frequência de incremento do timer. O registrador T0PC é incrementado até ficar igual ao T0PR. Neste momento a contagem T0TC é incrementada e T0PC é zerado. Portanto configura-se este registrador com o divisor de freqência menos um. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
T0MCR 0xE0004014 |
T0 Match Control Register. Registrador configuração dos registradores de comparação
Match Registers. Os bits deste registrador selecionam o que fazer quando o valor da contagem se iguala
ao Match Register correspondente. 1 (um) habilita. 0 (zero) desabilita.
|
Temos também os Match Registers T0MR0, T0MR1, T0MR2 e T0MR3 que tem os valores de contagem em que devem acontecer os eventos.
No programa principal do projeto a07_T0_FIQ temos o seguinte procedimento para configurar o timer para gerar interrupções:
T0TCR = 2; T0TCR=0; /* Limpa e habilita T0 */ /* Preescalonador do T0 para incrementar 32 vezes por segundo */ T0PR = (CRYSTALFREQ / 32) - 1; T0TCR=1; /* Configura T0 para gerar int na contagem 8 e 24 e resetar em 32 */ T0MCR=0x89; /* Interrompe em T0MR0 e T0MR1; Reset em T0MR2 */ T0IR=3; /* Interrompe quando encontrar T0MR0, T0MR1 */ /* Deve colocar 1 a menos nos T0MR porque o evento acontece no fim do ciclo */ T0MR0 = 7; /* Interrompe quando T0TC==8 */ T0MR1 = 23; /* Interrompe quando T0TC==24 */ T0MR2 = 31; /* Reinicia quando T0TC==32 */
Neste exemplo vamos demonstrar a configuração da interrupção tipo FIQ.
O gcc usa uma extenção especial de sintaxe para declarar rotinas de atendimento de interrupção: [no arquivo vic_cpsr.h]
/* Declaracoes especiais para rotinas de atendimento a interrupcoes*/ void SWI_Routine(void) __attribute__ ((interrupt("SWI"))); void FIQ_Routine(void) __attribute__ ((interrupt("FIQ")));Estas declarações encontram-se no arquivo de cabeçalho vic_cpsr.h. Neste arquivo também tem rotinas que geram instruções em linha para habilitar as interrupções no registrador de status CPSR:
/* Macros para habilitar/desabilitar IRQ/FIQ no CPSR */ #define habilitaFIQ() asm volatile(\ "mrs r3, cpsr\n" \ "bic r3, r3, # 0x40\n" \ "msr cpsr, r3\n") #define desabilitaFIQ() asm volatile(\ "mrs r3, cpsr\n" \ "orr r3, r3, # 0x40\n" \ "msr cpsr, r3\n")Usando estas intruções pode-se habilitar as interrupções tipo FIQ com o comando:
habilitaFIQ();
Os processadores da faília LPC23xx tem 32 fontes de interrupção, classificadas de acordo com a tabela a seguir.
bit | Máscara | Módulo | Fonte de interrupção |
---|---|---|---|
0 | 0x00000001 | WDT | Watchdog Interrupt |
1 | 0x00000004 | ARM-core | ICE DbgRX |
2 | 0x00000008 | ARM-core | ICE DbgTX |
4 | 0x00000010 | TIMER0 | Contagem atinge MR0, MR1 |
5 | 0x00000020 | TIMER1 | Contagem atinge MR0, MR1 |
6 | 0x00000040 | UART0 | Evento na porta serial UART0 |
7 | 0x00000080 | UART1 | Evento na porta serial UART1 |
8 | 0x00000100 | PWM1 | PWM1 Match ou Capture |
9 | 0x00000200 | I2C0 | Mudança de estado no I2C0 |
10 | 0x00000400 | SPI0 | Mudança de estado no SSP0 |
11 | 0x00000800 | SPI1 | Mudança de estado no SSP1 |
12 | 0x00001000 | PLL | PLL Lock (Travamento do PLL) |
13 | 0x00002000 | RTC | Relógio/ Despertador |
14 | 0x00004000 | EINT0 | Interrupção externa 0 |
15 | 0x00008000 | EINT1 | Interrupção externa 1 |
16 | 0x00010000 | EINT2 | Interrupção externa 2 |
17 | 0x00020000 | EINT3/GPIO | Interrupção externa 3 e GPIO |
18 | 0x00040000 | ADC0 | Fim de conversão do ADC0 |
19 | 0x00080000 | I2C1 | Mudança de estado no I2C1 |
20 | 0x00100000 | BOD | Brown Out Detect - Detector de tensão baixa |
21 | 0x00200000 | Ethernet | Evento na interface ethernet |
22 | 0x00400000 | USB | Evento na interface USB |
23 | 0x00800000 | CAN | Evento na interface CAN |
24 | 0x01000000 | SD/MMC | Evento na interface SD/MMC |
25 | 0x02000000 | GPDMA | Evento no DMA |
26 | 0x04000000 | TIMER2 | Contagem atinge MR0, MR1 |
27 | 0x08000000 | TIMER3 | Contagem atinge MR0, MR1 |
28 | 0x10000000 | UART2 | Evento na porta serial UART2 |
29 | 0x20000000 | UART3 | Evento na porta serial UART3 |
30 | 0x40000000 | I2C2 | Mudança de estado no I2C2 |
31 | 0x80000000 | I2S2 | Mudança de estado no I2S2 |
Os processadores da família LPC23xx tem um controlador de interrupções chamado VIC (Vectored Interrupt Controller). Este dispositivo permite administrar o sistema de interrupções fazendo coisas como vetorar as interrupções para as respectivas rotinas de atendimento, atribuir prioridades, habilitar/desabilitar e ativar interrupções por software.
Neste programa desejamos habilitar a interrupção do timer 0, número 4, com máscara 0x00000010. Queremos também configurar esta interrupção como FIQ. Isto é feito com os seguintes comandos.
VICIntSelect |= 0x10; /* Timer0=bit 4 como FIQ */ VICIntEnable = 0x10; /* Habilita int do Timer0 */
Foram usados os seguintes registradores do VIC:
VICAddress 0xFFFFF000 |
A rotina de atendimento tipo IRQ deve escrever 0 neste registrador para indicar ao VIC que a interrupção foi atendida. | |
VICIntEnable 0xFFFFF010 |
Bits 0 a 31: Valor 0: Mantem o estado anterior. Valor 1: Habilita a interrupção correspondente ao bit. |
VICIntClear 0xFFFFF014 |
Bits 0 a 31: Valor 0: Mantem o estado anterior. Valor 1: Desabilita a interrupção correspondente ao bit. |
VICIntSelect 0xFFFFF00C |
Bits 0 a 31: Valor 0: Configuara como FIQ. Valor 1: Configura como IRQ. |
A rotina de atendimento da FIQ acende ou apaga o LED, dependendo de qual T0MR gerou a interrupção. No final a rotina FIQ deve escrever no T0IR um valor (igual ao que foi lido no T0IR) para indicar que a interrupção foi atendida.
/* A rotina de atendimento da FIQ Liga o LED quando a contagem atinge MR0 Desliga o LED quando a contagem atinge MR1 */ void FIQ_Routine() { int k; k=T0IR; /* T0IR identifica quem causou a int */ if(k & 1) FIO3CLR = 0x01000000; /* T0MR0: Liga LED 1 */ if(k & 2) FIO3SET = 0x01000000; /* T0MR1: Desliga LED 1 */ T0IR = k; /* Deve limpar a INT no T0IR */ }
No sistema de interrupção vetorada, a rotina de atendimento recebe o vetor que pode transferir a execução para uma rotina específica para aquele tipo de interrupção.
Isto é feito por uma instrção tipo:
ldr PC, [PC,#-0x0120]
O programa exemplo arm06 demonstra como usar uma interrupção vetorada no do relógio RTC para escrever no display LCD. Neste programa o main.c é apenas uma rotina de teste. As rotinas de inerrupção estão no módulo lcd.c.
A habilitação é feita de forma similar à FIQ, mas pode-se ter diferentes rotinas de atendimento de acordo com a fonte de interrupção. O vetor ´ configurado usando uma escrita em VICVectAddr4 (Para a IRQ numero 4: Timer 0). O seguinte trecho de programa coloca 0 no bit 4 do VICIntSelect para selecionar como IRQ, liga o bit 4 do VICIntEnable para habilitar a interrupção no VIC e coloca o vetor no VICVectAddr4. Observe que o valor 0x10 é um número com apenas o bit 4 ligado.
CISS = 0x85; /* Configura o RTC para gerar 64 iterrupções por segundo */ ILR=0; /* Limpa o identificador de interrupções do RTC */ desabilitaIRQ(); /* Desabilita IRQ no reg CPSR da CPU */ VICVectAddr13 = (int)IRQ_RTC; /* Instala o vetor 13: RTC */ VICIntSelect &= ~0x2000; /* Seleciona como IRQ, mantendo os outros bits*/ VICIntEnable = 0x2000; /* Habilita IRQ do RTC */ habilitaIRQ();A rotina de atendimento de interrupção tipo IRQ também deve ter um tipo de declaração especial no gcc:
void IRQ_RTC(void) __attribute__ ((interrupt("IRQ")));No final da rotina de atendimento o programa deve escrever 0 no VICVectAddr para indicar para o VIC que a interrupção foi atendida. Também é necessário limpar a interrupção no dispositivo que a gerou, o caso o registrador RTC_ILR do relógio. Isto é feito lendo o RTC_ILR e escrevendo nele o mesmo valor.
void IRQ_RTC(void) { short k; /* Aqui vão as operações de atendimento */ k=RTC_ILR; /* Le o identificador de IRQ do RTC */ RTC_ILR = k; /* Limpa a IRQ do RTC */ VICVectAddr = 0; /* Rearma o VIC */ }
Anterior | Indice | Próximo |