赞
踩












Flash写入与EEPROM有点相似,不同的是FLASH写入需要软件手动擦除,而EEPROM不用

SPI配置流程
1、初始化通讯使用的目标引脚及端口时钟
2、使能SPI外设的时钟
3、配置SPI外设的模式、地址、速率等参数并使能SPI外设
4、编写基本SPI按字节收发的函数
将片选信号拉低
查看数据发送完成标志,如果标志不存在
将数据写入SPI数据寄存器
5、编写对FLASH擦除及读写操作的函数
6、编写测试程序,对读写数据进行校验


flash 0xAB指令

flash 0x90指令

注意FLASH地址是24位的

这里直接放spi_flash的板级支持包,直接调用即可
可以直接将CubeMX生成的源文件spi.c和spi.h替换成下述文件即可
spi.c
- /**
- ******************************************************************************
- * @file spi.c
- * @brief This file provides code for the configuration
- * of the SPI instances.
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2022 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- */
- /* Includes ------------------------------------------------------------------*/
- #include "spi.h"
-
- /* USER CODE BEGIN 0 */
-
- /* USER CODE END 0 */
-
- SPI_HandleTypeDef SpiHandle;
-
- static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
-
- static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
-
- /**
- * @brief SPI MSP Initialization
- * This function configures the hardware resources used in this example:
- * - Peripheral's clock enable
- * - Peripheral's GPIO Configuration
- * @param hspi: SPI handle pointer
- * @retval None
- */
- void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
-
- /*##-1- Enable peripherals and GPIO Clocks #################################*/
- /* Enable GPIO TX/RX clock */
- SPIx_SCK_GPIO_CLK_ENABLE();
- SPIx_MISO_GPIO_CLK_ENABLE();
- SPIx_MOSI_GPIO_CLK_ENABLE();
- SPIx_CS_GPIO_CLK_ENABLE();
- /* Enable SPI clock */
- SPIx_CLK_ENABLE();
-
- /*##-2- Configure peripheral GPIO ##########################################*/
- /* SPI SCK GPIO pin configuration */
- GPIO_InitStruct.Pin = SPIx_SCK_PIN;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
- GPIO_InitStruct.Alternate = SPIx_SCK_AF;
-
- HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);
-
- /* SPI MISO GPIO pin configuration */
- GPIO_InitStruct.Pin = SPIx_MISO_PIN;
- GPIO_InitStruct.Alternate = SPIx_MISO_AF;
-
- HAL_GPIO_Init(SPIx_MISO_GPIO_PORT, &GPIO_InitStruct);
-
- /* SPI MOSI GPIO pin configuration */
- GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
- GPIO_InitStruct.Alternate = SPIx_MOSI_AF;
- HAL_GPIO_Init(SPIx_MOSI_GPIO_PORT, &GPIO_InitStruct);
-
- GPIO_InitStruct.Pin = FLASH_CS_PIN ;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- HAL_GPIO_Init(FLASH_CS_GPIO_PORT, &GPIO_InitStruct);
- }
-
- void SPI_FLASH_Init(void)
- {
- /*##-1- Configure the SPI peripheral #######################################*/
- /* Set the SPI parameters */
- SpiHandle.Instance = SPIx;
- SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
- SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
- SpiHandle.Init.CLKPhase = SPI_PHASE_2EDGE;
- SpiHandle.Init.CLKPolarity = SPI_POLARITY_HIGH;
- SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
- SpiHandle.Init.CRCPolynomial = 7;
- SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
- SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
- SpiHandle.Init.NSS = SPI_NSS_SOFT;
- SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
-
- SpiHandle.Init.Mode = SPI_MODE_MASTER;
-
- HAL_SPI_Init(&SpiHandle);
-
- __HAL_SPI_ENABLE(&SpiHandle);
- }
-
-
- /**
- * @brief 擦除FLASH扇区
- * @param SectorAddr:要擦除的扇区地址
- * @retval 无
- */
- void SPI_FLASH_SectorErase(uint32_t SectorAddr)
- {
- /* 发送FLASH写使能命令 */
- SPI_FLASH_WriteEnable();
- SPI_FLASH_WaitForWriteEnd();
- /* 擦除扇区 */
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
- /* 发送扇区擦除指令*/
- SPI_FLASH_SendByte(W25X_SectorErase);
- /*发送擦除扇区地址的高位*/
- SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
- /* 发送擦除扇区地址的中位 */
- SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
- /* 发送擦除扇区地址的低位 */
- SPI_FLASH_SendByte(SectorAddr & 0xFF);
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
- /* 等待擦除完毕*/
- SPI_FLASH_WaitForWriteEnd();
- }
-
-
- /**
- * @brief 擦除FLASH扇区,整片擦除
- * @param 无
- * @retval 无
- */
- void SPI_FLASH_BulkErase(void)
- {
- /* 发送FLASH写使能命令 */
- SPI_FLASH_WriteEnable();
-
- /* 整块 Erase */
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
- /* 发送整块擦除指令*/
- SPI_FLASH_SendByte(W25X_ChipErase);
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
-
- /* 等待擦除完毕*/
- SPI_FLASH_WaitForWriteEnd();
- }
-
- /**
- * @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
- * @param pBuffer,要写入数据的指针
- * @param WriteAddr,写入地址
- * @param NumByteToWrite,写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
- * @retval 无
- */
- void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
- {
- /* 发送FLASH写使能命令 */
- SPI_FLASH_WriteEnable();
-
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
- /* 写页写指令*/
- SPI_FLASH_SendByte(W25X_PageProgram);
- /*发送写地址的高位*/
- SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
- /*发送写地址的中位*/
- SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
- /*发送写地址的低位*/
- SPI_FLASH_SendByte(WriteAddr & 0xFF);
-
- if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
- {
- NumByteToWrite = SPI_FLASH_PerWritePageSize;
- FLASH_ERROR("SPI_FLASH_PageWrite too large!");
- }
-
- /* 写入数据*/
- while (NumByteToWrite--)
- {
- /* 发送当前要写入的字节数据 */
- SPI_FLASH_SendByte(*pBuffer);
- /* 指向下一字节数据 */
- pBuffer++;
- }
-
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
-
- /* 等待写入完毕*/
- SPI_FLASH_WaitForWriteEnd();
- }
-
-
- /**
- * @brief 对FLASH写入数据,调用本函数写入数据前需要先擦除扇区
- * @param pBuffer,要写入数据的指针
- * @param WriteAddr,写入地址
- * @param NumByteToWrite,写入数据长度
- * @retval 无
- */
- void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
- {
- uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
-
- /*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
- Addr = WriteAddr % SPI_FLASH_PageSize;
-
- /*差count个数据值,刚好可以对齐到页地址*/
- count = SPI_FLASH_PageSize - Addr;
- /*计算出要写多少整数页*/
- NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
- /*mod运算求余,计算出剩余不满一页的字节数*/
- NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
-
- /* Addr=0,则WriteAddr 刚好按页对齐 aligned */
- if (Addr == 0)
- {
- /* NumByteToWrite < SPI_FLASH_PageSize */
- if (NumOfPage == 0)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
- }
- else /* NumByteToWrite > SPI_FLASH_PageSize */
- {
- /*先把整数页都写了*/
- while (NumOfPage--)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
- WriteAddr += SPI_FLASH_PageSize;
- pBuffer += SPI_FLASH_PageSize;
- }
-
- /*若有多余的不满一页的数据,把它写完*/
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
- }
- }
- /* 若地址与 SPI_FLASH_PageSize 不对齐 */
- else
- {
- /* NumByteToWrite < SPI_FLASH_PageSize */
- if (NumOfPage == 0)
- {
- /*当前页剩余的count个位置比NumOfSingle小,写不完*/
- if (NumOfSingle > count)
- {
- temp = NumOfSingle - count;
-
- /*先写满当前页*/
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
- WriteAddr += count;
- pBuffer += count;
-
- /*再写剩余的数据*/
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
- }
- else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
- }
- }
- else /* NumByteToWrite > SPI_FLASH_PageSize */
- {
- /*地址不对齐多出的count分开处理,不加入这个运算*/
- NumByteToWrite -= count;
- NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
- NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
-
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
- WriteAddr += count;
- pBuffer += count;
-
- /*把整数页都写了*/
- while (NumOfPage--)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
- WriteAddr += SPI_FLASH_PageSize;
- pBuffer += SPI_FLASH_PageSize;
- }
- /*若有多余的不满一页的数据,把它写完*/
- if (NumOfSingle != 0)
- {
- SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
- }
- }
- }
- }
-
- /**
- * @brief 读取FLASH数据
- * @param pBuffer,存储读出数据的指针
- * @param ReadAddr,读取地址
- * @param NumByteToRead,读取数据长度
- * @retval 无
- */
- void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
- {
- /* 选择FLASH: CS低电平 */
- SPI_FLASH_CS_LOW();
-
- /* 发送 读 指令 */
- SPI_FLASH_SendByte(W25X_ReadData);
-
- /* 发送 读 地址高位 */
- SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
- /* 发送 读 地址中位 */
- SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
- /* 发送 读 地址低位 */
- SPI_FLASH_SendByte(ReadAddr & 0xFF);
-
- /* 读取数据 */
- while (NumByteToRead--)
- {
- /* 读取一个字节*/
- *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
- /* 指向下一个字节缓冲区 */
- pBuffer++;
- }
-
- /* 停止信号 FLASH: CS 高电平 */
- SPI_FLASH_CS_HIGH();
- }
-
-
- /**
- * @brief 读取FLASH ID
- * @param 无
- * @retval FLASH ID
- */
- uint32_t SPI_FLASH_ReadID(void)
- {
- uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
-
- /* 开始通讯:CS低电平 */
- SPI_FLASH_CS_LOW();
-
- /* 发送JEDEC指令,读取ID */
- SPI_FLASH_SendByte(W25X_JedecDeviceID);
-
- /* 读取一个字节数据 */
- Temp0 = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* 读取一个字节数据 */
- Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* 读取一个字节数据 */
- Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* 停止通讯:CS高电平 */
- SPI_FLASH_CS_HIGH();
-
- /*把数据组合起来,作为函数的返回值*/
- Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
-
- return Temp;
- }
-
- /**
- * @brief 读取FLASH Device ID
- * @param 无
- * @retval FLASH Device ID
- */
- uint32_t SPI_FLASH_ReadDeviceID(void)
- {
- uint32_t Temp = 0;
-
- /* Select the FLASH: Chip Select low */
- SPI_FLASH_CS_LOW();
-
- /* Send "RDID " instruction */
- SPI_FLASH_SendByte(W25X_DeviceID);
- SPI_FLASH_SendByte(Dummy_Byte);
- SPI_FLASH_SendByte(Dummy_Byte);
- SPI_FLASH_SendByte(Dummy_Byte);
-
- /* Read a byte from the FLASH */
- Temp = SPI_FLASH_SendByte(Dummy_Byte);
-
- /* Deselect the FLASH: Chip Select high */
- SPI_FLASH_CS_HIGH();
-
- return Temp;
- }
- /*******************************************************************************
- * Function Name : SPI_FLASH_StartReadSequence
- * Description : Initiates a read data byte (READ) sequence from the Flash.
- * This is done by driving the /CS line low to select the device,
- * then the READ instruction is transmitted followed by 3 bytes
- * address. This function exit and keep the /CS line low, so the
- * Flash still being selected. With this technique the whole
- * content of the Flash is read with a single READ instruction.
- * Input : - ReadAddr : FLASH's internal address to read from.
- * Output : None
- * Return : None
- *******************************************************************************/
- void SPI_FLASH_StartReadSequence(uint32_t ReadAddr)
- {
- /* Select the FLASH: Chip Select low */
- SPI_FLASH_CS_LOW();
- /* Send "Read from Memory " instruction */
- SPI_FLASH_SendByte(W25X_ReadData);
- /* Send the 24-bit address of the address to read from -----------------------*/
- /* Send ReadAddr high nibble address byte */
- SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
- /* Send ReadAddr medium nibble address byte */
- SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
- /* Send ReadAddr low nibble address byte */
- SPI_FLASH_SendByte(ReadAddr & 0xFF);
- }
- /**
- * @brief 使用SPI读取一个字节的数据
- * @param 无
- * @retval 返回接收到的数据
- */
- uint8_t SPI_FLASH_ReadByte(void)
- {
- return (SPI_FLASH_SendByte(Dummy_Byte));
- }
- /**
- * @brief 使用SPI发送一个字节的数据
- * @param byte:要发送的数据
- * @retval 返回接收到的数据
- */
- uint8_t SPI_FLASH_SendByte(uint8_t byte)
- {
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 等待发送缓冲区为空,TXE事件 */
- while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_TXE ) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0);
- }
- /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */
- WRITE_REG(SpiHandle.Instance->DR, byte);
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 等待接收缓冲区非空,RXNE事件 */
- while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_RXNE ) == RESET)
- {//发送缓冲区会在下一个周期将数据发送出去
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1);
- }
- /* 读取数据寄存器,获取接收缓冲区数据 */
- return READ_REG(SpiHandle.Instance->DR);
- // static uint8_t Rx_Data[1];
- // static uint8_t Tx_Data[1];
- // Tx_Data[0]=byte;
- // if(HAL_SPI_TransmitReceive(&SpiHandle,Tx_Data,Rx_Data,1,1000)!=HAL_OK)
- // {
- // return 0;
- // }
- // return Rx_Data[0];
- }
- /*******************************************************************************
- * Function Name : SPI_FLASH_SendHalfWord
- * Description : Sends a Half Word through the SPI interface and return the
- * Half Word received from the SPI bus.
- * Input : Half Word : Half Word to send.
- * Output : None
- * Return : The value of the received Half Word.
- *******************************************************************************/
- uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord)
- {
-
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* Loop while DR register in not emplty */
- while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_TXE ) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(2);
- }
- /* Send Half Word through the SPIx peripheral */
- WRITE_REG(SpiHandle.Instance->DR, HalfWord);
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* Wait to receive a Half Word */
- while (__HAL_SPI_GET_FLAG( &SpiHandle, SPI_FLAG_RXNE ) == RESET)
- {
- if((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(3);
- }
- /* Return the Half Word read from the SPI bus */
- return READ_REG(SpiHandle.Instance->DR);
- }
- /**
- * @brief 向FLASH发送 写使能 命令
- * @param none
- * @retval none
- */
- void SPI_FLASH_WriteEnable(void)
- {
- /* 通讯开始:CS低 */
- SPI_FLASH_CS_LOW();
- /* 发送写使能命令*/
- SPI_FLASH_SendByte(W25X_WriteEnable);
- /*通讯结束:CS高 */
- SPI_FLASH_CS_HIGH();
- }
- /**
- * @brief 等待WIP(BUSY)标志被置0,即等待到FLASH内部数据写入完毕
- * @param none
- * @retval none
- */
- void SPI_FLASH_WaitForWriteEnd(void)
- {
- uint8_t FLASH_Status = 0;
- /* 选择 FLASH: CS 低 */
- SPI_FLASH_CS_LOW();
- /* 发送 读状态寄存器 命令 */
- SPI_FLASH_SendByte(W25X_ReadStatusReg);
- SPITimeout = SPIT_FLAG_TIMEOUT;
- /* 若FLASH忙碌,则等待 */
- do
- {
- /* 读取FLASH芯片的状态寄存器 */
- FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
- {
- if((SPITimeout--) == 0)
- {
- SPI_TIMEOUT_UserCallback(4);
- return;
- }
- }
- }
- while ((FLASH_Status & WIP_Flag) == SET); /* 正在写入标志 */
- /* 停止信号 FLASH: CS 高 */
- SPI_FLASH_CS_HIGH();
- }
- //进入掉电模式
- void SPI_Flash_PowerDown(void)
- {
- /* 选择 FLASH: CS 低 */
- SPI_FLASH_CS_LOW();
- /* 发送 掉电 命令 */
- SPI_FLASH_SendByte(W25X_PowerDown);
- /* 停止信号 FLASH: CS 高 */
- SPI_FLASH_CS_HIGH();
- }
- //唤醒
- void SPI_Flash_WAKEUP(void)
- {
- /*选择 FLASH: CS 低 */
- SPI_FLASH_CS_LOW();
- /* 发上 上电 命令 */
- SPI_FLASH_SendByte(W25X_ReleasePowerDown);
- /* 停止信号 FLASH: CS 高 */
- SPI_FLASH_CS_HIGH(); //等待TRES1
- }
- /**
- * @brief 等待超时回调函数
- * @param None.
- * @retval None.
- */
- static uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
- {
- /* 等待超时后的处理,输出错误信息 */
- FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
- return 0;
- }
-
- /*********************************************END OF FILE**********************/

spi.h
- /**
- ******************************************************************************
- * @file spi.h
- * @brief This file contains all the function prototypes for
- * the spi.c file
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2022 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- */
- /* Define to prevent recursive inclusion -------------------------------------*/
- #ifndef __SPI_H__
- #define __SPI_H__
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
-
- /* USER CODE BEGIN Includes */
-
- /* USER CODE END Includes */
-
- #define sFLASH_ID 0XEF4018 //W25Q128
-
-
- //#define SPI_FLASH_PageSize 4096
- #define SPI_FLASH_PageSize 256
- #define SPI_FLASH_PerWritePageSize 256
-
- /* Private define ------------------------------------------------------------*/
- /*命令定义-开头*******************************/
- #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 WIP_Flag 0x01 /* Write In Progress (WIP) flag */
- #define Dummy_Byte 0xFF
- /*命令定义-结尾*******************************/
-
- //SPI号及时钟初始化函数
- #define SPIx SPI1
- #define SPIx_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
- #define SPIx_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
- #define SPIx_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
- #define SPIx_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
- #define SPIx_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
-
- #define SPIx_FORCE_RESET() __HAL_RCC_SPI1_FORCE_RESET()
- #define SPIx_RELEASE_RESET() __HAL_RCC_SPI1_RELEASE_RESET()
-
- //SCK引脚
- #define SPIx_SCK_PIN GPIO_PIN_3
- #define SPIx_SCK_GPIO_PORT GPIOB
- #define SPIx_SCK_AF GPIO_AF5_SPI1
- //MISO引脚
- #define SPIx_MISO_PIN GPIO_PIN_4
- #define SPIx_MISO_GPIO_PORT GPIOB
- #define SPIx_MISO_AF GPIO_AF5_SPI1
- //MOSI引脚
- #define SPIx_MOSI_PIN GPIO_PIN_5
- #define SPIx_MOSI_GPIO_PORT GPIOB
- #define SPIx_MOSI_AF GPIO_AF5_SPI1
- //CS(NSS)引脚
- #define FLASH_CS_PIN GPIO_PIN_6
- #define FLASH_CS_GPIO_PORT GPIOG
- //设置为高电平
- #define digitalHi(p,i) {p->BSRR=i;}
- //输出低电平
- #define digitalLo(p,i) {p->BSRR=(uint32_t)i << 16;}
- #define SPI_FLASH_CS_LOW() digitalLo(FLASH_CS_GPIO_PORT,FLASH_CS_PIN )
- #define SPI_FLASH_CS_HIGH() digitalHi(FLASH_CS_GPIO_PORT,FLASH_CS_PIN )
- /*SPI接口定义-结尾****************************/
-
- /*等待超时时间*/
- #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
- #define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
-
- /*信息输出*/
- #define FLASH_DEBUG_ON 1
-
- #define FLASH_INFO(fmt,arg...) printf("<<-FLASH-INFO->> "fmt"\n",##arg)
- #define FLASH_ERROR(fmt,arg...) printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
- #define FLASH_DEBUG(fmt,arg...) do{\
- if(FLASH_DEBUG_ON)\
- printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
- }while(0)
-
-
-
- void SPI_FLASH_Init(void);
- void SPI_FLASH_SectorErase(uint32_t SectorAddr);
- void SPI_FLASH_BulkErase(void);
- void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
- void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
- void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
- uint32_t SPI_FLASH_ReadID(void);
- uint32_t SPI_FLASH_ReadDeviceID(void);
- void SPI_FLASH_StartReadSequence(uint32_t ReadAddr);
- void SPI_Flash_PowerDown(void);
- void SPI_Flash_WAKEUP(void);
-
-
- uint8_t SPI_FLASH_ReadByte(void);
- uint8_t SPI_FLASH_SendByte(uint8_t byte);
- uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord);
- void SPI_FLASH_WriteEnable(void);
- void SPI_FLASH_WaitForWriteEnd(void);
-
- #endif /* __SPI_FLASH_H */

