![]() |
Programação do LPC2378 usando o arm-elf-gcc Parte 9: Programação de memória Flash: IAP: In Application Programming |
![]() |
Anterior | Indice | Próximo |
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:
Entrada:
reg[0]=50; reg[1]=Setor_Inicial; reg[2]=Setor_Final; |
Saída
reg[0]=STATUS; |
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; |
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; |
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. |
Entrada:
reg[0]=54; |
Saída:
reg[0]=STATUS; reg[1]=número de identificação |
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) |
Entrada:
reg[0]=57; |
Saída:
Não retorna. |
Anterior | Indice | Próximo |