当前位置:首页 > 单片机 > 单片机
[导读]这次讲的是将程序、图片或其他文件下载到SPI Flash中。我使用的是W25X16的SPI Flash,他共有2MB空间,2个Block,512ge Sector,8096个Page。由于SPI Flash不能直接跑程序,我们从接口就知道了。接下去我们就来讲讲怎么

这次讲的是将程序、图片或其他文件下载到SPI Flash中。我使用的是W25X16的SPI Flash,他共有2MB空间,2个Block,512ge Sector,8096个Page。由于SPI Flash不能直接跑程序,我们从接口就知道了。

接下去我们就来讲讲怎么编写SPI flash的升级功能。这次的工程是基于之前的Internal Flash修改而来的。修改的部分主要在USB_User组里:

我只将改改的部分。

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;

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