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

GigaDevice(兆易创新)GD25Q64CSJGR 64Mbit FLASH

使用的是 STM32G070RBT6,

SPI1

PA12 -> MOSI

PA11->MISO

PA10->CS

PD8->SCK

FLASH代码

#include "flash.h"// 选中 Flash(拉低 CS#)
void GD25Q64_Select(void) {HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET);//HAL_Delay(0);
}// 取消选中 Flash(拉高 CS#)
void GD25Q64_Deselect(void) {HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);//HAL_Delay(0);
}// 发送 1 字节命令,并返回 Flash 响应
uint8_t GD25Q64_SendCmd(uint8_t cmd) {uint8_t rx_data = 0;HAL_SPI_TransmitReceive(&hspi1, &cmd, &rx_data, 1, 100); // 超时 100msreturn rx_data;
}// 等待 Flash 忙状态清除(擦除/编程后必须等待)
void GD25Q64_WaitBusy(void) {uint8_t status = 0;GD25Q64_Select();GD25Q64_SendCmd(CMD_READ_STATUS);do {status = GD25Q64_SendCmd(0xFF); // 持续读取状态寄存器} while (status & 0x01); // 忙标志位(BIT0)为 1 表示忙GD25Q64_Deselect();
}// 读取 Flash ID(验证通信)
void GD25Q64_ReadID(uint8_t *mfg_id, uint16_t *dev_id) {if (!mfg_id || !dev_id) return;uint8_t tx[1] = {0x9F}; // JEDEC读ID命令uint8_t rx[4] = {0};    // 接收缓冲区(1字节命令+3字节ID)// 片选拉低HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET);// 发送命令并接收ID(一次性完成,避免时序间断)HAL_SPI_TransmitReceive(&hspi1, tx, rx, 4, 100);// 片选拉高HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);// 解析结果(9F命令的ID在第2-4字节)*mfg_id = rx[1];          // 制造商ID(C8)*dev_id = (rx[2] << 8) | rx[3]; // 设备ID(4017)
/*if (!mfg_id || !dev_id) return;GD25Q64_Select();GD25Q64_SendCmd(CMD_READ_ID);// 发送固定地址 0x000000(用于 ID 读取)uint8_t addr[3] = {0x00, 0x00, 0x00};HAL_SPI_Transmit(&hspi1, addr, 3, 100);// 接收 1 字节制造商 ID 和 2 字节设备 IDuint8_t id_buf[3] = {0};HAL_SPI_Receive(&hspi1, id_buf, 3, 100);GD25Q64_Deselect();*mfg_id = id_buf[0];          // 兆易创新:0xC8*dev_id = (id_buf[1] << 8) | id_buf[2]; // GD25Q64:0x4017
*/
}// 写使能(擦除/编程前必须调用)
void GD25Q64_WriteEnable(void) {GD25Q64_Select();uint8_t cmd = CMD_WRITE_ENABLE;HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);GD25Q64_Deselect();
}// 解锁Flash(清除写保护)
void GD25Q64_Unlock(void) {GD25Q64_WriteEnable();  // 解锁前必须先写使能GD25Q64_Select();uint8_t cmd[3] = {CMD_UNPROTECT, 0x00, 0x00};HAL_SPI_Transmit(&hspi1, cmd, 3, 100);GD25Q64_Deselect();GD25Q64_WaitBusy();
}// 扇区擦除(4KB)
HAL_StatusTypeDef GD25Q64_EraseSector(uint32_t sector_addr) {if (sector_addr > 0x7FFFFF || (sector_addr % 4096) != 0) return HAL_ERROR;GD25Q64_WriteEnable();  // 擦除前必须写使能GD25Q64_Select();uint8_t cmd[4] = {CMD_SECTOR_ERASE,(uint8_t)(sector_addr >> 16),(uint8_t)(sector_addr >> 8),(uint8_t)sector_addr};HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi1, cmd, 4, 100);GD25Q64_Deselect();if (status == HAL_OK) {GD25Q64_WaitBusy();  // 等待擦除完成(约100ms)}return status;
}// 页编程(最大256字节)
HAL_StatusTypeDef GD25Q64_ProgramPage(uint32_t page_addr, uint8_t *data, uint32_t len) {if (!data || page_addr > 0x7FFFFF || len > 256 || (page_addr % 256) != 0) return HAL_ERROR;GD25Q64_WriteEnable();  // 编程前必须写使能GD25Q64_Select();uint8_t cmd[4] = {CMD_PAGE_PROGRAM,(uint8_t)(page_addr >> 16),(uint8_t)(page_addr >> 8),(uint8_t)page_addr};HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi1, cmd, 4, 100);if (status != HAL_OK) {GD25Q64_Deselect();return status;}status = HAL_SPI_Transmit(&hspi1, data, len, 1000);GD25Q64_Deselect();if (status == HAL_OK) {GD25Q64_WaitBusy();  // 等待编程完成(约1ms)}return status;
}// 读取数据
HAL_StatusTypeDef GD25Q64_ReadData(uint32_t addr, uint8_t *buf, uint32_t len) {if (!buf || addr > 0x7FFFFF || len == 0) return HAL_ERROR;GD25Q64_Select();uint8_t cmd[4] = {CMD_READ,(uint8_t)(addr >> 16),(uint8_t)(addr >> 8),(uint8_t)addr};HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi1, cmd, 4, 100);if (status != HAL_OK) {GD25Q64_Deselect();return status;}status = HAL_SPI_Receive(&hspi1, buf, len, 1000);GD25Q64_Deselect();return status;
}
#ifndef _FLASH_#define _FLASH_#include "main.h"extern SPI_HandleTypeDef hspi1;#define FLASH_CS_GPIO_Port  GPIOA
#define FLASH_CS_Pin        GPIO_PIN_10
#define FLASH_SCK_GPIO_Port GPIOD
#define FLASH_SCK_Pin       GPIO_PIN_8
#define FLASH_MOSI_GPIO_Port GPIOA
#define FLASH_MOSI_Pin      GPIO_PIN_12
#define FLASH_MISO_GPIO_Port GPIOA
#define FLASH_MISO_Pin      GPIO_PIN_11// GD25Q64 命令定义
#define CMD_READ_ID         0x90  // 读取 ID 命令
#define CMD_READ            0x03  // 读取数据命令
#define CMD_PAGE_PROGRAM    0x02  // 页编程命令(写数据)
#define CMD_SECTOR_ERASE    0x20  // 扇区擦除命令(4KB)
#define CMD_CHIP_ERASE      0xC7  // 整片擦除命令
#define CMD_READ_STATUS     0x05  // 读取状态寄存器命令
// 命令定义(需在flash.h中声明)#define CMD_WRITE_ENABLE    0x06    // 写使能
#define CMD_UNPROTECT       0x98    // 解除保护// 读取 Flash ID(验证通信)
void GD25Q64_ReadID(uint8_t *mfg_id, uint16_t *dev_id);
// 从指定地址读取数据
HAL_StatusTypeDef GD25Q64_ReadData(uint32_t addr, uint8_t *buf, uint32_t len);
// 扇区擦除(4KB,地址需对齐到扇区起始)
HAL_StatusTypeDef GD25Q64_EraseSector(uint32_t sector_addr);
// 页编程(写数据,一页 256 字节,地址需对齐到页起始)
HAL_StatusTypeDef GD25Q64_ProgramPage(uint32_t page_addr, uint8_t *data, uint32_t len);
// 解锁Flash(清除写保护)
void GD25Q64_Unlock(void);#endif

