Cree un algoritmo de descarga jflash y resuelva el problema de los errores de escritura de datos causados por el desbordamiento de la pila

1. Introducción al algoritmo de descarga jflash

jflash es un software desarrollado por segger y debe usarse junto con jlink. Cualquiera que haya usado jlink sabe que es muy útil durante la fase de desarrollo y depuración del proyecto.
El algoritmo de descarga de jflash es darse cuenta de que cuando no hay ningún chip en jflash, o desea usar jflash para descargar el programa a una memoria flash externa, jflash llama al programa del algoritmo de descarga de flash para completar las operaciones de borrado, lectura, escritura y verificación. del destello. La interfaz de jflash es la siguiente:
Insertar descripción de la imagen aquí

2. El proceso de producción del algoritmo de descarga jflash.

Para la producción del algoritmo de descarga jflash, el proyecto de plantilla correspondiente se proporciona en mdk, la ruta está en Keil_v5\ARM\Flash\_Template, puede usar directamente el proyecto de plantilla y agregarle su propio controlador flash.

Este artículo no presentará todo el proceso en detalle. Para conocer pasos específicos, consulte:
Escribir el algoritmo de descarga MDK SPI FLASH de STM32H7 desde cero .
O csdn lo reproduce y
escribe el algoritmo de descarga MDK SPI FLASH de STM32H7 desde cero .

Este artículo se centra en los problemas encontrados e introduce soluciones.

3. Durante el proceso de trasplante de sfud, error de compilación L6248E

Para este problema, puede consultar mi otro blog: producción mdk del algoritmo de descarga flash externo, error de compilación L6248E .

Principalmente porque en sfud, char *namelos punteros se definen en varios lugares para almacenar el nombre del modelo flash. Sin embargo, debido a que el algoritmo de descarga flash requiere que el código compilado sea un código independiente de la dirección, aquí no se pueden usar punteros y el nameespacio de direcciones debe estar claro. Aquí debe cambiar el puntero a una matriz, porque el espacio de direcciones de la matriz se determina después de la compilación. Los cambios son los siguientes:

Cambie todos *namelos punteros a matrices:

typedef struct __sfud_spi {
    
    
    /* SPI device name */
    char name[32];
    /* 以下有省略 */
} sfud_spi, *sfud_spi_t;

4. Resuelva el problema de desbordamiento de la pila durante la ejecución del código.

El algoritmo de descarga flash no tiene un archivo de inicio, por lo que no podemos establecer el tamaño de la pila para la ejecución del programa, pero la pila predeterminada es muy pequeña. Cuando hay demasiadas funciones anidadas o se definen demasiadas variables locales, se produce un desbordamiento de pila. Ocurrirá, lo que hará que el programa normal use Variables, este problema es difícil de localizar, encontré este problema durante las pruebas.

  • 4.1 Análisis del problema
    Analicémoslo a través del archivo de mapa.
    Primero, eche un vistazo al archivo de secuencia de comandos de enlace proporcionado por el proyecto de plantilla:
; Linker Control File (scatter-loading)
;

PRG 0 PI               ; Programming Functions
{
    
    
  PrgCode +0           ; Code
  {
    
    
    * (+RO)
  }
  PrgData +0           ; Data
  {
    
    
    * (+RW,+ZI)
  }
}

DSCR +0                ; Device Description
{
    
    
  DevDscr +0
  {
    
    
    FlashDev.o
  }
}

En el script anterior, PRG el área de memoria especificada es el área donde se encuentra el algoritmo de descarga flash. DSCREl área especificada se utiliza principalmente para almacenar FlashDeviceesta estructura. Al obtener la estructura en esta área, jflash puede conocer cierta información básica de flash.
Las áreas PRG y DSCR en el archivo de mapa generado por este script de enlace son las siguientes: Como
Insertar descripción de la imagen aquí
puede verse en la figura anterior .bss, el espacio ocupado por el segmento no está incluido en PrgData y la dirección 0x0000373c es exactamente la matriz de 4096 bytes definida en el código de la siguiente manera:
Insertar descripción de la imagen aquí
Código fuente de la siguiente manera:

