你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

从零编写STM32H7的MDK SPI FLASH下载算法

[复制链接]
STMCU小助手 发布时间:2023-2-20 21:04
Part1前言

当我们要下载编译好的镜像到Flash时,首先要做的一步就是选择合适的Flash下载算法,而这个算法本身就是一个FLM文件:


微信图片_20230220210427.png


代码既可以下载到内部flash,也可以下载到外部flash,或者一部分下载到内部,一部分下载到外部。


Part2一、将代码中的图片资源下载到外部flash

在UI设计中往往需要大量的图片和字体,图片和字体资源在代码中以静态数组的形式存在,这些大数组在内部flash中一般存放不下,所以需要把这些占用资源比较大的数组放在外部flash中,然后通过QSPI地址映射的方式访问,或者通过SPI将flash中的资源分批读取到RAM缓存中使用。

  • 通过MDK打开分散加载文件,配置“ExtFlashSection”段:
  1. ; *************************************************************
  2. ; *** Scatter-Loading Description File generated by uVision ***
  3. ; *************************************************************

  4. LR_IROM1 0x08000000 0x00020000  {    ; load region size_region
  5.   ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address
  6.    *.o (RESET, +First)
  7.    *(InRoot$Sections)
  8.    .ANY (+RO)
  9.    .ANY (+XO)
  10.   }
  11.   RW_IRAM1 0x20000000 0x00020000  {  ; RW data
  12.    .ANY (+RW +ZI)
  13.   }
  14.   RW_IRAM2 0x24000000 0x00080000  {
  15.    .ANY (+RW +ZI)
  16.   }
  17. }

  18. LR_EROM1 0x90000000 0x01000000  {    ; load region size_region
  19.     ER_EROM1 0x90000000 0x01000000  {  ; load address = execution address
  20.   *.o (ExtFlashSection)
  21.   *.o (FontFlashSection)
  22.   *.o (TextFlashSection)
  23. }
  24. }
复制代码


添加LR_EROM1 段,起始地址为0x90000000 ,大小为0x01000000  。


2.在代码中将图片资源分配到ExtFlashSection段

  1. #define LOCATION_ATTRIBUTE(name) __attribute__((section(name))) __attribute__((aligned(4)))

  2. KEEP extern const unsigned char image_watch_seconds[] LOCATION_ATTRIBUTE("ExtFlashSection") = // 4x202 ARGB8888 pixels.
  3. {
  4.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
  5.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
  6.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
  7.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
  8.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
  9.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
  10.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
  11.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
  12.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
  13.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
  14.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff,
  15.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0xff,
  16.     0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0xff, 0xf8, 0xfc, 0xf8, 0x00,
  17.     0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00, 0xf8, 0xfc, 0xf8, 0x00,
  18.     0xf8, 0xfc, 0xf8, 0x00
  19. };
复制代码


3.编译代码


