当前位置: 首页 > news >正文

STM32F429IGT6使用CubeMX配置SPI通信(W25Q256芯片)

1、硬件电路

需要系统性的看一下W25Q256芯片手册 

2、设置RCC,选择高速外部时钟HSE,时钟设置为180MHz

3、配置SPI

 

4、生成工程配置

 

5、相关代码

#define sFLASH_ID 0XEF4019 // W25Q256#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256#define W25Q256_WriteEnable 0x06    // 写使能指令
#define W25Q256_WriteDisable 0x04   // 写屏蔽指令
#define W25Q256_ReadStatusReg 0x05  // 读取状态寄存器1
#define W25Q256_WriteStatusReg 0x01 // 写入状态寄存器1
//#define W25Q256_ReadData 0x03       // 3字节模式读取数据指令
#define W25Q256_ReadData 0x13       // 4字节模式读取数据指令
#define W25Q256_FastReadData 0x0B   //
#define W25Q256_FastReadDual 0x3B
#define W25Q256_PageProgram 0x02 // 页写入指令
#define W25Q256_BlockErase 0xD8
#define W25Q256_SectorErase 0x20
#define W25Q256_ChipErase 0xC7
#define W25Q256_PowerDown 0xB9
#define W25Q256_ReleasePowerDown 0xAB
#define W25Q256_DeviceID 0xAB
#define W25Q256_ManufactDeviceID 0x90
#define W25Q256_JedecDeviceID 0x9F
#define W25Q256_Enter4ByteMode 0xB7 // 4字节地址模式指令
#define W25Q256_ReadStatusRegister3 0x15
#define W25Q256_WriteStatusRegister3 0x11   //写状态寄存器3指令
#define WIP_Flag 0x01
#define Dummy_Byte 0xFF#define FLASH_WriteAddress 0x00000
#define FLASH_ReadAddress FLASH_WriteAddress
#define FLASH_SectorToErase FLASH_WriteAddress/* 获取缓冲区的长度 */
#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/* 发送缓冲区初始化 */
extern uint8_t ReadBuff[4096];
extern uint8_t WriteBuff[4096];

