【MCU】如何将资源烧写至外部flash,如spi-flash

STM32将资源烧写至外部flash方式大致分为同应用程序一起烧录和单独烧录

烧录关键就是制作对应算法

方式一、使用通用工具如IDE、J-Flash加载烧写算法

烧录应用程序时一并写入,通过修改分散加载链接脚本将部分常量数据移至外部flash

制作烧录算法步骤如下:

主要实现两个文件,接口实现文件 <FLashPrg.c> 和设备描述文件 <FLashPrg.c>

FLashDev.c

 1 /**************************************************************************//**
 2  * @file     FlashDev.c
 3  * @brief    Flash Device Description for New Device Flash
 4  * @version  V1.0.0
 5  * @date     10. January 2018
 6  ******************************************************************************/
 7 /*
 8  * Copyright (c) 2010-2018 Arm Limited. All rights reserved.
 9  *
10  * SPDX-License-Identifier: Apache-2.0
11  *
12  * Licensed under the Apache License, Version 2.0 (the License); you may
13  * not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  * www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24  
25 #include "..\FlashOS.H"        // FlashOS Structures
26 
27 
28 struct FlashDevice const FlashDevice  =  {
29     FLASH_DRV_VERS,             // Driver Version, do not modify!
30     "STM32F429_W25Q128",        // Device Name 
31     EXTSPI,                     // Device Type
32     0x90000000,                 // Device Start Address
33     0x01000000,                 // Device Size in Bytes (256kB)
34     256,                        // Programming Page Size
35     0,                          // Reserved, must be 0
36     0xFF,                       // Initial Content of Erased Memory
37     100,                        // Program Page Timeout 100 mSec
38     3000,                       // Erase Sector Timeout 3000 mSec
39 
40 // Specify Size and Address of Sectors
41     0x001000, 0x000000,         // Sector Size  8kB (8 Sectors)
42 //    0x010000, 0x010000,         // Sector Size 64kB (2 Sectors) 
43 //    0x002000, 0x030000,         // Sector Size  8kB (8 Sectors)
44     SECTOR_END
45 };

FLashPrg.c

  1 /**************************************************************************//**
  2  * @file     FlashPrg.c
  3  * @brief    Flash Programming Functions adapted for New Device Flash
  4  * @version  V1.0.0
  5  * @date     10. January 2018
  6  ******************************************************************************/
  7 /*
  8  * Copyright (c) 2010-2018 Arm Limited. All rights reserved.
  9  *
 10  * SPDX-License-Identifier: Apache-2.0
 11  *
 12  * Licensed under the Apache License, Version 2.0 (the License); you may
 13  * not use this file except in compliance with the License.
 14  * You may obtain a copy of the License at
 15  *
 16  * www.apache.org/licenses/LICENSE-2.0
 17  *
 18  * Unless required by applicable law or agreed to in writing, software
 19  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 20  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 21  * See the License for the specific language governing permissions and
 22  * limitations under the License.
 23  */
 24  
 25 #include "..\FlashOS.H"        // FlashOS Structures
 26 #include ".\flash\bsp_spi_flash.h"
 27 
 28 
 29 #define PAGE_SIZE               SPI_FLASH_PageSize
 30 
 31 
 32 uint8_t auxBuf[PAGE_SIZE];
 33 uint32_t baseAddr;
 34 
 35 /* 
 36    Mandatory Flash Programming Functions (Called by FlashOS):
 37                 int Init        (unsigned long adr,   // Initialize Flash
 38                                  unsigned long clk,
 39                                  unsigned long fnc);
 40                 int UnInit      (unsigned long fnc);  // De-initialize Flash
 41                 int EraseSector (unsigned long adr);  // Erase Sector Function
 42                 int ProgramPage (unsigned long adr,   // Program Page Function
 43                                  unsigned long sz,
 44                                  unsigned char *buf);
 45 
 46    Optional  Flash Programming Functions (Called by FlashOS):
 47                 int BlankCheck  (unsigned long adr,   // Blank Check
 48                                  unsigned long sz,
 49                                  unsigned char pat);
 50                 int EraseChip   (void);               // Erase complete Device
 51       unsigned long Verify      (unsigned long adr,   // Verify Function
 52                                  unsigned long sz,
 53                                  unsigned char *buf);
 54 
 55        - BlanckCheck  is necessary if Flash space is not mapped into CPU memory space
 56        - Verify       is necessary if Flash space is not mapped into CPU memory space
 57        - if EraseChip is not provided than EraseSector for all sectors is called
 58 */
 59 
 60 
 61 /*
 62  *  Initialize Flash Programming Functions
 63  *    Parameter:      adr:  Device Base Address
 64  *                    clk:  Clock Frequency (Hz)
 65  *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 66  *    Return Value:   0 - OK,  1 - Failed
 67  */
 68 
 69 int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
 70 {
 71     /* Add your Code */
 72     baseAddr = adr;
 73     SPI_FLASH_Init();
 74     return (0);                                  // Finished without Errors
 75 }
 76 
 77 
 78 /*
 79  *  De-Initialize Flash Programming Functions
 80  *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 81  *    Return Value:   0 - OK,  1 - Failed
 82  */
 83 
 84 int UnInit (unsigned long fnc)
 85 {
 86     /* Add your Code */
 87     return (0);                                  // Finished without Errors
 88 }
 89 
 90 
 91 /*
 92  *  Erase complete Flash Memory
 93  *    Return Value:   0 - OK,  1 - Failed
 94  */
 95 
 96 int EraseChip (void)
 97 {
 98     /* Add your Code */
 99     SPI_FLASH_BulkErase();
100     return (0);                                  // Finished without Errors
101 }
102 
103 
104 /*
105  *  Erase Sector in Flash Memory
106  *    Parameter:      adr:  Sector Address
107  *    Return Value:   0 - OK,  1 - Failed
108  */
109 
110 int EraseSector (unsigned long adr)
111 {
112     /* Add your Code */
113     SPI_FLASH_SectorErase(adr - baseAddr);
114     return (0);                                  // Finished without Errors
115 }
116 
117 
118 /*
119  *  Program Page in Flash Memory
120  *    Parameter:      adr:  Page Start Address
121  *                    sz:   Page Size
122  *                    buf:  Page Data
123  *    Return Value:   0 - OK,  1 - Failed
124  */
125 
126 int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf)
127 {
128     /* Add your Code */
129     SPI_FLASH_PageWrite(buf, adr - baseAddr, sz);
130     return (0);                                  // Finished without Errors
131 }
132 
133 /*  
134  *  Verify Flash Contents
135  *    Parameter:      adr:  Start Address
136  *                    sz:   Size (in bytes)
137  *                    buf:  Data
138  *    Return Value:   (adr+sz) - OK, Failed Address
139  */
140 
141 /*
142    Verify function is obsolete because all other function leave 
143     the SPIFI in memory mode so a memory compare could be used.
144  */
145 unsigned long Verify (unsigned long adr, unsigned long sz, unsigned char *buf)
146 {
147     int i;
148     SPI_FLASH_BufferRead(auxBuf, adr - baseAddr, sz);
149     for (i = 0; i < PAGE_SIZE; i++) {
150         if (auxBuf[i] != buf[i]) {
151             return (adr + i);               // Verification Failed (return address)
152         }
153     }
154     return (adr + sz);                      // Done successfully
155 }

