242 lines
5.8 KiB
C
242 lines
5.8 KiB
C
#include "bsp_w25q.h"
|
|
#include "spi.h"
|
|
#include "main.h"
|
|
|
|
/* spi flash 片选引脚 - pb12 */
|
|
#define W25Q32_CS_LOW() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET)
|
|
#define W25Q32_CS_HIGH() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, 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_sector_erase(uint32_t sector_addr);
|
|
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,
|
|
};
|
|
|
|
|
|
/* 初始化函数 */
|
|
static void w25q32_init(void) {
|
|
W25Q32_CS_HIGH(); /* 初始时片选拉高 */
|
|
w25q32_wake_up(); /* 唤醒芯片 */
|
|
}
|
|
|
|
/* 读取芯片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) */
|
|
static 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); /* 等待芯片唤醒 */
|
|
}
|
|
|