STM32CubeProgrammer STM32CubeIDE下载算法 外部存储QSPI Flash

随言:

在外地出差,闲着也是闲着,写写笔记。

STM32CubeIDE QSPI间接模式和内存映射模式 读写W25Q64:STM32CubeIDE QSPI间接模式和内存映射模式 读写W25Q64_sudaroot的博客-优快云博客_qspi内存映射

MDK KEIL 下载算法外部存储QSPI FLASH:MDK KEIL 下载算法程序 外部存储QSPI FLASH_sudaroot的博客-优快云博客

STM32CubeProgrammer STM32CubeIDE下载算法  外部存储QSPI Flash:STM32CubeProgrammer STM32CubeIDE下载算法 外部存储QSPI Flash_sudaroot的博客-优快云博客

理论来说,STM32CubeProgrammer和 STM32 ST-LINK Utility下载算法程序是一样的,都能相互使用。

但是不知道为什么,STM32CubeProgrammer调用外部存储下载程序没有问题,STM32 ST-LINK Utility调用却失败。

不过也没关系了。不过没关系了,生产就用STM32CubeProgrammer,开发就用STM32CubeIDE。

所以一开始我是以STM32 ST-LINK Utility的例程去编程,然后无论我怎么测试都不行。但是我把生成的stldr下载算法文件放到

STM32CubeProgrammer这个软件试试,结果能正常下载,真的是耽误了我不少时间。

至于STM32 ST-LINK Utility为什么不行,搜索了一下,都没找解决相关问题的资料,故我放弃了,改用STM32CubeProgrammer。

结束:

下面是已经编辑好的源码,

工程有HAL库版本的,寄存器版本的(移植某点原子)。

可以根据自己的硬件自行更改。

附上链接:STM32CubeProgrammerFlashAlgorithm.rar_stm32cubeide外部flash下载-嵌入式文档类资源-优快云下载

