diff --git a/sdk/bsp/bsp.mk b/sdk/bsp/bsp.mk index a0b2023..157ca0b 100644 --- a/sdk/bsp/bsp.mk +++ b/sdk/bsp/bsp.mk @@ -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) diff --git a/sdk/bsp/include/flash_gd25q.h b/sdk/bsp/include/flash_gd25q.h new file mode 100644 index 0000000..5b4bfcc --- /dev/null +++ b/sdk/bsp/include/flash_gd25q.h @@ -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 diff --git a/sdk/bsp/lib/flash_gd25q.c b/sdk/bsp/lib/flash_gd25q.c new file mode 100644 index 0000000..a88dce8 --- /dev/null +++ b/sdk/bsp/lib/flash_gd25q.c @@ -0,0 +1,244 @@ +#include + +#include "../../bsp/include/spi.h" +#include "../../bsp/include/rvic.h" +#include "../../bsp/include/utils.h" +#include "../../bsp/include/flash_gd25q.h" + +/* GD25Q127特点: + * 1.总共128Mb大小,即16MB + * 2.总共64K页,每页大小256字节 + * 3.总共4K扇区,每个扇区大小为4K字节,16页 + * 4.总共256个block,每个block大小为64K字节,16个扇区 + * 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; +} diff --git a/sdk/examples/spi_master/main_gd25q.c b/sdk/examples/spi_master/main_gd25q.c new file mode 100644 index 0000000..4dad099 --- /dev/null +++ b/sdk/examples/spi_master/main_gd25q.c @@ -0,0 +1,128 @@ +#include + +#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); +}