/*** @brief   拉低片选线* @param   无* @retval  无*/
void SPI_FLASH_NSS_LOW(void)
{HAL_GPIO_WritePin(SPI5_NSS_GPIO_Port, SPI5_NSS_Pin, GPIO_PIN_RESET);
}/*** @brief   拉高片选线* @param   无* @retval  无*/
void SPI_FLASH_NSS_HIGH(void)
{HAL_GPIO_WritePin(SPI5_NSS_GPIO_Port, SPI5_NSS_Pin, GPIO_PIN_SET);
}/*** @brief   获取 FLASH ID* @param   无* @retval  FLASH ID*/
uint32_t SPI_FLASH_ReadID(void)
{uint32_t temp = 0;uint32_t temp0 = 0;uint32_t temp1 = 0;uint32_t temp2 = 0;// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送获取W25Q256芯片ID指令SPI_FLASH_SendByte(W25Q256_JedecDeviceID);// 接收数据temp0 = SPI_FLASH_ReadByte();temp1 = SPI_FLASH_ReadByte();temp2 = SPI_FLASH_ReadByte();// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();temp = temp0 << 16 | temp1 << 8 | temp2;return temp;
}/*** @brief   发送一个字节* @param   无* @retval  无*/
void SPI_FLASH_SendByte(uint8_t ch)
{HAL_SPI_Transmit(&hspi5, &ch, 1, 500);
}/*** @brief   发送n个字节* @param   pData:发送数据首地址* @param   data_number:发送数据个数(以字节为单位)* @retval  无*/
void SPI_FLASH_SendnByte(uint8_t *pData, uint32_t data_number)
{HAL_SPI_Transmit(&hspi5, pData, data_number, 500);
}/*** @brief   接收一个字节* @param   无* @retval  接收的数据*/
uint8_t SPI_FLASH_ReadByte(void)
{uint8_t rxData = 0;HAL_SPI_Receive(&hspi5, &rxData, 1, 500);return rxData;
}/*** @brief   接收n个字节* @param   pData:接收数据首地址* @param   data_number:接收数据个数(以字节为单位)* @retval  无*/
void SPI_FLASH_ReadnByte(uint8_t *pData, uint32_t data_number)
{HAL_SPI_Receive(&hspi5, pData, data_number, 500);
}/*** @brief   使能写命令* @param   无* @param   无* @retval  无*/
void SPI_FLASH_WriteEnable(void)
{// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送写使能指令SPI_FLASH_SendByte(W25Q256_WriteEnable);// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();
}/*** @brief   等待写入、擦除等操作完成* @param   无* @param   无* @retval  无*/
void SPI_FLASH_WaitForWriteEnd(void)
{uint8_t FLASH_Status = 0;// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送写状态寄存器1指令SPI_FLASH_SendByte(W25Q256_ReadStatusReg);do{// 获取写状态寄存器1的值并做判断。0:空闲、1:忙碌FLASH_Status = SPI_FLASH_ReadByte();} while (SET == (FLASH_Status & WIP_Flag));// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();
}/*** @brief   擦除扇区* @param   SectorAddr:擦除扇区首地址* @retval  无*/
void SPI_FLASH_SectorErase(uint32_t SectorAddr)
{// uint8_t ADDR[4] = {0x00,0x00,0x00,0x00};//  使能写命令SPI_FLASH_WriteEnable();// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送擦除扇区命令SPI_FLASH_SendByte(W25Q256_SectorErase);// 发送擦除地址24 ~ 31bitSPI_FLASH_SendByte((SectorAddr & 0xFF000000) >> 24);// 发送擦除地址16 ~ 23bitSPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);// 发送擦除地址8 ~ 15bitSPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);// 发送擦除地址0 ~ 7bitSPI_FLASH_SendByte(SectorAddr & 0xFF);// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();// HAL_Delay(3000);// 等待擦除操作结束SPI_FLASH_WaitForOperaEnd();
}/*** @brief   配置4字节模式* @param   无* @retval  无*/
void SPI_FLASH_FOUR_MODE(void)
{uint8_t temp = 0;// 使能写命令SPI_FLASH_WriteEnable();// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送写状态寄存器3命令SPI_FLASH_SendByte(W25Q256_WriteStatusRegister3);// 发送要写的数据SPI_FLASH_SendByte(0x02);// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送读状态寄存器3命令SPI_FLASH_SendByte(W25Q256_ReadStatusRegister3);// 读取数据temp = SPI_FLASH_ReadByte();// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();if (1 == (0x02 & temp)){// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送配置四字节模式指令SPI_FLASH_SendByte(W25Q256_Enter4ByteMode);// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();}SPI_FLASH_WaitForOperaEnd();
}/*** @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)
{// 使能写命令SPI_FLASH_WriteEnable();// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送页写入指令SPI_FLASH_SendByte(W25Q256_PageProgram);// 发送写入地址[24,31]bitSPI_FLASH_SendByte((WriteAddr & 0xFF000000) >> 24);// 发送写入地址[16,23]bitSPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);// 发送写入地址[8,15]bitSPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);// 发送写入地址[0,7]bitSPI_FLASH_SendByte(WriteAddr & 0xFF);if (NumByteToWrite > SPI_FLASH_PerWritePageSize){NumByteToWrite = SPI_FLASH_PerWritePageSize;printf("256\r\n");}for (int i = 0; i < NumByteToWrite; i++){SPI_FLASH_SendByte(pBuffer[i]);}// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();
}/*** @brief   FALSH不定量数据写入函数,调用本函数写入数据前需要先擦除扇区* @param   pBuffer:要写入数据的指针* @param   WriteAddr:写入数据地址* @param   NumByteToWrite:写入数据长度* @retval  无*/
void SPI_FLASH_BufferWrite(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{uint8_t NumOfPage = 0;uint8_t NumOfSingle = 0;uint8_t Addr = 0;uint8_t count = 0;uint8_t 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 (0 == Addr){/*NumByteToWrite < SPI_FLASH_PageSize*/if (0 == NumOfPage){SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成}else{/* 先把整数页都写了 */for (int i = 0; i < NumOfPage; i++){SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}/* 若有多余的不满一页的数据,把它写完 */SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成}}else /* 若地址与 SPI_FLASH_PageSize 不对齐 */{/*NumByteToWrite < SPI_FLASH_PageSize*/if (0 == NumOfPage){/* 当前页剩余的 count 个位置比 NumOfSingle 小,写不完 */if (NumOfSingle > count){temp = NumOfSingle - count;/* 先写满当前页 */SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成WriteAddr += count;pBuffer += count;/* 再写剩余的数据 */SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成}else /* 当前页剩余的 count 个位置能写完 NumOfSingle 个数据 */{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成}}else /*NumByteToWrite > SPI_FLASH_PageSize*/{/*先把距离页地址的count个数据减去,计算需要写的页数和NumOfSingle,然后写数据时先把原来减去的count个数据写入,写满当前页*//*再写剩余数据,即计算好的NumOfPage和NumOfSingle*/NumByteToWrite -= count;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成WriteAddr += count;pBuffer += count;/* 把整数页都写了 */for (int i = 0; i < NumOfPage; i++){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}if (0 != NumOfSingle){SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成}}}
}/*** @brief   读取FLASH数据* @param   pBuffer:存储读出数据的指针* @param   WriteAddr:读取地址* @param   NumByteToRead:读取数据长度* @retval  无*/
void SPI_FLASH_BufferRead(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送读取数据指令SPI_FLASH_SendByte(W25Q256_ReadData);// 发送读取地址[24,31]bitSPI_FLASH_SendByte((ReadAddr & 0xFF000000) >> 24);// 发送读取地址[16,23]bitSPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);// 发送读取地址[8,15]bitSPI_FLASH_SendByte((ReadAddr & 0xFF00) >> 8);// 发送读取地址[0,7]bitSPI_FLASH_SendByte(ReadAddr & 0xFF);// 读取数据for (int i = 0; i < NumByteToRead; i++){// 读取一个字节数据pBuffer[i] = SPI_FLASH_ReadByte();}// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();SPI_FLASH_WaitForOperaEnd(); // 等待操作完成
}/*** @brief   等待写入、擦除等操作结束* @param   none* @param   none* @param   none* @retval  none*/
void SPI_FLASH_WaitForOperaEnd(void)
{uint8_t FLASH_Status = 0;// 拉低片选线,开始通信SPI_FLASH_NSS_LOW();// 发送读状态寄存器1指令SPI_FLASH_SendByte(W25Q256_ReadStatusReg);do{// 接收读取状态寄存器1寄存器内容FLASH_Status = SPI_FLASH_ReadByte();} while (SET == (FLASH_Status & WIP_Flag));// 拉高片选线,结束通信SPI_FLASH_NSS_HIGH();
}
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI5_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */// 进入4字节地址模式SPI_FLASH_FOUR_MODE();printf("W25Q256 SPI readwrite test!!!\r\n");device_ID = SPI_FLASH_ReadID();printf("device_ID = 0x%x\r\n", device_ID);SPI_FLASH_SectorErase(0x00); // 擦除扇区数据// 读取擦除后的数据SPI_FLASH_BufferRead(ReadBuff, 0x00, 4096);printf("*****************读取擦出后的数据*****************\r\n");for (int i = 0; i < 4096; i++){printf("ReadBuff[%d] = 0x%02x\t", i, ReadBuff[i]);if (0 == (i + 1) % 8 && (i + 1) >= 8){printf("\r\n");}}for (int i = 0; i < 256; i++){WriteBuff[i] = i;}SPI_FLASH_BufferWrite(WriteBuff, 0xFF, 256);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成// 读数据SPI_FLASH_BufferRead(ReadBuff, 0xFF, 256);SPI_FLASH_WaitForOperaEnd(); // 等待操作完成printf("*****************读取写入后的数据*****************\r\n");for (int i = 0; i < 256; i++){printf("ReadBuff[%d] = 0x%02x\t", i, ReadBuff[i]);if (0 == (i + 1) % 8 && (i + 1) >= 8){printf("\r\n");}}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */LED_TIME();}/* USER CODE END 3 */
}

