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

【随手笔记】FLASH-W25Q16(三)

#include "bsp_w25q16.h"/*内部函数声明区*/
static HAL_StatusTypeDef bsp_w25q_Transmit(uint8_t * T_pData, uint16_t T_Size);
static HAL_StatusTypeDef bsp_w25q_Receive(uint8_t * R_pData, uint16_t R_Size);/*内部函数定义区*//*
函数参数:1、T_pData:发送数据缓冲区中取出数据发送出去2、T_Size :需要发送的数据的长度
*/
static HAL_StatusTypeDef bsp_w25q_Transmit(uint8_t * T_pData, uint16_t T_Size)
{return HAL_SPI_Transmit(&W25Q_SPI, T_pData, T_Size, 0xffff);
}/*
函数参数:1、R_pData:接收数据并放置到接收数据缓冲区中2、R_Size :需要接收的数据的长度
*/
static HAL_StatusTypeDef bsp_w25q_Receive(uint8_t * R_pData, uint16_t R_Size)
{return HAL_SPI_Receive(&W25Q_SPI, R_pData, R_Size, 0xffff);
}/*
写使能或失能参数:Type:1、为1时使能2、为0时失能
*/
HAL_StatusTypeDef Bsp_Write_En_De(uint8_t Type)
{uint8_t cmd;HAL_StatusTypeDef STD = HAL_ERROR;W25Q_CS_Level(0);SPI_Delay(1);switch(Type){case 1:cmd = W25Q_W_EN;break;case 0:cmd = W25Q_W_DIS;break;default:cmd = W25Q_W_DIS;break;}if(bsp_w25q_Transmit(&cmd, 1) == HAL_OK){STD = HAL_OK;}W25Q_CS_Level(1);return STD;
}/*
读状态寄存器参数:Select1、为0时是寄存器12、为1时是寄存器2参数:State(指针)1、返回的状态标志流程:先写入命令,然后读取状态
*/
HAL_StatusTypeDef Bsp_Read_State_Reg(uint8_t Select, uint8_t* State)
{uint8_t cmd;HAL_StatusTypeDef STD = HAL_ERROR;W25Q_CS_Level(0);SPI_Delay(1);switch(Select){case 0:cmd = W25Q_R_STA_REG1;break;case 1:cmd = W25Q_R_STA_REG2;break;default:cmd = W25Q_R_STA_REG1;break;}if(bsp_w25q_Transmit(&cmd, 1) == HAL_OK){if(bsp_w25q_Receive(State,1) == HAL_OK){STD = HAL_OK;}}W25Q_CS_Level(1);return STD;
}/*
判忙用处:判断当前flash是否在忙碌状态BUSY只读寄存器忙时高电平空闲低电平
*/
void Bsp_Judge_Busy(void)
{uint8_t State;do{Bsp_Read_State_Reg(0, &State);  //不要用指针类型局部变量传进去,必被卡死State &= 0x01;}while(State == 0x01);//寄存器为1时为忙
}/*
读数据参数:R_Addr1、读取数据的地址参数:R_Data(数组指针)1、获取读取的数据参数:R_Size1、读取的数据的大小
*/
HAL_StatusTypeDef Bsp_W25Q_Read_Data(uint32_t R_Addr, uint8_t * R_Data, uint16_t R_Size)
{HAL_StatusTypeDef STD = HAL_ERROR;uint8_t addr[4] = {0};addr[0] = W25Q_R_Data;addr[1] = (R_Addr >> 16) & 0xFF;addr[2] = (R_Addr >> 8) & 0xFF;addr[3] = (R_Addr) & 0xFF;Bsp_Judge_Busy();   //判忙W25Q_CS_Level(0);SPI_Delay(1);if(bsp_w25q_Transmit(addr, 4) == HAL_OK){if(bsp_w25q_Receive(R_Data,R_Size) == HAL_OK){STD = HAL_OK;}}W25Q_CS_Level(1);return STD;
}/*
写数据-页页的描述:1字节到 256 字节(一页)页写的前提条件:编程之前必须保证额你存空间是0xff,所以得先进行擦除(擦除后模式全为1)页写的注意事项:进行页编程时,如果数据字节数超过了 256 字节,地址将自动回到页的起始地址,覆盖掉之前的数据。参数:WriteAddr1、地址,三个字节地址参数:PW_Data(数组指针)1、要写入的数据,长度根据PW_size来定2、高位先传参数:PW_Size2、要写入的数据长度先通过状态寄存器判断是否在忙,然后写使能,接着判忙,拉底片选选中,发命令字节0x02,发三个地址,高位优先,然后发你要写的数据,最后拉高片选
*/HAL_StatusTypeDef Bsp_W25Q_Page_Write(uint32_t WriteAddr, uint8_t * PW_Data, uint16_t PW_Size)
{HAL_StatusTypeDef STD = HAL_ERROR;uint8_t addr[4] = {0};addr[0] = W25Q_Page_Program;addr[1] = (WriteAddr >> 16) & 0xFF;addr[2] = (WriteAddr >> 8) & 0xFF;addr[3] = (WriteAddr) & 0xFF;Bsp_Judge_Busy();   //判忙Bsp_Write_En_De(1);Bsp_Judge_Busy();W25Q_CS_Level(0);SPI_Delay(1);if(bsp_w25q_Transmit(addr, 4) == HAL_OK){if(bsp_w25q_Transmit(PW_Data, PW_Size) == HAL_OK){STD = HAL_OK;}}W25Q_CS_Level(1);Bsp_Judge_Busy();return STD;
}/*
扇区擦除扇区的描述:W25Q16总共2MB,分为32块(每块64KB),每块16个扇区,每个扇区4K个字节。扇区的备注:W25Q16的最小擦除单位就是一个扇区所以至少给芯片开辟一个4KB的缓存区,以防止一次性删除太多,而丢失数据。(显然单片机不会给他开辟这么大的空间)参数:num : 扇区的序号*/
HAL_StatusTypeDef Bsp_W25Q_Sector_Erase(uint32_t num)
{HAL_StatusTypeDef STD = HAL_ERROR;//一个扇区有4KB的大小,//为了使找到对应的扇区地址,所以要乘以4KB//(1<<12) = 4096num *= (1<<12);uint8_t addr[4] = {0};addr[0] = W25Q_Sector_Erase;addr[1] = (num >> 16) & 0xFF;addr[2] = (num >> 8) & 0xFF;addr[3] = (num) & 0xFF;Bsp_Judge_Busy();Bsp_Write_En_De(1);Bsp_Judge_Busy();W25Q_CS_Level(0);SPI_Delay(1);if(bsp_w25q_Transmit(addr, 4) == HAL_OK){STD = HAL_OK;}W25Q_CS_Level(1);Bsp_Judge_Busy();return STD;
}/*
块擦除块的描述:W25Q16有2MB的容量,而2MB有32个块,所以1块有64kB的大小,所以这个函数一次能擦除64KB的大小。参数:Block_Addr1、块地址,共32个块,对应32个地址,以64K为单位寻址2、高位先传流程:先开写使能、判忙,再写命令,再写3个字节的地址,最后写失能参数:num : 块的序号
*/
HAL_StatusTypeDef   Bsp_W25Q_Block_Erase(uint32_t num)
{uint8_t cmd = W25Q_Block_Erase;HAL_StatusTypeDef STD = HAL_ERROR;//总共有32个块,而一个块有64KB的大小,//为了使找到对应的块地址,所以要乘以64KBnum *= (1<<16);uint8_t addr[4] = {0};addr[0] = W25Q_Block_Erase;addr[1] = (num >> 16) & 0xFF;addr[2] = (num) & 0xFF;addr[3] = (num) & 0xFF;Bsp_Judge_Busy();Bsp_Write_En_De(1);Bsp_Judge_Busy();W25Q_CS_Level(0);SPI_Delay(1);if(bsp_w25q_Transmit(addr, 4) == HAL_OK){STD = HAL_OK;}W25Q_CS_Level(1);Bsp_Judge_Busy();return STD;
}/*
全片擦除描述:直接把芯片全部擦除
*/
HAL_StatusTypeDef Bsp_W25Q_Full_Erase(void)
{uint8_t cmd = W25Q_Full_Erase;HAL_StatusTypeDef STD = HAL_ERROR;Bsp_Judge_Busy();Bsp_Write_En_De(1);Bsp_Judge_Busy();W25Q_CS_Level(0);SPI_Delay(1);if(bsp_w25q_Transmit(&cmd, 1) == HAL_OK){STD = HAL_OK;}W25Q_CS_Level(1);Bsp_Judge_Busy();return STD;
}/*
读ID描述:读3个字节分别是生产厂家、存储器类型、容量
*/
HAL_StatusTypeDef Bsp_Read_Jedec_ID(uint8_t * R_Jedec_ID)
{uint8_t read_id[3] = {0};uint8_t cmd = W25Q_JEDEC_ID;HAL_StatusTypeDef STD = HAL_ERROR;Bsp_Judge_Busy();W25Q_CS_Level(0);SPI_Delay(1);if(bsp_w25q_Transmit(&cmd, 1) == HAL_OK){if(bsp_w25q_Receive(read_id, 3) == HAL_OK){STD = HAL_OK;}}W25Q_CS_Level(1);if(STD == HAL_OK){LOG_OUT("read_id= %x %x %x\r\n", read_id[0], read_id[1], read_id[2]);}else{LOG_OUT("read_id= err\r\n");}return STD;
}/** 电源开启*/
void W26Q16_Power_On(void)
{MX_SPI1_Init();//W25Q_WP_HIGH;rt_thread_mdelay(100);Bsp_Read_Jedec_ID(NULL);}/** 电源关闭*/
void W26Q16_Power_Off(void)
{//WP拉低开启读保护//W25Q_WP_LOW;W25Q_CS_Level(GPIO_PIN_RESET);rt_thread_mdelay(10);//失能SPI配置为IOw25q16_init_sleep();rt_thread_mdelay(1000);
}
#ifndef __DRV_W25Q16_H
#define __DRV_W25Q16_H#include "app_user.h"
#include "spi.h"/*句柄重命名*/
#define W25Q_SPI                hspi1#define SPI_Delay(ms)           rt_thread_mdelay(ms+1)/*片选引脚定义与函数调用*/
#define W25Q_CS_Pin             GPIO_PIN_4
#define W25Q_CS_Port            GPIOA#define W25Q_CS_Level(_CS_STATE__)      HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, (GPIO_PinState)_CS_STATE__)//#define W25Q_WP_HIGH   HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET)
//#define W25Q_WP_LOW    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET)#define W25Q_W_EN               0x06        //写使能
#define W25Q_W_DIS              0x04        //写禁止#define W25Q_R_Data             0x03        //读数据#define W25Q_R_STA_REG1     0x05        //读状态寄存器1,紧跟着的字节就是当前状态
#define W25Q_R_STA_REG2     0x35        //读状态寄存器2,紧跟着的字节就是当前状态#define W25Q_W_STA_REG      0x01        //写状态寄存器,写入两个字节,分别到寄存器1,和寄存器2#define W25Q_Page_Program   0x02        //页编程,先跟3个地址字节,再跟一个数据字节#define W25Q_Block_Erase    0xD8        //块擦除64k,三个地址字节#define W25Q_Sector_Erase   0x20        //扇区擦除,跟三个地址#define W25Q_Full_Erase     0xC7        //全片擦除//0x60#define W25Q_Susp_Erase     0x75        //暂停擦除#define W25Q_Rest_Erase     0x7A        //恢复擦除#define W25Q_PowDow_Mode    0xB9        //掉电模式#define W25Q_HPer_Mode      0xA3        //高性能模式#define W25Q_JEDEC_ID       0x9F        //读3个字节分别是生产厂家、存储器类型、容量/*写使能或失能*/
HAL_StatusTypeDef Bsp_Write_En_De(uint8_t Type);/*读状态寄存器*/
HAL_StatusTypeDef Bsp_Read_State_Reg(uint8_t Select, uint8_t* State);/*判忙*/
void Bsp_Judge_Busy(void);/*读数据*/
HAL_StatusTypeDef Bsp_W25Q_Read_Data(uint32_t R_Addr, uint8_t * R_Data, uint16_t R_Size);/*页写*/
HAL_StatusTypeDef Bsp_W25Q_Page_Write(uint32_t WriteAddr, uint8_t * PW_Data, uint16_t PW_Size);/*扇区擦除*/
HAL_StatusTypeDef Bsp_W25Q_Sector_Erase(uint32_t num);/*块擦除*/
HAL_StatusTypeDef   Bsp_W25Q_Block_Erase(uint32_t num);/*全片擦除*/
HAL_StatusTypeDef Bsp_W25Q_Full_Erase(void);/*读ID*/
HAL_StatusTypeDef Bsp_Read_Jedec_ID(uint8_t * R_Jedec_ID);void W26Q16_Power_On(void);
void W26Q16_Power_Off(void);
#endif /*W25Q16__H__*/
/* USER CODE BEGIN Header */
/********************************************************************************* @file    spi.c* @brief   This file provides code for the configuration*          of the SPI instances.******************************************************************************* @attention** Copyright (c) 2024 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"/* USER CODE BEGIN 0 *//* USER CODE END 0 */SPI_HandleTypeDef hspi1;/* SPI1 init function */
void MX_SPI1_Init(void)
{/* USER CODE BEGIN SPI1_Init 0 *//* USER CODE END SPI1_Init 0 *//* USER CODE BEGIN SPI1_Init 1 *//* USER CODE END SPI1_Init 1 */hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_2LINES;hspi1.Init.DataSize = SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;hspi1.Init.NSS = SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi1.Init.TIMode = SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial = 7;if (HAL_SPI_Init(&hspi1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN SPI1_Init 2 *//* USER CODE END SPI1_Init 2 */}void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(spiHandle->Instance==SPI1){/* USER CODE BEGIN SPI1_MspInit 0 *//* USER CODE END SPI1_MspInit 0 *//* SPI1 clock enable */__HAL_RCC_SPI1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**SPI1 GPIO ConfigurationPA5     ------> SPI1_SCKPA6     ------> SPI1_MISOPA7     ------> SPI1_MOSI*/GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN SPI1_MspInit 1 *//* USER CODE END SPI1_MspInit 1 */}
}void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{if(spiHandle->Instance==SPI1){/* USER CODE BEGIN SPI1_MspDeInit 0 *//* USER CODE END SPI1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_SPI1_CLK_DISABLE();/**SPI1 GPIO ConfigurationPA5     ------> SPI1_SCKPA6     ------> SPI1_MISOPA7     ------> SPI1_MOSI*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);/* USER CODE BEGIN SPI1_MspDeInit 1 *//* USER CODE END SPI1_MspDeInit 1 */}
}/* USER CODE BEGIN 1 *//* USER CODE END 1 */

void w25q16_init_sleep(void)
{extern SPI_HandleTypeDef hspi1;HAL_SPI_DeInit(&hspi1);__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
}
http://www.lryc.cn/news/479608.html

相关文章:

  • 2024软件测试面试热点问题
  • 【JAVA】java 企业微信信息推送
  • 介绍一下数组(c基础)(smart 版)
  • Java项目实战II基于Spring Boot的个人云盘管理系统设计与实现(开发文档+数据库+源码)
  • 探索数据科学与大数据技术专业本科生的广阔就业前景
  • 微服务架构面试内容整理-Zuul
  • 解决Knife4j 接口界面UI中文乱码问题
  • 微服务架构面试内容整理-Sleuth
  • Go语言的接口示例
  • 【Apache ECharts】<农作物病害发生防治面积>
  • 基于vue3实现的聊天机器人前端(附代码)
  • DICOM标准:深入详解DICOM医学影像中的传输语法
  • sql server 文件备份恢复
  • Gradle命令编译Android Studio工程项目并签名
  • lua入门教程:垃圾回收
  • 基于前后端分离架构,SaaS云平台与私有云部署的智慧校园源码,java电子班牌源码
  • 知识总结五
  • 一、初识C语言(1)
  • petty 状态管理库文档
  • SpringMVC学习记录(三)之响应数据
  • ENSP GVRP动态学习VLAN
  • 怎么给llama3.2-vision:90b模型进行量化剪枝蒸馏
  • flutter 专题四 Flutter渲染流程
  • 刘艳兵-DBA028-您可以在 ORCL1 和 ORCL2 数据库都运行其实例的主机上安装“独立服务器的 Oracle 网格基础结构“。哪两个陈述是正确的?
  • 前端三件套-css
  • 实验(未完成)
  • Python基础学习_01
  • 鸿萌数据迁移服务: 企业服务器整机在线热迁移, 实现不停机业务转移
  • 【C】无类型指针及函数指针
  • VR的左右眼渲染方法