修改好适配自己的硬件接口,编译会生成 .FLM格式的烧写算法文件,实际是通过如下命令生成的

IDE烧录:烧写程序时选择刚才生成的算法文件即可

J-Flash烧录:拷贝刚生成的算法到JLink/Devices目录下,指定算法文件如下图

 

 

方式二、使用特定工具如STM32CubeProgrammer,将数据直接烧写至外部flash

烧写算法制作工程如下:

 主要实现两个文件,接口实现文件 <Loader_Src.c> 和设备描述文件 <Dev_Inf.c>

Dev_Inf.c

 1 #include "Dev_Inf.h"
 2 
 3 /* This structure containes information used by ST-LINK Utility to program and erase the device */
 4 #if defined (__ICCARM__)
 5 __root struct StorageInfo const StorageInfo  =  {
 6 #else
 7 struct StorageInfo const StorageInfo  =  {
 8 #endif
 9     "M25P64_STM3210E-EVAL",         // Device Name + version number
10     SPI_FLASH,                      // Device Type
11     0x00000000,                     // Device Start Address
12     0x00800000,                     // Device Size in Bytes (8MBytes/64Mbits)
13     0x00000100,                     // Programming Page Size 16Bytes
14     0xFF,                           // Initial Content of Erased Memory
15 // Specify Size and Address of Sectors (view example below)
16     0x00000080, 0x00010000,         // Sector Num : 128 ,Sector Size: 64KBytes
17     0x00000000, 0x00000000,
18 };
19 
20 /*                                  Sector coding example
21     A device with succives 16 Sectors of 1KBytes, 128 Sectors of 16 KBytes,
22     8 Sectors of 2KBytes and 16384 Sectors of 8KBytes
23 
24     0x00000010, 0x00000400,         // 16 Sectors of 1KBytes
25     0x00000080, 0x00004000,         // 128 Sectors of 16 KBytes
26     0x00000008, 0x00000800,         // 8 Sectors of 2KBytes
27     0x00004000, 0x00002000,         // 16384 Sectors of 8KBytes
28     0x00000000, 0x00000000,         // end
29   */

Loader_Src.c

  1 #include "stm32f10x.h"
  2 #include "stm32_eval_spi_flash.h"
  3 #include "stm3210e_eval.h"
  4 
  5 
  6 /**
  7   * Description :
  8   * Initilize the MCU Clock, the GPIO Pins corresponding to the
  9   * device and initilize the FSMC with the chosen configuration
 10   * Inputs    :
 11   *      None
 12   * outputs   :
 13   *      R0     : "1"             : Operation succeeded
 14   *               "0"             : Operation failure
 15   * Note: Mandatory for all types of device
 16   */
 17 int Init (void)
 18 {
 19     SystemInit();
 20     sFLASH_Init();
 21     return 1;
 22 }
 23 
 24 
 25 /**
 26   * Description :
 27   * Read data from the device
 28   * Inputs    :
 29   *      Address       : Write location
 30   *      Size          : Length in bytes
 31   *      buffer        : Address where to get the data to write
 32   * outputs   :
 33   *      R0     : "1"             : Operation succeeded
 34   *               "0"             : Operation failure
 35   * Note: Mandatory for all types except SRAM and PSRAM
 36   */
 37 int Read (uint32_t Address, uint32_t Size, uint8_t* buffer)
 38 {
 39     sFLASH_ReadBuffer(buffer, Address, Size);
 40     return 1;
 41 }
 42 
 43 
 44 /**
 45   * Description :
 46   * Write data from the device
 47   * Inputs    :
 48   *      Address       : Write location
 49   *      Size          : Length in bytes
 50   *      buffer        : Address where to get the data to write
 51   * outputs   :
 52   *      R0           : "1"             : Operation succeeded
 53   *                     "0"             : Operation failure
 54   * Note: Mandatory for all types except SRAM and PSRAM
 55   */
 56 int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
 57 {
 58     sFLASH_WriteBuffer(buffer, Address, Size);
 59     return 1;
 60 }
 61 
 62 
 63 /**
 64   * Description :
 65   * Erase a full sector in the device
 66   * Inputs    :
 67   *     None
 68   * outputs   :
 69   *     R0     : "1" : Operation succeeded
 70   *              "0" : Operation failure
 71   * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH
 72   */
 73 int MassErase (void)
 74 {
 75     sFLASH_EraseBulk();
 76     return 1;
 77 }
 78 
 79 /**
 80   * Description :
 81   * Erase a full sector in the device
 82   * Inputs    :
 83   *      SectrorAddress    : Start of sector
 84   *      Size          : Size (in WORD)
 85   *      InitVal       : Initial CRC value
 86   * outputs   :
 87   *     R0     : "1" : Operation succeeded
 88   *              "0" : Operation failure
 89   * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH
 90   */
 91 int SectorErase (uint32_t EraseStartAddress, uint32_t EraseEndAddress)
 92 {
 93     EraseStartAddress = EraseStartAddress -  EraseStartAddress % 0x10000;
 94 
 95     while (EraseEndAddress >= EraseStartAddress) {
 96         sFLASH_EraseSector(EraseStartAddress);
 97         EraseStartAddress += 0x10000;
 98     }
 99 
100     return 1;
101 }
102 
103 /**
104   * Description :
105   * Calculates checksum value of the memory zone
106   * Inputs    :
107   *      StartAddress  : Flash start address
108   *      Size          : Size (in WORD)
109   *      InitVal       : Initial CRC value
110   * outputs   :
111   *     R0             : Checksum value
112   * Note: Optional for all types of device
113   */
114 uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal)
115 {
116     uint8_t missalignementAddress = StartAddress % 4;
117     uint8_t missalignementSize = Size ;
118     int cnt;
119     uint32_t Val;
120     uint8_t value;
121 
122     StartAddress -= StartAddress % 4;
123     Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4);
124 
125     for(cnt = 0; cnt < Size ; cnt += 4) {
126         sFLASH_ReadBuffer(&value, StartAddress, 1);
127         Val = value;
128         sFLASH_ReadBuffer(&value, StartAddress + 1, 1);
129         Val += value << 8;
130         sFLASH_ReadBuffer(&value, StartAddress + 2, 1);
131         Val += value << 16;
132         sFLASH_ReadBuffer(&value, StartAddress + 3, 1);
133         Val += value << 24;
134 
135         if(missalignementAddress) {
136             switch (missalignementAddress) {
137                 case 1:
138                     InitVal += (uint8_t) (Val >> 8 & 0xff);
139                     InitVal += (uint8_t) (Val >> 16 & 0xff);
140                     InitVal += (uint8_t) (Val >> 24 & 0xff);
141                     missalignementAddress -= 1;
142                     break;
143 
144                 case 2:
145                     InitVal += (uint8_t) (Val >> 16 & 0xff);
146                     InitVal += (uint8_t) (Val >> 24 & 0xff);
147                     missalignementAddress -= 2;
148                     break;
149 
150                 case 3:
151                     InitVal += (uint8_t) (Val >> 24 & 0xff);
152                     missalignementAddress -= 3;
153                     break;
154             }
155         } else if((Size - missalignementSize) % 4 && (Size - cnt) <= 4) {
156             switch (Size - missalignementSize) {
157                 case 1:
158                     InitVal += (uint8_t) Val;
159                     InitVal += (uint8_t) (Val >> 8 & 0xff);
160                     InitVal += (uint8_t) (Val >> 16 & 0xff);
161                     missalignementSize -= 1;
162                     break;
163 
164                 case 2:
165                     InitVal += (uint8_t) Val;
166                     InitVal += (uint8_t) (Val >> 8 & 0xff);
167                     missalignementSize -= 2;
168                     break;
169 
170                 case 3:
171                     InitVal += (uint8_t) Val;
172                     missalignementSize -= 3;
173                     break;
174             }
175         } else {
176             InitVal += (uint8_t) Val;
177             InitVal += (uint8_t) (Val >> 8 & 0xff);
178             InitVal += (uint8_t) (Val >> 16 & 0xff);
179             InitVal += (uint8_t) (Val >> 24 & 0xff);
180         }
181 
182         StartAddress += 4;
183     }
184 
185     return (InitVal);
186 }
187 
188 
189 /**
190   * Description :
191   * Verify flash memory with RAM buffer and calculates checksum value of
192   * the programmed memory
193   * Inputs    :
194   *      FlashAddr     : Flash address
195   *      RAMBufferAddr : RAM buffer address
196   *      Size          : Size (in WORD)
197   *      InitVal       : Initial CRC value
198   * outputs   :
199   *     R0             : Operation failed (address of failure)
200   *     R1             : Checksum value
201   * Note: Optional for all types of device
202   */
203 uint64_t Verify (uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size, uint32_t missalignement)
204 {
205     uint32_t InitVal = 0;
206     uint32_t VerifiedData = 0;
207     uint8_t TmpBuffer = 0x00;
208     uint64_t checksum;
209     Size *= 4;
210 
211     checksum = CheckSum((uint32_t)MemoryAddr + (missalignement & 0xf), Size - ((missalignement >> 16) & 0xF), InitVal);
212 
213     while (Size > VerifiedData) {
214         sFLASH_ReadBuffer(&TmpBuffer, MemoryAddr + VerifiedData, 1);
215 
216         if (TmpBuffer != *((uint8_t*)RAMBufferAddr + VerifiedData))
217             return ((checksum << 32) + MemoryAddr + VerifiedData);
218 
219         VerifiedData++;
220     }
221 
222     return (checksum << 32);
223 }

