Número de serie PIC editable en archivo HEX


8

Actualmente tengo un número de serie codificado en mi firmware para un diseño con el que estoy trabajando. El firmware puede leer e informar el número de serie. Eso funciona bien para lo que necesito. El problema es que cada nuevo número de serie requiere que cambie mi código y recompile. Esto es engorroso cuando hay muchas unidades que construir, tiene la posibilidad de introducir errores y es una mala práctica general. Me dan los números de serie y el diseño del hardware está escrito en piedra, por lo que no puedo agregar ninguna característica en el hardware para serializar las unidades (EEPROM / Silicon ID Chip / Pull-Ups). Lo que me gustaría hacer es ubicar el número de serie en una dirección fija, compilar el código una vez y luego editar esa dirección en el archivo HEX compilado para cada nuevo número de serie. El número está referenciado en varios lugares, así que idealmente, quiero definirlo y ubicarlo una vez, luego haga referencia a esa "variable" en todas partes en mi código. ¿Alguien sabe cómo ubicar datos constantes en una ubicación específica de memoria direccionable de mi elección, utilizando el compilador C18? ¿Hay alguna forma mejor de que alguien pueda sugerir?


1
Aproximadamente la mitad de los PIC18 tienen entre 128 bytes y 1K de EEPROM incorporados. Supongo que por su pregunta, ¿su PIC18 es uno del 50% que no tiene EEPROM?
tcrosley

Respuestas:


4

Específicamente para resolver la cuestión de vincular variables a direcciones específicas en la memoria flash en el PIC18 con el compilador C18, consulte la sección "Pragmas" en hlpC18ug.chm en el directorio doc donde está instalado el compilador.

Para hacer esto, debe definir una nueva "sección" en la memoria y vincularla a una dirección inicial.

#pragma romdata serial_no_section=0x1700

