STM32 SPI Flash DFU

发布者:xi24最新更新时间:2016-12-20 来源: eefocus关键字: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

{

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 引用地址:STM32 SPI Flash DFU

上一篇:STM32 Internal Flash DFU芯片内部flash代码升级
下一篇:STM32 Nor Flash DFU

推荐阅读最新更新时间:2024-03-16 15:26

STM32G0技术详解 _ SPI-RTC-ADC
对于SPI,STM32G0和STM32F0系列一样,还实现了一些小增强。G0主要是高度可配置,而且还支持标准的同步协议,优势表现在它仅需要少数引脚、使外部组件和MCU连接简单。 主要特性 SPI支持主或从模式(支持多主和多从)、全双工、单向或半双工、支持Motorola和TI标准。 它的最小接口只需要2根线,可配置数据和时钟格式,额外的协议层支持(Tx和Rx FIFOs,DMA,CRC),具有各种中断事件及标志。 模块简化框图 从图中可以看出,SPI一共有4个I/O引脚,分别为MOSI、MISO、SCK、NSS,所有的数据都是通过特定的接口传送到接收或者发送缓冲区,然后控制部分可以通过配置启用或者禁用。 SPI节
[单片机]
STM32G0技术详解 _ <font color='red'>SPI</font>-RTC-ADC
stm32中DMA基本使用
DMA有什么用? 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。 有多少个DMA资源? 有两个DMA控制器,DMA1有7个通道,DMA2有5个通道。 数据从什么地方送到什么地方? 外设到SRAM(I2C/UART等获取数据并送入SRAM); SRAM的两个区域之间; 外设到外设(ADC读取数据后送到TIM1控制其产生不同的PWM占空比); SRAM到外设(SRAM中预先保存的数据送入DAC产生各种波形); 还有一些目前还搞不清楚的。 DMA可以传递多少数
[单片机]
<font color='red'>stm32</font>中DMA基本使用
STM32:STM32学习记录6: IWDG
配置流程: 1:系统时钟初始化,包括系统时钟和要开放的IO口或者功能的时钟配置。 2:IO口初始化,包括引脚,速率,输入输出模式等。 3:初始化看门狗。 注意: 注意如何操作喂狗!!! #include stm32f10x.h #include stm32f10x_iwdg.h #define LED0_OFF GPIO_SetBits(GPIOA,GPIO_Pin_8) // LED0关 #define LED0_ON GPIO_ResetBits(GPIOA,GPIO_Pin_8)//LED0开 //初始化IO端口 void IO_Configuart(void) { GPIO_Ini
[单片机]
STM32芯片无法正常工作的现象及原因分析集锦
最近一年多开始使用STM32F4系列芯片,在使用开发板、评估板的时候一切正常,但当自己做板子的时候事故频发,最典型的就是无法启动、无法刷机,现将遇到的几个无法启动的原因分析如下: 1、芯片引脚短路 这是最典型的现象,也是最常见的原因,一般不工作的时候第一反应就是检查是否发生短路,短路引发芯片无法正常工作。 2、芯片VCAP引脚没有接电容 有一次自己做的板子,忘记在VCAP引脚引出电容,导致一直无法工作,经查Datasheet,发现VCAP引脚是专为芯片内部1.2V区域供电所用,若没有引出电容,1.2V区域将无法正常工作。 3、芯片VDDA(VREF)引脚没有供电 一次做AD转换,为求精确,将VDDA(VREF)引脚接上
[单片机]
<font color='red'>STM32</font>芯片无法正常工作的现象及原因分析集锦
STM32学习笔记:【002】BIN文件通过ST-LINK烧录STM32芯片
以下提供2种下载方式 KEIL编译下载 KEIL 5 在开发中还算是比较强大的一种平台。在开发中通过编译再下载会显得很方便。 尽管这个是老生常谈的问题,但还是在这里补全这个设置步骤 1.点击“魔法棒” 2.Debug 设置 ST官方下载方式 有时候,我们通过各种途径得到了一个bin或者hex文件(比如使用了 embed在线编译器 生成bin文件),那么我们应该怎么样把它烧录到板子中呢? 下面介绍由ST官方下载器烧录bin或者hex到开发板的过程 烧录文件:BIN、或者HEX文件 烧录方式:ST-LINK 烧录芯片:STM32F429I 烧录准备: 1.开发板自带的一根USB线 2.官方烧录软件: STM32
[单片机]
<font color='red'>STM32</font>学习笔记:【002】BIN文件通过ST-LINK烧录<font color='red'>STM32</font>芯片
STM32 驱动无线NRF24L01 的稳定修正
修正处 void sent_data(u8* fp,u16 flong) { u16 i; TX_Mode((u8*)&flong); //传送长度 while(!tran); //等待完成 tran=0; flong=flong/33+1; while(flong) { for(i=0;i 20000;i++); //这个延时的非常必要 大约2MS 左右 if(MAX_RT) return;//无应答返回 TX_Mode(fp); //传送数据 while(!tran); //等待完成 tran=0; fp+=32;flong--; } } 更加合理的延时写法 ,发送分两部分 首先发送内容长度
[单片机]
<font color='red'>STM32</font> 驱动无线NRF24L01 的稳定修正
STM32笔记--使用ST-Link下载hex文件
嵌入式产品开发过程中,日常使用ST-Link下载程序时都是在MDK编译器中下载源代码,但ST-Link其实也可以直接下载hex文件,STM32官方就有提供一个ST-Link下载程序的工具STM32 ST-LINK Utility,只需三步,就能将hex文件下载到单片机中,相比使用串口下载hex文件繁琐的步骤操作,真香 1 ST-LINK Utility下载安装 1.1 下载ST-LINK Utility ST-LINK Utility是意法半导体提供的开源工具,直接在意法半导体官网即可下载 下载链接:https://www.st.com/en/development-tools/stsw-link004.html 下载界面
[单片机]
<font color='red'>STM32</font>笔记--使用ST-Link下载hex文件
基于CC/CCS的Flash文件系统设计
摘要:在深入分析TI为开发DSP提供的RTS.LIB(RTS.SRC为源泉代码)的基础上,介绍对自定义的文件和设备的操作方法;设计一个简易的Flash文件系统,极大地方便了应用编程。 关键词:DSP CC/CCS Flash 文件系统 1 概述 在开发DSP的应用程序过程中,经常需要处理一些数据文件。这些数据文件可以是实际采集到的数据集合,也可以是用模拟仿真软件产生的数据集合,一般是以文件的形式存放在主机磁盘上的。一般的开发环境(如TI的CCS和CC)都提供了ANSI C标准操作文件格式,如打开一个文件fopen("盘符:路径文件名",“打开模式”)。嵌入式系统一般都外挂Flash。我们希望能够和读写主机磁盘文件一样操作Fl
[应用]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved