Arquitetura do ARM Cortex M3:
E/S, Interrupções
MC404 2o semestre de 2014


Atualizado em 17 Nov 2014
Prof. Célio

Os processadores ARM das famílias M e R (usados em sistemas embarcados e de tempo real como o Cortex M3 e M4) e da família A (usados em sistemas operacionais multiusuário/ multitarefa como Linux e Mac OS), usam E/S "mapeada em memória" ao contrário, por exemplo, dos processadores AVR (8 bits) e Intel (32,64 bits), que usam instruções especiais para E/S, do tipo "in" e "out". O "espaço de endereçamento" do Cortex M3 possui 32 bits, podendo endereçar, portanto, até 2**32 bytes (4 GBytes) de memória. Esse espaço é dividido em regiões de 512 MB conforme mostrado no mapa de memória do Cortex M3, onde apenas uma pequena quantidade existe físicamente em cada região: no chip que estamos usando, por exemplo, a região de memória flash (CODE) ocupa os primeiros 120 KB, a de SRAM os primeiros 20 KB (a partir do endereço 0x20000000), e a de periféricos ~ 0xFFF00000 bytes a partir do endereço 0x40000000.

O que significa "E/S mapeada em memória"? - significa que os diversos registradores de E/S associados a periféricos implementados no chip possuem endereços prefixados na "região de periféricos" conforme se pode ver no mapa de endereços de E/S do Cortex M3. Note nesse mapa a grande quantidade de periféricos (alguns complexos como USB, Ethernet, SPI), incorporados no chip da CPU. O acesso a esses registradores se faz através das instruções convencionais LDR (para executar uma operação de "entrada") e STR (para executar uma operação de "saida").

Passos para fazer E/S sobre um periférico genérico:

  1. Configuração (inicialização) do periférico:
    uma ou mais operações de saída (via instrução STR) para configurar o "modo de operação" do periférico.
  2. Leitura do estado do periférico:
    uma ou mais operações de entrada (via instrução LDR) para ler o o estado do periférico.
  3. Acionamento do periférico:
    uma ou mais operações de saída (instrução STR) para "acionar" o periférico.
Quando múltiplas operações de E/S são feitas sobre o mesmo periférico, usualmente existe um laço no passo 2 acima, para verificar se o periférico está "pronto" para a próxima operação, seguido pelo passo 3 e de volta ao passo 2. Este tipo de E/S é chamado de "busy waiting" pois a CPU vai executar "ociosamente" muitas instruções (milhares e até milhões) no laço de espera para o periférico ficar "pronto para a próxima operação". Isto pode ser inconveniente se a aplicação possui vários periféricos que poderiam ser acionados em paralelo: nesses casos o "busy waiting" pode ser eliminado com o uso de interrupções, assunto a ser discutido em seguida.

Interrupções no Cortex M3

Definição: uma interrupção é um evento assíncrono que desvia o fluxo de execução de instruções da CPU para uma posição prefixada de memória onde uma "rotina de interrupção" associada ao tipo do evento é executada (por exemplo, para fazer uma "operação de entrada" em um periférico). Quando a rotina de interrupção termina, a instrução imediatamente após aquela onde ocorreu o desvio é executada "como se a interrupção não tivesse ocorrido": este é um requisito essencial pois esta instrução poderia ser, por exemplo, um salto condicional (lembrando que saltos condicionais, ao serem executados, consultam os bits de "flags" do registrador de estado (PSR), que foram atualizados em instrução anterior ao salto. É essencial, portanto, que esses bits sejam preservados e restaurados pela interrupção. Fica claro, portanto, que algumas operações necessárias à preservação do "contexto do programa interrompido" sejam executadas pelo hardware quando ocorre uma interrupção, (o "contexto de um programa" inclui pelo menos os "flags" e os registradores sendo usados pelo programa).

Para que uma interrupção possa ocorrer vários requisitos são necessários:
(i) um "pedido de interrupção" deve ser sinalizado (se advindo de um periférico externo, por exemplo, por um sinal em algum pino da CPU),
(ii) interrupções devem estar globalmente habilitadas desligando o bit 7 da palavra de estado xPSR (via instrução cpsie i).
(iii) o "tipo da interrupção" não deve estar inibido em algum dos registradores especiais de "máscara de exceções".
(iv) a interrupção deve ser habilitada programando um dos registradores de E/S do periférico para este fim
(v)deve ser tambem habilitada para o nivel associado ao periférico no vetor de interrupções via programação de registrador do controlador de interrupções NVIC (Nested Vector Interrupt Controller).
(vi) nenhum pedido mais prioritário de interrupção existe (pois pedidos concorrentes podem ocorrer durante o tempo em que a instrução corrente está sendo executada).

Interrupções usualmente ocorrem no final da execução de uma instrução.
Existe a possibilidade de uma rotina de interrupção ser interrompida por uma interrupção mais prioritária que a atual (nesses casos se diz que temos "interrupções aninhadas" ("nested interrupts") e tanto o SW quanto o HW devem ter sido cuidadosamente projetados. Existem muitas situações a serem consideradas no Cortex M3 e que não serão abordadas aqui. Essas situações são exepcionais e podem ser evitadas pelo SW. Um caso em que elas podem ocorrer são os pedidos do tipo NMI ("Non Maskable Interrupt") em que um periférico muito rápido precisa ter seu "pedido de interrupção" atendido com o mínimo atraso. Este tipo de interrupção veio substituir de forma mais econômica a interrupção FIQ ("Fast Interrupt") da família A.

Definição: "mecanismo de interrupção" é o conjunto de "ações indivisíveis" (isto é, não interrompíveis) tomadas pelo HW no momento em que uma interrupção ocorre e antes que a primeira instrução da rotina de interrupção seja executada.

Definição: quando existem posições distintas de memória para cada tipo de interrupção para onde o fluxo de execução é desviado, se diz que o sistema implementa interrupções vetoradas. Essas posições usualmente ocupam palavras consecutivas no início da memória flash e são denominadas de vetor de interrupção. Elas contêm uma instrução de salto para a rotina de interrupção propriamente dita (que pode estar em qualquer posição da memória flash). Em algumas CPUs (AVR, por exemplo), a posição no vetor determina a prioridade da interrupção (quanto menor a posição, maior a prioridade). Veremos a seguir que o Cortex M3 tem um esquema mais flexível de prioridades.

Os processadores ARM das famílias M e R possuem "modos de operação" e um sistema de interrupções bem diferente dos da família A.

Mecanismo de interrupção do Cortex M3
(Essas operações são feitas em paralelo).
Nesse ponto a instrução contida no vetor é executada (salto para a rotina de interrupção). Observe que a rotina de interrupção pode usar livremente os registradores R0 a R3 e R12, pois os mesmos foram salvos na pilha pelo mecanismo de interrupção. Se ela precisar de mais registradores de "rascunho" precisará salvá-los.

Retorno da rotina de interrupção

Quando uma das instruções POP, BX ou LDR carrega o PC, o endereço do "stack frame" armazenado no LR é usado para desempilhar os registradores do "stack frame", retornando à próxima instrução do programa interrompido.