Número de série PIC editável no arquivo HEX

8

Atualmente, tenho um número de série codificado no firmware para um design com o qual estou trabalhando. O firmware pode ler e reportar o número de série. Isso funciona bem para o que eu preciso. O problema é que cada novo número de série exige que eu mude meu código e recompile. Isso é complicado quando há muitas unidades a serem construídas, é possível introduzir erros e é uma má prática geral. Os números de série são fornecidos a mim e o design do hardware é definido, portanto, não posso adicionar nenhum recurso no hardware para serializar as unidades (EEPROM / Chip de identificação de silicone / pull-ups). O que eu gostaria de fazer é localizar o número de série em um endereço fixo, compilar o código uma vez e editar esse endereço no arquivo HEX compilado para cada novo número de série. O número é referenciado em vários lugares, então, idealmente, desejo defini-lo e localizá-lo uma vez, referencie essa "variável" em qualquer outro lugar do meu código. Alguém sabe como localizar dados constantes em um local específico de memória endereçável de minha escolha, usando o compilador C18? Existe uma maneira melhor de sugerir alguém?

Joel B
fonte
1
Cerca da metade dos PIC18s possui de 128 bytes a 1K de EEPROM incorporados a eles. Presumo que, com sua pergunta, seu PIC18 seja um dos 50% que não possui EEPROM?
precisa saber é o seguinte

Respostas:

4

Especificamente, para resolver a questão de vincular variáveis ​​a endereços específicos na memória flash no PIC18 com o compilador C18, consulte a seção "Pragmas" no hlpC18ug.chm no diretório doc em que o compilador está instalado.

Para fazer isso, você precisa definir uma nova "seção" na memória e vinculá-la a um endereço inicial para

#pragma romdata serial_no_section=0x1700