7M0~6]}WEV(W3{9CZ5I8_R5.png


查看map文件,image_watch_seconds这个数组已经被分配到了0X90138690这个地址了,这个地址正是LR_EROM1 所在的区间。


Part3二、MDK下载算法原理1程序能够通过下载算法下载到芯片的原理

通过MDK创建一批与地址信息无关的函数,实现的功能主要有初始化,擦除,编程,读取,校验等,然后MDK调试下载阶段,会将算法文件加载到芯片的内部RAM里面(加载地址可以通过MDK设置),然后MDK通过与这个算法文件的交互,实现程序下载,调试阶段数据读取等操作。


2算法程序中擦除操作执行流程


SC~H`7SQW7MR4]WI)K{%RP5.png


算法程序中擦除操作执行流程
  • 加载算法到芯片RAM。
  • 执行初始化函数Init。
  • 执行擦除操作,根据用户的MDK配置,这里可以选择整个芯片擦除或者扇区擦除。
  • 执行Uinit函数。
  • 操作完毕。


3制作FLM文件步骤
  • 将ARM:CMSIS Pack文件夹(通常是C:\Keil\ARM\Pack\ARM\CMSIS\ version \Device_Template_Flash)中的工程复制到一个新文件夹中,取消文件夹的只读属性,重命名项目文件NewDevice.uvprojx以表示新的flash 设备名称,例如MyDevice.uvprojx。
  • 打开工程,从工具栏中,使用下拉选择目标来选择处理器架构。
  • 打开对话框Project - Options for Target - Output并更改Name of Executable字段的内容以表示设备,例如MyDevice。
  • 调整文件FlashPrg中的编程算法。
  • 调整文件FlashDev中的设备参数。
  • 使用Project - Build Target生成新的 Flash 编程算法。

以上步骤是利用官方的工程模板修改代码,这种方式网上已有很多教程(推荐使用这种方法),不再重复介绍,接下来介绍一种不使用模板工程制作的方法,目的是为了了解其实现原理。


Part4三、使用STM32CubeMX新建工程
4新建工程

硬件平台:   RT-Thread官方ART-PI H750开发版

软件:   STM32CubeMX,MDK

选择MCU型号(STM32H750XBH6)


{FDY0OIRG(7AA96PX1%XO.png
选择MCU型号


配置SPI







配置UART


2OE4M$R`38~L@7F$}$RLA3B.png


配置时钟树


~0HV%~)P44TTQZEA3B[1JQC.png




设置调试接口


1ZJX$BP9O0GEJAAZ(ALW2$M.png


设置工程并生成工程


D48WYLW`EFGMDK8D[[{5E7K.png


52. 移植SFUD串行 Flash 通用驱动库
SFUD 是什么

SFUD是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。

  • 主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址
  • 资源占用
    • 标准占用:RAM:0.2KB ROM:5.5KB
    • 最小占用:RAM:0.1KB ROM:3.6KB
  • 设计思路:
    • 什么是 SFDP :它是 JEDEC (固态技术协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B (点击这里查看)。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。
    • 不支持 SFDP 怎么办 :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( /sfud/inc/sfud_flash_def.h ) 中提供的 Flash 参数信息表 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。


移植SFUD

将下载到sfud源代码放置在工程目录中


CS_RO6]$RS7@YZOD_2GK649.png


将sfud添加到工程目录:


AXVS]LMBFQ{[@O7[(UH7H.png


修改sfud_port.c文件:

  1. #include <string.h>
  2. #include <sfud.h>
  3. #include <stdarg.h>
  4. #include "gpio.h"
  5. #include "spi.h"

  6. typedef struct {
  7.     SPI_HandleTypeDef *spix;
  8.     GPIO_TypeDef *cs_gpiox;
  9.     uint16_t cs_gpio_pin;
  10. } spi_user_data, *spi_user_data_t;

  11. static spi_user_data spi1;
  12. static char log_buf[256];
  13. void sfud_log_debug(const char *file, const long line, const char *format, ...);
  14. extern int rt_vsnprintf(char *buf, int size, const char *fmt, va_list args);
  15. extern int rt_kprintf(const char *fmt, ...);
  16. static void spi_lock(const sfud_spi *spi)
  17. {

  18. }

  19. static void spi_unlock(const sfud_spi *spi)
  20. {

  21. }
  22. /* about 100 microsecond delay */
  23. static void delay_100us(void) {
  24.     uint32_t delay = 2000;
  25.     while(delay--);
  26. }
  27. /**
  28. * SPI write data then read data
  29. */
  30. static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
  31.                                size_t read_size)
  32. {
  33.     sfud_err result = SFUD_SUCCESS;
  34.     /**
  35.      * add your spi write and read code
  36.      */
  37.     spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;

  38.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_RESET);
  39.     if (write_size) {
  40.         HAL_SPI_Transmit(spi_dev->spix, (uint8_t *)write_buf,write_size,1);
  41.     }
  42.     if (read_size) {
  43.         HAL_SPI_Receive(spi_dev->spix, read_buf,read_size,1);
  44.     }
  45. exit:
  46.     HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin,GPIO_PIN_SET);
  47.     return result;
  48. }

  49. sfud_err sfud_spi_port_init(sfud_flash *flash)
  50. {
  51.     sfud_err result = SFUD_SUCCESS;

  52.     switch (flash->index) {
  53.         case SFUD_W25Q128_DEVICE_INDEX: {
  54.             spi1.spix = &hspi1;
  55.             spi1.cs_gpiox = GPIOA;
  56.             spi1.cs_gpio_pin = GPIO_PIN_4;
  57.             /* 同步 Flash 移植所需的接口及数据 */
  58.             flash->spi.wr = spi_write_read;
  59.             flash->spi.lock = spi_lock;
  60.             flash->spi.unlock = spi_unlock;
  61.             flash->spi.user_data = &spi1;
  62.             /* about 100 microsecond delay */
  63.             flash->retry.delay = delay_100us;
  64.             /* adout 60 seconds timeout */
  65.             flash->retry.times = 60 * 10000;

  66.             break;
  67.         }
  68.     }

  69.     return result;
  70. }

  71. void sfud_log_debug(const char *file, const long line, const char *format, ...) {
  72.     va_list args;

  73.     /* args point to the first variable parameter */
  74.     va_start(args, format);
  75.     rt_kprintf("[SFUD](%s:%ld) ", file, line);
  76.     /* must use vprintf to print */
  77.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
  78.     rt_kprintf("%s\r\n", log_buf);
  79.     va_end(args);
  80. }

  81. void sfud_log_info(const char *format, ...) {
  82.     va_list args;

  83.     /* args point to the first variable parameter */
  84.     va_start(args, format);
  85.     rt_kprintf("[SFUD]");
  86.     /* must use vprintf to print */
  87.     rt_vsnprintf(log_buf, sizeof(log_buf), format, args);
  88.     rt_kprintf("%s\r\n", log_buf);
  89.     va_end(args);
  90. }
复制代码


测试SFUD

在main.c中添加测试代码:

  1. /* USER CODE END Header */
  2. /* Includes ------------------------------------------------------------------*/
  3. #include "main.h"
  4. #include "spi.h"
  5. #include "usart.h"
  6. #include "gpio.h"

  7. /* Private function prototypes -----------------------------------------------*/
  8. void SystemClock_Config(void);
  9. static void MPU_Config(void);
  10. /* USER CODE BEGIN PFP */
  11. extern int rt_kprintf(const char *fmt, ...);
  12. #include "sfud.h"
  13. /* USER CODE END PFP */

  14. /* Private user code ---------------------------------------------------------*/
  15. /* USER CODE BEGIN 0 */
  16. #define SFUD_DEMO_TEST_BUFFER_SIZE                     1024

  17. static uint8_t sfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];
  18. /**
  19. * SFUD demo for the first flash device test.
  20. *
  21. * @param addr flash start address
  22. * @param size test flash size
  23. * @param size test flash data buffer
  24. */
  25. static void sfud_demo(uint32_t addr, size_t size, uint8_t *data) {
  26.     sfud_err result = SFUD_SUCCESS;
  27.     const sfud_flash *flash = sfud_get_device_table() + 0;
  28.     size_t i;
  29.     /* prepare write data */
  30.     for (i = 0; i < size; i++) {
  31.         data[i] = i;
  32.     }
  33.     /* erase test */
  34.     result = sfud_erase(flash, addr, size);
  35.     if (result == SFUD_SUCCESS) {
  36.         rt_kprintf("Erase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,
  37.                 size);
  38.     } else {
  39.         rt_kprintf("Erase the %s flash data failed.\r\n", flash->name);
  40.         return;
  41.     }
  42.     /* write test */
  43.     result = sfud_write(flash, addr, size, data);
  44.     if (result == SFUD_SUCCESS) {
  45.         rt_kprintf("Write the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr,
  46.                 size);
  47.     } else {
  48.         rt_kprintf("Write the %s flash data failed.\r\n", flash->name);
  49.         return;
  50.     }
  51.     /* read test */
  52.     result = sfud_read(flash, addr, size, data);
  53.     if (result == SFUD_SUCCESS) {
  54.         rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr,
  55.                 size);
  56.         rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");
  57.         for (i = 0; i < size; i++) {
  58.             if (i % 16 == 0) {
  59.                 rt_kprintf("[%08X] ", addr + i);
  60.             }
  61.             rt_kprintf("%02X ", data[i]);
  62.             if (((i + 1) % 16 == 0) || i == size - 1) {
  63.                 rt_kprintf("\r\n");
  64.             }
  65.         }
  66.         rt_kprintf("\r\n");
  67.     } else {
  68.         rt_kprintf("Read the %s flash data failed.\r\n", flash->name);
  69.     }
  70.     /* data check */
  71.     for (i = 0; i < size; i++) {
  72.         if (data[i] != i % 256) {
  73.             rt_kprintf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
  74.    break;
  75.         }
  76.     }
  77.     if (i == size) {
  78.         rt_kprintf("The %s flash test is success.\r\n", flash->name);
  79.     }
  80. }

  81. /* USER CODE END 0 */

  82. int main(void)
  83. {

  84.   /* MPU Configuration--------------------------------------------------------*/
  85.   MPU_Config();

  86.   /* MCU Configuration--------------------------------------------------------*/

  87.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  88.   HAL_Init();

  89.   SystemClock_Config();

  90.   MX_GPIO_Init();
  91.   MX_SPI1_Init();
  92.   MX_UART4_Init();
  93.   /* USER CODE BEGIN 2 */
  94.   if (sfud_init() == SFUD_SUCCESS) {
  95.       sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);
  96.   }

  97.   while (1)
  98.   {

  99.   }

  100. }

  101. #endif /* USE_FULL_ASSERT */
复制代码

运行如下:


~Z~@6]$JBY}EL7U$S9VDPWU.png


63. 制作下载算法
重新生成不带main函数的工程

FM5({[5%Y2KW1XJDT3ZR)N9.png

添加修改编程算法文件FlashPrg.c

模板工程里面提供了FlashOS.h和FlashPrg.c ,复制到此工程中,然后对FlashPrg.c 代码进行填充。

  1. #include "FlashOS.H"
  2. #include "sfud.h"
  3. #include "gpio.h"
  4. #include "usart.h"
  5. #include "spi.h"

  6. static uint32_t base_adr;

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

  14. #if defined FLASH_MEM || defined FLASH_OTP
  15. int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
  16. {
  17.     MX_GPIO_Init();
  18.     MX_UART4_Init();
  19.     MX_SPI1_Init();
  20.     base_adr = adr;
  21.     if(sfud_init() == SFUD_SUCCESS) {
  22.         return 0;
  23.     } else {
  24.         return 1;
  25.     }
  26. }
  27. #endif


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

  33. #if defined FLASH_MEM || defined FLASH_OTP
  34. int UnInit (unsigned long fnc)
  35. {

  36.     return (0);
  37. }
  38. #endif

  39. /*
  40. *  Erase complete Flash Memory
  41. *    Return Value:   0 - OK,  1 - Failed
  42. */

  43. int EraseChip (void)
  44. {
  45.     int result = 0;
  46.     const sfud_flash *flash = sfud_get_device_table();
  47.     /* Add your Code */
  48.     result = sfud_erase (flash, 0, flash->chip.capacity);

  49.     if (result == SFUD_SUCCESS)
  50.         return 0;
  51.     else
  52.         return result;                                  // Finished without Errors
  53. }

  54. /*
  55. *  Erase Sector in Flash Memory
  56. *    Parameter:      adr:  Sector Address
  57. *    Return Value:   0 - OK,  1 - Failed
  58. */

  59. #ifdef FLASH_MEM
  60. int EraseSector (unsigned long adr)
  61. {
  62.     int result = 0;
  63.     uint32_t block_start;
  64.     const sfud_flash *flash;
  65.     flash  = sfud_get_device_table();
  66.     block_start  = adr - base_adr;
  67.     result = sfud_erase (flash, block_start, 4096);

  68.     if (result == SFUD_SUCCESS)
  69.         return 0;
  70.     else
  71.         return result;
  72. }
  73. #endif


  74. /*
  75. *  Program Page in Flash Memory
  76. *    Parameter:      adr:  Page Start Address
  77. *                    sz:   Page Size
  78. *                    buf:  Page Data
  79. *    Return Value:   0 - OK,  1 - Failed
  80. */

  81. #if defined FLASH_MEM || defined FLASH_OTP
  82. int ProgramPage (unsigned long block_start, unsigned long size, unsigned char *buffer)
  83. {
  84.     const sfud_flash *flash = sfud_get_device_table() + 0;
  85.     uint32_t start_addr = block_start - base_adr;

  86.     if(sfud_write(flash, start_addr, size, buffer) == SFUD_SUCCESS)
  87.         return 0;
  88.     else
  89.         return 1;
  90. }


  91. #define PAGE_SIZE            4096
  92. uint8_t aux_buf[PAGE_SIZE];
  93. unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
  94. {
  95.     int i;
  96.     const sfud_flash *flash = sfud_get_device_table();
  97.     sfud_read(flash, adr - base_adr, sz, aux_buf);

  98.     for (i = 0; i < PAGE_SIZE; i++) {
  99.         if (aux_buf[i] != buf[i])
  100.             return (adr + i);                 // Verification Failed (return address)
  101.     }

  102.     return (adr + sz);                    // Done successfully
  103. }

  104. #endif
复制代码


在工程中定义FLASH_MEM宏


微信图片_20230220211259.png


添加修改配置文件FlashDev.c

模板工程里面提供了FlashDev.c ,复制到此工程中,然后对代码进行修改。

  1. #include "FlashOS.H"        

  2. #ifdef FLASH_MEM
  3. struct FlashDevice const FlashDevice  =  {
  4.    FLASH_DRV_VERS,             // Driver Version, do not modify!
  5.    "STM32H750-ARTPI",          // Device Name
  6.    EXTSPI,                     // Device Type
  7.    0x90000000,                 // Device Start Address
  8.    0x08000000,                 // Device Size in Bytes (128MB)
  9.    0x00001000,                 // Programming Page Size 4096 Bytes
  10.    0x00,                       // Reserved, must be 0
  11.    0xFF,                       // Initial Content of Erased Memory
  12.    10000,                      // Program Page Timeout 100 mSec
  13.    6000,                       // Erase Sector Timeout 6000 mSec

  14. // Specify Size and Address of Sectors
  15.    0x1000, 0x000000,            // Sector Size  4kB
  16.    SECTOR_END
  17. };
  18. #endif // FLASH_MEM
复制代码

特别注意:"STM32H750-ARTPI"就是MDK的Option选项里面会识别出这个名字。0x90000000是MDK分散加载文件中定义的外部flash起始地址。


地址无关代码实现

C和汇编的配置勾选上:


KL5CE)S$H~6IOI1G(D35HTQ.png


ROPI地址无关实现

如果程序的所有只读段都与位置无关,则该程序为只读位置无关(ROPI, Read-only position independence)。ROPI段通常是位置无关代码(PIC,position-independent code),但可以是只读数据,也可以是PIC和只读数据的组合。选择“ ROPI”选项,可以避免用户不得不将代码加载到内存中的特定位置。这对于以下例程特别有用:

(1)加载以响应运行事件。

(2)在不同情况下使用其他例程的不同组合加载到内存中。

(3)在执行期间映射到不同的地址。


RWPI数据无关实现使用Read-Write position independence同理,表示的可读可写数据段。使用RWPI编译代码,解决RW段即全局变量的加载。首先编译的时候会为每一个全局变量生成一个相对于r9寄存器的偏移量,这个偏移量会在.text段中。

在加载elf阶段,将RW段加载到RAM当中之后,需要将r9寄存器指向此片内存的基地址,然后接下来就可以跳转到加载的elf的代码中去执行,就可以实现全局变量的加载了。

综上所述,勾选ROPI和RWPI选项,可以实现elf文件的动态加载,还遗留的一个小问题是elf模块如何调用系统函数,这与此文无关,留在以后再讲。


特别注意:

  • 由于模块中不含中断向量表,所以程序中不要开启任何中断。
  • startup_stm32h750xx.s不再需要参与编译


微信图片_20230220205842.png


修改分散加载文件

复制一份新的分散加载文件到工程目录中,然后修改成如下代码


J2(7FVO7MLDYI5VA15HGJ(A.png


--diag_suppress L6305用于屏蔽没有入口地址的警告信息。

  1. ; Linker Control File (scatter-loading)
  2. ;

  3. PRG 0 PI               ; Programming Functions
  4. {
  5.   PrgCode +0           ; Code
  6.   {
  7.     * (+RO)
  8.   }
  9.   PrgData +0           ; Data
  10.   {
  11.     * (+RW,+ZI)
  12.   }
  13. }

  14. DSCR +0                ; Device Description
  15. {
  16.   DevDscr +0
  17.   {
  18.     FlashDev.o
  19.   }
  20. }
复制代码

将程序可执行文件axf修改为flm格式

通过这个cmd.exe /C copy "!L" "..\@L.FLM"命令可以将生成的axf可执行文件修改为flm。


M]8}JQN})49_8NUM_XN}14X.png


将生成的flm文件拷贝到...\Keil_v5\ARM\Flash目录,即可被MDK识别到。


完整版请查看:附件

收藏 评论1 发布时间:2023-2-20 21:04

举报

1个回答
brack 回答时间:2023-3-10 15:13:10

可以分享附件吗?

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版