硬件:STM32H743IIT6 + W25Q64

        /**QUADSPI GPIO Configuration
        PF6     ------> QUADSPI_BK1_IO3
        PF7     ------> QUADSPI_BK1_IO2
        PF8     ------> QUADSPI_BK1_IO0
        PF9     ------> QUADSPI_BK1_IO1
        PB2     ------> QUADSPI_CLK
        PB6     ------> QUADSPI_BK1_NCS

正文:


1、资料

文档:

《UM0892 User manual STM32 ST-LINK utility software description》

例程:

我是用STM32 ST-LINK Utility安装路径下的N25Q512A_STM32F769I-EVAL,因为这个是用HAL库写的。

C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ExternalLoader\N25Q512A_STM32F769I-EVAL

2、Dev_Inf.c file

该文件中定义了存储信息结构。

下面显示了此构造函数定义的信息类型的示例:

#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo = {
#else
struct StorageInfo const StorageInfo = {
#endif
"External_Loader_Name",      // 设备名 + 版本号
MCU_FLASH,                   // 设备类型
0x08000000,                  // 设备开始地址
0x00100000,                  // 设备大小 (1MBytes/8Mbits)
0x00004000,                  // 页编程大小 16KBytes
0xFF,                        // 擦除后的默认值
// 指定扇区的大小和地址(下面的示例)
0x00000004, 0x00004000,      // Sector Num : 4 ,Sector Size: 16KBytes
0x00000001, 0x00010000,      // Sector Num : 1 ,Sector Size: 64KBytes
0x00000007, 0x00020000,      // Sector Num : 7 ,Sector Size: 128KBytes
0x00000000, 0x00000000,      // 结束

比如现在用的是W25Q64 是QSPI FLASH芯片,大小是8MByte,编程页大小是256字节,最小擦除单位是4KB。

下面我在编程页写4096字节,是为了提高写入的效率。

/* This structure containes information used by ST-LINK Utility to program and erase the device */
#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo  =
{
#else
struct StorageInfo const StorageInfo  =
{
#endif
    "STM32H743_W25Q64_REG", 	 	             // Device Name + version number
    SPI_FLASH,                  					   // Device Type    
    0x90000000,                						   // Device Start Address
    0x00800000,                 						 // Device Size in Bytes (8MBytes/64Mbits)
    0x1000,              						         // Programming Page Size 4096Bytes
    0xFF,                       						 // Initial Content of Erased Memory
// Specify Size and Address of Sectors (view example below)
    0x00000800, 0x00001000,     				  	 // Sector Num : 2048  ,Sector Size: 4KBytes
    0x00000000, 0x00000000,
};

3、Loader_Src.c file

  • int Init (void):Init函数,定义用于连接到外部存储器的GPIO,进行初始化,使用的IP的时钟。
  • int Write (uint32_t Address, uint32_t Size, uint8_t* buffer):它对用RAM范围内的地址定义的缓冲区进行编程。
  • int SectorErase (uint32_t StartAddress, uint32_t EndAddress):它擦除由起始地址和结束地址定义的存储扇区。
  • int Read (uint32_t Address, uint32_t Size, uint16_t* buffer):其中“地址” =读取操作的起始地址,“大小” =读取操作的大小,“缓冲区” =指向读取数据的指针。注意:对于QSPI / OSPI(Quad-SPI / Octo-SPI)存储器,可以在Init函数中定义存储器映射模式,在这种情况下,Read函数无效。
  • uint64_t Verify (uint32_t FlashAddr, uint32_t RAMBufferAddr, uint32_t Size):选择“编程时验证”模式时将调用此功能。这个功能检查编程的存储器是否对应于存储器中定义的缓冲区内存。
  • int MassErase (void):全部擦除,删除全部内存。

4、编程:

这次移植一下寄存器版本。HAL版本移植很简单,把缺失的文件补上,然后上根据硬件修改QSPI参数。

1、先把STM32 ST-LINK utility安装文件夹下的例程复制到桌面,重命名为test。

C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ExternalLoader\N25Q512A_STM32F769I-EVAL

2、重新选择芯片设备。

把红框的文件都删除了。

找到正点原子的寄存器QSPI测试代码。把下面文件夹的代码复制到我们的test文件夹,添加到工程中。

Dev_Inf.c 上面写出来了,下面是Loader_Src.c

#include "sys.h"
#include "sys.h"
#include "delay.h"
#include "w25qxx.h"
#include "led.h"
#include "qspi.h"
#include "usart.h"

#define		SPI_FLASH_CHECK		0x0FFFFFFF

/**
  * Description :
  * Initilize the MCU Clock, the GPIO Pins corresponding to the
  * device and initilize the FSMC with the chosen configuration
  * Inputs    :
  *      None
  * outputs   :
  *      R0             : "1" 			: Operation succeeded
  * 			  "0" 			: Operation failure
  * Note: Mandatory for all types of device
  */
int Init (void)
{
    __disable_irq(); 
    Stm32_Clock_Init(100, 1, 2, 2); //设置时钟,400Mhz
    delay_init(400);				//延时初始化
    W25QXX_Init();		            //初始化W25QXX
    
    return 1;
}


/**
  * Description :
  * Read data from the device
  * Inputs    :
  *      Address       : Write location
  *      Size          : Length in bytes
  *      buffer        : Address where to get the data to write
  * outputs   :
  *      R0             : "1" 			: Operation succeeded
  * 			  "0" 			: Operation failure
  * Note: Mandatory for all types except SRAM and PSRAM
  */
int Read (uint32_t Address, uint32_t Size, uint8_t* buffer)
{
    Address = Address & SPI_FLASH_CHECK;
    W25QXX_Read(buffer, Address, Size);
    return 1;
}


/**
  * Description :
  * Write data from the device
  * Inputs    :
  *      Address       : Write location
  *      Size          : Length in bytes
  *      buffer        : Address where to get the data to write
  * outputs   :
  *      R0           : "1" 			: Operation succeeded
  *                     "0" 			: Operation failure
  * Note: Mandatory for all types except SRAM and PSRAM
  */
int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
{
    Address = Address & SPI_FLASH_CHECK;
    W25QXX_Write_NoCheck(buffer, Address, Size);
    return 1;
}


/**
  * Description :
  * Erase a full sector in the device
  * Inputs    :
  *     None
  * outputs   :
  *     R0             : "1" : Operation succeeded
  * 			 "0" : Operation failure
  * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH
  */
int MassErase (void)
{
    W25QXX_Erase_Chip();
    return 1;
}

/**
  * Description :
  * Erase a full sector in the device
  * Inputs    :
  *      SectrorAddress	: Start of sector
  *      Size          : Size (in WORD)
  *      InitVal       : Initial CRC value
  * outputs   :
  *     R0             : "1" : Operation succeeded
  * 			 "0" : Operation failure
  * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH
  */
int SectorErase (uint32_t EraseStartAddress, uint32_t EraseEndAddress)
{
    EraseStartAddress = EraseStartAddress & SPI_FLASH_CHECK;
    EraseEndAddress = EraseEndAddress & SPI_FLASH_CHECK;
    EraseStartAddress = EraseStartAddress -  EraseStartAddress % W25QxJV_SUBSECTOR_SIZE;    //Erase 4KBytes

    while (EraseEndAddress >= EraseStartAddress)
    {
        W25QXX_Erase_Sector(EraseStartAddress);
        EraseStartAddress += W25QxJV_SUBSECTOR_SIZE;        //Erase 4KBytes
    }

    return 1;
}

/**
  * Description :
  * Calculates checksum value of the memory zone
  * Inputs    :
  *      StartAddress  : Flash start address
  *      Size          : Size (in WORD)
  *      InitVal       : Initial CRC value
  * outputs   :
  *     R0             : Checksum value
  * Note: Optional for all types of device
  */
uint32_t CheckSum(uint32_t StartAddress, uint32_t Size, uint32_t InitVal)
{
    uint8_t missalignementAddress = StartAddress % 4;
    uint8_t missalignementSize = Size ;
    int cnt;
    uint32_t Val;
    uint8_t value;
    StartAddress = StartAddress & SPI_FLASH_CHECK;
    StartAddress -= StartAddress % 4;
    Size += (Size % 4 == 0) ? 0 : 4 - (Size % 4);

    for(cnt = 0; cnt < Size ; cnt += 4)
    {
        W25QXX_Read(&value, StartAddress, 1);
        Val = value;
        W25QXX_Read(&value, StartAddress + 1, 1);
        Val += value << 8;
        W25QXX_Read(&value, StartAddress + 2, 1);
        Val += value << 16;
        W25QXX_Read(&value, StartAddress + 3, 1);
        Val += value << 24;

        if(missalignementAddress)
        {
            switch (missalignementAddress)
            {
                case 1:
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 1;
                    break;

                case 2:
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 2;
                    break;

                case 3:
                    InitVal += (uint8_t) (Val >> 24 & 0xff);
                    missalignementAddress -= 3;
                    break;
            }
        }
        else if((Size - missalignementSize) % 4 && (Size - cnt) <= 4)
        {
            switch (Size - missalignementSize)
            {
                case 1:
                    InitVal += (uint8_t) Val;
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    InitVal += (uint8_t) (Val >> 16 & 0xff);
                    missalignementSize -= 1;
                    break;

                case 2:
                    InitVal += (uint8_t) Val;
                    InitVal += (uint8_t) (Val >> 8 & 0xff);
                    missalignementSize -= 2;
                    break;

                case 3:
                    InitVal += (uint8_t) Val;
                    missalignementSize -= 3;
                    break;
            }
        }
        else
        {
            InitVal += (uint8_t) Val;
            InitVal += (uint8_t) (Val >> 8 & 0xff);
            InitVal += (uint8_t) (Val >> 16 & 0xff);
            InitVal += (uint8_t) (Val >> 24 & 0xff);
        }

        StartAddress += 4;
    }

    return (InitVal);
}


/**
  * Description :
  * Verify flash memory with RAM buffer and calculates checksum value of
  * the programmed memory
  * Inputs    :
  *      FlashAddr     : Flash address
  *      RAMBufferAddr : RAM buffer address
  *      Size          : Size (in WORD)
  *      InitVal       : Initial CRC value
  * outputs   :
  *     R0             : Operation failed (address of failure)
  *     R1             : Checksum value
  * Note: Optional for all types of device
  */
uint64_t Verify (uint32_t MemoryAddr, uint32_t RAMBufferAddr, uint32_t Size, uint32_t missalignement)
{
    uint32_t InitVal = 0;
    uint32_t VerifiedData = 0;
    uint8_t TmpBuffer = 0x00;
    uint64_t checksum;
    Size *= 4;
    MemoryAddr = MemoryAddr & SPI_FLASH_CHECK;
    checksum = CheckSum((uint32_t)MemoryAddr + (missalignement & 0xf), Size - ((missalignement >> 16) & 0xF), InitVal);

    while (Size > VerifiedData)
    {
        W25QXX_Read(&TmpBuffer, MemoryAddr + VerifiedData, 1);

        if (TmpBuffer != *((uint8_t*)RAMBufferAddr + VerifiedData))
            return ((checksum << 32) + MemoryAddr + VerifiedData);

        VerifiedData++;
    }

    return (checksum << 32);
}

在当前工程文件夹中生成stldr文件,cmd.exe /C copy "!L" ".\@L.stldr"

把生成好的stldr放到STM32CubeProgrammer安装文件夹的ExternalLoader里面。

打开STM32CubeProgrammer软件。如下图操作。

如果连接不上0x90000000,尝试多几次连接。

如果下载校验都成功,那么就成功了。

如果是使用STM32CubeIDE下载,则先要把stldr文件放到

C:\ ST \ STM32CubeIDE_1.3.0 \ STM32CubeIDE \ plugins \ com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_1.3.0.202002181050 \ tools \ bin \ ExternalLoader \

打开STM32CubeIDE软件,修改下载配置

如果擦除下载和校验都顺利的话,那么就成功了。

但是程序肯定不会运行的,缺少一个启动程序MemBoot。

同理,仿真也不行,必须有启动程序MemBoot才能仿真。

移植到其他芯片

如果移植到其他芯片的话,不是和我使用的H743一致,只需按照下面修改即可。

比如我借了一块的H750板子,下面是引脚分配图。FLASH芯片也是W25Q64

    PE2     ------> QUADSPI_BK1_IO2
    PB2     ------> QUADSPI_CLK
    PD11     ------> QUADSPI_BK1_IO0
    PD12     ------> QUADSPI_BK1_IO1
    PD13     ------> QUADSPI_BK1_IO3
    PB6     ------> QUADSPI_BK1_NCS 

以W25Q64_STM32H743I_HAL工程这个代码为例。

1、修改设备芯片STM32H750VB

2、修改QSPI引脚,因为H750板子还是W25Q64,并不是其他的芯片,故W25Q64驱动无需改动,否则改之。

把回调函数void HAL_QSPI_MspInit(QSPI_HandleTypeDef* hqspi)

void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* hqspi)引脚修改完成即可。