Isso cria uma nova seção chamada "serial_no_section" que inicia no endereço 0x1700 na memória flash (programa) (porque definimos "romdata" no #pragma).

Diretamente após a linha #pragma, defina suas variáveis ​​para:

#pragma romdata serial_no_section=0x1700
const rom int mySerialNumber = 0x1234;
#pragma romdata

Agora você tem 0x12 no endereço 0x1700 e 0x34 no endereço 0x1701 na memória (porque o PIC18 usa o modelo little-endian). O "const rom" garante que o compilador saiba que esse é um tipo de variável const e que a variável está na memória "rom" e, portanto, precisa ser acessado através de instruções de leitura de tabela.

A #pragma romdatadeclaração final garante que todas as seguintes declarações de variáveis ​​sejam vinculadas às seções de memória padrão, conforme o vinculador vê, se encaixa em vez de seguir na seção "serial_no_section".

Agora todo o código pode simplesmente fazer referência à variável "mySerialNumber" e você sabe exatamente em que endereço o número de série pode ser encontrado na memória.

A edição do código HEX pode ser um pouco desafiadora, pois você precisa calcular a soma de verificação para cada linha que editar. Estou trabalhando em uma classe C ++ para decodificar e codificar arquivos Intel HEX, o que deve facilitar isso, mas ainda não foi concluído. Arquivos de decodificação funcionam, a codificação novamente ainda não foi implementada. O projeto (se você estiver interessado) está aqui https://github.com/codinghead/Intel-HEX-Class

Espero que isto ajude

Stuart Cording
fonte
4

Fiz o número de série (s / n para abreviar) de maneira semelhante ao que Joel está descrevendo. Eu estava usando o compilador PIC18F4620 e CCS. A localização de s / n na memória Flash foi forçada nos últimos 4 bytes. Como eu estava usando apenas 80% do Flash, meu compilador e vinculador não escreveriam código executável nos últimos 4 bytes.

Então, eu tinha duas maneiras alternativas de escrever s / n em unidades individuais:

  • O depurador de circuito interno (ICD) do CCS tinha um recurso que permitia manipular qualquer local dentro do Flash. Foi um truque útil. Nas revisões posteriores, eles o removeram, infelizmente.
  • O PIC tinha um link serial para um PC. s / n foi carregado através dele. O firmware tinha uma rotina que recebia o s / n e o armazenava no Flash.

Responder ao comentário de Joel

Não sei sobre C18, mas o compilador CCS vem com funções de biblioteca write_program_eeprom(...)e read_program_eeprom(...). Aqui está como eles são na montagem.

.................... write_program_eeprom (i_ADDR, iWord);
EF84: BSF FD0.6
EF86: CLRF FF8
EF88: MOVLW 7F
EF8A: MOVWF FF7
EF8C: MOVLW F0
EF8E: MOVWF FF6
EF90: MOVLB 0
EF92: BRA EF24
EF94: MOVLW F0
EF96: MOVWF FF6
EF98: MOVFF 490, FF5
EF9C: TBLWT * +
EF9E: MOVFF 491, FF5
EFA2: TBLWT *
EFA4: BCF FA6.6
EFA6: BSF FA6.4
EFA8: RCALL EF3C
EFAA: RCALL EF3C
EFAC: CLRF FF8
EFAE: CLRF FF8
.................... iWord = read_program_eeprom (i_ADDR); 
EF60: CLRF FF8
EF62: MOVLW 7F
EF64: MOVWF FF7
EF66: MOVLW F0
EF68: MOVWF FF6
EF6A: TBLRD * +
EF6C: MOVF FF5, W
EF6E: TBLRD *
EF70: MOVFF FF5,03
EF74: CLRF FF8
EF76: MOVLB 4
EF78: MOVWF x90
EF7A: MOVFF 03.491
Nick Alexeev
fonte
1
Sim, é exatamente isso que estou pedindo! Você pode descrever quais atributos de código você usou para compactar seu S / N nos últimos bytes de flash?
Joel B
"O firmware tinha uma rotina que recebia o s / n e o armazenava no Flash" write_program_eeprom(...)e read_program_eeprom(...). A EEPROM e o Flash são duas coisas diferentes!
m.Alin
@ m.Alin É assim que as funções "enlatadas" que acompanham o CCS ccompiler foram chamadas. Eles realmente escreviam e liam Flash.
Nick Alexeev
2

Eu fiz isso algumas vezes. Normalmente, defino uma área de informações de firmware em um local fixo na memória do programa e, em seguida, escrevo um programa que cria um arquivo HEX serializado a partir do arquivo HEX do modelo. Todas essas são coisas fáceis de fazer.

Na produção, você executa o programa de serialização uma vez após a passagem de todos os testes. Torna o arquivo HEX temporário com o número de série exclusivo, programado no PIC e, em seguida, o arquivo HEX temporário excluído.

Eu não deixaria o local ser realocável, então tenho que encontrá-lo. Isso pode mudar a cada compilação à medida que o vinculador move as coisas. Eu fiz isso para PICs muito pequenos, como a série 10F, onde essas constantes fazem parte das instruções do MOVLW. Nesses casos, eu tenho que ler o arquivo MAP em tempo real para determinar onde estão esses locais. Eu tenho o arquivo MPLINK MAP analisando o código em uma biblioteca apenas para esse fim.

Para colocar algo em um local fixo, defina um segmento em um endereço fixo. O vinculador colocará esses segmentos absolutos primeiro, depois os realocáveis ​​em torno dele. Não se esqueça de usar CODE_PACK em vez de apenas CODE em uma PIC 18; caso contrário, você estará lidando com palavras inteiras de instância em vez de bytes individuais. Por exemplo (apenas digitado, não passe pela montagem):

.fwinfo code_pack h'1000 '; área de informações do firmware no endereço conhecido fixo
         db h'FFFFFFFF '; número de série, preenchido pelo programa de produção
         db fwtype; tipo ID deste firmware
         db fwver; número da versão
         db fwseq; construir número de sequência
Olin Lathrop
fonte
2

Eu sugeriria armazenar o número de série em um endereço fixo. Dependendo do seu compilador / vinculador e da parte em questão, existem algumas abordagens que você pode adotar:

  1. Defina uma seção realocável que conterá o número de série, use uma diretiva #pragma no seu código para forçar o número de série nessa seção e forçar o endereço dessa seção na especificação do link.
  2. Para partes que podem ler diretamente a memória de código, exclua uma área de memória da área que o vinculador está autorizado a usar (por exemplo, diga que a parte é, por exemplo, quatro bytes menor do que realmente é) e, em seguida, leia o número de série no código usando algo como `((const long sem sinal *) 0x3FFC)`.
  3. Para partes que não conseguem ler a memória de código diretamente, você pode colocar as instruções "RETLW" em algum endereço fixo e convencer o vinculador de que existem funções solicitáveis ​​que retornam 'byte' nesses endereços. Então se diria, por exemplo, "out_hex (ser_byte0 ()); out_hex (ser_byte1 ()); out_hex (ser_byte2 ()); para gerar os bytes do número de série.
supercat
fonte
Todo o PIC 18F pode ler sua memória de programa através do mecanismo de leitura de tabela.
Olin Lathrop
Isso é verdade. Algumas das partes de 14 bits também são capazes de ler a memória do programa. Mesmo em PICs que podem ler a memória do programa, no entanto, a retlwabordagem geralmente é muito mais rápida (em PICs de 18 bits, a calla a retlwleva quatro ciclos no total; o uso clrf TBLPTRU/movlw xx/movwf TBLPTRH/movlw xx/movwf TBLPTRL/tblrd *+/movf TABLAT,wleva oito).
22712
1

Eu faria o oposto: compile e vincule o código e descubra onde o valor é armazenado no arquivo vinculador. Pode ser necessário localizar a variável explicitamente em um segmento mapeado para piscar.

Não solicitei isso, mas o software para PC fornecido para o programador Wisp648 tem a capacidade de ler um arquivo .hex, modificar um local específico e gravar o arquivo .hex novamente (no mesmo ou em outro arquivo). Não há necessidade de ter meu programador presente. A fonte está disponível (em Python), a licença permite todo o uso: www.voti.nl/xwisp Pode ser útil depois que você resolver o seu problema principal.

Wouter van Ooijen
fonte
Obrigado @Wouter van Ooijen! Estou tentando evitar a abordagem "descobrir onde o valor está armazenado", pois isso provavelmente significa que o valor é realocado em compilações sucessivas e exige que eu (ou algum sujeito triste que esteja atrás de mim) descubra onde o valor está localizado novamente, com certeza introduzindo problemas.
Joel B