修改好适配自己的硬件接口,编译会生成 .stldr格式的烧写算法文件,实际是通过如下命令生成的

用法:烧写程序时选择刚才生成的算法文件即可

 

烧录方法总结

IDE烧写方式通常在功能开发验证阶段使用,且在有UI资源如字库图片时并不方便,在项目量产时效率低下

故需要借助专用工具,如J-Flash、ST工具CubeProgrammer,若有多个文件需要烧写时,就需要做文件合并准备

文件合并方法众多

  • 可使用J-Flash、CubeProgranmmer工具的文件另存为,将裸文件bin转为带地址信息的hex,然后可徒手撸,即直接将文件复制粘贴合并,亦可通过J-Flash的文件合并功能
  • 可借助合并工具

  

  

具体可参考:

求助硬汉app和boot合并成一个bin文件问题 - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz! (armbbs.cn)

二进制文件合并工具1.1 - 开发环境 - 硬汉嵌入式论坛 - Powered by Discuz! (armbbs.cn)

用 C++ Builder XE7 开发的 文件合并助手。用来合并图片,字库等文件非常方便(2021-04-25升级至V0.3) - 开发环境 - 硬汉嵌入式论坛 - Powered by Discuz! (armbbs.cn)

 

确保合并后文件烧写到各自指定地址,需要修改烧写算法支持

// 地址信息指定,确保地址范围包括个文件烧写地址
struct FlashDevice const FlashDevice  = {
	0x00000000,                 // Device Start Address
	0x01000000,                 // Device Size in Bytes
    
}

// 擦除接口根据各文件地址做对应处理,比如mcu内部flash、外部spi-flash
int erase(unsigned long addr)
{
    if (addr < spi_flash_address) {
        // 擦除内部flash
    } else {
        // 擦除外部flash
    }
}

// 烧写接口同擦除,地址来源hex文件
int progame(unsigned long addr)
{
    if (addr < spi_flash_address) {
        // 擦除内部flash
    } else {
        // 擦除外部flash
    }
}

 

posted @ 2020-11-03 23:43  壹点灵异  阅读(15268)  评论(0编辑  收藏  举报