STM32 SPI Flash DFU
這次講的是將程序、圖片或其他文件下載到SPI Flash中。我使用的是W25X16的SPI Flash,他共有2MB空間,2個(gè)Block,512ge Sector,8096個(gè)Page。由于SPI Flash不能直接跑程序,我們從接口就知道了。
接下去我們就來講講怎么編寫SPI flash的升級(jí)功能。這次的工程是基于之前的Internal Flash修改而來的。修改的部分主要在USB_User組里:
我只將改改的部分。
hw_config.c、usb_istr.c、usb_prop.c、usb_pwr.c這介個(gè)文件沒有什么還修改的。usb_desc.c文件需要修改下接口字符串描述符,由于我們的SPI Flash空間2M,所以我們將SPI Flash的2M空間全部設(shè)置成可讀可寫可擦除。
/*接口字符串描述符*/
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的驅(qū)動(dòng)代碼spi_flash.c,這個(gè)代碼可以網(wǎng)上下載。接下去將上個(gè)工程里的flash—_if.c文件修改成spi_if.c,并修改里面的函數(shù):
/*******************************************************************************
* 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寫入數(shù)據(jù)長度為%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地址寫數(shù)據(jù)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個(gè)數(shù)據(jù)rn",SectorAddress,DataLength);
SPI_Flash_Read(MAL_Buffer, SectorAddress, (uint16_t)DataLength);
return MAL_Buffer;
}
然后要修改的是dfu_mal.c這個(gè)文件。修改成如下就可以了:
/*******************************************************************************
* 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 : 擦除扇區(qū)
* 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);//指向擦除函數(shù)
}
/*******************************************************************************
* Function Name : MAL_Write
* Description : 寫扇區(qū)
* 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);//調(diào)用寫扇區(qū)函數(shù)
}
/*******************************************************************************
* Function Name : MAL_Read
* Description : 度扇區(qū)
* 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);//調(diào)用如扇區(qū)函數(shù)
}
/*******************************************************************************
* Function Name : MAL_GetStatus
* Description : 獲取狀態(tài)
* Input : None
* Output : None
* Return : MAL_OK
*******************************************************************************/
uint16_t MAL_GetStatus(uint32_t SectorAddress , uint8_t Cmd, uint8_t *buffer)
{ //更具地址查找定時(shí)表的對(duì)應(yīng)的選項(xiàng)
uint8_t x = (SectorAddress >> 26) & 0x03 ;
/* 0x000000000 --> 0 */
/* 0x640000000 --> 1 */
/* 0x080000000 --> 2 */
uint8_t y = Cmd & 0x01;
SET_POLLING_TIMING(TimingTable[x][y]); /* x: 擦除/寫 定時(shí) */
/* y: Media */
return MAL_OK;
}
最后的話,就是我們的main函數(shù)了,這里的main函數(shù)當(dāng)然沒有程序跳轉(zhuǎn)了,我在這里用到了4個(gè)按鍵,
WAKEUP按鍵(PA0)按下表示向spi flash的0地址寫入一組數(shù)據(jù)
TAMPER按鍵(PC13)按下表示讀取0地址開始的數(shù)據(jù)
USER1按鍵(PA8)按下表示擦寫0地址開始的那個(gè)扇區(qū)數(shù)據(jù)
USER2按鍵(PD3)按下表示向spi flash的0地址寫入另一組數(shù)據(jù)
這樣的話,就可以試試檢測(cè)spi flash 讀寫是否正確了。
uint8_t DeviceState;
uint8_t DeviceStatus[6];
u8 WRITE_Buffer[]="神舟III號(hào) SPI 讀寫訪問程序";//spi flash寫入數(shù)據(jù)緩存
u8 WRITE_Buffer1[]="神舟I號(hào) SPI 讀寫訪問程序";//spi flash寫入數(shù)據(jù)緩存
u8 READ_Buffer[sizeof(WRITE_Buffer)];//spi flash讀出數(shù)據(jù)緩存
/********************************************************
函數(shù):main()
描述:程序入口地址
參數(shù):無
返回:無
********************************************************/
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,一定要讀,否則讀寫會(huì)出錯(cuò)
printf("ID:%xrn",i);
}
/* Enter DFU mode */
DeviceState = STATE_dfuERROR;