Esto crea una nueva sección llamada "serial_no_section" que comienza en la dirección 0x1700 en la memoria flash (programa) (porque definimos "romdata" en el #pragma).

Directamente después de la línea #pragma, defina sus variables para:

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

Ahora tiene 0x12 en la dirección 0x1700 y 0x34 en la dirección 0x1701 en la memoria (porque PIC18 usa el modelo little-endian). El "const rom" asegura que el compilador sepa que este es un tipo de variable const, y que la variable se encuentra en la memoria "rom" y, por lo tanto, debe accederse a través de instrucciones de lectura de la tabla.

La #pragma romdatadeclaración final asegura que las siguientes declaraciones de variables estén vinculadas a las secciones de memoria predeterminadas, ya que el enlazador ve ajustes en lugar de seguir en la sección "serial_no_section".

Ahora todo el código puede simplemente hacer referencia a la variable "mySerialNumber", y usted sabe exactamente en qué dirección se puede encontrar el número de serie en la memoria.

Editar el código HEX puede ser un poco desafiante ya que necesita calcular la suma de verificación para cada línea que edita. Estoy trabajando en una clase de C ++ para decodificar y codificar archivos Intel HEX, lo que debería facilitarlo, pero aún no está terminado. La decodificación de archivos funciona, la codificación de nuevo aún no está implementada. El proyecto (si está interesado) está aquí https://github.com/codinghead/Intel-HEX-Class

Espero que esto ayude


4

He hecho el número de serie (s / n para abreviar) de una manera similar a lo que describe Joel. Estaba usando PIC18F4620 y el compilador CCS. La ubicación de s / n en la memoria Flash fue forzada a los últimos 4 bytes. Como estaba usando solo el 80% de Flash, mi compilador y el enlazador no escribían código ejecutable en los últimos 4 bytes.

Luego tuve 2 formas alternativas de escribir s / n en unidades individuales:

  • El depurador en circuito CCS (ICD) tenía una característica que permitía manipular cualquier ubicación dentro de Flash. Fue un truco útil. En revisiones posteriores lo han eliminado, desafortunadamente.
  • PIC tenía un enlace en serie a una PC. s / n fue cargado a través de él. El firmware tenía una rutina que recibiría el s / ny lo almacenaría en Flash.

Responder al comentario de Joel

No sé acerca de C18, pero el compilador CCS viene con funciones de biblioteca write_program_eeprom(...)y read_program_eeprom(...). Así es como se ven en la asamblea.

.................... 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

1
¡Sí, esto es exactamente lo que estoy pidiendo! ¿Puede describir qué atributos de código utilizó para empaquetar su S / N en los últimos bytes de flash?
Joel B

"El firmware tenía una rutina que recibiría el s / ny lo almacenaría en Flash" write_program_eeprom(...)y read_program_eeprom(...). ¡La EEPROM y Flash son dos cosas diferentes!
m.Alin

@ m.Alin Así se llamaron las funciones "enlatadas" que venían con CCS ccompiler. Realmente escribirían y leerían Flash.
Nick Alexeev

2

He hecho esto algunas veces. Por lo general, defino un área de información de firmware en una ubicación fija en la memoria del programa, luego escribo un programa que crea un archivo HEX serializado a partir del archivo HEX de plantilla. Todas estas son cosas fáciles de hacer.

En producción, ejecuta el programa de serialización una vez después de que todas las pruebas hayan pasado. Crea el archivo HEX temporal con el número de serie único, que se programa en el PIC, luego se elimina el archivo HEX temporal.

No permitiría que la ubicación fuera reubicable, luego tendría que encontrarla. Eso puede cambiar cada construcción a medida que el vinculador mueve las cosas. Lo he hecho para PIC muy pequeños como la serie 10F, donde estas constantes son parte de las instrucciones MOVLW. En esos casos, tengo que leer el archivo MAP sobre la marcha para determinar dónde están esas ubicaciones. Tengo el código de análisis de archivos MPLINK MAP en una biblioteca solo para ese propósito.

Para poner algo en una ubicación fija, defina un segmento en una dirección fija. El enlazador colocará dichos segmentos absolutos primero, luego los reubicables a su alrededor. No olvides usar CODE_PACK en lugar de solo CODE en un PIC 18, de lo contrario estarás lidiando con palabras de instrucción completas en lugar de bytes individuales. Por ejemplo (simplemente escrito, no se ejecuta más allá del ensamblador):

.fwinfo code_pack h'1000 '; área de información de firmware en una dirección conocida fija
         db h'FFFFFFFF '; número de serie, completado por el programa de producción
         db fwtype; tipo de identificación de este firmware
         db fwver; número de versión
         db fwseq; número de secuencia de compilación

2

Sugeriría almacenar el número de serie en una dirección fija. Dependiendo de su compilador / enlazador y la parte en cuestión, hay algunos enfoques que puede tomar:

  1. Defina una sección reubicable que contendrá el número de serie, use una directiva #pragma en su código para forzar el número de serie en esa sección y forzar la dirección de esa sección dentro de la especificación del enlace.
  2. Para las partes que pueden leer la memoria de código directamente, excluya un área de memoria del área que el enlazador puede usar (es decir, dígale que la parte es, por ejemplo, cuatro bytes más pequeña de lo que realmente es), y luego lea el número de serie en el código usando algo como `((unsigned long const *) 0x3FFC)`.
  3. Para las partes que no pueden leer la memoria de código directamente, puede poner las instrucciones "RETLW" en alguna dirección fija y luego convencer al vinculador de que hay funciones invocables que devuelven 'byte' en esas direcciones. Entonces uno diría, por ejemplo, "out_hex (ser_byte0 ()); out_hex (ser_byte1 ()); out_hex (ser_byte2 ()); para generar los bytes del número de serie.

Todos los PIC 18F pueden leer su memoria de programa a través del mecanismo de lectura de la tabla.
Olin Lathrop

Eso es verdad. Algunas de las partes de 14 bits también pueden leer la memoria del programa. Sin embargo, incluso en los PIC que pueden leer la memoria del programa, el retlwenfoque suele ser mucho más rápido (en los PIC de 18 bits, un calla a retlwtomará cuatro ciclos en total; el uso clrf TBLPTRU/movlw xx/movwf TBLPTRH/movlw xx/movwf TBLPTRL/tblrd *+/movf TABLAT,wtomaría ocho).
supercat

1

Yo haría lo contrario: compilar y vincular el código, luego averiguar dónde está almacenado el valor del archivo vinculador. Es posible que deba ubicar la variable explícitamente en un segmento que está asignado a flash.

No solicite esto, pero el software para PC que proporciono para mi programador Wisp648 tiene la capacidad de leer un archivo .hex, modificar una ubicación específica y volver a escribir el archivo .hex (en el mismo archivo o en otro). No es necesario que mi programador esté presente. La fuente está disponible (en Python), la licencia permite todo uso: www.voti.nl/xwisp Puede ser útil una vez que haya resuelto su problema principal.


Gracias @Wouter van Ooijen! Estoy tratando de evitar el enfoque de "averiguar dónde se almacena el valor", ya que eso probablemente significará que el valor se reubica en compilaciones sucesivas y me exigirá (o algún tipo triste que venga detrás de mí) para averiguar dónde está el valor se encuentra nuevamente, seguramente presentando problemas.
Joel B
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.