STM32 SPI Flash DFU

2024-06-04 18:38
文章标签 stm32 flash spi dfu

本文主要是介绍STM32 SPI Flash DFU,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这次讲的是将程序、图片或其他文件下载到SPI Flash中。我使用的是W25X16的SPI Flash,他共有2MB空间,2个Block,512ge Sector,8096个Page。由于SPI Flash不能直接跑程序,我们从接口就知道了。
接下去我们就来讲讲怎么编写SPI flash的升级功能。这次的工程是基于之前的Internal Flash修改而来的。修改的部分主要在USB_User组里:
STM32 SPI Flash DFU - ziye334 - ziye334的博客我只将改改的部分。
hw_config.c、usb_istr.c、usb_prop.c、usb_pwr.c这介个文件没有什么还修改的。usb_desc.c文件需要修改下接口字符串描述符,由于我们的SPI Flash空间2M,所以我们将SPI Flash的2M空间全部设置成可读可写可擦除。

/*接口字符串描述符*/ uint8_t DFU_StringInterface0[DFU_SIZ_STRING_INTERFACE0] = { DFU_SIZ_STRING_INTERFACE0, 0x03, //Interface 1: "@ SPI Flash: W25X16 /0x00000000/1*2048kg '@', 0, 'S', 0, 'P', 0, 'I', 0, ' ', 0, 'F', 0, 'l', 0, 'a', 0, 's', 0, /*18*/ 'h', 0, ' ', 0, ':', 0, ' ', 0, 'W', 0, '2', 0, '5', 0, 'X', 0, '1', 0, '6', 0, /*20*/ '/', 0, '0', 0, 'x', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0,/*22*/ '/', 0, '1', 0, '*', 0, '2', 0, '0', 0, '4', 0, '8', 0, 'K', 0, 'g', 0 /*18*/ };

接下去,添加我们的W25X16 SPI Flash的驱动代码spi_flash.c,这个代码可以网上下载。接下去将上个工程里的flash—_if.c文件修改成spi_if.c,并修改里面的函数:

/******************************************************************************* * Function Name : SPI_If_Init * Description : Initializes the Media on the STM32 * Input : None * Output : None * Return : None *******************************************************************************/ uint16_t SPI_If_Init(void) { SPI_Flash_Init(); return MAL_OK; }/******************************************************************************* * Function Name : SPI_If_Erase * Description : Erase sector * Input : None * Output : None * Return : None *******************************************************************************/ uint16_t SPI_If_Erase(uint32_t SectorAddress) { printf("正在擦除SPI Flash...\r\n"); SPI_Flash_Erase_Chip(); // SPI_Flash_Erase_Sector(SectorAddress); printf("擦除成功!\r\n"); return MAL_OK; }/******************************************************************************* * Function Name : SPI_If_Write * Description : Write sectors * Input : None * Output : None * Return : None *******************************************************************************/ uint16_t SPI_If_Write(uint32_t SectorAddress, uint32_t DataLength) { uint32_t idx, pages; printf("SPI_IFWrite写入数据长度为%d\r\n",DataLength); pages = (((DataLength & 0xFF00)) >> 8); if (DataLength & 0xFF) /* Not a 256 aligned data */ { for ( idx = DataLength; idx < ((DataLength & 0xFF00) + 0x100) ; idx++) // idx = DataLength; idx < ((DataLength & 0xFF00) + 0x100) ; idx++ { MAL_Buffer[idx] = 0xFF; } pages = (((DataLength & 0xFF00)) >> 8 ) + 1; } for (idx = 0; idx < pages; idx++) { printf("正在向0x%x地址写数据\r\n",SectorAddress); SPI_Flash_Write(&MAL_Buffer[idx*256], SectorAddress, 256); SectorAddress += 0x100; } return MAL_OK; }/******************************************************************************* * Function Name : SPI_If_Read * Description : Read sectors * Input : None * Output : None * Return : buffer address pointer *******************************************************************************/ uint8_t *SPI_If_Read(uint32_t SectorAddress, uint32_t DataLength) { printf("正在读取地址0x%x处开始的%d个数据\r\n",SectorAddress,DataLength); SPI_Flash_Read(MAL_Buffer, SectorAddress, (uint16_t)DataLength); return MAL_Buffer; }

然后要修改的是dfu_mal.c这个文件。修改成如下就可以了:

/******************************************************************************* * Function Name : MAL_Init * Description : STM32初始化的媒体初始化 * Input : None * Output : None * Return : None *******************************************************************************/ uint16_t MAL_Init(void) { SPI_If_Init(); /* SPI Flash */ return MAL_OK; }/******************************************************************************* * Function Name : MAL_Erase * Description : 擦除扇区 * Input : None * Output : None * Return : None *******************************************************************************/ uint16_t MAL_Erase(uint32_t SectorAddress) { switch (SectorAddress & MAL_MASK) //参看地址 { case SPI_FLASH_BASE: pMAL_Erase = SPI_If_Erase; break; default: return MAL_FAIL; } return pMAL_Erase(SectorAddress); //指向擦除函数 }/******************************************************************************* * Function Name : MAL_Write * Description : 写扇区 * Input : None * Output : None * Return : None *******************************************************************************/ uint16_t MAL_Write (uint32_t SectorAddress, uint32_t DataLength) { switch (SectorAddress & MAL_MASK) //查看地址 { case SPI_FLASH_BASE: pMAL_Write = SPI_If_Write; break; default: return MAL_FAIL; } return pMAL_Write(SectorAddress, DataLength);//调用写扇区函数 }/******************************************************************************* * Function Name : MAL_Read * Description : 度扇区 * Input : None * Output : None * Return : Buffer pointer *******************************************************************************/ uint8_t *MAL_Read (uint32_t SectorAddress, uint32_t DataLength) { switch (SectorAddress & MAL_MASK) //查看地址 { case SPI_FLASH_BASE: pMAL_Read = SPI_If_Read; break; default: return 0; } return pMAL_Read (SectorAddress, DataLength);//调用如扇区函数 }/******************************************************************************* * Function Name : MAL_GetStatus * Description : 获取状态 * Input : None * Output : None * Return : MAL_OK *******************************************************************************/ uint16_t MAL_GetStatus(uint32_t SectorAddress , uint8_t Cmd, uint8_t *buffer) { //更具地址查找定时表的对应的选项 uint8_t x = (SectorAddress >> 26) & 0x03 ; /* 0x000000000 --> 0 */ /* 0x640000000 --> 1 */ /* 0x080000000 --> 2 */ uint8_t y = Cmd & 0x01; SET_POLLING_TIMING(TimingTable[x][y]); /* x: 擦除/写 定时 */ /* y: Media */ return MAL_OK; }

最后的话,就是我们的main函数了,这里的main函数当然没有程序跳转了,我在这里用到了4个按键,
WAKEUP按键(PA0)按下表示向spi flash的0地址写入一组数据
TAMPER按键(PC13)按下表示读取0地址开始的数据
USER1按键(PA8)按下表示擦写0地址开始的那个扇区数据
USER2按键(PD3)按下表示向spi flash的0地址写入另一组数据
这样的话,就可以试试检测spi flash 读写是否正确了。

uint8_t DeviceState; uint8_t DeviceStatus[6];u8 WRITE_Buffer[]="神舟III号 SPI 读写访问程序"; //spi flash写入数据缓存 u8 WRITE_Buffer1[]="神舟I号 SPI 读写访问程序"; //spi flash写入数据缓存 u8 READ_Buffer[sizeof(WRITE_Buffer)]; //spi flash读出数据缓存/******************************************************** 函数:main() 描述:程序入口地址 参数:无 返回:无 ********************************************************/ int main(void) { BSP_Init(); printf(" |===============================================|\r\n"); printf(" STM32 DFU 程序开始 \r\n"); printf("|===============================================|\r\n"); SPI_Flash_Init(); { u32 i; i=SPI_Flash_ReadID(); //读取spi flash的芯片ID,一定要读,否则读写会出错 printf("ID:%x\r\n",i); } /* Enter DFU mode */ DeviceState = STATE_dfuERROR; //程序指向到这句话,说明DFU跳转不成功 DeviceStatus[0] = STATUS_ERRFIRMWARE; DeviceStatus[4] = DeviceState; USB_Configuration(); //初始化USB while(1) { if(KEY1_STATE()==0) //按键1按下,则向spi flash写入数据 { while(KEY1_STATE()==0); printf("开始写入W25X16 SPI FLASH芯片!\r\n"); SPI_Flash_Erase_Sector(0); SPI_Flash_Write(WRITE_Buffer,0,sizeof(WRITE_Buffer)); printf("写入完成!\r\n"); } if(KEY2_STATE()==0) //按键2按下,读出spi flash的数据 { while(KEY2_STATE()==0); printf("开始从W25X16 SPI FLASH芯片中读取数据!\r\n"); SPI_Flash_Read(READ_Buffer,0,sizeof(READ_Buffer)); printf("读取完成,读书的数据为:\r\n%s\r\n",READ_Buffer); } if(KEY3_STATE()==0) //按键3按下,擦除整块spi flash数据 { u8 i; while(KEY3_STATE()==0); printf("正在擦除W25X16 SPI FLASH芯片!\r\n"); SPI_Flash_Erase_Sector(0); // SPI_Flash_Erase_Chip(); printf("擦除完毕!\r\n"); for(i=0;i<sizeof(READ_Buffer);i++) { READ_Buffer[i]=0; } } if(KEY4_STATE()==0) //按键1按下,则向spi flash写入数据 { while(KEY4_STATE()==0); printf("开始写入W25X16 SPI FLASH芯片!\r\n"); SPI_Flash_Erase_Sector(0); SPI_Flash_Write(WRITE_Buffer1,0,sizeof(WRITE_Buffer1)); printf("写入完成!\r\n"); } } }


这个工程需要注意的是 *.dfu文件的制作,因为spi flash是外界的存储器,所以与单片机存储地址独立编址,即从0x00000000地址开始到0x001fffffff结束,所以在制作.dfu的时候,千万要设置地址在这个范围内。

这篇关于STM32 SPI Flash DFU的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1030806

相关文章

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

什么是 Flash Attention

Flash Attention 是 由 Tri Dao 和 Dan Fu 等人在2022年的论文 FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness 中 提出的, 论文可以从 https://arxiv.org/abs/2205.14135 页面下载,点击 View PDF 就可以下载。 下面我

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

基于stm32的河流检测系统-单片机毕业设计

文章目录 前言资料获取设计介绍功能介绍具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机设计精品

STM32的使用方法一

注:我采用的是STM32F103RC芯片、相应的电路图和STM32CubeIDE软件这是在STM32CubeIDE软件定义芯片后,所给的必要的代码逻辑,加上了注释 #include "main.h"/* Private variables ---------------------------------------------------------*//* Private function

STM32 HAL CAN通讯 实操

1、简介 相比于串口通讯,对于刚接触CAN通讯的小白来说,CAN通讯相对复杂,看各种视频、帖子理论,总是一知半解。本次通过傻瓜式操作,先实现CAN通讯的交互,以提高小白的信心,也便于自己复习观看。本次以STM32CubeMX进行初始化配置,通过Keil 5软件进行软件设计,通过CAN盒实现进行数据的交互。该流程实际以STM32F0、F1、F3、F4、F7实测好用(理论上都适用),这三种型号单片机