http://www.xdnf.cn/news/20358.html

相关文章:

  • c#动态树形表达式详解
  • uni-app 和 uni-app x 的区别
  • 【Cell Systems】SpotGF空间转录组去噪算法文献分享
  • 图像去雾:从暗通道先验到可学习融合——一份可跑的 PyTorch 教程
  • <video> 标签基础用法
  • MySQL-安装MySQL
  • UE4 Mac构建编译报错 no template named “is_void_v” in namespace “std”
  • 无需bootloader,BootROM -> Linux Kernel 启动模式
  • Java全栈开发工程师面试实录:从基础到实战的深度探讨
  • PyTorch图像数据转换为张量(Tensor)并进行归一化的标准操作
  • 管理中心理学问:动机与管理的关联
  • 什么是CRM?定义、作用、功能、选型|CRM百科
  • 使用若依加Trae快速搭建一对儿多对多CRUD
  • 移植Qt4.8.7到ARM40-A5
  • PiscCode基于 Mediapipe 实现轨迹跟踪
  • TOGAF之架构标准规范-迁移计划
  • nginx 反向代理使用变量的坑
  • 亚马逊商品转化率怎么提高?从传统运营到智能广告的系统化突破
  • Nginx 配置片段主要用于实现​​正向代理​​,可以用来转发 HTTP 和 HTTPS 请求
  • LangChain关于提示词的几种写法
  • 深度学习:Dropout 技术
  • c++ 第三方库与个人封装库
  • 【完整源码+数据集+部署教程】西兰花实例分割系统源码和数据集:改进yolo11-AggregatedAtt
  • leetcode 6 Z字形变化
  • 基于YOLOv8的车辆轨迹识别与目标检测研究分析软件源代码+详细文档
  • 整理了几道前端面试题
  • 字符串格式化——`vsnprintf`函数
  • 图像处理:实现多图点重叠效果
  • More Effective C++ 条款29:引用计数
  • 【完整源码+数据集+部署教程】骰子点数识别图像实例分割系统源码和数据集:改进yolo11-DCNV2