Arquitetura e modos de endereçamento do AVR ATmega88

Prof. Célio Guimarães
Atualizado em: 18/04/2008  

Este documento apresenta um resumo da arquitetura do microcontrolador AVR ATmega88 da Atmel e mostra algumas semelhanças e diferenças entre os modos de endereçamento do AVR e do Intel 8086. Pode, no entanto, ser lido sem conhecimento prévio da arquitetura do 8086.

Uma boa introdução à arquitetura do AVR ATmega88 encontra-se na seção "Architectural Overview" do datasheet manual, pgs 3 - 18. Leia-o após esta introdução. Por ter uma arquitetura RISC, todas as instruções do AVR ATmega88 possuem o mesmo tamanho, 16 bits, com exceção das instruções de endereçamento direto, LDS e STS que ocupam 32 bits. Um ponto importante a ressaltar é que, além da arquitetura RISC, a arquitetura dita Harvard dos microcontroladores AVR possui internamente barramentos separados para acessar instruções (16 bits) e para acessar dados (8 bits). Esses espaços distintos de endereçamento são chamados de área de programa ou de instruções (read only) e área de dados (read/write), permitindo uma eficiência maior, pois instruções podem ser lidas em paralelo com o acesso a dados. Uma instrução especial (LPM) permite ler dados (constantes) armazenados na área de programa.

O tamanho do espaço de endereçamento (*) de instruções é de 64K instruções (128 KB) (**); como o espaço de instruções também pode ser usado para armazenar dados é possível endereçar até 64KB (2**16 bytes) de dados na área de programa; o tamanho do espaço de dados é também 64KB, porém a capacidade física do modelo ATmega88 é muito menor do que os valores acima, apenas 8KB para instruções (4K instruções de 16 bits cada) e 512 + 32 bytes para dados, incluindo os registradores de propósito geral. Dependendo do modelo da família AVR de 8 bits, a capacidade física da memória de programa (FLASH) pode chegar a 64K instruções e a memória de dados (Static RAM) a 8KB. Você pode consultar uma tabela com as diversas capacidades de memória e de recursos de E/S da família AVR neste link.

Os 32 registradores de propósito geral (acumuladores), denotados R0 a R31 também podem ser endereçados pelas primeiras 32 posições da memória RAM. A notação Rr no datasheet e no manual do montador refere-se a um deles como operando fonte de uma instrução e Rd como operando destino. Além disso os pares de registradores (R26, R27), (R28, R29) e (R30, R31) podem ser usados como apontadores de 16 bits (indexadores) e são chamados respectivamente de X, Y e Z. Este recurso é inestimável para operar com vetores e na implementação do compilador C para a família AVR.
O registrador de estado (SREG), o apontador para pilha (o par SPH,SPL), e vários outros registradores para contrôle de E/S e de interrupções encontram-se nas 64 posições seguintes da memória RAM (endereços 0x20-0x5F), que constituem o espaço de E/S; elas são acessíveis diretamente através das instruções de entrada e saída in e out, que tomam como operando um valor de 0 a 0x3F (63) ou seja, o operando é um endereço no espaço de E/S e este endereço é denominado Port (Porta, em portuguës). A fim de suportar mais periféricos de E/S as 160 posições seguintes constituem o "conjunto estendido de registradores de E/S"; os 512 bytes seguintes começando no endereço 0x100 constituem a memória RAM para dados (Static RAM). Em resumo, os registradores de propósito geral R0 a R31, as 64 portas de E/S e os 160 registradores de E/S estendida estão mapeados, nesta ordem, no espaço de dados do AVR conforme mostra a figura 5-3 pg. 17 do datasheet e, portanto, também podem ser endereçados através das instruções de acesso à memória RAM LDS, LD, STS e ST.
Os mapa das memórias de programa e de dados podem ser vistos nas páginas 16 e 17 do datasheet. Veja neste link um mapa dos registradores de E/S (distribuído em aula) do modelo ATmega88.

As instruções de chamada de subrotina e as interrupções utilizam um par de registradores localizado no espaço de E/S (SPH,SPL, endereços 0x3E e 0x3D) como apontador de pilha, localizada usualmente no final da memória RAM, para armazenar (empilhar) o endereço de retorno da subrotina (ou da instrução interrompida). Obviamente, o par SPH,SPL deve ser inicializado antes de qualquer chamada de subrotina ou habilitação de interrupções.


(*)A capacidade máxima de endereçamento pela CPU (de instruções, dados e E/S) de uma família de processadores (por exemplo, a família AVR da Atmel) é também chamada de tamanho do espaço lógico de endereçamento. É a mesma para todos os modelos da família. A capacidade (configuração) física varia com o modelo, conforme já mencionado.