#define BUF_SIZE 4096
uint8_t aux_buf[BUF_SIZE];

También se puede ver en el archivo de mapa que las variables en sfud.o también están en la sección .bss, en la posición 0x0000473c:
Insertar descripción de la imagen aquí
pero DSCRla posición inicial es 0x0000373c, lo que muestra que la sección .bss no asigna espacio aquí. Esto también muestra que la sección .bss no ocupa el tamaño del programa generado, sino que el archivo de inicio la carga en otra parte de sram al inicio, y luego se inicializa a 0, y se colocarán la sección .bss y el espacio de pila. en Asignar espacio juntos.
Si se trata de un programa normal, por supuesto no hay problema. Pero nuestro programa de algoritmo de descarga flash no puede funcionar de esta manera porque no tiene un archivo de inicio y los datos en la sección .bss no se cargan en sram cuando se ejecuta el algoritmo flash. Las variables en la sección bss todavía están en el espacio que comienza en 0x0000373c.
En Initla función, agregue el código para imprimir la pila, de la siguiente manera:

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
    
    

    /* Add your Code */
    int result = 0;

    UART0_Init(115200, USART_WordLength_8b, USART_StopBits_1b, USART_Parity_No);

    SFUD_INFO("MSP: 0x%x\n", __get_MSP());

    SFUD_INFO("Init: adr=0x%x, clk=0x%x, fnc=0x%x\n", adr, clk, fnc);

    g_size = 0;

    result = sfud_init();
    if(result != SFUD_SUCCESS) {
    
    
        return result;
    }
    return (0);                                  // Finished without Errors
}

El código anterior imprime el valor de MSP. Lo probé de la siguiente manera:

MSP: 0x200038d4

Debido a que mi código se ejecuta en 0x20000000, la posición de desplazamiento de MSP es 0x38d4. Resta 0x0000373c para obtener 408 bytes, lo que significa que el tamaño de la pila debe estar dentro de 408 bytes. Si excede, se sobrescribirá la variable en .bss.

  • 4.2 Mejorar el programa
    El problema anterior ocurre porque las variables están en la sección .bss ¿Qué pasa si las variables no están en la sección .bss?
    Cambiamos las siguientes partes del código:
#define BUF_SIZE 4096
uint8_t aux_buf[BUF_SIZE] = {
    
    1};

El código anterior le da un valor inicial a la matriz aux_buf [], por lo que el archivo de mapa compilado es el siguiente:
Insertar descripción de la imagen aquíInsertar descripción de la imagen aquí
Se puede ver que aux_buf está en la sección .data, es decir, se ha convertido en parte del programa y el impreso El valor de pila MSP también ha cambiado. El desbordamiento de pila no afectará a aux_buf. Sin embargo, la sección .bss aquí todavía almacena variables no inicializadas en sfud.o, que se utilizan para leer y escribir flash. Hay este código en sfud_write:
Insertar descripción de la imagen aquí
cmd_data aquí está en la sección .bss, que resulta ser 261byte=0x105, correspondiente al archivo de mapa.
Cuando vea esto, comprenderá que si la pila se desborda, cmd_data se sobrescribirá, lo que afectará la escritura de datos de la memoria flash. Este es el mismo fenómeno que medí en pruebas reales: a menudo escribo la dirección flash incorrecta en 0xfc porque la pila crece hacia abajo y sobrescribe cmd_data[252].

  • 4.3 Solución
    Se puede ver en el análisis anterior que hay dos problemas con este programa. ① Las variables en la sección .bss del programa generado no tienen un archivo de inicio para asignarles espacio; ② La pila predeterminada también lo es. pequeño y la pila se desbordará.
    Empecemos por estos dos lugares.
    • 1. Cree un área separada para la sección .bss.
      Dado que a la dirección variable de la sección .bss no se le ha asignado espacio, y su dirección se determina después de la compilación, y la sección .bss está al final del PRGárea, primero puede separar la sección .bss y modificar el script de enlace como sigue:
; Linker Control File (scatter-loading)
;

PRG 0 PI               ; Programming Functions
{
    
    
  PrgCode +0           ; Code
  {
    
    
    * (+RO)
  }
  PrgData +0           ; Data
  {
    
    
    * (+RW)
  }
  PrgZI +0             ; ZI
  {
    
    
    * (+ZI)
  }
}

DSCR +0                ; Device Description
{
    
    
  DevDscr +0
  {
    
    
    FlashDev.o
  }
}

Archivo de mapa generado:
Insertar descripción de la imagen aquí
aunque la imagen de arriba muestra que .bss tiene un espacio separado al vincularse, no hay ningún archivo de inicio para asignarle espacio cuando el programa se está ejecutando, y la posición de la pila se especifica como el desplazamiento inicial al final del programa en 0x00003694.Bytes (no tenemos forma de saber cuánto es el desplazamiento, lo imprimí para que tenga aproximadamente 400 bytes), todavía existe el problema de la cobertura de desbordamiento, por lo que es necesario ajustar la posición inicial de la pila.
Podemos crear una matriz grande, que se usa para expandir el espacio de direcciones ocupado por el programa compilado y usarse indirectamente como una pila. El script de enlace modificado es el siguiente:

; Linker Control File (scatter-loading)
;

PRG 0 PI               ; Programming Functions
{
    
    
  PrgCode +0           ; Code
  {
    
    
    * (+RO)
  }
  PrgData +0           ; Data
  {
    
    
    * (+RW)
  }
  PrgZI +0             ; ZI
  {
    
    
    * (+ZI)
  }
}

EXTSPACE +0x2000	; 和PRG区域间隔8192byte
{
    
    
  EXSTACKAPACE +0
  {
    
    
    * (.exstackspace)
  }
}

DSCR +0                ; Device Description
{
    
    
  DevDscr +0
  {
    
    
    FlashDev.o
  }
}

El intervalo anterior 0x2000 es relativo a la posición final de PrgData, porque ZI no ocupa espacio en el programa compilado, es decir, el programa finaliza después de PrgData. El propósito de 0x2000 es reservar un área de 8K para .bss al final del programa, que es ZI.
Hasta ahora, el espacio de .bss se ha resuelto porque el espacio reservado es lo suficientemente grande, incluso si la pila se desborda, no importa. Pero para ser más riguroso, aún es necesario reservar la ubicación del espacio de la pila.
Defina la matriz FlashPrg.cy asígnela en EXTSPACE:

#define EXT_STACK_SIZE  (2048)
#define EXTSTACK_AREA_ATTRIBUTES  __attribute__ ((section(".exstackspace"))) __attribute__((aligned(4)))
volatile uint8_t ext_stack_space[EXT_STACK_SIZE] EXTSTACK_AREA_ATTRIBUTES;

El 2048 anterior representa EXTSPACEque 2048 bytes están ocupados en el espacio como área de expansión de la pila, y la posición inicial y el PrgDataárea están compensados ​​por 0x2000.
El archivo de mapa es el siguiente:
Insertar descripción de la imagen aquí
La asignación de espacio modificada es la siguiente:
Insertar descripción de la imagen aquí

Hasta ahora, se ha resuelto el problema de los errores de escritura flash.

5. Código completo

  • 1. Target.linLos expedientes son los siguientes:
; Linker Control File (scatter-loading)
;

PRG 0 PI               ; Programming Functions
{
    
    
  PrgCode +0           ; Code
  {
    
    
    * (+RO)
  }
  PrgData +0           ; Data
  {
    
    
    * (+RW)
  }
  PrgZI +0             ; ZI
  {
    
    
    * (+ZI)
  }
}

