294 lines
7.2 KiB
C
294 lines
7.2 KiB
C
#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); /* 等待芯片唤醒 */
|
||
}
|
||
|