15.1 FLASH
Flash,全名叫做Flash EEPROM Memory,即平時(shí)所說(shuō)的“閃存”,它結(jié)合了ROM和RAM的長(zhǎng)處,不僅可以反復(fù)擦除,還可以快速讀取數(shù)據(jù),STM32運(yùn)行的程序其實(shí)就是存放在Flash當(dāng)中,但是由于STM32的Flash一般1M左右,只能存儲(chǔ)程序大小的數(shù)據(jù),所以往往需要外擴(kuò)Flash來(lái)存儲(chǔ)數(shù)據(jù),比如LCD界面當(dāng)中的漢字字庫(kù),以及文件系統(tǒng)中讀取的文件內(nèi)容。
但是一般Flash的擦除次數(shù)有限制,STM32F1系列最新的文檔指出,片內(nèi)的FLASH擦寫(xiě)次數(shù)大約在1W次左右,所以一般Flash用于擦除次數(shù)不多,但是數(shù)據(jù)量很大的場(chǎng)合。
這個(gè)Flash讀寫(xiě)實(shí)驗(yàn)我們用到的芯片是W25Q128,這是一款采用SPI協(xié)議進(jìn)行讀寫(xiě)的Flash芯片,存儲(chǔ)容量為128Mbit,合計(jì)16Mbyte,工作電壓2.7V~3.6V。這個(gè)實(shí)驗(yàn)我們采用STM32內(nèi)置的SPI模塊來(lái)進(jìn)行對(duì)芯片的讀寫(xiě)操作,STM32F1的SPI功能很強(qiáng)大,SPI時(shí)鐘最高可以到18MHz,支持DMA,可以配置為SPI協(xié)議或者I2S協(xié)議。
15.2 硬件SPI模塊
通過(guò)之前51單片機(jī)開(kāi)發(fā)我們可以知道,SPI協(xié)議一共需要四根線來(lái)完成數(shù)據(jù)通信,即片選CS,總線時(shí)鐘SCK,主機(jī)輸入從機(jī)輸出MISO和主機(jī)輸出從機(jī)輸入MOSI四根數(shù)據(jù)線。STM32的內(nèi)部SPI模塊結(jié)構(gòu)框,硬件SPI的優(yōu)勢(shì)就在于開(kāi)發(fā)者不需要考慮SPI的詳細(xì)參數(shù)以及時(shí)序,只需要配置內(nèi)部的寄存器,設(shè)置速率,電平就可以實(shí)現(xiàn)SPI通信。
15.3 相關(guān)寄存器
15.3.1 SPI控制寄存器1:SPIx_CR1
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
BIDIMODE | BIDIOE | CRCEN | CRCNEXT | DFF | RXONLY | SSM | SSI | LSBFIRST | SPE | BR[2:0] | MSTR | CPOL | CPHA |
Bit 15:雙向數(shù)據(jù)模式使能
0:選擇雙線雙向模式
1:選擇單線雙向模式
Bit 14:雙向模式下的輸出使能
0:輸出禁止(只收模式)
1:輸出使能(只發(fā)模式)
Bit 13:硬件CRC校驗(yàn)使能
0:禁止CRC計(jì)算
1:?jiǎn)?dòng)CRC計(jì)算
Bit 12:下一個(gè)發(fā)送CRC
0:下一個(gè)發(fā)送的值來(lái)自發(fā)送緩沖區(qū)
1:下一個(gè)發(fā)送的值來(lái)自發(fā)送CRC寄存器
Bit 11:數(shù)據(jù)幀格式
0:使用8位數(shù)據(jù)幀格式進(jìn)行發(fā)送/接收
1:使用16位數(shù)據(jù)幀格式進(jìn)行發(fā)送/接收
Bit 10:只接收
0:全雙工(發(fā)送和接收)
1:禁止輸出(只接收模式)
Bit 9:軟件從設(shè)備管理
0:禁止軟件從設(shè)備管理
1:?jiǎn)⒂密浖脑O(shè)備管理
Bit 8:內(nèi)部從設(shè)備選擇
注:該位只在SSM位為1時(shí)有意義。它決定了NSS上的電平,在NSS引腳上的I/O操作無(wú)效
Bit 7:幀格式
0:先發(fā)送MSB
1:先發(fā)送LSB
Bit 6:SPI使能
0:禁止SPI設(shè)備
1:開(kāi)啟SPI設(shè)備
Bit 5~Bit 3:波特率控制
000:f PCLK /2
001:f PCLK /4
010:f PCLK /8
011:f PCLK /16
100:f PCLK /32
101:f PCLK /64
110:f PCLK /128
111:f PCLK /256
Bit 2:主設(shè)備選擇
0:配置為從設(shè)備
1:配置為主設(shè)備
Bit 1:時(shí)鐘極性
0:空閑狀態(tài)時(shí),SCK保持低電平
1:空閑狀態(tài)時(shí),SCK保持高電平
Bit 0:時(shí)鐘相位
0:數(shù)據(jù)采樣從第一個(gè)時(shí)鐘邊沿開(kāi)始
1:數(shù)據(jù)采樣從第二個(gè)時(shí)鐘邊沿開(kāi)始
15.3.2 SPI狀態(tài)寄存器:SPIx_SR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | BSY | OVR | MODF | CRCERR | UDR | CHSIDE | TXE | RXNE |
Bit 7:忙標(biāo)志
0:SPI不忙
1:SPI正忙于通信,或者發(fā)送緩沖非空
Bit 6:溢出標(biāo)志
0:沒(méi)有出現(xiàn)溢出錯(cuò)誤
1:出現(xiàn)溢出錯(cuò)誤
Bit 5:模式錯(cuò)誤(在SPI模式下不使用)
0:沒(méi)有出現(xiàn)模式錯(cuò)誤
1:出現(xiàn)模式錯(cuò)誤
Bit 4:CRC錯(cuò)誤標(biāo)志(在SPI模式下不使用)
0:收到的CRC值和SPI_RXCRCR寄存器中的值匹配
1:收到的CRC值和SPI_RXCRCR寄存器中的值不匹配
Bit 3:下溢標(biāo)志位(在SPI模式下不使用)
0:未發(fā)生下溢
1:發(fā)生下溢
Bit 2:聲道(在SPI模式下不使用)
0:需要傳輸或者接收左聲道
1:需要傳輸或者接收右聲道
Bit 1:發(fā)送緩沖為空
0:發(fā)送緩沖非空
1:發(fā)送緩沖為空
Bit 0:接收緩沖非空
0:接收緩沖為空
1:接收緩沖非空
15.4 實(shí)驗(yàn)例程
功能:在Flash中寫(xiě)入一段字符串,而后讀出來(lái)并顯示在TFTLCD上。
(1)創(chuàng)建w25q128.h并輸入以下代碼。
/*********************************************************************************************************
FLASH 驅(qū) 動(dòng) 文 件
*********************************************************************************************************/
#ifndef _W25Q128_H_
#define _W25Q128_H_
#include "sys.h"
/*********************************************************************************************************
端 口 定 義
*********************************************************************************************************/
#define W25QXX_CS PBout( 12 ) //W25QXX的片選信號(hào)
/*********************************************************************************************************
數(shù) 據(jù) 定 義
*********************************************************************************************************/
//SPI總線速度設(shè)置
#define SPI_SPEED_2 0
#define SPI_SPEED_4 1
#define SPI_SPEED_8 2
#define SPI_SPEED_16 3
#define SPI_SPEED_32 4
#define SPI_SPEED_64 5
#define SPI_SPEED_128 6
#define SPI_SPEED_256 7
//指令表
#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
/*********************************************************************************************************
函 數(shù) 列 表
*********************************************************************************************************/
void W25QXX_Init( void ) ; //初始化Flash
void W25QXX_Read( u8* pBuffer, u32 Address, u16 Len ) ; //讀取Flash
void W25QXX_Write( u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite ) ; //寫(xiě)入Flash
void W25QXX_Erase_Chip( void ) ; //整片擦除
void W25QXX_Erase_Sector( u32 Dst_Addr ) ; //扇區(qū)擦除
#endif
(2)創(chuàng)建w25q128.c并輸入以下代碼。
/*********************************************************************************************************
FLASH 驅(qū) 動(dòng) 程 序
*********************************************************************************************************/
#include "w25q128.h"
#include "delay.h"
/***************************************************
Name :SPI2_SetSpeed
Function :SPI2速度設(shè)置函數(shù)
Paramater :
SpeedSet:0~7
Return :None
***************************************************/
void SPI2_SetSpeed( u8 SpeedSet )
{
SpeedSet &= 0x07 ; //限制范圍
SPI2->CR1 &= 0xFFC7 ;
SPI2->CR1 |= SpeedSet<<3 ; //設(shè)置SPI2速度
SPI2->CR1 |= 1<<6 ; //SPI設(shè)備使能
}
/***************************************************
Name :SPI2_ReadWriteByte
Function :SPI2讀寫(xiě)一個(gè)字節(jié)
Paramater :
TxData:要寫(xiě)入的字節(jié)
Return :讀取到的字節(jié)
***************************************************/
u8 SPI2_ReadWriteByte( u8 TxData )
{
u16 retry=0;
//等待發(fā)送區(qū)空
while( ( SPI2->SR&0x02 )==0 )
{
retry ++ ;
//超時(shí)退出
if( retry>=0xFFFE )
return 0 ;
}
SPI2->DR = TxData ; //發(fā)送一個(gè)byte
//等待接收完一個(gè)byte
retry = 0 ;
while( ( SPI2->SR&0x01 )==0 )
{
retry ++ ;
//超時(shí)退出
if( retry>=0xFFFE )
return 0 ;
}
return SPI2->DR ; //返回收到的數(shù)據(jù)
}
/***************************************************
Name :W25QXX_Init
Function :初始化W25Q128芯片
Paramater :None
Return :None
***************************************************/
void W25QXX_Init()
{
RCC->APB2ENR |= 1<<3 ; //PORTB時(shí)鐘使能
GPIOB->CRH &= 0x0000FFFF ;
GPIOB->CRH |= 0xBBB30000 ; //PB12推挽輸出+PB13/14/15復(fù)用
GPIOB->ODR |= 0x7<<13 ; //PB13/14/15上拉
W25QXX_CS = 1 ; //SPI FLASH不選中
//初始化SPI
RCC->APB1ENR |= 1<<14 ; //SPI2時(shí)鐘使能
SPI2->CR1 |= 0<<10 ; //全雙工模式
SPI2->CR1 |= 1<<9 ; //軟件nss管理
SPI2->CR1 |= 1<<8 ;
SPI2->CR1 |= 1<<2 ; //SPI主機(jī)
SPI2->CR1 |= 0<<11 ; //8bit數(shù)據(jù)格式
SPI2->CR1 |= 1<<1 ; //空閑模式下SCK為1 CPOL=1
SPI2->CR1 |= 1<<0 ; //數(shù)據(jù)采樣從第二個(gè)時(shí)間邊沿開(kāi)始,CPHA=1
//對(duì)SPI2屬于APB1的外設(shè).時(shí)鐘頻率最大為36M
SPI2->CR1 |= 3<<3 ; //Fsck=Fpclk1/256
SPI2->CR1 |= 0<<7 ; //MSBfirst
SPI2->CR1 |= 1<<6 ; //SPI設(shè)備使能
SPI2_ReadWriteByte( 0xFF ) ; //啟動(dòng)傳輸
SPI2_SetSpeed( SPI_SPEED_2 ) ; //設(shè)置為18M時(shí)鐘,高速模式
}
/***************************************************
Name :W25QXX_Wait_Busy
Function :等待空閑
Paramater :None
Return :None
***************************************************/
void W25QXX_Wait_Busy()
{
u8 byte=0 ;
// 等待BUSY位清空
do
{
W25QXX_CS = 0 ; //使能器件
SPI2_ReadWriteByte( W25X_ReadStatusReg ) ; //發(fā)送讀取狀態(tài)寄存器命令
byte = SPI2_ReadWriteByte( 0xFF ) ; //讀取一個(gè)字節(jié)
W25QXX_CS = 1 ; //取消片選
}while( ( byte&0x01 )==0x01 ) ;
}
/***************************************************
Name :W25QXX_Erase_Chip
Function :擦除整個(gè)芯片
Paramater :None
Return :None
***************************************************/
void W25QXX_Erase_Chip()
{
W25QXX_CS = 0 ; //使能器件
SPI2_ReadWriteByte( W25X_WriteEnable ) ; //發(fā)送寫(xiě)使能
W25QXX_CS = 1 ; //取消片選
W25QXX_Wait_Busy() ;
W25QXX_CS=0 ; //使能器件
SPI2_ReadWriteByte( W25X_ChipErase ) ; //發(fā)送片擦除命令
W25QXX_CS = 1 ; //取消片選
W25QXX_Wait_Busy() ; //等待芯片擦除結(jié)束
}
/***************************************************
Name :W25QXX_Erase_Sector
Function :擦除一個(gè)扇區(qū)
Paramater :
Address:扇區(qū)地址
Return :None
***************************************************/
void W25QXX_Erase_Sector( u32 Address )
{
Address *= 4096 ;
W25QXX_CS = 0 ; //使能器件
SPI2_ReadWriteByte( W25X_WriteEnable ) ; //發(fā)送寫(xiě)使能
W25QXX_CS = 1 ; //取消片選
W25QXX_Wait_Busy();
W25QXX_CS = 0 ; //使能器件
SPI2_ReadWriteByte( W25X_SectorErase ) ; //發(fā)送扇區(qū)擦除指令
SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ; //發(fā)送24bit地址
SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ;
SPI2_ReadWriteByte( ( u8 )Address ) ;
W25QXX_CS = 1 ; //取消片選
W25QXX_Wait_Busy() ; //等待擦除完成
}
/***************************************************
Name :W25QXX_Read
Function :在指定地址開(kāi)始讀取指定長(zhǎng)度的數(shù)據(jù)
Paramater :
pBuffer:數(shù)據(jù)存儲(chǔ)區(qū)
Address:開(kāi)始讀取的地址
Len:要讀取的字節(jié)數(shù)
Return :None
***************************************************/
void W25QXX_Read( u8 *pBuffer, u32 Address, u16 Len )
{
u16 i ;
W25QXX_CS = 0 ; //使能器件
SPI2_ReadWriteByte( W25X_ReadData ) ; //發(fā)送讀取命令
SPI2_ReadWriteByte( ( u8 )( Address>>16 ) ) ; //發(fā)送24bit地址
SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ;
SPI2_ReadWriteByte( ( u8 )Address );
for( i=0; i>16 ) ) ; //發(fā)送24bit地址
SPI2_ReadWriteByte( ( u8 )( Address>>8 ) ) ;
SPI2_ReadWriteByte( ( u8 )Address ) ;
for( i=0; ipageremain
else
{
pBuffer += pageremain ;
Address += pageremain ;
Len -= pageremain ; //減去已經(jīng)寫(xiě)入了的字節(jié)數(shù)
//一次可以寫(xiě)入256個(gè)字節(jié)
if( Len>256 )
pageremain = 256 ;
//不夠256個(gè)字節(jié)了
else
pageremain = Len ;
}
}
}
/***************************************************
Name :W25QXX_Write_NoCheck
Function :在指定地址開(kāi)始寫(xiě)入指定長(zhǎng)度的數(shù)據(jù)
Paramater :
pBuffer:數(shù)據(jù)存儲(chǔ)區(qū)
Address:開(kāi)始寫(xiě)入的地址
Len:要寫(xiě)入的字節(jié)數(shù)
Return :None
***************************************************/
u8 W25QXX_BUFFER[ 4096 ] ;
void W25QXX_Write( u8 *pBuffer, u32 Address, u16 Len )
{
u32 secpos ;
u16 secoff ;
u16 secremain ;
u16 i ;
u8 *W25QXX_BUF ;
W25QXX_BUF = W25QXX_BUFFER ;
secpos = Address/4096 ; //扇區(qū)地址
secoff = Address%4096 ; //在扇區(qū)內(nèi)的偏移
secremain = 4096-secoff ; //扇區(qū)剩余空間大小
//不大于4096個(gè)字節(jié)
if( Len<=secremain )
secremain = Len ;
while( 1 )
{
W25QXX_Read( W25QXX_BUF, secpos*4096, 4096 ) ; //讀出整個(gè)扇區(qū)的內(nèi)容
//校驗(yàn)數(shù)據(jù)
for( i=0; i4096 )
secremain = 4096 ;
//下一個(gè)扇區(qū)可以寫(xiě)完了
else
secremain = Len ;
}
}
}
(3)在1.c文件中輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "w25q128.h"
const u8 TEXT_Buffer[] = { "WarShip STM32F1 SPI TEST" } ;
#define SIZE sizeof( TEXT_Buffer )
int main()
{
u8 datatemp[ SIZE ] ;
u32 FLASH_SIZE ;
STM32_Clock_Init( 9 ) ; //STM32時(shí)鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
LCD_Init() ; //LCD初始化
W25QXX_Init() ; //W25QXX初始化
POINT_COLOR = RED ; //設(shè)置字體為紅色
FLASH_SIZE = 128*1024*1024 ; //FLASH 大小為16M字節(jié)
W25QXX_Write( (u8*)TEXT_Buffer, FLASH_SIZE-100, SIZE ) ; //從倒數(shù)第100個(gè)地址處開(kāi)始,寫(xiě)入SIZE長(zhǎng)度的數(shù)據(jù)
W25QXX_Read( datatemp, FLASH_SIZE-100, SIZE ) ; //從倒數(shù)第100個(gè)地址處開(kāi)始,讀出SIZE個(gè)字節(jié)
LCD_ShowString( 0, 0, datatemp ) ; //顯示讀到的字符串
while( 1 )
{
}
}
-
FlaSh
+關(guān)注
關(guān)注
10文章
1644瀏覽量
148755 -
STM32
+關(guān)注
關(guān)注
2273文章
10926瀏覽量
357771 -
文件系統(tǒng)
+關(guān)注
關(guān)注
0文章
287瀏覽量
19990
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
【紫光同創(chuàng)國(guó)產(chǎn)FPGA教程】【第八章】SD卡讀寫(xiě)實(shí)驗(yàn)
![【紫光同創(chuàng)國(guó)產(chǎn)FPGA教程】【第八章】SD卡<b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>](https://file.elecfans.com//web1/M00/DD/EE/o4YBAGAY4mqAbUHfAABWzEWrkVo638.jpg)
STM32入門(mén)學(xué)習(xí)筆記之外置FLASH讀寫(xiě)實(shí)驗(yàn)(上)
![STM32入門(mén)學(xué)習(xí)筆記之<b class='flag-5'>外置</b><b class='flag-5'>FLASH</b><b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>(上)](https://file.elecfans.com/web2/M00/91/FF/pYYBAGPtx_2AbQ3aAAGvUEY284I232.jpg)
STM32入門(mén)學(xué)習(xí)筆記之外置FLASH讀寫(xiě)實(shí)驗(yàn)(下)
【GD32F470紫藤派開(kāi)發(fā)板使用手冊(cè)】第十二講 SDIO-SD卡讀寫(xiě)實(shí)驗(yàn)
![【GD32F470紫藤派開(kāi)發(fā)板使用手冊(cè)】第十二講 SDIO-SD卡<b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBiaAKDTYAACMnCUwRmY025.png)
如何對(duì)擴(kuò)展存儲(chǔ)器進(jìn)行讀寫(xiě)實(shí)驗(yàn)?
如何通過(guò)對(duì)flash的讀寫(xiě)實(shí)現(xiàn)stm32的編程操作?
基于單片機(jī)的存儲(chǔ)器讀寫(xiě)實(shí)驗(yàn)
如何讀寫(xiě)flash
基于STM32F407利用HAL庫(kù)使用SPI對(duì)W25Q128進(jìn)行讀寫(xiě)實(shí)驗(yàn)
接觸式IC卡讀寫(xiě)實(shí)驗(yàn)
![接觸式IC卡<b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>](https://file1.elecfans.com//web2/M00/A4/66/wKgZomUMNAeAEOxvAABrWDpS160882.jpg)
AVR內(nèi)部EEPROM讀寫(xiě)實(shí)驗(yàn)
PIC單片機(jī)的EEPROM讀寫(xiě)實(shí)例
使用DSP進(jìn)行靜態(tài)隨機(jī)存取存儲(chǔ)器SRAM的讀寫(xiě)實(shí)驗(yàn)報(bào)告書(shū)免費(fèi)下載
![使用DSP進(jìn)行靜態(tài)隨機(jī)存取存儲(chǔ)器SRAM的<b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>報(bào)告書(shū)免費(fèi)下載](https://file.elecfans.com/web1/M00/A0/2B/o4YBAF1EBlCAW1QLAAM2VmOYCGM200.png)
單片機(jī)實(shí)驗(yàn)匯編--擴(kuò)展存儲(chǔ)器讀寫(xiě)實(shí)驗(yàn)
![單片機(jī)<b class='flag-5'>實(shí)驗(yàn)</b>匯編--擴(kuò)展存儲(chǔ)器<b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
【GD32F303紅楓派開(kāi)發(fā)板使用手冊(cè)】第二十三講 SDIO-SD卡讀寫(xiě)實(shí)驗(yàn)
![【GD32F303紅楓派開(kāi)發(fā)板使用手冊(cè)】第二十三講 SDIO-SD卡<b class='flag-5'>讀寫(xiě)實(shí)驗(yàn)</b>](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBiaAKDTYAACMnCUwRmY025.png)
評(píng)論