K1Guitar/AT32F403ARCT7_BOOT/device/W25Q128/W25Q128.c

211 lines
6.1 KiB
C
Raw Normal View History

// File: w25q128.c
#include "w25q128.h"
#include "wk_system.h"
/* W25Q128 挂在 SPI1 上PA5=SCK, PA6=MISO, PA7=MOSICS 用 PA4 GPIO 控制 */
#define W25Q128_SPI SPI1
#define W25Q128_CS_PORT GPIOA
#define W25Q128_CS_PIN GPIO_PINS_4
#define SPI_CS_LOW() gpio_bits_reset(W25Q128_CS_PORT, W25Q128_CS_PIN)
#define SPI_CS_HIGH() gpio_bits_set(W25Q128_CS_PORT, W25Q128_CS_PIN)
// 内部私有函数声明
static uint8_t W25Q128_ReadWriteByte(uint8_t TxData);
static void W25Q128_WriteEnable(void);
static void W25Q128_WaitBusy(void);
/**
* @brief SPI1 (AT32 )
*
* @param TxData:
* @retval
*/
uint8_t SPI1_ReadWriteByte(uint8_t TxData)
{
/* 等发送缓冲空(可写数据) */
while (spi_i2s_flag_get(W25Q128_SPI, SPI_I2S_TDBE_FLAG) == RESET);
/* 写发送数据寄存器 */
spi_i2s_data_transmit(W25Q128_SPI, TxData);
/* 等接收缓冲满(收到数据) */
while (spi_i2s_flag_get(W25Q128_SPI, SPI_I2S_RDBF_FLAG) == RESET);
/* 读接收数据寄存器(自动清 RDBF */
return (uint8_t)spi_i2s_data_receive(W25Q128_SPI);
}
/**
* @brief W25Q128 ( CS SPI1 wk_spi1_init )
*/
void W25Q128_Init(void)
{
gpio_init_type g;
/* CS 引脚 PA4推挽输出初始拉高释放 */
gpio_default_para_init(&g);
g.gpio_mode = GPIO_MODE_OUTPUT;
g.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
g.gpio_pull = GPIO_PULL_NONE;
g.gpio_pins = W25Q128_CS_PIN;
gpio_init(W25Q128_CS_PORT, &g);
SPI_CS_HIGH();
}
/**
* @brief SPI读写函数便
*/
static uint8_t W25Q128_ReadWriteByte(uint8_t TxData)
{
return SPI1_ReadWriteByte(TxData);
}
/**
* @brief 使 (/)
*/
static void W25Q128_WriteEnable(void)
{
SPI_CS_LOW(); // 片选选中
W25Q128_ReadWriteByte(W25X_WriteEnable); // 发送写使能命令
SPI_CS_HIGH(); // 释放片选
}
/**
* @brief (BUSY位为1)
*/
static void W25Q128_WaitBusy(void)
{
uint8_t status;
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_ReadStatusReg1); // 发送读状态寄存器命令
do {
status = W25Q128_ReadWriteByte(0xFF); // 循环读取状态字
} while (status & 0x01); // 等待BUSY位清零
SPI_CS_HIGH();
}
/**
* @brief ID
* @retval W25Q128 0xEF17
*/
uint16_t W25Q128_ReadID(void)
{
uint16_t id = 0;
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_ManufactDeviceID); // 发送读取ID命令
W25Q128_ReadWriteByte(0x00); // 3个空字节
W25Q128_ReadWriteByte(0x00);
W25Q128_ReadWriteByte(0x00);
id |= W25Q128_ReadWriteByte(0xFF) << 8; // Manufacturer ID
id |= W25Q128_ReadWriteByte(0xFF); // Device ID
SPI_CS_HIGH();
return id;
}
/**
* @brief
* @param pBuf:
* @param ReadAddr: (0~16MB-1)
* @param NumByteToRead:
*/
void W25Q128_Read(uint8_t* pBuf, uint32_t ReadAddr, uint16_t NumByteToRead)
{
uint16_t i;
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_ReadData); // 发送读数据命令
W25Q128_ReadWriteByte((ReadAddr >> 16) & 0xFF); // 发送24位地址
W25Q128_ReadWriteByte((ReadAddr >> 8) & 0xFF);
W25Q128_ReadWriteByte(ReadAddr & 0xFF);
for (i = 0; i < NumByteToRead; i++) {
pBuf[i] = W25Q128_ReadWriteByte(0xFF); // 循环读取
}
SPI_CS_HIGH();
}
/**
* @brief ()
* @param pBuf:
* @param WriteAddr:
* @param NumByteToWrite: ()
*/
void W25Q128_Write(uint8_t* pBuf, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint16_t i;
uint16_t pageSize = 256; // W25Q128 页大小
uint16_t toWrite;
while (NumByteToWrite > 0) {
// 计算当前页可以写入的字节数
toWrite = pageSize - (WriteAddr % pageSize);
if (toWrite > NumByteToWrite) toWrite = NumByteToWrite;
W25Q128_WriteEnable(); // 写使能
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_PageProgram); // 页编程命令
W25Q128_ReadWriteByte((WriteAddr >> 16) & 0xFF);
W25Q128_ReadWriteByte((WriteAddr >> 8) & 0xFF);
W25Q128_ReadWriteByte(WriteAddr & 0xFF);
for (i = 0; i < toWrite; i++) {
W25Q128_ReadWriteByte(pBuf[i]);
}
SPI_CS_HIGH();
W25Q128_WaitBusy(); // 等待本次页编程完成
// 更新指针和剩余字节数
NumByteToWrite -= toWrite;
WriteAddr += toWrite;
pBuf += toWrite;
}
}
/**
* @brief (4KB)
* @param SectorAddr:
*/
void W25Q128_Erase_Sector(uint32_t SectorAddr)
{
W25Q128_WriteEnable(); // 写使能
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_SectorErase); // 扇区擦除命令
W25Q128_ReadWriteByte((SectorAddr >> 16) & 0xFF);
W25Q128_ReadWriteByte((SectorAddr >> 8) & 0xFF);
W25Q128_ReadWriteByte(SectorAddr & 0xFF);
SPI_CS_HIGH();
W25Q128_WaitBusy(); // 擦除需要时间,等待完成
}
/**
* @brief
* @note
*/
void W25Q128_Erase_Chip(void)
{
W25Q128_WriteEnable(); // 写使能
SPI_CS_LOW();
W25Q128_ReadWriteByte(W25X_ChipErase); // 全片擦除命令
SPI_CS_HIGH();
W25Q128_WaitBusy(); // 等待全片擦除完成
}
void W25Q128_WriteSector_4K(uint8_t* buf, uint32_t addr,uint32_t len)
{
// 1. 必须 4K 对齐
if(addr % 4096 != 0) return;
// 2. 擦除 1 个扇区4KB
W25Q128_Erase_Sector(addr);
// 3. 写入 4096 字节(你的函数自动分页写,完全支持)
W25Q128_Write(buf, addr, len);
}