STM32F7xx —— QSPI
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?STM32F7xx —— QSPI
?
目錄
STM32F7xx —— QSPI
一、QSPI
二、幾個(gè)重要的函數(shù)
三、幾個(gè)重要的結(jié)構(gòu)
四、QSPI接口設(shè)計(jì)(僅供參考)
五、QSPI驅(qū)動(dòng)W25Q256
?
?
一、QSPI
? ? ? ? SPI 是 Queued SPI 的簡(jiǎn)寫,是 Motorola公司推出的 SPI 接口的擴(kuò)展,比 SPI 應(yīng)用更加廣泛。在 SPI 協(xié)議的基礎(chǔ)上,Motorola 公司對(duì)其功能進(jìn)行了增強(qiáng),增加了隊(duì)列傳輸機(jī)制,推出了隊(duì)列串行外圍接口協(xié)議(即 QSPI 協(xié)議),使用該接口,用戶可以一次性傳輸包含多達(dá)16個(gè)8位或16位數(shù)據(jù)的傳輸隊(duì)列。一旦傳輸啟動(dòng),直到傳輸結(jié)束,都不需要CPU干預(yù),極大的提高了傳輸效率。該協(xié)議在ColdFire系列MCU得到廣泛應(yīng)用。與SPI相比,QSPI的最大結(jié)構(gòu)特點(diǎn)是以80字節(jié)的RAM代替了SPI的發(fā)送和接收寄存器。QSPI 是一種專用的通信接口,連接單、雙或四(條數(shù)據(jù)線) SPI Flash 存儲(chǔ)介質(zhì)。
?該接口可以在以下三種模式下工作:
① 間接模式:使用 QSPI 寄存器執(zhí)行全部操作
② 狀態(tài)輪詢模式:周期性讀取外部 Flash 狀態(tài)寄存器,而且標(biāo)志位置 1 時(shí)會(huì)產(chǎn)生中斷(如擦除或燒寫完成,會(huì)產(chǎn)生中斷)
③ 內(nèi)存映射模式:外部 Flash 映射到微控制器地址空間,從而系統(tǒng)將其視作內(nèi)部存儲(chǔ)器。
QSPI通過(guò)6根線與SPI芯片通信,下圖是內(nèi)部框圖:
QSPI每條命令,必須包含一個(gè)或多個(gè)階段:指令、地址、交替字節(jié)、空指令和數(shù)據(jù)。
QSPI發(fā)送命令:等待QSPI空閑;設(shè)置命令參數(shù)。
QSPI讀數(shù)據(jù):設(shè)置數(shù)據(jù)傳輸長(zhǎng)度;設(shè)置QSPI工作模式并設(shè)置地址;讀取數(shù)據(jù)。
QSPI寫數(shù)據(jù):設(shè)置數(shù)據(jù)傳輸長(zhǎng)度;設(shè)置QSPI工作模式并設(shè)置地址;寫數(shù)據(jù)。
?
二、幾個(gè)重要的函數(shù)
HAL_StatusTypeDef HAL_QSPI_Init (QSPI_HandleTypeDef *hqspi); // 初始化HAL_StatusTypeDef HAL_QSPI_Command(QSPI_HandleTypeDef *hqspi, QSPI_CommandTypeDef *cmd, uint32_t Timeout); // 發(fā)送命令HAL_StatusTypeDef HAL_QSPI_Transmit (QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout); // 發(fā)送數(shù)據(jù)HAL_StatusTypeDef HAL_QSPI_Receive (QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout); // 接收數(shù)據(jù)三、幾個(gè)重要的結(jié)構(gòu)
// QSPI操作句柄 typedef struct {QUADSPI_TypeDef *Instance; /* QSPI registers base address */QSPI_InitTypeDef Init; /* QSPI communication parameters */uint8_t *pTxBuffPtr; /* Pointer to QSPI Tx transfer Buffer */__IO uint16_t TxXferSize; /* QSPI Tx Transfer size */__IO uint16_t TxXferCount; /* QSPI Tx Transfer Counter */uint8_t *pRxBuffPtr; /* Pointer to QSPI Rx transfer Buffer */__IO uint16_t RxXferSize; /* QSPI Rx Transfer size */__IO uint16_t RxXferCount; /* QSPI Rx Transfer Counter */DMA_HandleTypeDef *hdma; /* QSPI Rx/Tx DMA Handle parameters */__IO HAL_LockTypeDef Lock; /* Locking object */__IO HAL_QSPI_StateTypeDef State; /* QSPI communication state */__IO uint32_t ErrorCode; /* QSPI Error code */uint32_t Timeout; /* Timeout for the QSPI memory access */ }QSPI_HandleTypeDef;// Instance:QSPI基地址 --- QUADSPI // Init:設(shè)置QSPI參數(shù) // pTxBuffPtr,TxXferSize,TxXferCount:發(fā)送緩存指針 發(fā)送數(shù)據(jù)量 剩余數(shù)據(jù)量 // pRxBuffPtr,RxXferSize,RxXferCount:接收緩存指針 發(fā)送數(shù)據(jù)量 剩余數(shù)據(jù)量 // hdma與DMA相關(guān), 其他為過(guò)程變量不需要關(guān)心 // 參數(shù)配置 時(shí)鐘分頻系數(shù) FIFO閾值 采樣移位 FLASH大小 片選高電平時(shí)間 時(shí)鐘模式 閃存ID 雙閃存模式設(shè)置 typedef struct {uint32_t ClockPrescaler; /* Specifies the prescaler factor for generating clock based on the AHB clock.This parameter can be a number between 0 and 255 */ uint32_t FifoThreshold; /* Specifies the threshold number of bytes in the FIFO (used only in indirect mode)This parameter can be a value between 1 and 32 */uint32_t SampleShifting; /* Specifies the Sample Shift. The data is sampled 1/2 clock cycle delay later to take in account external signal delays. (It should be QSPI_SAMPLE_SHIFTING_NONE in DDR mode)This parameter can be a value of @ref QSPI_SampleShifting */uint32_t FlashSize; /* Specifies the Flash Size. FlashSize+1 is effectively the number of address bits required to address the flash memory. The flash capacity can be up to 4GB (addressed using 32 bits) in indirect mode, but the addressable space in memory-mapped mode is limited to 256MBThis parameter can be a number between 0 and 31 */uint32_t ChipSelectHighTime; /* Specifies the Chip Select High Time. ChipSelectHighTime+1 defines the minimum number of clock cycles which the chip select must remain high between commands.This parameter can be a value of @ref QSPI_ChipSelectHighTime */ uint32_t ClockMode; /* Specifies the Clock Mode. It indicates the level that clock takes between commands.This parameter can be a value of @ref QSPI_ClockMode */uint32_t FlashID; /* Specifies the Flash which will be used,This parameter can be a value of @ref QSPI_Flash_Select */uint32_t DualFlash; /* Specifies the Dual Flash Mode StateThis parameter can be a value of @ref QSPI_DualFlash_Mode */ }QSPI_InitTypeDef; // 采樣移位 #define QSPI_SAMPLE_SHIFTING_NONE ((uint32_t)0x00000000U) /*!<No clock cycle shift to sample data*/ #define QSPI_SAMPLE_SHIFTING_HALFCYCLE ((uint32_t)QUADSPI_CR_SSHIFT) /*!<1/2 clock cycle shift to sample data*/四、QSPI接口設(shè)計(jì)(僅供參考)
#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE();#define QSPI_BK1_NCS_PORT GPIOB #define QSPI_BK1_NCS_PIN GPIO_PIN_6 #define QSPI_BK1_NCS_AF GPIO_AF10_QUADSPI #define QSPI_BK1_NCS_CONFIG() GPIOConfigExt(QSPI_BK1_NCS_PORT, QSPI_BK1_NCS_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, QSPI_BK1_NCS_AF)#define QSPI_BK1_CLK_PORT GPIOB #define QSPI_BK1_CLK_PIN GPIO_PIN_2 #define QSPI_BK1_CLK_AF GPIO_AF9_QUADSPI #define QSPI_BK1_CLK_CONFIG() GPIOConfigExt(QSPI_BK1_CLK_PORT, QSPI_BK1_CLK_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, QSPI_BK1_CLK_AF)#define QSPI_BK1_IO0_PORT GPIOF #define QSPI_BK1_IO0_PIN GPIO_PIN_8 #define QSPI_BK1_IO0_AF GPIO_AF10_QUADSPI #define QSPI_BK1_IO0_CONFIG() GPIOConfigExt(QSPI_BK1_IO0_PORT, QSPI_BK1_IO0_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, QSPI_BK1_IO0_AF)#define QSPI_BK1_IO1_PORT GPIOF #define QSPI_BK1_IO1_PIN GPIO_PIN_9 #define QSPI_BK1_IO1_AF GPIO_AF10_QUADSPI #define QSPI_BK1_IO1_CONFIG() GPIOConfigExt(QSPI_BK1_IO1_PORT, QSPI_BK1_IO1_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, QSPI_BK1_IO1_AF)#define QSPI_BK1_IO2_PORT GPIOF #define QSPI_BK1_IO2_PIN GPIO_PIN_7 #define QSPI_BK1_IO2_AF GPIO_AF9_QUADSPI #define QSPI_BK1_IO2_CONFIG() GPIOConfigExt(QSPI_BK1_IO2_PORT, QSPI_BK1_IO2_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, QSPI_BK1_IO2_AF)#define QSPI_BK1_IO3_PORT GPIOF #define QSPI_BK1_IO3_PIN GPIO_PIN_6 #define QSPI_BK1_IO3_AF GPIO_AF9_QUADSPI #define QSPI_BK1_IO3_CONFIG() GPIOConfigExt(QSPI_BK1_IO3_PORT, QSPI_BK1_IO3_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, QSPI_BK1_IO3_AF) // 封裝幾個(gè)必要的接口 static QSPI_HandleTypeDef qspi_handle;static void qspi_gpio_init(void) {QSPI_CLK_ENABLE();QSPI_BK1_NCS_CONFIG();QSPI_BK1_CLK_CONFIG();QSPI_BK1_IO0_CONFIG();QSPI_BK1_IO1_CONFIG();QSPI_BK1_IO2_CONFIG();QSPI_BK1_IO3_CONFIG(); }static void qspi_mode_init(void) {qspi_handle.Instance = QUADSPI; // QSPIqspi_handle.Init.ClockPrescaler = 2; // QPSI分頻比,W25Q256最大頻率為104M 所以此處應(yīng)該為2,QSPI頻率就為216/(2+1)=72MHZqspi_handle.Init.FifoThreshold = 4; // FIFO閾值為4個(gè)字節(jié)qspi_handle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; // 采樣移位半個(gè)周期(DDR模式下,必須設(shè)置為0)qspi_handle.Init.FlashSize = POSITION_VAL(0X2000000) - 1; // SPI FLASH大小,W25Q256大小為32M字節(jié)qspi_handle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE; // 片選高電平時(shí)間為4個(gè)時(shí)鐘(13.8*4=55.2ns),即手冊(cè)里面的tSHSL參數(shù)qspi_handle.Init.ClockMode = QSPI_CLOCK_MODE_0; // 模式0qspi_handle.Init.FlashID = QSPI_FLASH_ID_1; // 第一片flashqspi_handle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; // 禁止雙閃存模式HAL_QSPI_Init(&qspi_handle); //QSPI初始化 }void QSPIInit(void) {qspi_gpio_init();qspi_mode_init(); }// QSPI發(fā)送命令 // instruction:要發(fā)送的指令 // address:發(fā)送到的目的地址 // dummyCycles:空指令周期數(shù) // instructionMode:指令模式;QSPI_INSTRUCTION_NONE,QSPI_INSTRUCTION_1_LINE,QSPI_INSTRUCTION_2_LINE,QSPI_INSTRUCTION_4_LINE // addressMode:地址模式; QSPI_ADDRESS_NONE,QSPI_ADDRESS_1_LINE,QSPI_ADDRESS_2_LINE,QSPI_ADDRESS_4_LINE // addressSize:地址長(zhǎng)度;QSPI_ADDRESS_8_BITS,QSPI_ADDRESS_16_BITS,QSPI_ADDRESS_24_BITS,QSPI_ADDRESS_32_BITS // dataMode:數(shù)據(jù)模式; QSPI_DATA_NONE,QSPI_DATA_1_LINE,QSPI_DATA_2_LINE,QSPI_DATA_4_LINE void QSPISendCMD(uint32_t instruction, uint32_t address, uint32_t dummyCycles, uint32_t instructionMode, uint32_t addressMode, uint32_t addressSize, uint32_t dataMode) {QSPI_CommandTypeDef Cmdhandler;Cmdhandler.Instruction = instruction; // 指令Cmdhandler.Address = address; // 地址Cmdhandler.DummyCycles = dummyCycles; // 設(shè)置空指令周期數(shù)Cmdhandler.InstructionMode = instructionMode; // 指令模式Cmdhandler.AddressMode = addressMode; // 地址模式Cmdhandler.AddressSize = addressSize; // 地址長(zhǎng)度Cmdhandler.DataMode = dataMode; // 數(shù)據(jù)模式Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; // 每次都發(fā)送指令Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; // 無(wú)交替字節(jié)Cmdhandler.DdrMode = QSPI_DDR_MODE_DISABLE; // 關(guān)閉DDR模式Cmdhandler.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;HAL_QSPI_Command(&qspi_handle, &Cmdhandler, 5000); }// 接收指定長(zhǎng)度數(shù)據(jù) uint8_t QSPIReceive(uint8_t *buffer, uint32_t length) {qspi_handle.Instance->DLR = length - 1;if(HAL_QSPI_Receive(&qspi_handle, buffer, 5000) == HAL_OK){return 0; //接收數(shù)據(jù)}else{return 1;} }// 發(fā)送指定長(zhǎng)度數(shù)據(jù) uint8_t QSPITransmit(uint8_t *buffer, uint32_t length) {qspi_handle.Instance->DLR = length - 1;if(HAL_QSPI_Transmit(&qspi_handle, buffer, 5000) == HAL_OK){return 0; //發(fā)送數(shù)據(jù)}else{return 1;} }五、QSPI驅(qū)動(dòng)W25Q256
W25Q256:32M? 512塊,每塊16個(gè)扇區(qū),每個(gè)扇區(qū)4K。具體指令看手冊(cè)。封裝了如下接口(初始化讀寫擦除等接口是以后移植文件系統(tǒng)的基礎(chǔ)):
#define W25QXX_WRITE_ENABLE 0x06 #define W25QXX_WRITE_DISABLE 0x04 #define W25QXX_READ_STATUS_REG1 0x05 #define W25QXX_READ_STATUS_REG2 0x35 #define W25QXX_READ_STATUS_REG3 0x15 #define W25QXX_WRITE_STATUS_REG1 0x01 #define W25QXX_WRITE_STATUS_REG2 0x31 #define W25QXX_WRITE_STATUS_REG3 0x11 #define W25QXX_READ_DATA 0x03 #define W25QXX_FAST_READ_DATA 0x0B #define W25QXX_FAST_READ_DUAL 0x3B #define W25QXX_PAGE_PROGRAM 0x02 #define W25QXX_BLOCK_ERASE 0xD8 #define W25QXX_SECTOR_ERASE 0x20 #define W25QXX_CHIP_ERASE 0xC7 #define W25QXX_DEVICEID 0xAB #define W25QXX_MANUFACT_DEVICEID 0x90 #define W25QXX_JEDEC_DEVICEID 0x9F #define W25QXX_EABLE_4BYTE_ADDR 0xB7 #define W25QXX_EXIT_4BYTE_ADDR 0xE9 #define W25QXX_SET_READ_PARAM 0xC0 #define W25QXX_ENTER_QPIMODE 0x38 #define W25QXX_EXIT_QPIMODE 0xFFuint8_t w25qxx_qpi_mode = 0; // QSPI模式標(biāo)志:0,SPI模式;1,QPI模式.// 讀取W25QXX的狀態(tài)寄存器,W25QXX一共有3個(gè)狀態(tài)寄存器 // 狀態(tài)寄存器1: // BIT7 6 5 4 3 2 1 0 // SPR RV TB BP2 BP1 BP0 WEL BUSY // SPR:默認(rèn)0,狀態(tài)寄存器保護(hù)位,配合WP使用 // TB,BP2,BP1,BP0:FLASH區(qū)域?qū)懕Wo(hù)設(shè)置 // WEL:寫使能鎖定 // BUSY:忙標(biāo)記位(1,忙;0,空閑) // 默認(rèn):0x00 // 狀態(tài)寄存器2: // BIT7 6 5 4 3 2 1 0 // SUS CMP LB3 LB2 LB1 (R) QE SRP1 // 狀態(tài)寄存器3: // BIT7 6 5 4 3 2 1 0 // HOLD/RST DRV1 DRV0 (R) (R) WPS ADP ADS // reg:狀態(tài)寄存器號(hào),范:1~3 // 返回值:狀態(tài)寄存器值 static uint8_t w25qxx_read_status(uint8_t reg) {uint8_t value = 0, command = 0;switch(reg){case 1:command = W25QXX_READ_STATUS_REG1; // 讀狀態(tài)寄存器1指令break;case 2:command = W25QXX_READ_STATUS_REG2; // 讀狀態(tài)寄存器2指令break;case 3:command = W25QXX_READ_STATUS_REG3; // 讀狀態(tài)寄存器3指令break;default:command = W25QXX_READ_STATUS_REG1;break;}if(w25qxx_qpi_mode){QSPISendCMD(command, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_4_LINES); //QPI,寫command指令,地址為0,4線傳數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,1個(gè)字節(jié)數(shù)據(jù)}else{QSPISendCMD(command, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_1_LINE); //SPI,寫command指令,地址為0,單線傳數(shù)據(jù)_8位地址_無(wú)地址_單線傳輸指令,無(wú)空周期,1個(gè)字節(jié)數(shù)據(jù)}QSPIReceive(&value, 1);return value; }// 寫狀態(tài)寄存器 static void w25qxx_write_status(uint8_t reg, uint8_t status) {uint8_t command = 0;switch(reg){case 1:command = W25QXX_WRITE_STATUS_REG1; //寫狀態(tài)寄存器1指令break;case 2:command = W25QXX_WRITE_STATUS_REG2; //寫狀態(tài)寄存器2指令break;case 3:command = W25QXX_WRITE_STATUS_REG3; //寫狀態(tài)寄存器3指令break;default:command = W25QXX_WRITE_STATUS_REG1;break;}if(w25qxx_qpi_mode){QSPISendCMD(command, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_4_LINES); // QPI,寫command指令,地址為0,4線傳數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,1個(gè)字節(jié)數(shù)據(jù)}else{QSPISendCMD(command, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_1_LINE); // SPI,寫command指令,地址為0,單線傳數(shù)據(jù)_8位地址_無(wú)地址_單線傳輸指令,無(wú)空周期,1個(gè)字節(jié)數(shù)據(jù)}QSPITransmit(&status, sizeof(status)); }// 寫使能 將S1寄存器的WEL置位 static void w25qxx_write_enable(void) {if(w25qxx_qpi_mode){QSPISendCMD(W25QXX_WRITE_ENABLE, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // QPI,寫使能指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)}else{QSPISendCMD(W25QXX_WRITE_ENABLE, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // SPI,寫使能指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_單線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)} }// 寫失能 將WEL清零 void W25QXX_Write_Disable(void) {if(w25qxx_qpi_mode){QSPISendCMD(W25QXX_WRITE_DISABLE, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // QPI,寫禁止指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)}else{QSPISendCMD(W25QXX_WRITE_DISABLE, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // SPI,寫禁止指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_單線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)} }// 等待空閑 void w25qxx_wait_busy(void) {while((w25qxx_read_status(1) & 0x01) == 0x01); // 等待BUSY位清空 }// W25QXX進(jìn)入QSPI模式 static void w25qxx_qspi_init(void) {uint8_t reg2;reg2 = w25qxx_read_status(2); // 先讀出狀態(tài)寄存器2的原始值if((reg2 & 0X02) == 0) // QE位未使能{w25qxx_write_enable(); // 寫使能reg2 |= 1 << 1; // 使能QE位w25qxx_write_status(2, reg2); // 寫狀態(tài)寄存器2}QSPISendCMD(W25QXX_ENTER_QPIMODE, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // 寫command指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_單線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)w25qxx_qpi_mode = 1; // 標(biāo)記QSPI模式 }// 0XEF13,表示芯片型號(hào)為W25Q80 // 0XEF14,表示芯片型號(hào)為W25Q16 // 0XEF15,表示芯片型號(hào)為W25Q32 // 0XEF16,表示芯片型號(hào)為W25Q64 // 0XEF17,表示芯片型號(hào)為W25Q128 // 0XEF18,表示芯片型號(hào)為W25Q256 static void w25qxx_id_get(void) {uint8_t temp[2];uint16_t device_id;if(w25qxx_qpi_mode){QSPISendCMD(W25QXX_MANUFACT_DEVICEID, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_4_LINES, QSPI_ADDRESS_24_BITS, QSPI_DATA_4_LINES); // QPI,讀id,地址為0,4線傳輸數(shù)據(jù)_24位地址_4線傳輸?shù)刂穇4線傳輸指令,無(wú)空周期,2個(gè)字節(jié)數(shù)據(jù)}else{QSPISendCMD(W25QXX_MANUFACT_DEVICEID, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_1_LINE, QSPI_ADDRESS_24_BITS, QSPI_DATA_1_LINE); // SPI,讀id,地址為0,單線傳輸數(shù)據(jù)_24位地址_單線傳輸?shù)刂穇單線傳輸指令,無(wú)空周期,2個(gè)字節(jié)數(shù)據(jù)}QSPIReceive(temp, 2);device_id = (temp[0] << 8) | temp[1];printf("QSPI Flash Device ID: %X\r\n", device_id); }void W25QXXInit(void) {uint8_t temp;QSPIInit();w25qxx_qspi_init(); // 使能QSPI模式w25qxx_id_get(); // 讀取FLASH ID.temp = w25qxx_read_status(3); // 讀取狀態(tài)寄存器3,判斷地址模式if((temp & 0X01) == 0) // 如果不是4字節(jié)地址模式,則進(jìn)入4字節(jié)地址模式{w25qxx_write_enable(); // 寫使能QSPISendCMD(W25QXX_EABLE_4BYTE_ADDR, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // QPI,使能4字節(jié)地址指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)}w25qxx_write_enable(); // 寫使能QSPISendCMD(W25QXX_SET_READ_PARAM, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_4_LINES); // QPI,設(shè)置讀參數(shù)指令,地址為0,4線傳數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,1個(gè)字節(jié)數(shù)據(jù)temp = 3 << 4; // 設(shè)置P4&P5=11,8個(gè)dummy clocks,104MQSPITransmit(&temp, 1); }// 擦除一塊4096字節(jié) 最少需要150ms void W25QXXSectorErase(uint32_t addr) {//addr /= 4096;addr *= 4096;w25qxx_write_enable();w25qxx_wait_busy();QSPISendCMD(W25QXX_SECTOR_ERASE, addr, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_4_LINES, QSPI_ADDRESS_32_BITS, QSPI_DATA_NONE); // QPI,寫扇區(qū)擦除指令,地址為0,無(wú)數(shù)據(jù)_32位地址_4線傳輸?shù)刂穇4線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)w25qxx_wait_busy(); }// 擦除整個(gè)芯片 void W25QXXChipErase(void) {w25qxx_write_enable(); //SET WELw25qxx_wait_busy();QSPISendCMD(W25QXX_CHIP_ERASE, 0, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE); // QPI,寫全片擦除指令,地址為0,無(wú)數(shù)據(jù)_8位地址_無(wú)地址_4線傳輸指令,無(wú)空周期,0個(gè)字節(jié)數(shù)據(jù)w25qxx_wait_busy(); //等待芯片擦除結(jié)束 }// 寫最多256字節(jié) void W25QXXWritePage(uint32_t addr, uint8_t *buffer, uint16_t length) {w25qxx_write_enable(); //寫使能QSPISendCMD(W25QXX_PAGE_PROGRAM, addr, 0, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_4_LINES, QSPI_ADDRESS_32_BITS, QSPI_DATA_4_LINES); // QPI,頁(yè)寫指令,地址為WriteAddr,4線傳輸數(shù)據(jù)_32位地址_4線傳輸?shù)刂穇4線傳輸指令,無(wú)空周期,NumByteToWrite個(gè)數(shù)據(jù)QSPITransmit(buffer, length);w25qxx_wait_busy(); //等待寫入結(jié)束 }// 寫最多65536字節(jié) 無(wú)擦除動(dòng)作 void W25QXXWriteExt(uint32_t addr, uint8_t *buffer, uint16_t length) {uint16_t pageremain = 256 - addr % 256; // 單頁(yè)剩余的字節(jié)數(shù)if(addr + length - 1 > (32 * 1024 * 1024)){return;}if(length <= pageremain){pageremain = length; // 不大于256個(gè)字節(jié)}while(1){// 分頁(yè)寫入W25QXXWritePage(addr, buffer, pageremain);if(length == pageremain){break; //寫入結(jié)束了}else{buffer += pageremain;addr += pageremain;length -= pageremain; // 減去已經(jīng)寫入了的字節(jié)數(shù)if(length > 256){pageremain = 256; // 一次可以寫入256個(gè)字節(jié)}else{pageremain = length; // 不夠256個(gè)字節(jié)了}}} }// 寫最多65536字節(jié) 帶擦除動(dòng)作 static uint8_t W25QXX_BUFFER[4096]; void W25QXXWrite(uint32_t addr, uint8_t* buffer, uint16_t length) {uint32_t secpos;uint16_t secoff, secremain, i;uint8_t * w25q_buf;w25q_buf = W25QXX_BUFFER;secpos = addr / 4096; // 扇區(qū)地址secoff = addr % 4096; // 在扇區(qū)內(nèi)的偏移secremain = 4096 - secoff; // 扇區(qū)剩余空間大小if(length <= secremain){secremain = length; // 不大于4096個(gè)字節(jié)}while(1){WatchdogFeed();W25QXXRead(secpos * 4096, w25q_buf, 4096); // 讀出整個(gè)扇區(qū)的內(nèi)容for(i = 0; i < secremain; ++i){if(w25q_buf[secoff + i] != 0XFF){break; // 需要擦除}}if(i < secremain) // 需要擦除{W25QXXSectorErase(secpos); // 擦除這個(gè)扇區(qū)for(i = 0; i < secremain; ++i){w25q_buf[i + secoff] = buffer[i];}W25QXXWriteExt(secpos * 4096, w25q_buf, 4096); // 寫入整個(gè)扇區(qū)}else{W25QXXWriteExt(addr, buffer, secremain); // 寫已經(jīng)擦除了的,直接寫入扇區(qū)剩余區(qū)間.}if(length == secremain){break;}else{secpos++;secoff = 0;buffer += secremain;addr += secremain;length -= secremain;if(length > 4096){secremain = 4096;}else{secremain = length;}}}; }// 讀取SPI FLASH,僅支持QPI模式 在指定地址開(kāi)始讀取指定長(zhǎng)度的數(shù)據(jù) 65536 void W25QXXRead(uint32_t addr, uint8_t *buffer, uint16_t length) {QSPISendCMD(W25QXX_FAST_READ_DATA, addr, 8, QSPI_INSTRUCTION_4_LINES, QSPI_ADDRESS_4_LINES, QSPI_ADDRESS_32_BITS, QSPI_DATA_4_LINES); // QPI,快速讀數(shù)據(jù),地址為ReadAddr,4線傳輸數(shù)據(jù)_32位地址_4線傳輸?shù)刂穇4線傳輸指令,8空周期,length個(gè)數(shù)據(jù)QSPIReceive(buffer, length); }也可以使用SPI操作W25QXX。
?
?
?
?
?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的STM32F7xx —— QSPI的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 阵列信号处理基础
- 下一篇: EndnoteX9修改风格