AVR- enviando el programa de aplicación al cargador de arranque

4

Ahora es el momento de enviar el código de la aplicación al gestor de arranque, que se ha programado en un controlador ATmega32A. Debe enviarse en formato hexadecimal, pero no tengo idea de "¿Cómo enviarlo?"

El archivo hex compilado para un código de aplicación de atmel studio es el siguiente:

    :100000000C942A000C943F000C943F000C943F0089
    :100010000C943F000C943F000C943F000C943F0064
    :100020000C943F000C943F000C943F000C943F0054
    :100030000C943F000C943F000C943F000C943F0044
    :100040000C943F000C943F000C943F000C943F0034
    :100050000C943F0011241FBECFE5D8E0DEBFCDBF1A
    :1000600010E0A0E6B0E0E0E2F2E002C005900D9200
    :10007000A23EB107D9F70E94BD000C940E010C946A
    :100080000000D09A899A88988AB188618AB980B527
    :100090008F7B80BD529880B5866080BD80B5877F9C
    :1000A00080BD80B58F7C80BD89E189B910BC089581
    :1000B0005D9BFECF8CB908950F931F93CF93DF9371
    :1000C000FC0101900020E9F73197E81BF90B51F092
    :1000D000EC018C010E0F1F1F89910E945800C01760
    :1000E000D107D1F7DF91CF911F910F9108955F9BB9
    :1000F000FECF8CB190E008950E9477008335E1F740
    :100100000E9477008935C1F70E9477008335A1F7F7
    :100110000E947700833581F70E947700843561F76C
    :100120000E947700813441F70E947700823521F7E1
    :100130000E947700843501F70895CF93DF93EC0197
    :100140000E945C000E9477008F3421F00E947700AB
    :100150008F34E1F70E9477008B3461F02FE78AE15A
    :1001600096E0215080409040E1F700C00000CE01B1
    :100170000E949D00DF91CF9108950E9441002FE7DA
    :100180008AE196E0215080409040E1F700C00000F5
    :100190000E947C002FE382E49FE021508040904049
    :1001A000E1F700C0000080E690E00E949D008DE62F
    :1001B00090E00E949D002FE78AE196E02150804068
    :1001C0009040E1F700C0000087E790E00E945C00EB
    :1001D0002FE78AE196E0215080409040E1F700C08F
    :1001E000000084E990E00E945C002FE78AE196E03D
    :1001F000215080409040E1F700C000008EEB90E07D
    :100200000E945C002FE78AE196E0215080409040F8
    :10021000E1F700C0000080E090E00895F894FFCF7F
    :1002200041545E4E5754494D453F0D0A0041542BF1
    :1002300043474D490D0A0041545E4950494E4954C7
    :100240003D2261697274656C677072732E636F6DA5
    :10025000220D0A0041545E49504F50454E3D312C0D
    :1002600022544350222C223132322E3136352E3256
    :1002700033302E3137222C373836390D0A004154AD
    :100280005E495053454E443D312C22646576696386
    :10029000652D69642C6770735F64617461220D0A57
    :0202A00000005C
    :00000001FF

Según el estándar, la primera línea tiene datos 0C942A000C943F000C943F000C943F00 y suma de comprobación 89 . ¿Tengo que enviar los 16 bytes de datos seguidos de la suma de comprobación? En algunos programas, algunas líneas ni siquiera tienen 16 bytes de datos. Solo tiene 10 bytes con suma de comprobación al final, por ejemplo: :0A0B4000CDBFED010895F894FFCF3A .

No hay ejemplos claros en ninguna parte. Espero que alguien debe tener alguna experiencia para ayudarme.

    
pregunta gzix

3 respuestas

2

Esto necesitará un trabajo adicional de su parte para integrarlo en su código, pero debería darle algunas ideas. El primer paso en el gestor de arranque será incluir encabezados relacionados con la programación del FLASH:

#include <avr/boot.h>
#include <avr/pgmspace.h>

