tinyriscv/sdk/bsp/lib/flash_n25q.c

243 lines
6.1 KiB
C
Raw Normal View History

#include <stdint.h>
#include "../../bsp/include/spi.h"
#include "../../bsp/include/rvic.h"
#include "../../bsp/include/utils.h"
#include "../../bsp/include/flash_n25q.h"
/* N25Q064特点:
* 1.64Mb8MB
* 2.12864KB
* 3.20484KB
* 4.37768256B
* 5.()
*/
static uint8_t current_spi_mode;
static uint32_t spi_base_addr;
void flash_n25q_init(uint32_t controller, uint16_t clk_div)
{
spi_base_addr = controller;
spi_set_clk_div(spi_base_addr, clk_div);
spi_set_role_mode(spi_base_addr, SPI_ROLE_MODE_MASTER);
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
spi_set_cp_mode(spi_base_addr, SPI_CPOL_0_CPHA_0);
spi_set_msb_first(spi_base_addr);
spi_master_set_ss_delay(spi_base_addr, 1);
spi_set_ss_level(spi_base_addr, 1);
spi_set_ss_ctrl_by_sw(spi_base_addr, 1);
spi_set_enable(spi_base_addr, 1);
}
void flash_n25q_set_spi_mode(uint8_t mode)
{
current_spi_mode = mode;
}
void flash_n25q_set_spi_controller(uint32_t controller)
{
spi_base_addr = controller;
}
// 写使能
// 擦除或者编程或者写寄存器之前必须先发送写使能命令
void flash_n25q_write_enable(uint8_t en)
{
uint8_t cmd;
if (en)
cmd = CMD_WRITE_ENABLE;
else
cmd = CMD_WRITE_DISABLE;
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_set_ss_level(spi_base_addr, 1);
}
// 读寄存器
uint8_t flash_n25q_read_reg(uint8_t cmd)
{
uint8_t data;
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_read_bytes(spi_base_addr, &data, 1);
spi_set_ss_level(spi_base_addr, 1);
return data;
}
// 写寄存器
void flash_n25q_write_reg(uint8_t cmd, uint8_t data)
{
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_write_bytes(spi_base_addr, &data, 1);
spi_set_ss_level(spi_base_addr, 1);
}
// 读状态寄存器
uint8_t flash_n25q_read_status_reg()
{
uint8_t data;
data = flash_n25q_read_reg(CMD_READ_STATUS_REG);
return data;
}
// 是否正在擦除或者编程
uint8_t flash_n25q_is_busy()
{
if (flash_n25q_read_status_reg() & 0x1)
return 1;
else
return 0;
}
// 读数据
// addr: 0, 1, 2, ...
void flash_n25q_read(uint8_t data[], uint32_t len, uint32_t addr)
{
uint8_t cmd, i;
uint8_t tran_addr[3];
if (current_spi_mode == SPI_MODE_STANDARD)
cmd = CMD_READ;
else
cmd = CMD_FAST_READ;
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_write_bytes(spi_base_addr, tran_addr, 3);
if (current_spi_mode != SPI_MODE_STANDARD) {
for (i = 0; i < (DUMMY_CNT >> 1); i++)
spi_master_read_bytes(spi_base_addr, data, 1);
spi_reset_rxfifo(spi_base_addr);
}
spi_master_read_bytes(spi_base_addr, data, len);
spi_set_ss_level(spi_base_addr, 1);
}
static void sector_erase(uint8_t cmd, uint32_t addr)
{
uint8_t tran_addr[3];
flash_n25q_write_enable(1);
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_write_bytes(spi_base_addr, tran_addr, 3);
spi_set_ss_level(spi_base_addr, 1);
while (flash_n25q_is_busy());
flash_n25q_write_enable(0);
}
// 子扇区擦除
// subsector第几个子扇区: 0 ~ N
void flash_n25q_subsector_erase(uint32_t subsector)
{
sector_erase(CMD_SUBSECTOR_ERASE, N25Q_SUBSECTOR_TO_ADDR(subsector));
}
// 扇区擦除
// sector第几个扇区: 0 ~ N
void flash_n25q_sector_erase(uint32_t sector)
{
sector_erase(CMD_SECTOR_ERASE, N25Q_SECTOR_TO_ADDR(sector));
}
// 页编程
// page第几页: 0 ~ N
void flash_n25q_page_program(uint8_t data[], uint32_t len, uint32_t page)
{
uint8_t tran_addr[3];
uint8_t cmd;
uint32_t addr;
flash_n25q_write_enable(1);
addr = N25Q_PAGE_TO_ADDR(page);
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
cmd = CMD_PAGE_PROGRAM;
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_write_bytes(spi_base_addr, tran_addr, 3);
spi_master_write_bytes(spi_base_addr, data, len);
spi_set_ss_level(spi_base_addr, 1);
while (flash_n25q_is_busy());
flash_n25q_write_enable(0);
}
// 使能QUAD SPI模式
void flash_n25q_enable_quad_mode(uint8_t en)
{
uint8_t data;
flash_n25q_write_enable(1);
data = flash_n25q_read_reg(CMD_READ_ENHANCED_VOL_CONF_REG);
if (en) {
data &= ~(1 << 7);
data |= 1 << 6;
} else {
data |= 0x3 << 6;
}
flash_n25q_write_reg(CMD_WRITE_ENHANCED_VOL_CONF_REG, data);
flash_n25q_write_enable(0);
}
// 设置n25q dummy cycles
void flash_n25q_set_dummy_clock_cycles(uint8_t num)
{
uint8_t data;
flash_n25q_write_enable(1);
data = flash_n25q_read_reg(CMD_READ_VOL_CONF_REG);
data &= ~(0xf << 4);
data |= num << 4;
flash_n25q_write_reg(CMD_WRITE_VOL_CONF_REG, data);
flash_n25q_write_enable(0);
}
// 读flash ID
n25q_id_t flash_n25q_read_id(uint8_t cmd)
{
n25q_id_t id;
uint8_t data[3];
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_read_bytes(spi_base_addr, data, 3);
spi_set_ss_level(spi_base_addr, 1);
id.manf_id = data[0];
id.mem_type = data[1];
id.mem_cap = data[2];
return id;
}