Files
2026-02-25 15:12:13 +08:00

294 lines
7.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "bsp_w25q.h"
#include "spi.h"
#include <string.h>
#include "app_leakage.h"
/* spi flash 片选引脚 - pb12 */
#define W25Q32_CS_LOW() HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET)
#define W25Q32_CS_HIGH() HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET)
/* spi 传输函数 */
static void w25q32_spi_transmit(uint8_t *data, uint16_t size) {
HAL_SPI_Transmit(&hspi2, data, size, HAL_MAX_DELAY);
}
static void w25q32_spi_receive(uint8_t *data, uint16_t size) {
HAL_SPI_Receive(&hspi2, data, size, HAL_MAX_DELAY);
}
static uint8_t w25q32_spi_transmit_receive(uint8_t data) {
uint8_t rx_data;
HAL_SPI_TransmitReceive(&hspi2, &data, &rx_data, 1, HAL_MAX_DELAY);
return rx_data;
}
/* 内部函数声明 */
static void w25q32_init(void);
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_chip_erase(void);
static void w25q32_write_enable(void);
static void w25q32_write_disable(void);
static uint8_t w25q32_read_status_reg(void);
static void w25q32_wait_for_write_end(void);
static void w25q32_block_erase(uint32_t block_addr);
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len);
static uint8_t w25q32_read_id(void);
static void w25q32_power_down(void);
static void w25q32_wake_up(void);
/* w25q32 对象实例 */
w25q32_t w25q32 = {
.init = w25q32_init,
.read = w25q32_read,
.write = w25q32_write,
.chip_erase = w25q32_chip_erase,
.sector_erase = w25q32_sector_erase,
};
/* 从W25Q32读取设备信息到app_leakage */
static void gui_tjc_hmi_read_device_info_from_w25q(void)
{
/* 创建一个临时缓冲区 */
app_leakage_sub_device_flash_data_t temp_buffer[APP_LEAKAGE_SUB_DEVICE_NUM];
/* 一次性读取所有设备信息 */
w25q32.read(W25Q32_DEVICE_INFO_ADDR,
(uint8_t*)temp_buffer,
DEVICE_INFO_STORAGE_SIZE);
/* 检查数据有效性 */
uint8_t data_valid = 1;
for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++)
{
/* 如果所有字段都是0xFF说明是空数据 */
if(temp_buffer[i].state == 0xFF &&
temp_buffer[i].com == 0xFF &&
temp_buffer[i].modbus_id == 0xFF)
{
data_valid = 0;
break;
}
}
if(data_valid)
{
/* 复制到app_leakage结构体中 */
for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++)
{
leakage.sub_device_data[i].flash_data = temp_buffer[i];
}
}
else
{
/* Flash为空初始化设备信息为默认值 */
for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++)
{
memset(&leakage.sub_device_data[i].flash_data, 0,
sizeof(app_leakage_sub_device_flash_data_t));
leakage.sub_device_data[i].flash_data.state = DISABLE;
}
}
}
/* 初始化函数 */
static void w25q32_init(void) {
W25Q32_CS_HIGH(); /* 初始时片选拉高 */
w25q32_wake_up(); /* 唤醒芯片 */
gui_tjc_hmi_read_device_info_from_w25q();
}
/* 读取芯片id */
static uint8_t w25q32_read_id(void) {
uint8_t id = 0;
uint8_t cmd = W25Q32_JEDEC_ID;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
w25q32_spi_receive(&id, 1); /* 忽略前两个字节 */
w25q32_spi_receive(&id, 1);
w25q32_spi_receive(&id, 1); /* 设备id在第三个字节 */
W25Q32_CS_HIGH();
return id;
}
/* 写使能 */
static void w25q32_write_enable(void) {
uint8_t cmd = W25Q32_WRITE_ENABLE;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 写禁止 */
static void w25q32_write_disable(void) {
uint8_t cmd = W25Q32_WRITE_DISABLE;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 读取状态寄存器 */
static uint8_t w25q32_read_status_reg(void) {
uint8_t status;
uint8_t cmd = W25Q32_READ_STATUS_REG1;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
status = w25q32_spi_transmit_receive(0x00);
W25Q32_CS_HIGH();
return status;
}
/* 等待写入完成 */
static void w25q32_wait_for_write_end(void) {
while (w25q32_read_status_reg() & W25Q32_STATUS_BUSY) {
/* 可添加延时或看门狗喂狗 */
}
}
/* 扇区擦除 (4kb) */
void w25q32_sector_erase(uint32_t sector_addr)
{
uint8_t cmd[4];
/* 确保地址是4k对齐 */
sector_addr &= ~(W25Q32_SECTOR_SIZE - 1);
w25q32_write_enable();
cmd[0] = W25Q32_SECTOR_ERASE;
cmd[1] = (sector_addr >> 16) & 0xFF;
cmd[2] = (sector_addr >> 8) & 0xFF;
cmd[3] = sector_addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 块擦除 (64kb) */
static void w25q32_block_erase(uint32_t block_addr) {
uint8_t cmd[4];
/* 确保地址是64k对齐 */
block_addr &= ~(W25Q32_BLOCK_SIZE - 1);
w25q32_write_enable();
cmd[0] = W25Q32_BLOCK_ERASE_64K;
cmd[1] = (block_addr >> 16) & 0xFF;
cmd[2] = (block_addr >> 8) & 0xFF;
cmd[3] = block_addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 整片擦除 */
static void w25q32_chip_erase(void) {
uint8_t cmd = W25Q32_CHIP_ERASE;
w25q32_write_enable();
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 页写入 (最大256字节) */
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len) {
uint8_t cmd[4];
if (len > W25Q32_PAGE_SIZE) {
len = W25Q32_PAGE_SIZE;
}
w25q32_write_enable();
cmd[0] = W25Q32_PAGE_PROGRAM;
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
w25q32_spi_transmit(data, len);
W25Q32_CS_HIGH();
w25q32_wait_for_write_end();
}
/* 任意长度写入 */
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len) {
uint32_t page_remaining;
uint32_t offset = 0;
while (len > 0) {
/* 计算当前页剩余字节数 */
page_remaining = W25Q32_PAGE_SIZE - (addr % W25Q32_PAGE_SIZE);
/* 本次写入的长度 */
uint32_t write_len = (len < page_remaining) ? len : page_remaining;
/* 写入一页数据 */
w25q32_page_write(addr, &data[offset], write_len);
/* 更新地址和偏移 */
addr += write_len;
offset += write_len;
len -= write_len;
}
}
/* 读取数据 */
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len) {
uint8_t cmd[4];
cmd[0] = W25Q32_READ_DATA;
cmd[1] = (addr >> 16) & 0xFF;
cmd[2] = (addr >> 8) & 0xFF;
cmd[3] = addr & 0xFF;
W25Q32_CS_LOW();
w25q32_spi_transmit(cmd, 4);
w25q32_spi_receive(data, len);
W25Q32_CS_HIGH();
}
/* 进入掉电模式 */
static void w25q32_power_down(void) {
uint8_t cmd = W25Q32_POWER_DOWN;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
}
/* 唤醒芯片 */
static void w25q32_wake_up(void) {
uint8_t cmd = W25Q32_RELEASE_POWER_DOWN;
W25Q32_CS_LOW();
w25q32_spi_transmit(&cmd, 1);
W25Q32_CS_HIGH();
HAL_Delay(5); /* 等待芯片唤醒 */
}