(**)O registrador PC (Program Counter) contém o endereço a nível de 16 bits da próxima instrução e seu tamanho varia conforme o modelo do AVR, de 10 bits (1K instruções) a 16 bits (64K instruções), (são 12 bits no ATmega88). As instruções IJMP e ICALL (presentes em todos os modelos) permitem saltar (ou chamar uma subrotina) usando um endereço de 16 bits contido no par Z, o que nos permite concluir que o tamanho do espaço lógico de endereçamento de instruções é de fato 128 KB.

Há modelos mais avançados, que permitem estender os espaços de programa e de dados além dos limites de 128KB e 64KB, através de registradores de páginas (localizados no espaço de E/S). Ao nosso ver, se a sua aplicação requer tanta memória é preferível partir diretamente para os microcontroladores de 32 bits da família ARM (pois a programação de aplicções que requerem memória paginada é extremamente complexa).

1. Instruções de movimentação de dados

São semelhantes ao MOV do 8086, porém com vários (infelizmente) mnemônicos especializados (*):

  1. as instruções LD (LoaD) e LDD (Load with Displ) carregam num registrador um byte da memória SRAM apontado por um dos indexadores X, Y ou Z (e nestas notas de aula coletivamente chamados W);
  2. as instruções ST(STore) e STD (STore with Displ) armazenam um registrador (8 bits) no byte da memória SRAM apontado por um dos indexadores X, Y ou Z;
  3. os registradores X, Y e Z podem adicionalmente usar pós-decrementação (indicado por W+) ou pré-decrementação (indicado por -W); são extremamente úteis para percorrer os elementos de um vetor;
  4. a notação a seguir: [W] indica que o operando é a posição de memória apontada por W. Observe que os manuais do AVR usam a notação: (W)
  5. A área de programa é endereçada pela CPU para endereçar instruções através do PC a nível de 16 bits e para endereçar dados através do registrador Z a nivel de 8 bits : a instrução especial LPM transfere da área de programa um byte apontado pelo registrador Z para o registrador R0; como o montador calcula o endereço dos rótulos de instruções em unidades de palavras de 16 bits, o endereço a ser colocado em Z ao se usar a instrução LPM deve ser sempre rótulo * 2;
  6. nenhuma instrução de movimentação de dados altera bits do registrador de estado (SREG)

