历史上的今天
返回首页

历史上的今天

今天是:2024年11月04日(星期一)

正在发生

2020年11月04日 | STM32 SPI Flash DFU

2020-11-04 来源:eefocus

这次讲的是将程序、图片或其他文件下载到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...rn");

SPI_Flash_Erase_Chip();

// SPI_Flash_Erase_Sector(SectorAddress);

printf("擦除成功!rn");

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写入数据长度为%drn",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地址写数据rn",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个数据rn",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(" |===============================================|rn");

printf("                  STM32 DFU 程序开始              rn");

printf("|===============================================|rn");

SPI_Flash_Init();

{

u32 i;

i=SPI_Flash_ReadID();    //读取spi flash的芯片ID,一定要读,否则读写会出错

printf("ID:%xrn",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芯片!rn");  

SPI_Flash_Erase_Sector(0);

SPI_Flash_Write(WRITE_Buffer,0,sizeof(WRITE_Buffer));

printf("写入完成!rn");

}

if(KEY2_STATE()==0)    //按键2按下,读出spi flash的数据

{

while(KEY2_STATE()==0);

printf("开始从W25X16 SPI FLASH芯片中读取数据!rn");

SPI_Flash_Read(READ_Buffer,0,sizeof(READ_Buffer));

printf("读取完成,读书的数据为:rn%srn",READ_Buffer);

}

if(KEY3_STATE()==0)    //按键3按下,擦除整块spi flash数据

{ u8 i;

while(KEY3_STATE()==0);

printf("正在擦除W25X16 SPI FLASH芯片!rn");

SPI_Flash_Erase_Sector(0);

// SPI_Flash_Erase_Chip();

printf("擦除完毕!rn");

for(i=0;i {

READ_Buffer[i]=0;

推荐阅读

史海拾趣

Hosiden Corporation公司的发展小趣事

Hosiden Corporation的创立可以追溯到其早期作为电子元器件制造商的起步阶段。公司自成立以来,便专注于电子连接器和电缆的研发与生产,逐步在汽车电子、医疗和工业市场等领域建立起稳固的市场地位。通过不断的技术积累和产品质量提升,Hosiden逐渐在竞争激烈的电子行业中崭露头角。

CUI公司的发展小趣事

在全球化的背景下,电子行业中的CUI技术也呈现出国际合作与竞争并存的局面。一些国内企业通过与国际知名企业的技术合作,引进先进的CUI生产线和工艺,提高了自身的技术水平和市场竞争力。同时,国际市场的竞争也促使国内企业不断创新,寻求差异化的发展道路。

川土(Chipanalog)公司的发展小趣事

经过数月的紧张研发与测试,川土微电子成功推出了其首款自研产品——一款高性能的隔离器芯片。这款芯片的问世不仅填补了国内市场的空白,也标志着川土微电子在模拟芯片领域的初步成功。随后,公司开始逐步扩大产品线,涵盖了接口、高性能模拟等多个系列。

Chip Technologies Inc公司的发展小趣事

为了进一步扩大市场份额,Chip Technologies Inc积极寻求与国际知名企业的合作。通过与这些企业建立战略合作关系,公司不仅获得了更多的技术支持和市场资源,还成功将产品推向了全球市场。这些合作不仅提升了公司的品牌知名度,也为公司的长期发展奠定了坚实的基础。

FASTRAX公司的发展小趣事

1999年,FASTRAX在芬兰赫尔辛基成立,专注于为全球设备生产商和设计商提供高性能的GPS接收模块。公司凭借对GNSS技术的深入理解,迅速在市场中崭露头角。其首创的带天线GPS接收模块以其高效、稳定的性能,赢得了客户的广泛赞誉。

Advanced Thermal Solutions公司的发展小趣事

随着市场需求的不断增长,ATS意识到单纯的咨询服务已无法满足客户的全面需求。于是,公司决定转型为一家完整的散热解决方案提供商。ATS开始投入大量资源进行产品设计和制造,不断推出创新型的散热器产品。这些产品凭借高性能和卓越的质量,在市场中迅速脱颖而出,ATS也逐渐在电子产品热管理领域建立了领先地位。

问答坊 | AI 解惑

RF公司:手机射频芯片发展最新趋势及动向

RF Micro Device公司高级市场经理 Brent Wilkins    今天的新一代蜂窝电话设计越来越复杂,需要提供多频段、多模式支持,具有蓝牙个人区域网络、GPS定位、WLAN等功能,而且超宽带和电视接收功能已经开始出现,此外像游戏、图像、音频和视频 ...…

查看全部问答>

工程师调查表

尊敬的工程师会员,您好! 请您帮助我们网站建设技术频道,我们需要您最最权威的数据。请您按照自己的想法填写附件表格并反馈给我们,对于您提供的信息,我们一定是慎重参考!非常感谢你们!你们的回复是我们网站发展的动力。…

查看全部问答>

上海KT人才现受某美资公司委托招聘RF相关人才

上海KT人公司是中国最大最专业的IC电子人才咨询公司之一,多年来专注于IC与电子行业中高级人才服务,客户主要为欧美著名半导体公司(如TI、ADI、LSI、Cisco、Conexant等)和美资集成电路设计新公司共20多家,主要寻找IC设计、芯片制造、IC市场与销 ...…

查看全部问答>

上传一个HDD/PLAYER/ESS方案

上传一个HDD/PLAYER/ESS方案,可惜没有SCH,用PADS2005打开,ASC可以用PROTEL99导入.…

查看全部问答>

怎么没有这样的主板?

1、支持wince5.0可使用 .net + sqlce2.0 开发应用程序; 2、必须的外部接口包括:usb、以太网接口、打印串口 3、能控制按键音、报警音 4、能控制屏幕背光 5、需支持对5v左右电压的电池或电板充电 6、128X128支持汉显屏幕 7、主板长宽…

查看全部问答>

8259a 是否只支持硬件中断

如题?所支持哪些类型中断 谢谢…

查看全部问答>

<50元的FPGA核心板,会否有朋友顶啊?

    近来忙着家事,有一段时间没有上来了,今天顺着2011-1-11,这么多棍棍的日子,上来溜达一下。     看到自从夏老师到网站上来座镇解答FPGA的相关问题,网站上FPGA的热情洋溢,很有气氛,觉得这里有蛮多朋友 ...…

查看全部问答>

有没申请过Cosmic公司免费的ST16K代码限制的编译器的?

一般申请要多久才能批呀还有申请时要注意什么我都申请快一天了这么还没呀…

查看全部问答>