diff --git a/sdk/bsp/bsp.mk b/sdk/bsp/bsp.mk index 2a79637..f95f85a 100644 --- a/sdk/bsp/bsp.mk +++ b/sdk/bsp/bsp.mk @@ -29,6 +29,7 @@ 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.lds diff --git a/sdk/bsp/include/flash_ctrl.h b/sdk/bsp/include/flash_ctrl.h new file mode 100644 index 0000000..316cbae --- /dev/null +++ b/sdk/bsp/include/flash_ctrl.h @@ -0,0 +1,72 @@ +// Generated register defines for flash_ctrl + +// Copyright information found in source file: +// Copyright lowRISC contributors. + +// Licensing information found in source file: +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef _FLASH_CTRL_REG_DEFS_ +#define _FLASH_CTRL_REG_DEFS_ + +#ifdef __cplusplus +extern "C" { +#endif +// Register width +#define FLASH_CTRL_PARAM_REG_WIDTH 32 + +#define FLASH_CTRL_BASE_ADDR (0x0E000000) +#define FLASH_CTRL_REG(offset) (*((volatile uint32_t *)(FLASH_CTRL_BASE_ADDR + offset))) + +typedef enum { + FLASH_OP_READ = 0, + FLASH_OP_PROGRAM, + FLASH_OP_ERASE, + FLASH_OP_INIT +} flash_op_mode_e; + +void flash_ctrl_init(); +void flash_ctrl_deinit(); +void flash_ctrl_qspi_init(); +void flash_ctrl_read(uint32_t start_addr, uint32_t *data, uint32_t len); +uint8_t flash_ctrl_page_program(uint32_t page_addr, uint32_t *data, uint32_t len); +uint8_t flash_ctrl_sector_erase(uint32_t sector_addr); + +// flash_ctrl control register +#define FLASH_CTRL_CTRL_REG_OFFSET 0x0 +#define FLASH_CTRL_CTRL_REG_RESVAL 0x0 +#define FLASH_CTRL_CTRL_START_BIT 0 +#define FLASH_CTRL_CTRL_OP_MODE_MASK 0x3 +#define FLASH_CTRL_CTRL_OP_MODE_OFFSET 1 +#define FLASH_CTRL_CTRL_OP_MODE_FIELD \ + ((bitfield_field32_t) { .mask = FLASH_CTRL_CTRL_OP_MODE_MASK, .index = FLASH_CTRL_CTRL_OP_MODE_OFFSET }) +#define FLASH_CTRL_CTRL_SW_CTRL_BIT 3 +#define FLASH_CTRL_CTRL_PROGRAM_INIT_BIT 4 +#define FLASH_CTRL_CTRL_WRITE_ERROR_BIT 5 +#define FLASH_CTRL_CTRL_RESERVED_MASK 0x3ffffff +#define FLASH_CTRL_CTRL_RESERVED_OFFSET 6 +#define FLASH_CTRL_CTRL_RESERVED_FIELD \ + ((bitfield_field32_t) { .mask = FLASH_CTRL_CTRL_RESERVED_MASK, .index = FLASH_CTRL_CTRL_RESERVED_OFFSET }) + +// flash_ctrl address register +#define FLASH_CTRL_ADDR_REG_OFFSET 0x4 +#define FLASH_CTRL_ADDR_REG_RESVAL 0x0 +#define FLASH_CTRL_ADDR_RW_ADDRESS_MASK 0x7fffff +#define FLASH_CTRL_ADDR_RW_ADDRESS_OFFSET 0 +#define FLASH_CTRL_ADDR_RW_ADDRESS_FIELD \ + ((bitfield_field32_t) { .mask = FLASH_CTRL_ADDR_RW_ADDRESS_MASK, .index = FLASH_CTRL_ADDR_RW_ADDRESS_OFFSET }) +#define FLASH_CTRL_ADDR_RESERVED_MASK 0x1ff +#define FLASH_CTRL_ADDR_RESERVED_OFFSET 23 +#define FLASH_CTRL_ADDR_RESERVED_FIELD \ + ((bitfield_field32_t) { .mask = FLASH_CTRL_ADDR_RESERVED_MASK, .index = FLASH_CTRL_ADDR_RESERVED_OFFSET }) + +// flash_ctrl data register +#define FLASH_CTRL_DATA_REG_OFFSET 0x8 +#define FLASH_CTRL_DATA_REG_RESVAL 0x0 + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // _FLASH_CTRL_REG_DEFS_ +// End generated register defines for flash_ctrl \ No newline at end of file diff --git a/sdk/bsp/lib/flash_ctrl.c b/sdk/bsp/lib/flash_ctrl.c new file mode 100644 index 0000000..21f50cd --- /dev/null +++ b/sdk/bsp/lib/flash_ctrl.c @@ -0,0 +1,122 @@ +#include + +#include "../../bsp/include/flash_ctrl.h" +#include "../../bsp/include/utils.h" + + +void flash_ctrl_init() +{ + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= 1 << FLASH_CTRL_CTRL_SW_CTRL_BIT; +} + +void flash_ctrl_deinit() +{ + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) &= ~(1 << FLASH_CTRL_CTRL_SW_CTRL_BIT); +} + +// 初始化flash为QSPI模式 +void flash_ctrl_qspi_init() +{ + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) &= ~(FLASH_CTRL_CTRL_OP_MODE_MASK << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= (FLASH_OP_INIT << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= 1 << FLASH_CTRL_CTRL_START_BIT; + while (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_START_BIT)); +} + +static void flash_ctrl_program_init() +{ + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= 1 << FLASH_CTRL_CTRL_PROGRAM_INIT_BIT; +} + +static void flash_ctrl_program_deinit() +{ + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) &= ~(1 << FLASH_CTRL_CTRL_PROGRAM_INIT_BIT); +} + +// 读数据 +void flash_ctrl_read(uint32_t start_addr, uint32_t *data, uint32_t len) +{ + uint32_t addr, i; + + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) &= ~(FLASH_CTRL_CTRL_OP_MODE_MASK << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= (FLASH_OP_READ << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + + addr = start_addr; + len = len >> 2; + + for (i = 0; i < len; i++) { + FLASH_CTRL_REG(FLASH_CTRL_ADDR_REG_OFFSET) = addr & FLASH_CTRL_ADDR_RW_ADDRESS_MASK; + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= 1 << FLASH_CTRL_CTRL_START_BIT; + while (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_START_BIT)); + data[i] = FLASH_CTRL_REG(FLASH_CTRL_DATA_REG_OFFSET); + addr += 4; + } +} + +// 以word为单位进行烧写,一次最多烧一个page(256个字节) +// 返回值,1:成功,0:失败 +uint8_t flash_ctrl_page_program(uint32_t page_addr, uint32_t *data, uint32_t len) +{ + uint32_t i, index; + uint32_t prog_len, remain_len; + + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) &= ~(FLASH_CTRL_CTRL_OP_MODE_MASK << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= (FLASH_OP_PROGRAM << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + + FLASH_CTRL_REG(FLASH_CTRL_ADDR_REG_OFFSET) = page_addr & FLASH_CTRL_ADDR_RW_ADDRESS_MASK; + + if (len > 4) + flash_ctrl_program_init(); + + remain_len = len; + index = 0; + + while (remain_len > 0) { + // 一次最多烧32个byte + if (remain_len > 32) + prog_len = 32; + else + prog_len = remain_len; + + remain_len -= prog_len; + // word的个数 + prog_len = prog_len >> 2; + + // 每次烧写一个word + for (i = 0; i < prog_len; i++) { + FLASH_CTRL_REG(FLASH_CTRL_DATA_REG_OFFSET) = data[index]; + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= 1 << FLASH_CTRL_CTRL_START_BIT; + while (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_START_BIT)); + index++; + } + } + + if (len > 4) { + flash_ctrl_program_deinit(); + while (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_START_BIT)); + } + + if (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_WRITE_ERROR_BIT)) + return 0; + else + return 1; +} + +// 扇区擦除 +// 返回值,1:成功,0:失败 +uint8_t flash_ctrl_sector_erase(uint32_t sector_addr) +{ + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) &= ~(FLASH_CTRL_CTRL_OP_MODE_MASK << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= (FLASH_OP_ERASE << FLASH_CTRL_CTRL_OP_MODE_OFFSET); + + FLASH_CTRL_REG(FLASH_CTRL_ADDR_REG_OFFSET) = sector_addr & FLASH_CTRL_ADDR_RW_ADDRESS_MASK; + + FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) |= 1 << FLASH_CTRL_CTRL_START_BIT; + while (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_START_BIT)); + + if (FLASH_CTRL_REG(FLASH_CTRL_CTRL_REG_OFFSET) & (1 << FLASH_CTRL_CTRL_WRITE_ERROR_BIT)) + return 0; + else + return 1; +} diff --git a/sdk/examples/flash_ctrl/.gitignore b/sdk/examples/flash_ctrl/.gitignore new file mode 100644 index 0000000..2518f32 --- /dev/null +++ b/sdk/examples/flash_ctrl/.gitignore @@ -0,0 +1,8 @@ +# Object files +*.o +*.ko +*.obj +*.bin +*.dump +*.mem +flash_ctrl diff --git a/sdk/examples/flash_ctrl/Makefile b/sdk/examples/flash_ctrl/Makefile new file mode 100644 index 0000000..f5b5fe3 --- /dev/null +++ b/sdk/examples/flash_ctrl/Makefile @@ -0,0 +1,20 @@ +RISCV_ARCH := rv32im +RISCV_ABI := ilp32 +RISCV_MCMODEL := medlow + + +TARGET = flash_ctrl + + +#CFLAGS += -DSIMULATION +#CFLAGS += -O2 +#ASM_SRCS += +#LDFLAGS += +#INCLUDES += -I. + +C_SRCS := \ + main.c \ + + +BSP_DIR = ../../bsp +include ../../bsp/bsp.mk diff --git a/sdk/examples/flash_ctrl/README.md b/sdk/examples/flash_ctrl/README.md new file mode 100644 index 0000000..04514fd --- /dev/null +++ b/sdk/examples/flash_ctrl/README.md @@ -0,0 +1 @@ +flash读、擦除、编程例程。 \ No newline at end of file diff --git a/sdk/examples/flash_ctrl/main.c b/sdk/examples/flash_ctrl/main.c new file mode 100644 index 0000000..c9fee37 --- /dev/null +++ b/sdk/examples/flash_ctrl/main.c @@ -0,0 +1,69 @@ +#include + +#include "../../bsp/include/uart.h" +#include "../../bsp/include/xprintf.h" +#include "../../bsp/include/pinmux.h" +#include "../../bsp/include/flash_ctrl.h" + + +#define DATA_BUF_LEN (32) + +// bytes = DATA_BUF_LEN * 4 +#define DATA_BYTES (DATA_BUF_LEN << 2) + +static uint32_t write_data_buf[DATA_BUF_LEN]; +static uint32_t read_data_buf[DATA_BUF_LEN]; + + +int main() +{ + uint32_t i; + + // UART引脚配置 + pinmux_set_io0_func(IO0_UART0_TX); + pinmux_set_io3_func(IO3_UART0_RX); + // UART初始化 + uart_init(UART0, uart0_putc); + + flash_ctrl_init(); + + // 擦除0子扇区 + if (!flash_ctrl_sector_erase(0)) + xprintf("erase failed...\n"); + + // 构造编程数据 + for (i = 0; i < DATA_BUF_LEN; i++) + write_data_buf[i] = i; + + // 编程第0页 + if (!flash_ctrl_page_program(0, write_data_buf, DATA_BYTES)) + xprintf("program failed...\n"); + + // 读0x0地址开始的数据 + flash_ctrl_read(0, read_data_buf, DATA_BYTES); + + flash_ctrl_deinit(); + + // 打印读到的数据 + for (i = 0; i < DATA_BUF_LEN; i++) + xprintf("0x%x\n", read_data_buf[i]); + +/************************** QSPI测试 **************************/ + + flash_ctrl_init(); + + // QSPI初始化 + flash_ctrl_qspi_init(); + + // 读0x0地址开始的数据 + flash_ctrl_read(0, read_data_buf, DATA_BYTES); + + flash_ctrl_deinit(); + + xprintf("\nquad spi test, read data:\n"); + // 打印读到的数据 + for (i = 0; i < DATA_BUF_LEN; i++) + xprintf("0x%x\n", read_data_buf[i]); + + while (1); +}