生活随笔
收集整理的這篇文章主要介紹了
《STM32从零开始学习历程》——SPI读写FLASH
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
《STM32從零開始學習歷程》@EnzoReventon
SPI讀寫FLASH
相關鏈接: SPI物理層及FLASH芯片介紹 SPI協(xié)議層 SPI特性及架構
參考資料: [野火EmbedFire]《STM32庫開發(fā)實戰(zhàn)指南——基于野火霸天虎開發(fā)板》 [正點原子]STM32F4開發(fā)指南-庫函數(shù)版本_V1.2 [ST]《STM32F4xx中文參考手冊》 SPI協(xié)議及總線協(xié)議介紹 W25Q128產(chǎn)品數(shù)據(jù)手冊
1 實現(xiàn)功能
實現(xiàn)對FLASH一扇區(qū)的擦除 對該FLASH扇區(qū)寫入數(shù)據(jù),并讀取該數(shù)據(jù),通過串口調試助手進行調試觀察 寫入256個數(shù)據(jù),并讀取寫入的數(shù)據(jù)以及其余未寫入的數(shù)據(jù)。 對該扇區(qū)所有數(shù)據(jù)都寫入。
2 硬件設計
本文使用的外設為SPI1(正點原子F4探索者開發(fā)板)、FLASH以及USART1。 USART用來調試程序,我們還是使用USART1,因此將PB9,PB10與TX,RX相連接即可。
查閱正點原子F4探索者開發(fā)板硬件手冊,了解SPI引腳與GPIO的對應情況。 由上圖可以看出:SPI的SCK,MISO,MOSI分別與芯片的PB3,PB4,PB5連接,片選信號F_CS與PB14相連接,因此在后面程序配置的時候需要注意不能配置錯引腳。
3 軟件設計流程
① 使能SPIx和IO口時鐘 RCC_AHBxPeriphClockCmd() / RCC_APBxPeriphClockCmd(); ② 初始化IO口為復用功能 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); ③ 設置引腳復用映射: GPIO_PinAFConfig(); ② 初始化SPIx,設置SPIx工作模式 void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct); ③ 使能SPIx void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState); ④ 編寫字節(jié)發(fā)送函數(shù):uint8_t SPI_FLASH_ByteWrite(uint8_t data)
發(fā)送數(shù)據(jù)(指令):void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
接收返回的數(shù)據(jù):uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;
⑤ 編寫擦除扇區(qū)函數(shù):void SPI_FLASH_Erase_Sector(uint32_t addr);
⑥ 編寫寫入數(shù)據(jù)函數(shù):void SPI_FLASH_Page_Write(uint32_t addr, uint8_t *buf, uint32_t size); ⑦ 編寫讀取數(shù)據(jù)函數(shù):void SPI_FLASH_Read_Buff(uint32_t addr, uint8_t *buf, uint32_t size); ⑧ 查看SPI傳輸狀態(tài) SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);
⑨ 編寫SPI發(fā)送函數(shù) 控制片選引腳:GPIO_ResetBits()、GPIO_SetBits(); ⑩ 主函數(shù)調用,優(yōu)化程序(超時函數(shù)、宏定義、等待空閑函數(shù)、寫使能函數(shù))
4 代碼分析
這里大家可以按照自己的需求以及編程習慣進行定義,宏定義的好處在于便于程序的移植,方便改動程序。
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define FLASH_SPI SPI1
#define FLASH_SPI_CLK RCC_APB2Periph_SPI1
#define FLASH_SPI_CLK_INIT RCC_APB2PeriphClockCmd #define FLASH_SPI_SCK_PIN GPIO_Pin_3
#define FLASH_SPI_SCK_GPIO_PORT GPIOB
#define FLASH_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB
#define FLASH_SPI_SCK_SOURCE GPIO_PinSource3
#define FLASH_SPI_SCK_AF GPIO_AF_SPI1 #define FLASH_SPI_MOSI_PIN GPIO_Pin_5
#define FLASH_SPI_MOSI_GPIO_PORT GPIOB
#define FLASH_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOB
#define FLASH_SPI_MOSI_SOURCE GPIO_PinSource5
#define FLASH_SPI_MOSI_AF GPIO_AF_SPI1 #define FLASH_SPI_MISO_PIN GPIO_Pin_4
#define FLASH_SPI_MISO_GPIO_PORT GPIOB
#define FLASH_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB
#define FLASH_SPI_MISO_SOURCE GPIO_PinSource4
#define FLASH_SPI_MISO_AF GPIO_AF_SPI1 #define FLASH_SPI_CS_PIN GPIO_Pin_14
#define FLASH_SPI_CS_GPIO_PORT GPIOB
#define FLASH_SPI_CS_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_CS_LOW() GPIO_ResetBits(FLASH_SPI_CS_GPIO_PORT,FLASH_SPI_CS_PIN)
#define FLASH_SPI_CS_HIGH() GPIO_SetBits(FLASH_SPI_CS_GPIO_PORT,FLASH_SPI_CS_PIN)
#define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
static void SPI_GPIO_Config ( void ) ;
void SPI_Mode_Config ( void ) ;
void SPI_FLASH_Init ( void ) ;
uint8_t
SPI_FLASH_ByteWrite ( uint8_t data
) ;
uint8_t
SPI_FLASH_Read_ID ( void ) ;
void SPI_FLASH_Erase_Sector ( uint32_t addr
) ;
void SPI_FLASH_Write_Enable ( void ) ;
void SPI_FLASH_Wait_For_Standby ( void ) ;
void SPI_FLASH_Read_Buff ( uint32_t addr
, uint8_t
* buf
, uint32_t size
) ;
void SPI_FLASH_Write_Buff ( uint32_t addr
, uint8_t
* buf
, uint32_t size
) ;
void SPI_FLASH_Page_Write ( uint32_t addr
, uint8_t
* buf
, uint32_t size
) ;
SPI子函數(shù):
static uint32_t SPITimeOut
= ( ( uint32_t
) ( 10 * SPIT_FLAG_TIMEOUT
) ) ;
static uint32_t
SPI_TIMEOUT_UserCallback ( uint8_t errorCode
) ;
static void SPI_GPIO_Config ( void )
{ GPIO_InitTypeDef GPIO_InitStructure
; FLASH_SPI_CLK_INIT ( FLASH_SPI_CLK
, ENABLE
) ; RCC_AHB1PeriphClockCmd ( FLASH_SPI_SCK_GPIO_CLK
| FLASH_SPI_MOSI_GPIO_CLK
| FLASH_SPI_MISO_GPIO_CLK
| FLASH_SPI_CS_GPIO_CLK
, ENABLE
) ; GPIO_PinAFConfig ( FLASH_SPI_SCK_GPIO_PORT
, FLASH_SPI_SCK_SOURCE
, FLASH_SPI_SCK_AF
) ; GPIO_PinAFConfig ( FLASH_SPI_MOSI_GPIO_PORT
, FLASH_SPI_MOSI_SOURCE
, FLASH_SPI_MOSI_AF
) ; GPIO_PinAFConfig ( FLASH_SPI_MISO_GPIO_PORT
, FLASH_SPI_MISO_SOURCE
, FLASH_SPI_MISO_AF
) ; GPIO_InitStructure
. GPIO_Pin
= FLASH_SPI_SCK_PIN
; GPIO_InitStructure
. GPIO_Mode
= GPIO_Mode_AF
; GPIO_InitStructure
. GPIO_Speed
= GPIO_Speed_50MHz
; GPIO_InitStructure
. GPIO_OType
= GPIO_OType_PP
; GPIO_InitStructure
. GPIO_PuPd
= GPIO_PuPd_NOPULL
; GPIO_Init ( FLASH_SPI_SCK_GPIO_PORT
, & GPIO_InitStructure
) ; GPIO_InitStructure
. GPIO_Pin
= FLASH_SPI_MOSI_PIN
; GPIO_Init ( FLASH_SPI_MOSI_GPIO_PORT
, & GPIO_InitStructure
) ; GPIO_InitStructure
. GPIO_Pin
= FLASH_SPI_MISO_PIN
; GPIO_Init ( FLASH_SPI_MOSI_GPIO_PORT
, & GPIO_InitStructure
) ; GPIO_InitStructure
. GPIO_Pin
= GPIO_Pin_14
; GPIO_InitStructure
. GPIO_Mode
= GPIO_Mode_OUT
; GPIO_InitStructure
. GPIO_Speed
= GPIO_Speed_50MHz
; GPIO_InitStructure
. GPIO_OType
= GPIO_OType_PP
; GPIO_InitStructure
. GPIO_PuPd
= GPIO_PuPd_NOPULL
; GPIO_Init ( FLASH_SPI_CS_GPIO_PORT
, & GPIO_InitStructure
) ; }
void SPI_Mode_Config ( void )
{ SPI_InitTypeDef SPI_InitStructure
; SPI_InitStructure
. SPI_BaudRatePrescaler
= SPI_BaudRatePrescaler_2
; SPI_InitStructure
. SPI_CPHA
= SPI_CPHA_1Edge
; SPI_InitStructure
. SPI_CPOL
= SPI_CPOL_Low
; SPI_InitStructure
. SPI_CRCPolynomial
= 7 ; SPI_InitStructure
. SPI_DataSize
= SPI_DataSize_8b
; SPI_InitStructure
. SPI_Direction
= SPI_Direction_2Lines_FullDuplex
; SPI_InitStructure
. SPI_FirstBit
= SPI_FirstBit_MSB
; SPI_InitStructure
. SPI_Mode
= SPI_Mode_Master
; SPI_InitStructure
. SPI_NSS
= SPI_NSS_Soft
; SPI_Init ( FLASH_SPI
, & SPI_InitStructure
) ; SPI_Cmd ( FLASH_SPI
, ENABLE
) ; }
== == == == == == == == == == == == == == == == == == == == == == == ==
SPI FLASH 外設初始化
== == == == == == == == == == == == == == == == == == == == == == == ==
* /
void SPI_FLASH_Init ( void )
{ SPI_GPIO_Config ( ) ; SPI_Mode_Config ( ) ;
}
uint8_t
SPI_FLASH_ByteWrite ( uint8_t data
)
{ uint8_t re_data
; SPITimeOut
= SPIT_FLAG_TIMEOUT
; while ( SPI_I2S_GetFlagStatus
( FLASH_SPI
, SPI_I2S_FLAG_TXE
) == RESET
) { if ( ( SPITimeOut
-- ) == 0 ) return SPI_TIMEOUT_UserCallback ( 1 ) ; } SPI_I2S_SendData ( FLASH_SPI
, data
) ; SPITimeOut
= SPIT_FLAG_TIMEOUT
; while ( SPI_I2S_GetFlagStatus
( FLASH_SPI
, SPI_I2S_FLAG_RXNE
) == RESET
) { if ( ( SPITimeOut
-- ) == 0 ) return SPI_TIMEOUT_UserCallback ( 2 ) ; } re_data
= SPI_I2S_ReceiveData ( FLASH_SPI
) ; return re_data
;
}
uint8_t
SPI_FLASH_Read_ID ( void )
{
uint8_t id
; FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_ReleasePowerDown
) ; SPI_FLASH_ByteWrite ( 0xFF ) ; SPI_FLASH_ByteWrite ( 0xFF ) ; SPI_FLASH_ByteWrite ( 0xFF ) ; id
= SPI_FLASH_ByteWrite ( 0xFF ) ; FLASH_SPI_CS_HIGH ( ) ; return id
; }
void SPI_FLASH_Erase_Sector ( uint32_t addr
)
{ SPI_FLASH_Write_Enable ( ) ; FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_SectorErase
) ; SPI_FLASH_ByteWrite ( ( addr
>> 16 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( ( addr
>> 8 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( addr
& 0xFF ) ; FLASH_SPI_CS_HIGH ( ) ; SPI_FLASH_Wait_For_Standby ( ) ; }
void SPI_FLASH_Page_Write ( uint32_t addr
, uint8_t
* buf
, uint32_t size
)
{ SPI_FLASH_Write_Enable ( ) ; FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_PageProgram
) ; SPI_FLASH_ByteWrite ( ( addr
>> 16 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( ( addr
>> 8 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( addr
& 0xFF ) ; while ( size
-- ) { SPI_FLASH_ByteWrite ( * buf
) ; buf
++ ; } FLASH_SPI_CS_HIGH ( ) ; SPI_FLASH_Wait_For_Standby ( ) ; }
void SPI_FLASH_Read_Buff ( uint32_t addr
, uint8_t
* buf
, uint32_t size
)
{ FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_ReadData
) ; SPI_FLASH_ByteWrite ( ( addr
>> 16 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( ( addr
>> 8 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( addr
& 0xFF ) ; while ( size
-- ) { * buf
= SPI_FLASH_ByteWrite ( 0xFF ) ; buf
++ ; } FLASH_SPI_CS_HIGH ( ) ;
}
寫入數(shù)據(jù),不受256數(shù)據(jù)限制
void SPI_FLASH_Write_Buff ( uint32_t addr
, uint8_t
* buf
, uint32_t size
)
{ uint32_t count
= 0 ; while ( size
-- ) { count
++ ; if ( count
== 1 || ( count
% 256 ) == 1 || ( addr
% 4096 ) == 0 ) { FLASH_SPI_CS_HIGH ( ) ; SPI_FLASH_Wait_For_Standby ( ) ; SPI_FLASH_Write_Enable ( ) ; FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_PageProgram
) ; SPI_FLASH_ByteWrite ( ( addr
>> 16 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( ( addr
>> 8 ) & 0xFF ) ; SPI_FLASH_ByteWrite ( addr
& 0xFF ) ; } SPI_FLASH_ByteWrite ( * buf
) ; buf
++ ; addr
++ ; } FLASH_SPI_CS_HIGH ( ) ; SPI_FLASH_Wait_For_Standby ( ) ; }
void SPI_FLASH_Write_Enable ( void )
{ FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_WriteEnable
) ; FLASH_SPI_CS_HIGH ( ) ;
}
void SPI_FLASH_Wait_For_Standby ( void )
{ uint8_t status
; FLASH_SPI_CS_LOW ( ) ; SPI_FLASH_ByteWrite ( W25X_ReadStatusReg
) ; SPITimeOut
= SPIT_LONG_TIMEOUT
; while ( 1 ) { status
= SPI_FLASH_ByteWrite ( 0xFF ) ; if ( ( status
& 0x01 ) == 0 ) break ; if ( ( SPITimeOut
-- ) == 0 ) { SPI_TIMEOUT_UserCallback ( 3 ) ; break ; } } FLASH_SPI_CS_HIGH ( ) ;
}
static uint32_t
SPI_TIMEOUT_UserCallback ( uint8_t errorCode
)
{ printf ( "\r\nSPI 等待超時!errorCode = %d\r\n" , errorCode
) ; return errorCode
;
}
主函數(shù)
uint8_t read_buff
[ 4096 ] = { 0 } ; uint8_t write_buff
[ 4096 ] = { 0 } ; int main ( void )
{ int i
= 0 ; NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2
) ; delay_init ( 168 ) ; uart_init ( 115200 ) ; LED_Init ( ) ; SPI_FLASH_Init ( ) ; printf ( "\r\n=======================================\r\n" ) ; printf ( "this is id : 0x%x" , SPI_FLASH_Read_ID ( ) ) ; printf ( "\r\n擦除開始" ) ; SPI_FLASH_Erase_Sector ( 4096 * 0 ) ; SPI_FLASH_Erase_Sector ( 4096 * 1 ) ; printf ( "\r\n擦除完成" ) ; SPI_FLASH_Read_Buff ( 0 , read_buff
, 4096 ) ; for ( i
= 0 ; i
< 4096 ; i
++ ) { if ( read_buff
[ i
] != 0xFF ) { printf ( "\r\n擦除失敗" ) ; } } printf ( "\r\n擦除完成" ) ; for ( i
= 0 ; i
< 256 ; i
++ ) { write_buff
[ i
] = i
; } printf ( "\r\n開始寫入" ) ; SPI_FLASH_Write_Buff ( 0 , write_buff
, 256 ) ; printf ( "\r\n寫入完成" ) ; SPI_FLASH_Read_Buff ( 0 , write_buff
, 4096 ) ; printf ( "\r\n讀取到的數(shù)據(jù):\r\n" ) ; for ( i
= 0 ; i
< 4096 ; i
++ ) { printf ( "0x%02x " , write_buff
[ i
] ) ; } while ( 1 ) { } }
5 效果展示
寫入256個數(shù)據(jù)。
可以看到前256個數(shù)據(jù)已經(jīng)被寫入為我們想要寫入的數(shù)據(jù)了,其余數(shù)據(jù)均為擦除后的0xFF。
對整個扇區(qū)寫入數(shù)據(jù)。 修改主函數(shù)部分參數(shù)。
for ( i
= 0 ; i
< 4096 ; i
++ ) { write_buff
[ i
] = i
; } printf ( "\r\n開始寫入" ) ; SPI_FLASH_Write_Buff ( 0 , write_buff
, 4096 ) ; printf ( "\r\n寫入完成" ) ; SPI_FLASH_Read_Buff ( 0 , write_buff
, 4096 ) ; printf ( "\r\n讀取到的數(shù)據(jù):\r\n" ) ; for ( i
= 0 ; i
< 4096 ; i
++ ) { printf ( "0x%02x " , write_buff
[ i
] ) ; }
可以看出整個扇區(qū)的數(shù)據(jù)都被寫入。
總結
以上是生活随笔 為你收集整理的《STM32从零开始学习历程》——SPI读写FLASH 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內容還不錯,歡迎將生活随笔 推薦給好友。