Algunas otras definiciones que ayudan a definir las cosas más adelante y definen algunos códigos de respuesta al final del procesamiento de cada línea son:

#define HEX2DEC(x)  (((x < 'A') ? ((x) - 48) : ((x) - 55)))
#define SPM_PAGEMASK ((uint32_t) ~(SPM_PAGESIZE - 1))
enum response_t {RSP_OK, RSP_CHECKSUM_FAIL, RSP_INVALID, RSP_FINISHED};

Luego, se puede usar una rutina como la siguiente para procesar el formato hexadecimal de Intel y escribir en FLASH. Está escrito para un dispositivo más grande, de modo que maneja las direcciones extendidas en los archivos hexadecimales para que pueda eliminar eso en su dispositivo más pequeño para reducir el tamaño del código, pero no hará ningún daño dejarlo en su lugar. También deberá agregar su propio código de inicio / recepción de UART y determinar qué hacer si las cosas se agotan, en este caso usé un temporizador de vigilancia.

enum response_t process_line()
{
    char c, line_buffer[128], data_buffer[64];
    uint8_t line_len = 0, data_len = 0, data_count, line_type, line_pos, data;
    uint8_t addrh, addrl, checksum, recv_checksum;
    uint16_t addr, extended_addr = 0, i;
    static uint32_t full_addr, last_addr = 0xFFFFFFFF;

