sdk: add support for gd25xx nor flash

Signed-off-by: liangkangnan <liangkangnan@163.com>
verilator
liangkangnan 2022-10-10 09:00:03 +08:00
parent 26a221a132
commit ccadad262f
4 changed files with 486 additions and 66 deletions

View File

@ -1,66 +1,67 @@
RISCV_TOOLS_PATH := /opt/riscv32/bin
RISCV_TOOLS_PREFIX := riscv32-unknown-elf-
RISCV_GCC := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gcc)
RISCV_AS := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)as)
RISCV_GXX := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)g++)
RISCV_OBJDUMP := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objdump)
RISCV_GDB := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gdb)
RISCV_AR := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)ar)
RISCV_OBJCOPY := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objcopy)
RISCV_READELF := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)readelf)
BIN_TO_MEM := $(BSP_DIR)/../../tools/BinToMem.py
.PHONY: all
all: $(TARGET)
ASM_SRCS += $(BSP_DIR)/crt0.S
ASM_SRCS += $(BSP_DIR)/trap_entry.S
C_SRCS += $(BSP_DIR)/lib/utils.c
C_SRCS += $(BSP_DIR)/lib/xprintf.c
C_SRCS += $(BSP_DIR)/lib/uart.c
C_SRCS += $(BSP_DIR)/lib/sim_ctrl.c
C_SRCS += $(BSP_DIR)/lib/timer.c
C_SRCS += $(BSP_DIR)/lib/gpio.c
C_SRCS += $(BSP_DIR)/lib/rvic.c
C_SRCS += $(BSP_DIR)/lib/i2c.c
C_SRCS += $(BSP_DIR)/lib/spi.c
C_SRCS += $(BSP_DIR)/lib/pinmux.c
C_SRCS += $(BSP_DIR)/lib/flash_n25q.c
C_SRCS += $(BSP_DIR)/lib/flash_ctrl.c
LINKER_SCRIPT := $(BSP_DIR)/link_rom.lds
INCLUDES += -I$(BSP_DIR)
LDFLAGS += -T $(LINKER_SCRIPT) -nostartfiles -Wl,--gc-sections -Wl,--check-sections
ASM_OBJS := $(ASM_SRCS:.S=.o)
C_OBJS := $(C_SRCS:.c=.o)
LINK_OBJS += $(ASM_OBJS) $(C_OBJS)
LINK_DEPS += $(LINKER_SCRIPT)
CLEAN_OBJS += $(TARGET) $(LINK_OBJS) $(TARGET).dump $(TARGET).bin $(TARGET).hex $(TARGET).mem
CFLAGS += -march=$(RISCV_ARCH)
CFLAGS += -mabi=$(RISCV_ABI)
CFLAGS += -mcmodel=$(RISCV_MCMODEL) -ffunction-sections -fdata-sections -fno-builtin-printf -fno-builtin-malloc
$(TARGET): $(LINK_OBJS) $(LINK_DEPS) Makefile
$(RISCV_GCC) $(CFLAGS) $(INCLUDES) $(LINK_OBJS) -o $@ $(LDFLAGS)
$(RISCV_OBJCOPY) -O binary $@ $@.bin
$(RISCV_OBJDUMP) --disassemble-all $@ > $@.dump
$(BIN_TO_MEM) $@.bin $@.mem
$(ASM_OBJS): %.o: %.S
$(RISCV_GCC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
$(C_OBJS): %.o: %.c
$(RISCV_GCC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
.PHONY: clean
clean:
rm -f $(CLEAN_OBJS)
RISCV_TOOLS_PATH := /opt/riscv32/bin
RISCV_TOOLS_PREFIX := riscv32-unknown-elf-
RISCV_GCC := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gcc)
RISCV_AS := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)as)
RISCV_GXX := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)g++)
RISCV_OBJDUMP := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objdump)
RISCV_GDB := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)gdb)
RISCV_AR := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)ar)
RISCV_OBJCOPY := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)objcopy)
RISCV_READELF := $(abspath $(RISCV_TOOLS_PATH)/$(RISCV_TOOLS_PREFIX)readelf)
BIN_TO_MEM := $(BSP_DIR)/../../tools/BinToMem.py
.PHONY: all
all: $(TARGET)
ASM_SRCS += $(BSP_DIR)/crt0.S
ASM_SRCS += $(BSP_DIR)/trap_entry.S
C_SRCS += $(BSP_DIR)/lib/utils.c
C_SRCS += $(BSP_DIR)/lib/xprintf.c
C_SRCS += $(BSP_DIR)/lib/uart.c
C_SRCS += $(BSP_DIR)/lib/sim_ctrl.c
C_SRCS += $(BSP_DIR)/lib/timer.c
C_SRCS += $(BSP_DIR)/lib/gpio.c
C_SRCS += $(BSP_DIR)/lib/rvic.c
C_SRCS += $(BSP_DIR)/lib/i2c.c
C_SRCS += $(BSP_DIR)/lib/spi.c
C_SRCS += $(BSP_DIR)/lib/pinmux.c
C_SRCS += $(BSP_DIR)/lib/flash_n25q.c
C_SRCS += $(BSP_DIR)/lib/flash_gd25q.c
C_SRCS += $(BSP_DIR)/lib/flash_ctrl.c
LINKER_SCRIPT := $(BSP_DIR)/link_rom.lds
INCLUDES += -I$(BSP_DIR)
LDFLAGS += -T $(LINKER_SCRIPT) -nostartfiles -Wl,--gc-sections -Wl,--check-sections
ASM_OBJS := $(ASM_SRCS:.S=.o)
C_OBJS := $(C_SRCS:.c=.o)
LINK_OBJS += $(ASM_OBJS) $(C_OBJS)
LINK_DEPS += $(LINKER_SCRIPT)
CLEAN_OBJS += $(TARGET) $(LINK_OBJS) $(TARGET).dump $(TARGET).bin $(TARGET).hex $(TARGET).mem
CFLAGS += -march=$(RISCV_ARCH)
CFLAGS += -mabi=$(RISCV_ABI)
CFLAGS += -mcmodel=$(RISCV_MCMODEL) -ffunction-sections -fdata-sections -fno-builtin-printf -fno-builtin-malloc
$(TARGET): $(LINK_OBJS) $(LINK_DEPS) Makefile
$(RISCV_GCC) $(CFLAGS) $(INCLUDES) $(LINK_OBJS) -o $@ $(LDFLAGS)
$(RISCV_OBJCOPY) -O binary $@ $@.bin
$(RISCV_OBJDUMP) --disassemble-all $@ > $@.dump
$(BIN_TO_MEM) $@.bin $@.mem
$(ASM_OBJS): %.o: %.S
$(RISCV_GCC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
$(C_OBJS): %.o: %.c
$(RISCV_GCC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
.PHONY: clean
clean:
rm -f $(CLEAN_OBJS)

View File

@ -0,0 +1,47 @@
#ifndef _FLASH_GD25Q_H_
#define _FLASH_GD25Q_H_
#define GD25Q_PAGE_SIZE (256)
#define GD25Q_PAGE_TO_ADDR(page) ((page) << 8)
#define GD25Q_SECTOR_TO_ADDR(sector) ((sector) << 12)
#define CMD_WRITE_STATUS_REG1 (0x01)
#define CMD_WRITE_STATUS_REG2 (0x31)
#define CMD_WRITE_STATUS_REG3 (0x11)
#define CMD_READ_STATUS_REG1 (0x05)
#define CMD_READ_STATUS_REG2 (0x35)
#define CMD_READ_STATUS_REG3 (0x15)
#define CMD_PAGE_PROGRAM (0x02)
#define CMD_QUAD_PAGE_PROGRAM (0x32)
#define CMD_READ (0x03)
#define CMD_QUAD_IO_FAST_READ (0xeb)
#define CMD_WRITE_ENABLE (0x06)
#define CMD_WRITE_DISABLE (0x04)
#define CMD_SECTOR_ERASE (0x20)
#define CMD_BLOCK32K_ERASE (0x52)
#define CMD_BLOCK64K_ERASE (0xd8)
#define CMD_READ_ID (0x90)
#define CMD_QUAD_IO_READ_ID (0x94)
#define DUMMY_CNT (0x4)
typedef struct {
uint8_t manf_id;
uint8_t dev_id;
} gd25q_id_t;
void flash_gd25q_init(uint32_t controller, uint16_t clk_div);
void flash_gd25q_set_spi_mode(uint8_t mode);
void flash_gd25q_set_spi_controller(uint32_t controller);
gd25q_id_t flash_gd25q_read_id();
void flash_gd25q_write_enable(uint8_t en);
uint8_t flash_gd25q_read_reg(uint8_t cmd);
void flash_gd25q_write_reg(uint8_t cmd, uint8_t data);
uint8_t flash_gd25q_is_busy();
void flash_gd25q_read(uint8_t data[], uint32_t len, uint32_t addr);
void flash_gd25q_sector_erase(uint32_t sector);
void flash_gd25q_page_program(uint8_t data[], uint32_t len, uint32_t page);
void flash_gd25q_enable_quad_mode(uint8_t en);
#endif

244
sdk/bsp/lib/flash_gd25q.c Normal file
View File

@ -0,0 +1,244 @@
#include <stdint.h>
#include "../../bsp/include/spi.h"
#include "../../bsp/include/rvic.h"
#include "../../bsp/include/utils.h"
#include "../../bsp/include/flash_gd25q.h"
/* GD25Q127特点:
* 1.128Mb16MB
* 2.64K256
* 3.4K4K16
* 4.256blockblock64K16
* 5.()
*/
static uint8_t current_spi_mode;
static uint32_t spi_base_addr;
void flash_gd25q_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_gd25q_set_spi_mode(uint8_t mode)
{
current_spi_mode = mode;
}
void flash_gd25q_set_spi_controller(uint32_t controller)
{
spi_base_addr = controller;
}
// 写使能
// 擦除或者编程或者写寄存器之前必须先发送写使能命令
void flash_gd25q_write_enable(uint8_t en)
{
uint8_t cmd;
if (en)
cmd = CMD_WRITE_ENABLE;
else
cmd = CMD_WRITE_DISABLE;
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
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);
spi_set_spi_mode(spi_base_addr, current_spi_mode);
}
// 读寄存器
uint8_t flash_gd25q_read_reg(uint8_t cmd)
{
uint8_t data;
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
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);
spi_set_spi_mode(spi_base_addr, current_spi_mode);
return data;
}
// 写寄存器
void flash_gd25q_write_reg(uint8_t cmd, uint8_t data)
{
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
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);
spi_set_spi_mode(spi_base_addr, current_spi_mode);
}
// 是否正在擦除或者编程
uint8_t flash_gd25q_is_busy()
{
if (flash_gd25q_read_reg(CMD_READ_STATUS_REG1) & 0x1)
return 1;
else
return 0;
}
// 读数据
// addr: 0, 1, 2, ...
void flash_gd25q_read(uint8_t data[], uint32_t len, uint32_t addr)
{
uint8_t cmd, i;
uint8_t tran_addr[4];
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
tran_addr[3] = 0x00;
if (current_spi_mode == SPI_MODE_STANDARD) {
cmd = CMD_READ;
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_read_bytes(spi_base_addr, data, len);
spi_set_ss_level(spi_base_addr, 1);
} else {
cmd = CMD_QUAD_IO_FAST_READ;
// 标准模式发送CMD
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
spi_set_ss_level(spi_base_addr, 0);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_set_spi_mode(spi_base_addr, SPI_MODE_QUAD);
// QSPI模式发送ADDR
spi_master_write_bytes(spi_base_addr, tran_addr, 4);
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_gd25q_write_enable(1);
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
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_gd25q_is_busy());
flash_gd25q_write_enable(0);
spi_set_spi_mode(spi_base_addr, current_spi_mode);
}
// 扇区擦除
// sector第几个扇区: 0 ~ N
void flash_gd25q_sector_erase(uint32_t sector)
{
sector_erase(CMD_SECTOR_ERASE, GD25Q_SECTOR_TO_ADDR(sector));
}
// 页编程
// page第几页: 0 ~ N
void flash_gd25q_page_program(uint8_t data[], uint32_t len, uint32_t page)
{
uint8_t tran_addr[3];
uint8_t cmd;
uint32_t addr;
flash_gd25q_write_enable(1);
addr = GD25Q_PAGE_TO_ADDR(page);
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
if (current_spi_mode == SPI_MODE_STANDARD)
cmd = CMD_PAGE_PROGRAM;
else
cmd = CMD_QUAD_PAGE_PROGRAM;
spi_set_ss_level(spi_base_addr, 0);
spi_set_spi_mode(spi_base_addr, SPI_MODE_STANDARD);
spi_master_write_bytes(spi_base_addr, &cmd, 1);
spi_master_write_bytes(spi_base_addr, tran_addr, 3);
spi_set_spi_mode(spi_base_addr, current_spi_mode);
spi_master_write_bytes(spi_base_addr, data, len);
spi_set_ss_level(spi_base_addr, 1);
while (flash_gd25q_is_busy());
flash_gd25q_write_enable(0);
}
// 使能QUAD SPI模式
void flash_gd25q_enable_quad_mode(uint8_t en)
{
uint8_t data;
flash_gd25q_write_enable(1);
data = flash_gd25q_read_reg(CMD_READ_STATUS_REG2);
if (en) {
data |= 1 << 1;
} else {
data &= ~(1 << 1);
}
flash_gd25q_write_reg(CMD_WRITE_STATUS_REG2, data);
flash_gd25q_write_enable(0);
}
// 读flash ID
gd25q_id_t flash_gd25q_read_id()
{
gd25q_id_t id;
uint8_t cmd;
uint8_t tran_addr[3];
uint8_t data[2];
tran_addr[0] = 0x00;
tran_addr[1] = 0x00;
tran_addr[2] = 0x00;
cmd = CMD_READ_ID;
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_read_bytes(spi_base_addr, data, 2);
spi_set_ss_level(spi_base_addr, 1);
id.manf_id = data[0];
id.dev_id = data[1];
return id;
}