InstruçãoEfeito
MOV Rd, Rr Rd := Rr
MOVW Rd+1:Rd, Rr+1:Rr Rd+1:Rd := Rr+1:Rr   Exs: MOVW X,Z     MOVW R25:R24, R17:R16
LD Rd, W Rd := [W]   Obs:  W = X, Y ou Z
LD Rd, W+ Rd := [W], W := W + 1     W+ significa: pós-decrementação
LD Rd, -W W := W - 1, Rd := [W]     -W significa: pré-decrementação
ST W, Rr [W] := Rr
ST W+, Rr [W] := Rr, W := W + 1
ST -W, Rr W := W - 1, [W] := Rr
LDD Rd, W+q Rd := [W' + q] , 0 ≤ q ≤ 63   Obs:   (i) não altera W'   (ii) W' = Z ou Y
STD W+q, Rd [W' + q] := Rd , 0 ≤ q ≤ 63   Obs:   (i) não altera W'   (ii) W' = Z ou Y
LDS Rd,end Rd := [end]   Endereçamento direto à RAM: end tem 16 bits e a instrução 32 bits
STS end, Rd [end] := Rd   Endereçamento direto à RAM: end tem 16 bits e a instrução 32 bits
LPM R0 := [Z]  onde o byte apontado por Z está na região de instruções
LPM Rd, Z Rd := [Z]  byte apontado por Z na região de instruções
LPM Rd, Z+ Rd := [Z] , Z := Z +1  byte apontado por Z na região de instruções, pós-decrementa Z

(*)O montador do AVR também aceita mnemônicos de instruções e de registradores em letras minúsculas.

 

2. Instrução de comparação (ou lógico/aritmética) seguida de salto condicional

As instruções de comparação (CP, CPI e CPC) e as instruções lógico/aritméticas alteram certos bits do registrador SREG, dependendo da instrução; os bits que podem ser alterados são coletivamente chamados de flags : são os bits 5 a 0 do registrador de E/S SREG (Porta 0x3F), denominados T, H, S, V, Z e C (Transfer, Half carry, Sign, oVerflow, Zero e Carry), respectivamente (*); a coluna Flags no resumo do conjunto de instruções mostra para cada instrução quais bits são alterados; são esses bits que as instruções de salto condicional testam (avaliando uma expressão booleana sobre os mesmos), a fim de decidir se o salto deve ser feito ou não.
O AVR admite tanto operandos de 8 bits com sinal como sem sinal. As instruções de salto condicional são mais restritas no AVR que no 8086, conforme mostra a tabela de equivalências abaixo (onde na significa não se aplica: nesses casos o programador pode ter que alterar a lógica da sua expressão, por exemplo, trocando a ordem dos operandos de uma instrução de comparação para poder usar em seguida o salto condicional disponível)

Comparação 8086 x AVR
  com sinal sem sinal
operação 8086 AVR 8086 avr
= je (jz) breq je (jz) breq
!= jne (jnz) brne jne (jnz) brne
< jl brlt jb brlo
<= jle na jbe na
>= jge brge jae brsh
> jg na ja na

  (*) Bits dos registradores do AVR são numerados de 0 a 7 a partir do menos significativo (mais à direita). Eles podem ser lidos/modificados/testados através do grupo de instruções Bit and Bit-test instructions no resumo de instruções distribuído em aula.

3. Operandos imediatos


(*) Esta instrução pode ser facilmente simulada através da seguinte macro :
.macro	 addi               ; macro toma como paâmetros (Rd, K)
         subi	@0, -(@1)   ; onde @0=Rd e @1=K
.endmacro
e poderia ser invocada, por exemplo,  assim:
         addi   r16, 64

4. Instruções lógicas

Estas instruções permitem ligar/desligar bits de registradores e portas de E/S do microcontrolador. Se executadas sobre portas de E/S elas terão finalidades específicas de E/S dependendo da porta (veja no datasheet).

  1. Ligando um ou mais bits de um registrador ou porta:
    or Rd, Rr
    ori Rd, constante
    out Porta, Rr
    sbi Porta, b    ; 0 <= Porta <= 31 e b= 0,1,...,7
    
    Obs: liga (torna 1) os bits do 1º operando que estão ligados no 2º operando (usualmente chamado de máscara); não muda os outros bits do 1º operando.

  2. Desligando um ou mais bits de um registrador ou porta:
    and Rd, Rr
    andi Rd, constante
    out Porta, Rr
    cbi Porta, b    ; 0 <= Porta <= 31 e b= 0,1,...,7
    
    Obs: desliga (torna 0) os bits do 1º operando que estão desligados no 2º operando (usualmente chamado de máscara); não muda os outros bits do 1º operando.

  3. Exercício: que instruções Vocë usaria para complementar os bits de um registrador?

  4. Testando bits de um registrador ou porta:
    sbrc Rr, b         ; salta a próxima instrução se o bit b do reg Rr estiver desligado 
                       ; em geral a próxima instrução é um salto incondicional (rjmp)
    sbrs Rr, b         ; salta a próxima instrução se o bit b do reg Rr estiver ligado 
    sbic Porta, b      ; salta próxima instrução se o bit b da Porta estiver desligado
    sbis Porta, b      ; salta próxima instrução se o bit b da Porta estiver ligado
    brts rótulo        ; desvia para rótulo se o bit T (do reg de estado) estiver ligado
    brtc rótulo        ; desvia para rótulo se o bit T (do reg de estado) estiver desligado
    outras: brcs, brcc, brvs, brvc 
    

5. Instruções de salto e chamada de subrotina

6. Instruções de deslocamento de bits

Estas 5 instruções têm várias utilidades entre as quais multiplicar e dividir valores numéricos (com e sem sinal e com precisão variável de 1 ou mais bytes) por potências de 2. Todas elas deslocam um bit de um registrador para a direita ou para a esquerda, dependendo da instrução. O bit que sai sempre entra no bit de Carry (CY) que pode ser encarado como uma extensão do registrador; o bit que entra no lugar do 1º bit deslocado depende da instrução: Se agora quisermos multiplicar por 2 um valor de 16 bits sem sinal contido em, digamos, R0 (byte - significativo) e R1 (byte + significativo) basta executar em sequência as instruções: LSL R0 e ROL R1; de quebra, se houver CY após a segunda instrução saberemos que houve overflow (estouro) na multiplicação. A multiplicação por 4, 8 etc é trivial, assim como a divisão por 2, 4, etc. Para dividirmos um valor numérico de 16 bits com sinal por dois usaremos a instrução ASR (descubra qual a 2ª instrução e quais são os operandos!)

Existe uma instrução especial na mesma categoria, SWAP Rd que faz o giro de 4 bits do registrador Rd, tendo como efeito, portanto, a troca dos 4 bits menos sigificativos com os 4 bits mais significativos de Rd. Nesta instrução o CY não é afetado.

(*) Lembrete: o bit mais à direita de um registrador é o bit 0 e o mais à esquerda é o bit 7, ou seja, nesta ordem: b7, b6, ..., b1, b0

7. Programando em assembler no AVR ATmega88

  1. Um resumo do conjunto de instruções do modelo ATmega88 está no documento avr_instr_set.pdf (distribuído em aula), que é suficiente para fazer programas simples.
    O manual completo (instruction set) detalha todas as instruções da família de microcontroladores AVR. Algumas delas não estão disponiveis no ATmega88 (consulte para este fim o ATmega88 Instruction Set Summary distribuído em aula)

  2. Diretivas e sintaxe da linguagem de montagem (assembler) encontram-se neste manual: assembler user guide

  3. Para dominar os vários recursos de E/S e de interrupções do ATmega88 V. deve consultar o datasheet completo.