EXTSPACE +0x2000
{
    
    
  EXSTACKAPACE +0
  {
    
    
    * (.exstackspace)
  }
}

DSCR +0                ; Device Description
{
    
    
  DevDscr +0
  {
    
    
    FlashDev.o
  }
}
  • 2. FlashPrg.cLos expedientes son los siguientes:
/**************************************************************************//**
 * @file     FlashPrg.c
 * @brief    Flash Programming Functions adapted for New Device Flash
 * @version  V1.0.0
 * @date     10. January 2018
 ******************************************************************************/
/*
 * Copyright (c) 2010-2018 Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "FlashOS.H"        // FlashOS Structures
#include "uart.h"
#include "sfud.h"

#define EXT_STACK_SIZE  (2048)
#define EXTSTACK_AREA_ATTRIBUTES  __attribute__ ((section(".exstackspace"))) __attribute__((aligned(4)))
volatile uint8_t ext_stack_space[EXT_STACK_SIZE] EXTSTACK_AREA_ATTRIBUTES;

#define BUF_SIZE 4096
uint8_t aux_buf[BUF_SIZE];

/* 
   Mandatory Flash Programming Functions (Called by FlashOS):
                int Init        (unsigned long adr,   // Initialize Flash
                                 unsigned long clk,
                                 unsigned long fnc);
                int UnInit      (unsigned long fnc);  // De-initialize Flash
                int EraseSector (unsigned long adr);  // Erase Sector Function
                int ProgramPage (unsigned long adr,   // Program Page Function
                                 unsigned long sz,
                                 unsigned char *buf);

   Optional  Flash Programming Functions (Called by FlashOS):
                int BlankCheck  (unsigned long adr,   // Blank Check
                                 unsigned long sz,
                                 unsigned char pat);
                int EraseChip   (void);               // Erase complete Device
      unsigned long Verify      (unsigned long adr,   // Verify Function
                                 unsigned long sz,
                                 unsigned char *buf);

       - BlanckCheck  is necessary if Flash space is not mapped into CPU memory space
       - Verify       is necessary if Flash space is not mapped into CPU memory space
       - if EraseChip is not provided than EraseSector for all sectors is called
*/

/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
    
    

    /* Add your Code */
    int result = 0;

    __disable_irq();

    UART0_Init(115200, USART_WordLength_8b, USART_StopBits_1b, USART_Parity_No);

    SFUD_INFO("MSP: 0x%x\n", __get_MSP());

    SFUD_INFO("Init: adr=0x%x, clk=0x%x, fnc=0x%x\n", adr, clk, fnc);

    g_size = 0;

    result = sfud_init();
    if(result != SFUD_SUCCESS) {
    
    
        return result;
    }
    return (0);                                  // Finished without Errors
}