View File

@ -0,0 +1,128 @@
#include <stdint.h>
#include "../../bsp/include/uart.h"
#include "../../bsp/include/spi.h"
#include "../../bsp/include/xprintf.h"
#include "../../bsp/include/utils.h"
#include "../../bsp/include/rvic.h"
#include "../../bsp/include/pinmux.h"
#include "../../bsp/include/sim_ctrl.h"
#include "../../bsp/include/flash_gd25q.h"
#define BUFFER_SIZE (64)
uint8_t program_data[BUFFER_SIZE];
uint8_t read_data[BUFFER_SIZE];
// 标准三线SPI测试
static void standard_spi_test()
{
uint16_t i;
gd25q_id_t id;
xprintf("Standard SPI test started...\n");
flash_gd25q_set_spi_mode(SPI_MODE_STANDARD);
// 读flash ID
id = flash_gd25q_read_id();
xprintf("manf id = 0x%2x\n", id.manf_id);
xprintf("dev id = 0x%2x\n", id.dev_id);
// 初始化要编程的数据
for (i = 0; i < BUFFER_SIZE; i++)
program_data[i] = i + 1;
// 擦除第0个扇区
flash_gd25q_sector_erase(0);
xprintf("program data: \n");
// 打印要编程的数据
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", program_data[i]);
// 编程第1页
flash_gd25q_page_program(program_data, BUFFER_SIZE, 1);
// 读第1页
flash_gd25q_read(read_data, BUFFER_SIZE, GD25Q_PAGE_TO_ADDR(1));
xprintf("read data: \n");
// 打印读出来的数据
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", read_data[i]);
for (i = 0; i < BUFFER_SIZE; i++) {
if (program_data[i] != read_data[i]) {
xprintf("test failed!!!\n");
return;
}
}
xprintf("Standard SPI test succ...\n");
}
// QSPI测试
static void quad_spi_test()
{
uint16_t i;
xprintf("\nQuad SPI test started...\n");
// 使能QSPI模式
flash_gd25q_enable_quad_mode(1);
flash_gd25q_set_spi_mode(SPI_MODE_QUAD);
// 初始化要编程的数据
for (i = 0; i < BUFFER_SIZE; i++)
program_data[i] = i + 2;
// 擦除第1个扇区
flash_gd25q_sector_erase(1);
xprintf("program data: \n");
// 打印要编程的数据
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", program_data[i]);
// 编程第16页
flash_gd25q_page_program(program_data, BUFFER_SIZE, 16);
// 读第16页
flash_gd25q_read(read_data, BUFFER_SIZE, GD25Q_PAGE_TO_ADDR(16));
xprintf("read data: \n");
// 打印读出来的数据
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", read_data[i]);
// 失能QSPI模式
flash_gd25q_enable_quad_mode(0);
spi_set_spi_mode(SPI0, SPI_MODE_STANDARD);
flash_gd25q_set_spi_mode(SPI_MODE_STANDARD);
for (i = 0; i < BUFFER_SIZE; i++) {
if (program_data[i] != read_data[i]) {
xprintf("test failed!!!\n");
return;
}
}
xprintf("Quad SPI test succ...\n");
}
int main()
{
// UART引脚配置
pinmux_set_io0_func(IO0_UART0_TX);
pinmux_set_io3_func(IO3_UART0_RX);
// SPI引脚配置
pinmux_set_io10_func(IO10_SPI_CLK);
pinmux_set_io11_func(IO11_SPI_SS);
pinmux_set_io12_func(IO12_SPI_DQ0);
pinmux_set_io13_func(IO13_SPI_DQ1);
pinmux_set_io14_func(IO14_SPI_DQ2);
pinmux_set_io15_func(IO15_SPI_DQ3);
uart_init(UART0, uart0_putc);
// 115200bps
uart_set_baud_div(UART0, 0x68);
flash_gd25q_init(SPI0, 5);
standard_spi_test();
quad_spi_test();
while (1);
}