21,616
社区成员




/**
* @file w25q.c
* @brief w25q flash驱动
* 接口: 1个SPI + 1个GPIO
* @par date version author remarks
* 2018-12-01 v4.0 esone
*
*/
/** 头文件包含区 ------------------------------------------------ */
#include "w25q128.h"
#include "spi.h"
/** 接口 -------------------------------------------------------- */
/** ★ SPI口CUBE配置: 8bit, MSB First,5.25Mbits/s, HIGH, 2 edge, disable, software */
/** ★ GPIO口CUBE配置(接w25q128的CS的引脚): 输出推挽 + 上拉电阻; 标签: W25Q_CS */
static SPI_HandleTypeDef* p_w25q_spi = &hspi1; /**< ★ SPI口 */
#define W25Q_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET) /**< ★ GPIO口 */
#define W25Q_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET)
#define W25Q_WP_HIGH() HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET)
#define W25Q_RST_HIGH() HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_SET)
/** 私有变量 -------------------------------------------------------- */
static uint8_t addr_4b_flg = 0;
/** 内部函数 --------------------------------------------------- */
static void w25q_cmd(uint8_t* p_data, uint16_t size);
static void w25q_wr_cmd(uint8_t* p_data, uint16_t size);
static void w25q_wr_enable(void);
static void w25q_wr_disable(void);
static void w25q_busy_wait(void);
static void w25q_erase_4k(uint32_t addr);
static uint8_t w25q_rd_ads(void);
static void w25q_set_4b(void);
static uint16_t w25q_id(void);
/** 私有宏(类型定义) -------------------------------------------- */
#define W25Q256 0XEF18
#define W25Q_ID 0x90 /**< 4: 制造商ID(0xEF);5:设备ID */
#define W25Q_STATUS_1 0x05 /**< 读取状态寄存器(S7 -S0 ) */
#define W25Q_STATUS_3 0x15 /**< 读取状态寄存器(S23-S16) */
#define W25Q_WR_ENABLE 0x06
#define W25Q_WR_DISABLE 0x04
#define W25Q_4K_ERASE 0x20 /**< 擦除4K空间 */
#define W25Q_64K_ERASE 0xD8 /**< 擦除64K空间 */
#define W25Q_RD_DATA_1B 0x03 /**< 读取1B数据 */
#define W25Q_RD_DATA 0x0B /**< 快速读取数据 */
#define W25Q_WR_PAGE 0x02 /**< 写不超过1页数据 */
#define W25Q_4BYTE_ADDR 0xB7 /**< 设置4字节地址 */
#define DUMMY 0xFF /**< 无效命令 */
#define W25Q_BUSY 0x01 /**< BUSY位 */
#define W25Q_ADS 0x01 /**< ADS位 */
#define W25Q_ERASE_CHIP 0xC7
/** 公有函数 --------------------------------------------------- */
/**
* @brief 芯片初始化
* @param None
* @retval None
* @note
*/
void w25q_init(void)
{
/** 片选除能 */
W25Q_CS_HIGH();
W25Q_WP_HIGH();
W25Q_RST_HIGH();
/** SPI使能 */
__HAL_SPI_ENABLE(p_w25q_spi);
/** 读取flash的id */
uint16_t id = w25q_id();
printf("id = %x \r\n", id);
/** 如果是W25Q256,设置为4字节地址*/
if(id == W25Q256)
{
uint8_t ads = w25q_rd_ads(); /**< 读取状态位ads,判断是否为4字节地址 */
if(ads == 0) /**< 如果不是4字节地址 */
{
w25q_set_4b(); /**< 设置为4字节地址 */
addr_4b_flg = 1;
}
}
// w25q_test();
}
/**
* @brief 在指定地址,读指定长度的数据
* @param addr 32位地址
* @param size 字节数(< 256)
* @param p_dat 数据存储区指针
* @retval NONE
* @note
*/
void w25q_rd_data(uint32_t addr, uint16_t size, uint8_t* p_dat)
{
uint8_t addr_len = 3;
uint8_t cmd_buf[6] = {W25Q_RD_DATA, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY};
if(addr_4b_flg)
{
addr_len = 4;
cmd_buf[1] = (uint8_t)(addr >> 24);
cmd_buf[2] = (uint8_t)(addr >> 16);
cmd_buf[3] = (uint8_t)(addr >> 8);
cmd_buf[4] = (uint8_t)addr;
}
else
{
cmd_buf[1] = (uint8_t)(addr >> 16);
cmd_buf[2] = (uint8_t)(addr >> 8);
cmd_buf[3] = (uint8_t)addr;
}
W25Q_CS_LOW();
HAL_SPI_Transmit(p_w25q_spi, &cmd_buf[0], addr_len + 2, 1000);
HAL_SPI_Receive(p_w25q_spi, p_dat, size, 1000);
W25Q_CS_HIGH();
}
/**
* @brief 在指定地址,写指定长度的数据
* @param addr 32位地址
* @param size 字节数(< 256)
* @param p_dat 数据存储区指针
* @retval NONE
* @note
*/
void w25q_wr_data(uint32_t addr, uint16_t size, uint8_t* p_dat)
{
uint8_t page_remain = 256 - addr % 256; /**< 当前页剩余字节数 */
uint8_t wr_bytes_cur_page; /**< 当前页写入字节数 */
uint8_t wr_bytes_next_page; /**< 下一页写入字节数 */
uint8_t addr_len = 3;
uint8_t cmd_buf[5] = {W25Q_WR_PAGE, DUMMY, DUMMY, DUMMY, DUMMY};
/** 写入数据在新的8K区域,擦除新区域 */
if((addr % 8192) == 0)
{
w25q_erase_4k(addr);
w25q_busy_wait();
w25q_erase_4k(addr + 4096);
w25q_busy_wait();
}
/** 写入数据是否跨页 */
if(size <= page_remain) /**< 未跨页 */
{
wr_bytes_cur_page = size;
wr_bytes_next_page = 0;
}
else /**< 跨页 */
{
wr_bytes_cur_page = page_remain;
wr_bytes_next_page = size - page_remain;
}
printf("flash_addr is %d\r\n", addr);
/** 输入地址 */
if(addr_4b_flg)
{
addr_len = 4;
cmd_buf[1] = (uint8_t)(addr >> 24);
cmd_buf[2] = (uint8_t)(addr >> 16);
cmd_buf[3] = (uint8_t)(addr >> 8);
cmd_buf[4] = (uint8_t)addr;
}
else
{
cmd_buf[1] = (uint8_t)(addr >> 16);
cmd_buf[2] = (uint8_t)(addr >> 8);
cmd_buf[3] = (uint8_t)addr;
}
for(int j = 1; j < 5; j++)
{
printf("cmd_buf[%d] is %d\r\n", j, cmd_buf[j]);
}
/** 写数据到当前页 */
w25q_wr_enable();
W25Q_CS_LOW();
HAL_SPI_Transmit(p_w25q_spi, &cmd_buf[0], addr_len + 1, 1000);
HAL_SPI_Transmit(p_w25q_spi, p_dat, wr_bytes_cur_page, 1000);
W25Q_CS_HIGH();
w25q_wr_disable();
/** 写数据到下一页 */
if(wr_bytes_next_page)
{
if(addr_4b_flg)
{
cmd_buf[1] = (uint8_t)((addr + page_remain) >> 24);
cmd_buf[2] = (uint8_t)((addr + page_remain) >> 16);
cmd_buf[3] = (uint8_t)((addr + page_remain) >> 8);
cmd_buf[4] = 0;
}
else
{
cmd_buf[1] = (uint8_t)((addr + page_remain) >> 16);
cmd_buf[2] = (uint8_t)((addr + page_remain) >> 8);
cmd_buf[3] = 0;
}
for(int j = 1; j < 5; j++)
{
printf("cmd_buf[%d] is %d\r\n", j, cmd_buf[j]);
}
w25q_wr_enable();
W25Q_CS_LOW();
HAL_SPI_Transmit(p_w25q_spi, &cmd_buf[0], addr_len + 1, 1000);
HAL_SPI_Transmit(p_w25q_spi, p_dat + wr_bytes_cur_page, wr_bytes_next_page, 1000);
W25Q_CS_HIGH();
w25q_wr_disable();
}
}
void w25q_erase_chip(void)
{
uint8_t cmd_buf[1] = {W25Q_ERASE_CHIP};
w25q_wr_enable();
w25q_busy_wait();
W25Q_CS_LOW();
HAL_SPI_Transmit(p_w25q_spi, cmd_buf, 1, 1000);
W25Q_CS_HIGH();
w25q_busy_wait();
// w25q_wr_disable();
}
/** 私有函数 --------------------------------------------------- */
/**
* @brief w25q通讯命令(读写)
* @param p_data 命令缓冲区指针
* @param size 命令字节数
* @retval None
* @note
*/
static void w25q_cmd(uint8_t* p_data, uint16_t size)
{
w25q_busy_wait();
W25Q_CS_LOW();
HAL_SPI_TransmitReceive(p_w25q_spi, p_data, p_data, size, 1000);
W25Q_CS_HIGH();
}
/**
* @brief w25q通讯命令(单写)
* @param p_data 命令缓冲区指针
* @param size 命令字节数
* @retval None
* @note
*/
static void w25q_wr_cmd(uint8_t* p_data, uint16_t size)
{
w25q_busy_wait();
W25Q_CS_LOW();
HAL_SPI_Transmit(p_w25q_spi, p_data, size, 1000);
W25Q_CS_HIGH();
HAL_Delay(1);
}
/**
* @brief 写使能
* @param None
* @retval None
* @note
*/
static void w25q_wr_enable(void)
{
uint8_t cmd_buf = W25Q_WR_ENABLE;
w25q_wr_cmd(&cmd_buf, 1);
}
/**
* @brief 写除能
* @param None
* @retval None
* @note
*/
static void w25q_wr_disable(void)
{
uint8_t cmd_buf = W25Q_WR_DISABLE;
w25q_wr_cmd(&cmd_buf, 1);
}
/**
* @brief w25q忙等待
* @param None
* @retval None
* @note
*/
static void w25q_busy_wait(void)
{
uint8_t cmd_buf[2] = {W25Q_STATUS_1, DUMMY};
W25Q_CS_LOW();
HAL_SPI_TransmitReceive(p_w25q_spi, cmd_buf, cmd_buf, 2, 1000);
do
{
HAL_SPI_TransmitReceive(p_w25q_spi, cmd_buf, cmd_buf, 2, 1000);
cmd_buf[1] &= W25Q_BUSY;
}while(cmd_buf[1]);
W25Q_CS_HIGH();
}
/**
* @brief 4k块擦除
* @param addr 32位地址
* @retval None
* @note
*/
static void w25q_erase_4k(uint32_t addr)
{
uint8_t addr_len = 3;
uint8_t cmd_buf[5] = {W25Q_4K_ERASE, DUMMY, DUMMY, DUMMY, DUMMY};
if(addr_4b_flg)
{
addr_len = 4;
cmd_buf[1] = (uint8_t)(addr >> 24);
cmd_buf[2] = (uint8_t)(addr >> 16);
cmd_buf[3] = (uint8_t)(addr >> 8);
cmd_buf[4] = (uint8_t)addr;
}
else
{
cmd_buf[1] = (uint8_t)(addr >> 16);
cmd_buf[2] = (uint8_t)(addr >> 8);
cmd_buf[3] = (uint8_t)addr;
}
w25q_wr_enable();
w25q_cmd(&cmd_buf[0], addr_len + 1);
w25q_wr_disable();
}
/**
* @brief 读取状态位ADS
* @param None
* @retval ADS
* @note ADS = 0 为3字节地址; ADS = 1 为4字节地址
*/
static uint8_t w25q_rd_ads(void)
{
uint8_t cmd_buf[2] = {W25Q_STATUS_3, DUMMY};
W25Q_CS_LOW();
HAL_SPI_TransmitReceive(p_w25q_spi, cmd_buf, cmd_buf, 2, 1000);
cmd_buf[1] &= W25Q_ADS;
W25Q_CS_HIGH();
return(cmd_buf[1]);
}
/**
* @brief 设置为4字节地址
* @param None
* @retval None
* @note
*/
static void w25q_set_4b(void)
{
uint8_t cmd_buf[2] = {W25Q_4BYTE_ADDR, DUMMY};
w25q_cmd(&cmd_buf[0], 2);
}
/**
* @brief 制造商ID(0xEF) + 设备ID
* @param None
* @retval 0xEF00 + 0xID
* @note
*/
static uint16_t w25q_id(void)
{
uint16_t id;
uint8_t cmd_buf[6] = {W25Q_ID, DUMMY, DUMMY, 0, DUMMY, DUMMY};
w25q_cmd(&cmd_buf[0], 6);
id = (uint16_t)(cmd_buf[4] << 8) + cmd_buf[5];
return(id);
}
[/code]