/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int UnInit (unsigned long fnc) {
    
    

    /* Add your Code */
    SFUD_INFO("UnInit: fnc=0x%x\n", fnc);
    return (0);                                  // Finished without Errors
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip (void) {
    
    

  /* Add your Code */
    int result = 0;

    const sfud_flash *flash = sfud_get_device(SFUD_DEVICE_INDEX);
    result = sfud_erase (flash, 0, flash->chip.capacity);
    if (result != SFUD_SUCCESS) {
    
    
        return result;
    }

    SFUD_INFO("EraseChip ok.\n");
    return (0);                                  // Finished without Errors
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector (unsigned long adr) {
    
    

    /* Add your Code */
    int result = 0;
    uint32_t block_start;
    const sfud_flash *flash = sfud_get_device(SFUD_DEVICE_INDEX);

    block_start = adr;
    result = sfud_erase (flash, block_start, 4096);
    if (result != SFUD_SUCCESS) {
    
    
        return result;
    }

    SFUD_INFO("EraseSector ok: adr=0x%x\n", adr);
    return (0);                                  // Finished without Errors
}


/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
    
    

    /* Add your Code */
    const sfud_flash *flash = sfud_get_device(SFUD_DEVICE_INDEX);
    uint32_t start_addr = adr;

    SFUD_INFO("ProgramPage, addr=0x%x, size=%d\n", adr, sz);

    if(sfud_write(flash, start_addr, sz, buf) != SFUD_SUCCESS) {
    
    
        SFUD_INFO("ProgramPage err!\n");
        return -1;
    }

    if(start_addr < 0x20000) {
    
    
        g_size += sz;
    }

    return (0);                                  // Finished without Errors
}

unsigned long Verify(unsigned long adr, unsigned long sz, unsigned char *buf)
{
    
    
    const sfud_flash *flash = sfud_get_device(SFUD_DEVICE_INDEX);
    uint32_t start_addr = adr;
    uint32_t len;
    uint32_t n = 0;
    uint32_t size = sz;

    // SFUD_INFO("Verify: addr=0x%x, size=0x%x, buf=0x%p\n", adr, sz, buf);

    while (size)
    {
    
    
        if (size < BUF_SIZE) {
    
    
            len = size;
        } else {
    
    
            len = BUF_SIZE;
        }

        sfud_read(flash, start_addr, len, aux_buf);
        for (int i = 0; i < len; i++) {
    
    
            if (aux_buf[i] != buf[n + i]) {
    
    
                SFUD_INFO("Verify err, addr=0x%x, aux_buf[%d]=0x%x\n", start_addr + i, i, aux_buf[i]);
                return (start_addr + i);   // Verification Failed (return address)
            }
        }

        size -= len;
        start_addr += len;
        n += len;
    }
    SFUD_INFO("Verify ok: 0x%x\n", adr + sz);
    return (adr + sz);                    // Done successfully
}

int BlankCheck (unsigned long adr,unsigned long sz,unsigned char pat)
{
    
    
    const sfud_flash *flash = sfud_get_device(SFUD_DEVICE_INDEX);
    uint32_t start_addr = adr;
    uint32_t len;

    SFUD_INFO("BlankCheck: addr=0x%x, size=0x%x, pat=0x%x\n", adr, sz, pat);

    while (sz)
    {
    
    
        if (sz < BUF_SIZE) {
    
    
            len = sz;
        } else {
    
    
            len = BUF_SIZE;
        }

        sfud_read(flash, start_addr, len, aux_buf);
        for (int i = 0; i < len; i++) {
    
    
            if (aux_buf[i] != pat) {
    
    
                SFUD_INFO("BlankCheck err, addr=0x%x\n", start_addr + i);
                return (start_addr + i + 1);   // Verification Failed (return address)
            }
        }

        sz -= len;
        start_addr += len;
    }
    SFUD_INFO("BlankCheck ok: 0x%x\n", adr + sz);
    return (0);
}

6. Agregar nuevos algoritmos en jflash

  • 1. Crear una carpeta Cree una carpeta a continuación
    .C:\Users\'你电脑的用户名'\AppData\Roaming\SEGGER\JLinkDevices
  • 2. La estructura del archivo JLinkDevices debe ser similar a la siguiente:
JLinkDevices
└── W25Q128
    └── W25Q128JM
        ├── W25Q128_SPI_FLASH.FLM
        └── W25Q128.xml

Entre ellos W25Q128_SPI_FLASH.FLMse encuentra el algoritmo de descarga flash generado por mdk.

  • 3. Contenido W25Q128.xml
<Database>
<Device>
       <ChipInfo Vendor="WINBIND" Name="Cortex-M7" WorkRAMAddr="0x20000000" WorkRAMSize="0x20000"Core="JLINK_CORE_CORTEX_M7" />
       <FlashBankInfo Name="QSPI Flash" BaseAddr="0x00000000" MaxSize="0x01000000" Loader="W25Q128_SPI_FLASH.FLM" LoaderType="FLASH_ALGO_TYPE_OPEN" />
</Device>
</Database>

Supongo que te gusta

Origin blog.csdn.net/weixin_40837318/article/details/131858389
Recomendado
Clasificación