Lab. Processadores: Programação do LPC2378 usando o gcc

| Laboratório de Processadores Programação do LPC2378 usando o arm-elf-gcc Parte 9: Programação de memória Flash: IAP: In Application Programming |

O LPC2378 tem uma ROM com um programa tipo boot-loader que serve para programar a sua própria memória Flash. Um computador pode comunicar-se com o boot-loader através da interface serial, fornecedo os comandos e dados do programa a ser gavado na memória Flash, usando a técnica conhecida pela sigla ISP (In System Programming).

As funções da ROM do boot-loader podem também ser chamadas como subrotinas de um programa aplicativo. Chamamos isto de IAP (In Application Programming).

As funções do IAP são acessíveis em um único ponto de entrada no endereço `0x7ffffff0`. Recomenda-se usar em vez disto o endereço `0x7ffffff1` para forçar o LPC2378 a executar a função do IAP em modo THUMB. Este ponto de entrada recebe como parâmetros, nos registradores R0 e R1, dois apontadores para arrays de inteiros de 32 bits sem sinal. Estes arrays tem os parâmetros de entrada e de saída das funções IAP.

Nos nossos exemplos de programação, o monitor mon23/ inclui funções para programar a memória flash incorporada. Estas funções encontram-se no módulo iap.c.

Em linguagem C, o acesso às funções IAP pode ser feito da seguinte maneira:

    /* Tipo de dados da funcao IAP */
    typedef void (*IAP)(unsigned *rin, unsigned *rout);
    /* Ponto de entrada do IAP */
    #define IAP_ENTRY ((IAP)0x7ffffff1)
    /* Array dos parametros de E/S do IAP */
    unsigned regs[5];

    /* Array com as mensagens de status do IAP */
    static const char *sstatus[]={
    "Done","Command error", "Invalid src addr","Invalid dest addr",
    "Src not mapped","Dest not mapped","Count_error",
    "Invalid sector","Sector not blank","Sector not prepared",
    "Compare error", "Busy"};

    /* Exemplo de uso do IAP */
    void ReadPartID()
    {
    UART0puts("Read part ID: ");
    regs[0]=54;		/* Comando IAP 54: Read Part ID */
    IAP_ENTRY(regs,regs);	/* Chama a ROM IAP */
    UART0puts(sstatus[regs[0]]);	/* Esceve mensagem de status */
    UART0puts("! ID=");
    escreve_num(regs[1]);		/* Escreve o numero Part ID */
    }

O LPC2378 tem 512kBytes de memória Flash dividida em 28 setores, com tamanhos e edereços iniciais conforme mostra a tabela a seguir:

Setor | Endereço inicial | Endereço final | Tamanho (Bytes)
--- | --- | --- | ---
0 | 0x00000000 | 0x00000FFF | 4096
1 | 0x00001000 | 0x00001FFF | 4096
2 | 0x00002000 | 0x00002FFF | 4096
3 | 0x00003000 | 0x00003FFF | 4096
4 | 0x00004000 | 0x00004FFF | 4096
5 | 0x00005000 | 0x00005FFF | 4096
6 | 0x00006000 | 0x00006FFF | 4096
7 | 0x00007000 | 0x00007FFF | 4096
8 | 0x00008000 | 0x0000FFFF | 32768
9 | 0x00010000 | 0x00017FFF | 32768
10 | 0x00018000 | 0x0001FFFF | 32768
11 | 0x00020000 | 0x00027FFF | 32768
12 | 0x00028000 | 0x0002FFFF | 32768
13 | 0x00030000 | 0x00037FFF | 32768
14 | 0x00038000 | 0x0003FFFF | 32768
15 | 0x00040000 | 0x00047FFF | 32768
16 | 0x00048000 | 0x0004FFFF | 32768
17 | 0x00050000 | 0x00057FFF | 32768
18 | 0x00058000 | 0x0005FFFF | 32768
19 | 0x00060000 | 0x00067FFF | 32768
20 | 0x00068000 | 0x0006FFFF | 32768
21 | 0x00070000 | 0x00077FFF | 32768
22 | 0x00078000 | 0x00078FFF | 4096
23 | 0x00079000 | 0x00079FFF | 4096
24 | 0x0007A000 | 0x0007AFFF | 4096
25 | 0x0007B000 | 0x0007BFFF | 4096
26 | 0x0007C000 | 0x0007CFFF | 4096
27 | 0x0007D000 | 0x0007DFFF | 4096

Pode-se escrever a seguinte função para obter o endereço na memória Flash a partir do número do sertor:

    unsigned sect2addr(int sector)
    {
    unsigned addr;
    addr=(sector << 12);
    if(sector > 8) addr=(sector << 15)-0x38000;
    if(sector > 0x16) addr=(sector << 12)+0x62000;
    return addr;
    }

Os parâmetros da função `IAP_ENTRY` são especificados inicializando-se os valores do array `regs[]`. O primeiro (`regs[0]`) seleciona qual será a operação; os outros fornecem informações adicionais.

A tabela a seguir apresenta os comandos da ROM IAP:

50 Preparar setores para escrita
  Este comando deve ser executado antes de apagar ou escrever setores.

  Entrada:
      reg[0]=50;
      reg[1]=Setor_Inicial;
      reg[2]=Setor_Final;
  | Saída
      reg[0]=STATUS;

51 Copiar da RAM para a Flash
  Este comando grava um conjunto de bytes da RAM (Endereço 0x40000000 a 0x40007FFF) para a flash (a partir do endereço 0x00000000). O número de bytes deve ser 256, 512, 1024 ou 4096. Outros valores de número de bytes não são aceitos. O endereço de destino na Flash deve ser múltiplo de 256;

  Entrada:
      reg[0]=51;
      reg[1]=Endereço destino na Flash.
      reg[2]=Numero de bytes (256 | 512 | 1024 | 4096)
      reg[3]=Frequência de clock (CCLK) em Hz
  | Saída:
      reg[0]=STATUS;

52 Apagar setores
  A memória Flash deve estar apagada (com todos os bytes com valor 0xFF) para que possa ser gravada. Este comando apaga um conjunto de setores.

  Entrada:
      reg[0]=52;
      reg[1]=Número do setor inicial
      reg[2]=Número do setor final
      reg[3]=Frequência de clock (CCLK) em Hz
  | Saída:
      reg[0]=STATUS;

53 Verificar se setores estão apagados

  Entrada:
      reg[0]=53;
      reg[1]=Número do setor inicial
      reg[2]=Número do setor final
  | Saída:
      reg[0]=STATUS;
      reg[1]=Endereço da primeira palavra não apagada.
      reg[1]=Valor da primeira palavra não apagada.

54 Le número de identificação do microcontrolador
  Para o LPC2378 este número é 117702437 decimal.

  Entrada:
      reg[0]=54;
  | Saída:
      reg[0]=STATUS;
      reg[1]=número de identificação

55 Le número de versão do Boot Loader

  Entrada:
      reg[0]=55;
  | Saída:
      reg[0]=STATUS;
      reg[1]=número de versão (major)
      reg[2]=número de versão (minor)

57 Entra em modo ISP
  Este comando invoca o Boot Loador no modo ISP (In System Programming) de modo que se possa usar um programador externo (como o lpc21isp).

  Entrada:
      reg[0]=57;
  | Saída:
      Não retorna.