    c = uart_getc();
    while (c != '\r')
    {
        if (c == ':')
            line_len = 0;
        else if (c == '\n')
            ;
        else if (c == '
void enter_loader()
{
    enum response_t response = RSP_OK;

    uart_puts("+OK/\r\n");
    while (response != RSP_FINISHED)
    {
        response = process_line();
        if (response == RSP_OK)
            uart_puts("+OK/");
        else if (response != RSP_FINISHED)
            uart_puts("+FAIL/");
        wdt_reset();
    }   
    boot_rww_enable ();
    while (1) // Use watchdog to reboot
        ;
}
') ; else if (line_len < sizeof(line_buffer)) line_buffer[line_len++] = c; c = uart_getc(); } if (line_len < 2) return RSP_INVALID; data_count = (HEX2DEC(line_buffer[0]) << 4) + HEX2DEC(line_buffer[1]); if (line_len != data_count * 2 + 10) return RSP_INVALID; addrh = (HEX2DEC(line_buffer[2]) << 4) + HEX2DEC(line_buffer[3]); addrl = (HEX2DEC(line_buffer[4]) << 4) + HEX2DEC(line_buffer[5]); addr = (addrh << 8) + addrl; line_type = (HEX2DEC(line_buffer[6]) << 4) + HEX2DEC(line_buffer[7]); line_pos = 8; checksum = data_count + addrh + addrl + line_type; for (i=0; i < data_count; i++) { data = (HEX2DEC(line_buffer[line_pos]) << 4) + HEX2DEC(line_buffer[line_pos + 1]); line_pos += 2; data_buffer[data_len++] = data; checksum += data; } checksum = 0xFF - checksum + 1; recv_checksum = (HEX2DEC(line_buffer[line_pos]) << 4) + HEX2DEC(line_buffer[line_pos + 1]); if (checksum != recv_checksum) return RSP_CHECKSUM_FAIL; if (line_type == 1) { if (last_addr != 0xFFFFFFFF) { boot_page_write (last_addr & SPM_PAGEMASK); boot_spm_busy_wait(); } return RSP_FINISHED; } else if ((line_type == 2) || (line_type == 4)) extended_addr = (data_buffer[0] << 8) + data_buffer[1]; else if (line_type == 0) { full_addr = ((uint32_t) extended_addr << 16) + addr; if ((full_addr & SPM_PAGEMASK) != (last_addr & SPM_PAGEMASK)) { if (last_addr != 0xFFFFFFFF) { boot_page_write (last_addr & SPM_PAGEMASK); boot_spm_busy_wait(); } boot_page_erase (full_addr); boot_spm_busy_wait (); } for (i=0; i < data_len; i+=2) { uint16_t w = data_buffer[i] + ((uint16_t) data_buffer[i + 1] << 8); boot_page_fill (full_addr + i, w); } last_addr = full_addr; } return RSP_OK; }

Lee una línea hexadecimal completa y verifica la suma de comprobación, por lo tanto, coteje el formato hexadecimal de Intel para ver cómo funciona en detalle antes de usarlo. A partir de ahí, la idea general es que cuando alcanza un nuevo límite de página de FLASH realiza un borrado, pero de lo contrario sigue adelante y escribe los datos.

Cuando se ingresa al gestor de arranque, este es el código principal que estaba usando para llamarlo, pero una vez más, tendrá que averiguar qué hacer cuando ocurre una falla. En mi caso, estaba usando algún software de PC personalizado, así que le envié algunas cadenas para indicar el estado, pero para una carga de terminal, es posible que solo desee establecer un indicador EEPROM en función de si tuvo éxito y debería iniciarlo o mostrarlo. un mensaje amigable para los humanos y vuelva a llamar al gestor de arranque:

#include <avr/boot.h>
#include <avr/pgmspace.h>

De todos modos, eso debería darle un buen comienzo y el código anterior se ha probado bastante bien con un firmware bastante complejo. Solo necesitará un poco de trabajo para escribir el UART que falta y otro código de inicialización para determinar cuándo se debe llamar al gestor de arranque para su aplicación. También puede necesitar algunos ajustes para un ATmega32A, pero creo que el enfoque debería funcionar bastante bien en todos los dispositivos AVR.

    
respondido por el PeterJ
5

Con respecto al formato HEX:

Como se sugiere en el comentario, lea acerca del formato Intel HEX. enlace

Básicamente, lo que dice es que cada línea corresponde a un bloque de datos. El formato de la línea es el siguiente:

:XYZC

Donde:

  • X es 1 byte que especifica la longitud de la carga útil
  • Y es 1 byte que especifica el tipo de carga útil *
  • Z es la carga útil de longitud X bytes
  • C es 1 byte de la suma de comprobación de la línea

*

  

’00’ Registro de datos
  ’01’ Fin del registro de archivo
  ’02’ Dirección del segmento extendido
  ’03’ Iniciar registro de dirección de segmento
  ’04’ Registro de dirección lineal extendido
  ’05’ Iniciar registro de dirección lineal

Consulte enlace para ver la especificación completa.

Sobre el método de transmisión:

También se menciona en el comentario: está mucho mejor enviando el archivo completo como está. De esa manera, no necesita un programa especializado en el lado de la PC, solo un terminal que se comunique con su dispositivo. Luego analice el texto en chip.

Cómo escribirlo:

El método más sencillo es comenzar a leer las notas de aplicación de Atmel:

  

Todas las operaciones de programación automática se realizan utilizando la instrucción SPM

Esto se puede encontrar aquí: enlace

El AVR109 es un famoso gestor de arranque para dispositivos Mega. Puede encontrar mucha información aquí.

    
respondido por el Dzarda
2

Hay herramientas para tales cosas. Lo primero y más importante: realmente no desea dejar que el controlador descubra dónde colocar qué, ya que eso requeriría analizar el archivo en el controlador.

En su lugar, convierta el archivo en un archivo binario (que puede escribirse 1: 1 en modo flash), luego deje que el controlador lo transfiera a la dirección de la aplicación (debe averiguarlo antes). Un posible programa que veo: su aplicación está vinculada a la dirección 0x0; esto significa que si el cargador de arranque se encuentra en esa dirección específica, no funcionará (deberá vincularla a otra dirección diferente). Si el gestor de arranque reside en alguna otra dirección (preferiblemente al final del flash), está listo para comenzar.

Encuentre un script que se convierta en binario y haga todo lo demás aquí: enlace

Está diseñado para otra familia Atmel (AVR32) pero debes tener la idea. Si tiene preguntas, hágamelo saber.

    
respondido por el Tom L.

Lea otras preguntas en las etiquetas