3、编译,放到STM32CubeProgrammer安装文件夹的ExternalLoader里面文件夹下面。

4、测试下载。

5、如果不成功有可能void SystemClock_Config(void)这个时钟函数有问题,

我一般是用Cube系列软件生成的,再粘贴过来。

  全篇完。

本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解,记录成长笔记。
笔记是以最简单的方式,只展示最核心的原理。
若有与 大神大大 见解有歧义,我绝对坚信 大神大大 见解是对的,我的是错的。
若无积分等无法下载源码,可加入QQ群657407920下载交流经验。感谢~!

 

 

### STM32 芯片烧录与擦除教程 #### 工具准备 为了实现STM32芯片的烧录与擦除操作,需准备好以下工具和环境配置: - **硬件设备**:ST-LINK调试器、目标开发板(如正点原子STM32F103 Nano开发板)、USB线缆。 - **软件工具**:STM32 ST-LINK Utility (V4.5.0.0)[^2] 或者 STM32CubeProgrammer (V2.4.0)[^1]。 - **编程环境**:Keil MDK (V5.23)。 --- #### 配置启动模式 在进行烧录前,需要设置STM32的目标芯片进入特定的工作模式。对于串口ISP烧录方式,通常通过调整引脚状态来完成: - 将`BOOT0`连接至`3.3V`,使能系统存储器引导模式。 - `BOOT1`保持接地(`GND`)。 - 使用串口模块时,确保其信号端子正确连接到MCU对应的UART接口上,具体如下: - RXD(接收数据) → MCU TX1(PA9) - TXD(发送数据) → MCU RX1(PA10) - GND → MCU GND[^3] 按上述方法完成后,按下复位按钮让单片机重新初始化并切换入相应工作状态以便后续程序加载过程顺利执行。 --- #### 利用STM32CubeProgrammer 进行外部QSPI Flash管理 针对更复杂的场景比如对外部QSPI Flash的操作,则可以借助于STM32CubeProgrammer这款多功能工具来进行深入处理。它不仅支持标准内部Flash写入删除功能还提供了额外选项用于访问外设资源像Quad SPI NOR Memories等类型器件。 以下是基本流程概述: 1. 打开STM32CubeProgrammer应用程序界面; 2. 在菜单栏选择合适的连接媒介——这里推荐采用SWD(Serial Wire Debug),因为它相比JTAG具有更低管脚需求同时保留高效性能表现; 3. 设置好波特率参数以及其他必要通信属性之后点击Connect建立链接关系; 4. 成功接入后可浏览左侧导航树形结构找到Memory标签页,在此区域能够发现有关Internal FLASH以及External QSPI Flash的相关条目; 5. 对应选定待操作对象然后依据实际业务逻辑实施相应的动作指令集例如Erase All Blocks或者Write Binary File等等命令项。 --- #### 借助STM32 ST-LINK Utility 实现基础固件部署 另一种常用手段即依靠官方出品的应用级图形化界面解决方案—STM32 ST-LINK Utility。该方案特别适合初学者快速入门学习阶段应用场合下使用。 主要步骤列举如下: 1. 启动STM32 ST-LINK Utility客户端窗口; 2. 确认当前已插上的stlink v2驱动被识别无误; 3. 加载预先编译好的bin/hex文件形式镜像文档; 4. 定义下载地址范围,默认情况下会自动填充为目标微控制器内置flash起始位置处; 5. 开启Download进程直至结束提示成功消息为止最后记得Reset & Run触发重启机制激活新安装进去的新版firmware代码片段生效运行起来。 --- ```python # 示例Python脚本模拟简单交互式控制台演示如何调用subprocess库配合stm32cubeprogrammer_cli命令行工具批量作业自动化程度提升效率案例分享 import subprocess def run_stm32_programmer_command(command_args): result = subprocess.run(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode != 0: raise Exception(f"Command failed with error:\n{result.stderr}") return result.stdout if __name__ == "__main__": try: output = run_stm32_programmer_command(["stm32cubeprogrammer_cli", "--connect", "port=swd freq=4000"]) print(output) erase_output = run_stm32_programmer_command(["stm32cubeprogrammer_cli", "--erase", "all"]) print(erase_output) write_output = run_stm32_programmer_command(["stm32cubeprogrammer_cli", "--write", "file=path/to/firmware.bin address=0x8000000 verify=yes"]) print(write_output) except Exception as e: print(e) ``` ---
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值