main.c
- /* USER CODE BEGIN Header */
- /**
- ******************************************************************************
- * @file : main.c
- * @brief : Main program body
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2022 STMicroelectronics.
- * All rights reserved.</center></h2>
- *
- * This software component is licensed by ST under BSD 3-Clause license,
- * the "License"; You may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- * opensource.org/licenses/BSD-3-Clause
- *
- ******************************************************************************
- */
- /* USER CODE END Header */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "spi.h"
- #include "usart.h"
- #include "gpio.h"
- #include <stdio.h>
-
- void SystemClock_Config(void);
-
- typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;
-
- /* 获取缓冲区的长度 */
- #define TxBufferSize1 (countof(TxBuffer1) - 1)
- #define RxBufferSize1 (countof(TxBuffer1) - 1)
- #define countof(a) (sizeof(a) / sizeof(*(a)))
- #define BufferSize (countof(Tx_Buffer)-1)
- #define FLASH_WriteAddress 0x00000
- #define FLASH_ReadAddress FLASH_WriteAddress
- #define FLASH_SectorToErase FLASH_WriteAddress
-
-
- /* 发送缓冲区初始化 */
- uint8_t Tx_Buffer[] = "hello world!";
- uint8_t Rx_Buffer[BufferSize];
-
- //读取的ID存储位置
- __IO uint32_t DeviceID = 0;
- __IO uint32_t FlashID = 0;
- __IO TestStatus TransferStatus1 = FAILED;
- TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
-
- HAL_Init();
-
- SystemClock_Config();
- MX_GPIO_Init();
- /* 16M串行flash W25Q128初始化 */
- SPI_FLASH_Init();
- MX_USART1_UART_Init();
- printf("\r\n这是一个16M串行flash(W25Q128)实验(QSPI驱动) \r\n");
- /* 16M串行flash W25Q128初始化 */
- /* 获取 Flash Device ID */
- DeviceID = SPI_FLASH_ReadDeviceID();
-
- HAL_Delay( 200 );
-
- /* 获取 SPI Flash ID */
- FlashID = SPI_FLASH_ReadID();
-
- printf("\r\nFlashID is 0x%X, Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);
-
- /* 检验 SPI Flash ID */
- if (FlashID == sFLASH_ID)
- {
- printf("\r\n检测到SPI FLASH W25Q128 !\r\n");
-
- /* 擦除将要写入的 SPI FLASH 扇区,FLASH写入前要先擦除 */
- SPI_FLASH_SectorErase(FLASH_SectorToErase);
-
- /* 将发送缓冲区的数据写到flash中 */
- SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);
- printf("\r\n写入的数据为:\r\n%s", Tx_Buffer);
-
- /* 将刚刚写入的数据读出来放到接收缓冲区中 */
- SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
- printf("\r\n读出的数据为:\r\n%s", Rx_Buffer);
-
- /* 检查写入的数据与读出的数据是否相等 */
- TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
- if( PASSED == TransferStatus1 )
- {
- LED_ALLON;
- printf("\r\n16M串行flash(W25Q128)测试成功!\n\r");
- }
- else
- {
- LED2_ON;
- printf("\r\n16M串行flash(W25Q128)测试失败!\n\r");
- }
- }// if (FlashID == sFLASH_ID)
- else
- {
- LED2_ON;
- printf("\r\n获取不到 W25Q128 ID!\n\r");
- }
-
- SPI_Flash_PowerDown();
- while (1)
- {
-
- }
-
- }
-
- TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
- {
- while(BufferLength--)
- {
- if(*pBuffer1 != *pBuffer2)
- {
- return FAILED;
- }
-
- pBuffer1++;
- pBuffer2++;
- }
- return PASSED;
- }
-
- /**
- * @brief System Clock Configuration
- * @retval None
- */
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
-
- /** Configure the main internal regulator output voltage
- */
- __HAL_RCC_PWR_CLK_ENABLE();
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 25;
- RCC_OscInitStruct.PLL.PLLN = 336;
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
- RCC_OscInitStruct.PLL.PLLQ = 4;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- /** Initializes the CPU, AHB and APB buses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
-
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
- {
- Error_Handler();
- }
- }
-
- /* USER CODE BEGIN 4 */
-
- /* USER CODE END 4 */
-
- /**
- * @brief This function is executed in case of error occurrence.
- * @retval None
- */
- void Error_Handler(void)
- {
- /* USER CODE BEGIN Error_Handler_Debug */
- /* User can add his own implementation to report the HAL error return state */
- __disable_irq();
- while (1)
- {
- }
- /* USER CODE END Error_Handler_Debug */
- }
-
- #ifdef USE_FULL_ASSERT
- /**
- * @brief Reports the name of the source file and the source line number
- * where the assert_param error has occurred.
- * @param file: pointer to the source file name
- * @param line: assert_param error line source number
- * @retval None
- */
- void assert_failed(uint8_t *file, uint32_t line)
- {
- /* USER CODE BEGIN 6 */
- /* User can add his own implementation to report the file name and line number,
- ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
- /* USER CODE END 6 */
- }
- #endif /* USE_FULL_ASSERT */
-
- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

LED和串口UART配置这里就不过多介绍了,感谢大家的阅读!^_^
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。