6、实验现象

 

http://www.lryc.cn/news/121872.html

相关文章:

  • C++11异步与通信之 packaged_task
  • 磁盘的管理
  • 数据结构:完全二叉树的性质
  • 【数据结构】‘双向链表’冲冲冲
  • Linux 编译CEF源码详细记录
  • LeetCode 2810. Faulty Keyboard【模拟,双端队列,字符串】简单
  • 两个数组的交集-C语言/Java
  • Arduino+esp32学习笔记
  • 计算机网络-专业术语
  • E. Maximum Monogonosity
  • 已解决Excel file format cannot be determined, you must specify an engine manually
  • Centos yum命令大全
  • 内网横向移动—ARP攻击图片捕捉数据劫持DNS劫持
  • react之Hooks的介绍、useState与useEffect副作用的使用
  • django——创建 Django 项目和 APP
  • == 和 equals 的对比 [面试题]
  • SpringBoot集成Redis及Redis使用方法
  • Redis可以用作数据库吗?它的适用场景是什么?
  • @Param详解
  • 自定义分页工具类
  • 文本数据保存
  • Python爬虫:抓取表情包的下载链接
  • (文章复现)基于灰狼算法(GWO)的交直流混合微网经济调度matlab代码
  • 【Kubernetes】Kubernetes的调度
  • 题目:2511.最多可以摧毁的敌人城堡数量
  • 22 | 书籍推荐数据分析
  • vscode extension 怎么区分dev prod
  • Java学习手册——第一篇Java简介
  • Prometheus流程图(自绘)-核心组件-流程详解
  • 回归模型常见评估指标mae,mse,rmse