Introdução ao processador ARM Cortex-M0+ - Embarcados
Introdução ao processador ARM Cortex-M0+
Processador ARM Cortex-M0+
Ciclo de instrução do ARM Cortex-M0+
Shadowed stack
Suporte a exceções
Modos de sleep do ARM Cortex-M0+
Este post faz parte da série ARM Cortex-M0+. Leia também os outros posts da série:
Introdução à programação do ARM Cortex-M0+ em Assembly
Neste artigo são apresentadas as principais características dos processadores ARM Cortex-M0+, destacando a estrutura do processador e os recursos disponíveis ao programador. Apresenta uma breve descrição do conjunto de instruções que será detalhado em outro artigo. Convido você, leitor, a conferir um breve histórico da ARM e as características de algumas linhas de produto.
A família ARM Cortex-M0+ é a mais simples dos processadores ARM Cortex-M, sendo destinada para aplicações de baixo consumo de energia. Foi criada para agregar novos recursos à família M0 e aumentar a eficiência energética dos microcontroladores.
O processador é estruturado conforme o modelo de arquitetura ARMv6-M, que define a ISA (do inglês, Instruction Set Architecture), os recursos visíveis ao programador e ao módulo de debug, e as especificações de microarquitetura (estágios de pipeline, tempo de execução das instruções, entre outros).
É uma arquitetura caracterizada pela operação load-store. Isto é, os dados devem ser carregados da memória para os registradores do core, processados, e posteriormente armazenados de volta na memória. Para tal, possui 16 registradores de 32 bits. Alguns desses registradores têm funções específicas, tais como:
R15, contador de programa;
R14, registrador Link;
R13, ponteiro de pilha. A pilha sempre indica o último item empilhado. O ponteiro de pilha é decrementado a cada operação de empilhamento. Primeiro o ponteiro é decrementado e, em seguida, o dado é empilhado.
Os registradores R0~R12 são divididos em duas regiões: Low e High. A região Low representa os registradores R0~R7. Já a região High, os registradores R8~R12.
Figura 1: Conjunto de registradores da arquitetura ARM.
O registrador de estados do processador PSR agrupa informações dos seguintes registradores: APSR, IPSR e EPSR.
APSR é o registrador de estado da aplicação que contém as flags condicionais para última instrução que foi executada (Valor negativo, Valor Zero, entre outros);
IPSR é registrador de estado para interrupções que contém o código do vetor de interrupção;
EPSR é o registrador de estado do programa em execução. Indica, por exemplo, se o processador está em modo Thumb.
Todos os barramentos internos são de 32 bits. Devido a isso, o espaço de endereçamento é de 4 GB. O mapa de memória do processador separa o espaço de endereçamento em múltiplas regiões, sendo representadas por diferentes tecnologias de memória e atributos. Assim sendo, pode-se dizer que a arquitetura é baseada no modelo de von Neumann, pois todas as regiões são acessadas pelo mesmo barramento.
Figura 2: Espaço de endereçamento de 32 bits (4 GB).
Todos os módulos do sistema são conectados seguindo padrão de interconexão chamado AMBA. Essa arquitetura de interconexão mantém o processador e a memória conectados em um barramento de alta velocidade, denominado barramento do sistema.
O barramento do sistema é estruturado conforme o protocolo AHB Lite (do inglês, Advanced High Performance Bus), permitindo transferências de dados de 8, 16 e 32 bits. Além disso, é possível configurar ciclos de espera – wait states – para acesso à memória.
Wait state: Para operações de acesso à memória que duram mais que um ciclo de clock, o processador deve aguardar até que o procedimento seja finalizado. Isso é feito adicionado ciclos de espera, denominado wait state.
Os periféricos são conectados em outro barramento, chamado APB. O APB é conectado ao barramento do sistema através de um módulo de interface (Bus Bridge). Com isso, o APB pode operar em frequências diferentes do barramento do sistema. Cabe ressaltar que os periféricos são mapeados em memória.
Figura 3: Sistema de interconexão.
Além disso, existe um barramento dedicado para operações rápidas, chamado Single Cycle I/O Interface. Nesse barramento, os periféricos de I/O podem são acessados em um único ciclo de clock [1]. Nesse contexto, pode ser considerada uma arquitetura híbrida (Harvard limitada), pois possui um barramento dedicado para acessar registradores de periféricos de modo mais rápido [2].
Possui conjunto de instruções simples com 56 instruções. De modo geral, é um subconjunto Thumb (do inglês, Thumb Instruction Set Architecture) que inclui a tecnologia Thumb-2. A maioria das instruções são de 16 bits, as demais possuem 32 bits. Embora possua instruções com tamanhos diferentes, ainda é classificado como RISC (do inglês, Reduced Instruction Set Computing) [2].
A seguir são destacadas as instruções de 16 bits do subconjunto Thumb. É importante destacar que o conjunto de instruções Thumb é subconjunto de instruções ARM (32 bits). Para conferir todas operações realizadas na execução das instruções, consulte esta referência: The ARM Cortex-M0+ Instruction Set.
Hint: Instruções que notificam o processador sobre determinado estado. Por exemplo, a instrução YELD sinaliza que o contexto atual pode ser trocado. Assim o processador pode tomar a ação de alterar o contexto. Já a instrução WFI faz com que o processador entre em modo sleep até que ocorra um evento.
Pipeline: O pipeline é caracterizado por permitir que o ciclo de instrução seja realizado em série para mais de uma instrução. Para tal, o ciclo de instrução é dividido em estágios. No caso de dois estágios, uma instrução é buscada na memória ao mesmo tempo que a atual está sendo executada.
Figura 4: Pipeline com dois estágios.
Para suporte de sistemas operacionais, o processador possui modos de execução e exceção dedicados. Além disso, o fabricante do chip pode incluir um timer em hardware de 24 bits chamado Systick (System Tick Timer) e outros recursos como: unidade de proteção de memória (MMU), vetores de interrupção realocáveis e shadowed stack.
Existem dois modos de operação: Thread e Handler. O modo Thread é definido quando a operação do processador é iniciada (modo de Reset). O processador entra em modo Handler quando ocorre uma exceção (interrupção). Quando o contexto é restabelecido, o processador retorna para o estado Thread.
Figura 5: Modos de operação do ARM Cortex-M0+.
Existem duas pilhas, denominadas Main e Process Stack Pointer. O motivo dessa duplicação é o seguinte: No modo de operação Handler, a pilha Main (MSP) é utilizada. Já no modo Thread, essa definição é realizada via configuração do registrador de controle do processador. Esse recurso permite que tarefas de um sistema operacional não sejam corrompidas pela aplicação.
Além dos modos de operação, existem dois estados de execução: Privilegiado e Não Privilegiado. O estado de privilégio significa que o código de aplicação pode executar todas as instruções disponíveis e acessar todos os recursos de hardware, por exemplo, acessar o registrador de controle do processador. O modo de operação Handler sempre é executado com privilégio. Já o modo não privilegiado tem as seguintes restrições:
Pode ter o acesso restrito para alguns periféricos;
Não pode acessar o Systick, NVIC, e os registradores de controle do processador;
Algumas instruções têm a execução limitada (MSR e MRS) e outras não podem ser utilizadas (CPS – controle de interrupção).
Possui um sistema flexível para controlar interrupções, denominado NVIC. Tal sistema tem suporte para 32 fontes de interrupção, com funções de priorização (4 níveis) e ativação.
Figura 6: Sistema de interrupções do ARM Cortex-M0+.
Ao todo, existem seis tipos de exceções mais o Reset [1]:
Hardware fault: Tem a maior prioridade, sendo causada por algum erro, por exemplo, ao executar uma instrução indefinida, ou realizar uma operação de Load em um endereço que não está alinhado;
NMI: Interrupção gerada por periféricos ou via software. Não pode ser mascarada;
IRQ: Interrupção gerada por periféricos ou via software;
SVCall: Exceção gerada pela execução da instrução SVC;
PendSV: Requisição de interrupção feita pelo sistema (SO). Usada para trocar o contexto, isto é, atender a chamada SVC;
Systick: Exceção gerada quando a contagem do Systick chega ao valor zero.
Toda exceção possui um número de identificação, um endereço na tabela de interrupções e uma prioridade de execução. Na tabela de interrupções, os primeiros 16 endereços possuem funções específicas, sendo o restante dependente do fabricante do microcontrolador. A primeira posição é destinada para indicar o endereço da região de stack. A segunda, para indicar o ponto de entrada da aplicação.
Figura 7: Vetor de interrupções.
A latência de interrupção é de 15 ciclos de clock e se mantém constante – zero jitter – independente das instruções executadas. O único fator que altera esse tempo é a configuração de wait states no acesso à memória.
As ISRs não necessitam de instruções para o ponto de entrada, evitando a sobrecarga/aumento das operações. Isso ocorre devido à operação de carga dos registradores – hardware stacking – na pilha durante a troca de contexto [1].
Latência: Ciclos de clock necessários para que o processador responda ao evento de interrupção.
Jitter: Variações que podem ocorrer no tempo tomado para uma interrupção.
Considerando aplicações de baixo consumo, o processador tem suporte para dois modos de sleep: normal e profundo (deep). O comportamento desses modos é dependente do chip (fabricante). Podem ser adicionados modos específicos de baixo consumo (ou, power saving), totalizado 4 modos de sleep.
Outras propriedades que resultam em redução de consumo são destacadas a seguir:
Wakeup: Possui módulo que permite monitorar interrupções em modo sleep. Quando ocorre uma exceção o processador retoma o estado de execução para tratar a ISR;
Sleep-on-exit: Permite que o processador retorne para o modo de sleep quando uma ISR é tratada.
[1] ARM Cortex-M0+ Processors
[2] Ebook: YU, J. The Definitive Guide to ARM® Cortex®-M0 and Cortex-M0+ Processors. Second Edition.