STM32系列(HAL库)——F103C8T6通过SPI方式读写W25Q64—(Flash存储模块)
1.软件准备
(1)编程平台:Keil5
(2)CubeMX
(3)XCOM(串口调试助手)
2.硬件准备
(1)W25Q64模块
(2)F1的板子,本例使用经典F103C8T6
(3)ST-link 下载器
(4)USB-TTL模块
(5)杜邦线若干
3.模块资料
(1)模块简介:
- W25Q64(64M-bit),W25Q16(16M-bit)和W25Q32(32M-bit)是为系统提供一个最小的空间、引脚和功耗的存储器解决方案的串行Flash存储器。25Q系列比普通的串行Flash存储器更灵活,性能更优越。基于双倍/四倍的SPI,它们能够可以立即完成提供数据给RAM,包括存储声音、文本和数据。芯片支持的工作电压2.7V到3.6V,正常工作时电流小于5mA,掉电时低于1uA。所有芯片提供标准的封装。
- W25Q64/16/32由每页256字节组成。每页的256字节用一次页编程指令即可完成。每次可以擦除16页(1个扇区)、128页(32KB块)、256页(64KB块)和全片擦除。
- W25Q64的内存空间结构:一页256字节,4K(4096字节)为一个扇区,16个扇区为1块,容量为8M字节,共有128个块,2048个扇区。
- W25Q64/16/32支持标准串行外围接口(SPI),和高速的双倍/四倍输出,双倍/四倍用的引脚:串行时钟、片选端、串行数据I/00(DI)、I/01(DO)、I/O2(WP)和I/03(HOLD)。SPI最高支持8OMHz,当用快读双倍/四倍指令时,相当于双倍输出时最高速率160MHz,四倍输出时最高速率32OMHz。这个传输速率比得上8位和16位的并行Flash存储器。
(2)模块参数:
- 采用串行Nor flash外扩存储芯片
- 支持SPI接口
- 工作电压:2.7~3.6V
- 容量: 32Mbit(W25Q32)、64Mbit(W25Q64)、128Mbit(W25Q128)
(3)参考原理图:
更多资料可参考:W25Q64数据手册
4.CubeMX配置
(1)芯片选择
(2)配置RCC、SYS、时钟树
配置RCC
配置SYS
配置时钟树
(3)配置串口1
(4)配置SPI1
(5)配置GPIO
(6)设置路径、生成代码工程
5、Keil5代码
(1)勾选Use MicroLIB
(2)创建W25Qxx.c和W25Qxx.h文件
(3)添加上述的W25Qxx.c文件进工程
——————上述两步参考之前系列教学步骤,在此不再赘述(点击跳转)
(4)W25Qxx.c和W25Qxx.h代码
#ifndef __W25Qxx_H
#define __W25Qxx_H/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx.h"
#include "spi.h"#define W25Q128FV_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */
#define W25Q128FV_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */
#define W25Q128FV_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */
#define W25Q128FV_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */#define W25Q128FV_DUMMY_CYCLES_READ 4
#define W25Q128FV_DUMMY_CYCLES_READ_QUAD 10#define W25Q128FV_BULK_ERASE_MAX_TIME 250000
#define W25Q128FV_SECTOR_ERASE_MAX_TIME 3000
#define W25Q128FV_SUBSECTOR_ERASE_MAX_TIME 800
#define W25Qx_TIMEOUT_VALUE 1000/* Reset Operations */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99#define ENTER_QPI_MODE_CMD 0x38
#define EXIT_QPI_MODE_CMD 0xFF/* Identification Operations */
#define READ_ID_CMD 0x90
#define DUAL_READ_ID_CMD 0x92
#define QUAD_READ_ID_CMD 0x94
#define READ_JEDEC_ID_CMD 0x9F/* Read Operations */
#define READ_CMD 0x03
#define FAST_READ_CMD 0x0B
#define DUAL_OUT_FAST_READ_CMD 0x3B
#define DUAL_INOUT_FAST_READ_CMD 0xBB
#define QUAD_OUT_FAST_READ_CMD 0x6B
#define QUAD_INOUT_FAST_READ_CMD 0xEB/* Write Operations */
#define WRITE_ENABLE_CMD 0x06
#define WRITE_DISABLE_CMD 0x04/* Register Operations */
#define READ_STATUS_REG1_CMD 0x05
#define READ_STATUS_REG2_CMD 0x35
#define READ_STATUS_REG3_CMD 0x15#define WRITE_STATUS_REG1_CMD 0x01
#define WRITE_STATUS_REG2_CMD 0x31
#define WRITE_STATUS_REG3_CMD 0x11/* Program Operations */
#define PAGE_PROG_CMD 0x02
#define QUAD_INPUT_PAGE_PROG_CMD 0x32/* Erase Operations */
#define SECTOR_ERASE_CMD 0x20
#define CHIP_ERASE_CMD 0xC7#define PROG_ERASE_RESUME_CMD 0x7A
#define PROG_ERASE_SUSPEND_CMD 0x75/* Flag Status Register */
#define W25Q128FV_FSR_BUSY ((uint8_t)0x01) /*!< busy */
#define W25Q128FV_FSR_WREN ((uint8_t)0x02) /*!< write enable */
#define W25Q128FV_FSR_QE ((uint8_t)0x02) /*!< quad enable */#define W25Qx_Enable() HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_RESET)
#define W25Qx_Disable() HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_SET)#define W25Qx_OK ((uint8_t)0x00)
#define W25Qx_ERROR ((uint8_t)0x01)
#define W25Qx_BUSY ((uint8_t)0x02)
#define W25Qx_TIMEOUT ((uint8_t)0x03)uint8_t BSP_W25Qx_Init(void);
static void BSP_W25Qx_Reset(void);
static uint8_t BSP_W25Qx_GetStatus(void);
uint8_t BSP_W25Qx_WriteEnable(void);
void BSP_W25Qx_Read_ID(uint8_t *ID);
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size);
uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size);
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address);
uint8_t BSP_W25Qx_Erase_Chip(void);#endif
#include "W25Qxx.h"/*********************************************************************************** 函数功能: 模块初始化*/
uint8_t BSP_W25Qx_Init(void)
{ BSP_W25Qx_Reset(); return BSP_W25Qx_GetStatus();
}static void BSP_W25Qx_Reset(void)
{uint8_t cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};W25Qx_Enable();/* Send the reset command */HAL_SPI_Transmit(&hspi1, cmd, 2, W25Qx_TIMEOUT_VALUE); W25Qx_Disable();}/*********************************************************************************** 函数功能: 获取设备状态*/
static uint8_t BSP_W25Qx_GetStatus(void)
{uint8_t cmd[] = {READ_STATUS_REG1_CMD};uint8_t status;W25Qx_Enable();/* Send the read status command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE); /* Reception of the data */HAL_SPI_Receive(&hspi1,&status, 1, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();/* Check the value of the register */if((status & W25Q128FV_FSR_BUSY) != 0){return W25Qx_BUSY;}else{return W25Qx_OK;}
}/*********************************************************************************** 函数功能: 写使能*/
uint8_t BSP_W25Qx_WriteEnable(void)
{uint8_t cmd[] = {WRITE_ENABLE_CMD};uint32_t tickstart = HAL_GetTick();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE); /*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE){ return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*********************************************************************************** 函数功能: 获取设备ID*/
void BSP_W25Qx_Read_ID(uint8_t *ID)
{uint8_t cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE); /* Reception of the data */HAL_SPI_Receive(&hspi1,ID, 2, W25Qx_TIMEOUT_VALUE);W25Qx_Disable();}/*********************************************************************************** 函数功能: 读数据* 输入参数: 缓存数组指针、读地址、字节数*/
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{uint8_t cmd[4];/* Configure the command */cmd[0] = READ_CMD;cmd[1] = (uint8_t)(ReadAddr >> 16);cmd[2] = (uint8_t)(ReadAddr >> 8);cmd[3] = (uint8_t)(ReadAddr);W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE); /* Reception of the data */if (HAL_SPI_Receive(&hspi1, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}W25Qx_Disable();return W25Qx_OK;
}/*********************************************************************************** 函数功能: 写数据* 输入参数: 缓存数组指针、写地址、字节数*/
uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{uint8_t cmd[4];uint32_t end_addr, current_size, current_addr;uint32_t tickstart = HAL_GetTick();/* Calculation of the size between the write address and the end of the page */current_addr = 0;while (current_addr <= WriteAddr){current_addr += W25Q128FV_PAGE_SIZE;}current_size = current_addr - WriteAddr;/* Check if the size of the data is less than the remaining place in the page */if (current_size > Size){current_size = Size;}/* Initialize the adress variables */current_addr = WriteAddr;end_addr = WriteAddr + Size;/* Perform the write page by page */do{/* Configure the command */cmd[0] = PAGE_PROG_CMD;cmd[1] = (uint8_t)(current_addr >> 16);cmd[2] = (uint8_t)(current_addr >> 8);cmd[3] = (uint8_t)(current_addr);/* Enable write operations */BSP_W25Qx_WriteEnable();W25Qx_Enable();/* Send the command */if (HAL_SPI_Transmit(&hspi1,cmd, 4, W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}/* Transmission of the data */if (HAL_SPI_Transmit(&hspi1, pData,current_size, W25Qx_TIMEOUT_VALUE) != HAL_OK){return W25Qx_ERROR;}W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE){ return W25Qx_TIMEOUT;}}/* Update the address and size variables for next page programming */current_addr += current_size;pData += current_size;current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE;} while (current_addr < end_addr);return W25Qx_OK;
}/*********************************************************************************** 函数功能: 扇区擦除* 输入参数: 地址*/
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address)
{uint8_t cmd[4];uint32_t tickstart = HAL_GetTick();cmd[0] = SECTOR_ERASE_CMD;cmd[1] = (uint8_t)(Address >> 16);cmd[2] = (uint8_t)(Address >> 8);cmd[3] = (uint8_t)(Address);/* Enable write operations */BSP_W25Qx_WriteEnable();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE); /*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Q128FV_SECTOR_ERASE_MAX_TIME){ return W25Qx_TIMEOUT;}}return W25Qx_OK;
}/*********************************************************************************** 函数功能: 芯片擦除*/
uint8_t BSP_W25Qx_Erase_Chip(void)
{uint8_t cmd[4];uint32_t tickstart = HAL_GetTick();cmd[0] = CHIP_ERASE_CMD;/* Enable write operations */BSP_W25Qx_WriteEnable();/*Select the FLASH: Chip Select low */W25Qx_Enable();/* Send the read ID command */HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE); /*Deselect the FLASH: Chip Select high */W25Qx_Disable();/* Wait the end of Flash writing */while(BSP_W25Qx_GetStatus() != W25Qx_BUSY);{/* Check for the Timeout */if((HAL_GetTick() - tickstart) > W25Q128FV_BULK_ERASE_MAX_TIME){ return W25Qx_TIMEOUT;}}return W25Qx_OK;
}
(5) usart.c函数添加
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 *//* USER CODE BEGIN 1 */
/*********************************************************
*
*重定义 fputc 函数
*
*********************************************************/
int fputc(int ch,FILE *f)
{HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch,1,HAL_MAX_DELAY );return ch;
}
/* USER CODE END 1 */
(6)main函数
#include <string.h>
#include <stdio.h>
#include "W25Qxx.h"uint8_t wData[0x100]; //写缓存数组
uint8_t rData[0x100]; //读缓存数组
uint8_t ID[4]; //设备ID缓存数组
uint32_t i;void SystemClock_Config(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_SPI1_Init();MX_USART1_UART_Init();printf("\r\n SPI-W25Qxx Example \r\n\r\n");/*-Step1- 验证设备ID ************************************************Step1*/ BSP_W25Qx_Init();BSP_W25Qx_Read_ID(ID);//第一位厂商ID固定0xEF,第二位设备ID根据容量不同,具体为://W25Q16为0x14、32为0x15、40为0x12、64为0x16、80为0x13、128为0x17if((ID[0] != 0xEF) | (ID[1] != 0x16)) { printf("something wrong in Step1 \r\n");}else{printf(" W25Qxx ID is : ");for(i=0;i<2;i++){printf("0x%02X ",ID[i]);}printf("\r\n");}/*-Step2- 擦除块 ************************************************Step2*/ if(BSP_W25Qx_Erase_Block(0) == W25Qx_OK)printf(" QSPI Erase Block OK!\r\n");elseprintf("something wrong in Step2\r\n");/*-Step3- 写数据 ************************************************Step3*/ for(i =0;i<0x100;i ++){wData[i] = i;rData[i] = 0;}if(BSP_W25Qx_Write(wData,0x00,0x100)== W25Qx_OK)printf(" QSPI Write OK!\r\n");elseprintf("something wrong in Step3\r\n");/*-Step4- 读数据 ************************************************Step4*/ if(BSP_W25Qx_Read(rData,0x00,0x100)== W25Qx_OK)printf(" QSPI Read ok\r\n\r\n");elseprintf("something wrong in Step4\r\n");printf("QSPI Read Data : \r\n");for(i =0;i<0x100;i++)printf("0x%02X ",rData[i]);printf("\r\n\r\n");/*-Step5- 数据对比 ************************************************Step5*/ if(memcmp(wData,rData,0x100) == 0 ) printf(" W25Q64FV QuadSPI Test OK\r\n");elseprintf(" W25Q64FV QuadSPI Test False\r\n");while (1){}}
6.接线图及效果
本例程源码下载:点击跳转
STM32系列(HAL库)——F103C8T6通过SPI方式读写W25Q64—(Flash存储模块)相关推荐
- STM32系列(HAL库)——F103C8T6使用SPI方式点亮OLED
目录 1.软件准备 2.硬件准备 3.CubeMX配置 (1)芯片选择 (2)配置RCC.SYS.时钟树 (3)配置SPI (4)配置GPIO (5)生成代码工程 4.代码移植 (1)复制文件 (2) ...
- STM32系列(HAL库)——F103C8T6硬件SPI点亮带字库OLED屏
1.软件准备 (1)编程平台:Keil5 (2)CubeMX (3)程序:点击下载 2.硬件准备 (1)1.3寸带字库OLED 注意,成品模块无RES引脚,模块正常工作时RES置于高电平,成品模块是硬 ...
- STM32系列(HAL库)——F103C8T6通过MFRC522、RFID射频卡、门禁卡模块读取卡片ID(二)
本文继上一篇:STM32系列(HAL库)--F103C8T6通过MFRC522.RFID射频卡.门禁卡模块读取卡片ID 本文介绍在运用RC522模块时,运用链表结构存储数据的操作 Let's go! ...
- STM32系列(HAL库)——F103C8T6通过NRF24L01(2.4G)无线模块进行双机通信
本文参考:STM32L051C8T6 HAL库 + nRF24L01 收发案例(硬件SPI通讯) 1.软件准备 (1)编程平台:Keil5 (2)CubeMX (3)XCOM(串口调试助手) 2.硬件 ...
- STM32系列(HAL库)——F103C8T6通过MFRC522、RFID射频卡、门禁卡模块读取卡片ID
1.软件准备 (1)编程平台:Keil5 (2)CubeMX (3)XCOM(串口调试助手) 2.硬件准备 (1)MFRC-522模块 (2)F1的板子,本例使用经典F103C8T6 (3)ST-li ...
- STM32系列(HAL库)——F103C8T6点亮1.44寸TFT-LCD彩屏
1.软件准备 (1)编程平台:Keil5 (2)CubeMX (3)中景园屏幕资料链接:点击跳转 提取码:8888 2.硬件准备 (1)1.44寸TFT彩屏 (2)F1的板子,本例使用经 ...
- STM32系列(HAL库)——F103C8T6 通过GY906/MLX90614红外测温模块实现温度测量
1.软件准备 (1)编程平台:Keil5 (2)CubeMX (3)XCOM(串口调试助手) 2.硬件准备 (1)GY-906-BCC红外测温模块 (2)F1的板子,本例使用经典F103C8T6 (3 ...
- 【STM32】HAL库 STM32CubeMX教程十四---SPI
前言: 本系列教程将HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 在我们的HAL库中,对硬件SPI函数做了很好的集成,使得之前SPI几百行代码,在HAL库中,只需 ...
- STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例)
STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例) 目录 STM32CubeMX | STM32 F1系列HAL库低功耗 ...
最新文章
- python打开网页存图_python 获取网页图片 保存在本地
- webpack打包HTML配置自动,十三、HtmlWebpackPlugin的使用 ------- 2019-04-25
- jq实现文字个数限制_jQuery插件InputLimitor实现文本框输入限制字数统计
- VC6.0下调bug的流程
- 搭建微服务器:express+https+api代理
- 腾讯AI Lab联合清华,港中文长文解析图深度学习的历史、最新进展到应用
- 搜索引擎ElasticSearchV5.4.2系列一之ES介绍
- 理解transformer
- Windows线程同步--关键段和旋转锁
- 【Android Studio安装部署系列】二十三、Android studio查看Gradle版本号
- Ubuntu16下载tomcat8
- java实现用户分组,java实现分组算法,根据每组多少人来进行分组
- Xcode设置苹果应用的app icon和launch image(应用图标和启动页面)
- 一个VSCode便可以免费画ER图
- linux上dig命令,Linux中dig命令起什么作用呢?
- python xlwt_使用Python和xlwt向Excel文件中写入中文
- PxCook的基本使用
- php静态登录界面网页代码,css+html如何仿花瓣网实现静态登陆页面?(代码实例)...
- [渝粤教育] 西南科技大学 外国文学 在线考试复习资料
- 360全景拍摄有哪些技巧?