sdk:examples: add spi_master

Signed-off-by: liangkangnan <liangkangnan@163.com>
pull/4/head
liangkangnan 2021-09-17 09:09:38 +08:00
parent 718e16a46d
commit 75de08cfc8
6 changed files with 467 additions and 0 deletions

8
sdk/examples/spi_master/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Object files
*.o
*.ko
*.obj
*.bin
*.dump
*.mem
spi_master

View File

@ -0,0 +1,21 @@
RISCV_ARCH := rv32im
RISCV_ABI := ilp32
RISCV_MCMODEL := medlow
TARGET = spi_master
#CFLAGS += -DSIMULATION
#CFLAGS += -O2
#ASM_SRCS +=
#LDFLAGS +=
#INCLUDES += -I.
C_SRCS := \
main.c \
flash_n25q.c
BSP_DIR = ../../bsp
include ../../bsp/bsp.mk

View File

@ -0,0 +1 @@
spi_master例程。

View File

@ -0,0 +1,285 @@
#include <stdint.h>
#include "../../bsp/include/spi.h"
#include "../../bsp/include/rvic.h"
#include "../../bsp/include/utils.h"
#include "flash_n25q.h"
/* N25Q064特点:
* 1.64Mb8MB
* 2.12864KB
* 3.20484KB
* 4.37768256B
* 5.()
*/
void flash_n25q_init(uint16_t clk_div)
{
spi0_set_clk_div(clk_div);
spi0_set_role_mode(SPI_ROLE_MODE_MASTER);
spi0_set_spi_mode(SPI_MODE_STANDARD);
spi0_set_cp_mode(SPI_CPOL_0_CPHA_0);
spi0_set_msb_first();
spi0_master_set_ss_delay(1);
spi0_set_ss_level(1);
spi0_set_ss_ctrl_by_sw(1);
spi0_set_enable(1);
}
// 写使能
// 擦除或者编程操作之前必须先发送写使能命令
void flash_n25q_write_enable(uint8_t en)
{
uint8_t cmd;
if (en)
cmd = CMD_WRITE_ENABLE;
else
cmd = CMD_WRITE_DISABLE;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_set_ss_level(1);
}
// 读寄存器
uint8_t flash_n25q_read_reg(uint8_t cmd)
{
uint8_t data;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_read_bytes(&data, 1);
spi0_set_ss_level(1);
return data;
}
// 写寄存器
void flash_n25q_write_reg(uint8_t cmd, uint8_t data)
{
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_write_bytes(&data, 1);
spi0_set_ss_level(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_data(uint8_t data[], uint32_t len, uint32_t addr)
{
uint8_t cmd;
uint8_t tran_addr[3];
cmd = CMD_READ;
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_write_bytes(tran_addr, 3);
spi0_master_read_bytes(data, len);
spi0_set_ss_level(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;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_write_bytes(tran_addr, 3);
spi0_set_ss_level(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;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_write_bytes(tran_addr, 3);
spi0_master_write_bytes(data, len);
spi0_set_ss_level(1);
while (flash_n25q_is_busy());
flash_n25q_write_enable(0);
}
// 读增强型易失配置寄存器
uint8_t flash_n25q_read_enhanced_volatile_conf_reg()
{
uint8_t data;
data = flash_n25q_read_reg(CMD_READ_ENHANCED_VOL_CONF_REG);
return data;
}
// 读非易失配置寄存器
uint8_t flash_n25q_read_nonvolatile_conf_reg()
{
uint8_t data;
data = flash_n25q_read_reg(CMD_READ_NONVOL_CONF_REG);
return data;
}
// 写增强型易失配置寄存器
void flash_n25q_write_enhanced_volatile_conf_reg(uint8_t data)
{
flash_n25q_write_reg(CMD_WRITE_ENHANCED_VOL_CONF_REG, data);
}
// 使能QUAD SPI模式
void flash_n25q_enable_quad_mode(uint8_t en)
{
uint8_t data;
flash_n25q_write_enable(1);
data = flash_n25q_read_enhanced_volatile_conf_reg();
if (en) {
data &= ~(1 << 7);
data |= 1 << 6;
} else {
data |= 0x3 << 6;
}
flash_n25q_write_enhanced_volatile_conf_reg(data);
flash_n25q_write_enable(0);
}
// 设置n25q dummy cycles
void flash_n25q_set_dummy_clock_cycles(uint8_t num)
{
uint8_t data;
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);
}
void flash_n25q_quad_fast_read(uint32_t addr, uint8_t data[], uint32_t len)
{
uint8_t tran_addr[3];
uint8_t cmd, i;
cmd = CMD_4_4_4_FAST_READ;
tran_addr[0] = (addr >> 16) & 0xff;
tran_addr[1] = (addr >> 8) & 0xff;
tran_addr[2] = (addr >> 0) & 0xff;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_write_bytes(tran_addr, 3);
for (i = 0; i < DUMMY_CNT_4_4_4; i++)
spi0_master_read_bytes(data, 1);
spi0_reset_rxfifo();
spi0_master_read_bytes(data, len);
spi0_set_ss_level(1);
}
// 标准SPI模式读flash ID
n25q_id_t flash_n25q_read_id()
{
n25q_id_t id;
uint8_t cmd;
uint8_t data[3];
cmd = CMD_READ_ID;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_read_bytes(data, 3);
spi0_set_ss_level(1);
id.manf_id = data[0];
id.mem_type = data[1];
id.mem_cap = data[2];
return id;
}
// DUAL/QUAD SPI模式读flash ID
n25q_id_t flash_n25q_multi_io_read_id()
{
n25q_id_t id;
uint8_t cmd;
uint8_t data[3];
cmd = CMD_MULTI_IO_READ_ID;
spi0_set_ss_level(0);
spi0_master_write_bytes(&cmd, 1);
spi0_master_read_bytes(data, 3);
spi0_set_ss_level(1);
id.manf_id = data[0];
id.mem_type = data[1];
id.mem_cap = data[2];
return id;
}

View File

@ -0,0 +1,64 @@
#ifndef _FLASH_N25Q_H_
#define _FLASH_N25Q_H_
#define N25Q_PAGE_SIZE (256)
#define N25Q_PAGE_TO_ADDR(page) (page << 8)
#define N25Q_SUBSECTOR_TO_ADDR(subsector) (subsector << 12)
#define N25Q_SECTOR_TO_ADDR(sector) (sector << 16)
#define CMD_WRITE_STATUS_REG (0x01)
#define CMD_PAGE_PROGRAM (0x02)
#define CMD_READ (0x03)
#define CMD_FAST_READ (0x0b)
#define CMD_QUAD_OUTPUT_FAST_READ (0x6b)
#define CMD_4_4_4_FAST_READ (0xeb)
#define CMD_WRITE_DISABLE (0x04)
#define CMD_READ_STATUS_REG (0x05)
#define CMD_WRITE_ENABLE (0x06)
#define CMD_SUBSECTOR_ERASE (0x20)
#define CMD_CLEAR_FLAG_STATUS_REG (0x50)
#define CMD_READ_FLAG_STATUS_REG (0x70)
#define CMD_BULK_ERASE (0xC7)
#define CMD_SECTOR_ERASE (0xD8)
#define CMD_WRITE_LOCK_REG (0xE5)
#define CMD_READ_LOCK_REG (0xE8)
#define CMD_READ_ID (0x9F)
#define CMD_MULTI_IO_READ_ID (0xAF)
#define CMD_WRITE_ENHANCED_VOL_CONF_REG (0x61)
#define CMD_READ_ENHANCED_VOL_CONF_REG (0x65)
#define CMD_READ_VOL_CONF_REG (0x85)
#define CMD_WRITE_VOL_CONF_REG (0x81)
#define CMD_READ_NONVOL_CONF_REG (0xB5)
#define DUMMY_CNT_4_4_4 (0x7)
typedef struct {
uint8_t manf_id;
uint8_t mem_type;
uint8_t mem_cap;
} n25q_id_t;
void flash_n25q_init(uint16_t clk_div);
n25q_id_t flash_n25q_read_id();
n25q_id_t flash_n25q_multi_io_read_id();
void flash_n25q_write_enable(uint8_t en);
uint8_t flash_n25q_read_reg(uint8_t cmd);
void flash_n25q_write_reg(uint8_t cmd, uint8_t data);
uint8_t flash_n25q_read_status_reg();
uint8_t flash_n25q_is_busy();
void flash_n25q_read_data(uint8_t data[], uint32_t len, uint32_t addr);
void flash_n25q_subsector_erase(uint32_t subsector);
void flash_n25q_sector_erase(uint32_t sector);
void flash_n25q_page_program(uint8_t data[], uint32_t len, uint32_t page);
uint8_t flash_n25q_read_enhanced_volatile_conf_reg();
void flash_n25q_write_enhanced_volatile_conf_reg(uint8_t data);
void flash_n25q_enable_quad_mode(uint8_t en);
void flash_n25q_set_dummy_clock_cycles(uint8_t num);
void flash_n25q_quad_fast_read(uint32_t addr, uint8_t data[], uint32_t len);
uint8_t flash_n25q_read_nonvolatile_conf_reg();
#endif

View File

@ -0,0 +1,88 @@
#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 "flash_n25q.h"
#define BUFFER_SIZE (64)
uint8_t program_data[BUFFER_SIZE];
uint8_t read_data[BUFFER_SIZE];
int main()
{
uint16_t i;
n25q_id_t id;
pinmux_set_io0_func(IO0_UART0_TX);
pinmux_set_io3_func(IO3_UART0_RX);
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);
uart0_init(uart0_putc);
flash_n25q_init(5);
xprintf("read ID through standard SPI mode\n");
id = flash_n25q_read_id();
xprintf("manf id = 0x%2x\n", id.manf_id);
xprintf("mem type = 0x%2x\n", id.mem_type);
xprintf("mem cap = 0x%2x\n", id.mem_cap);
// 初始化要编程的数据
for (i = 0; i < BUFFER_SIZE; i++)
program_data[i] = i;
xprintf("start erase subsector...\n");
// 擦除第0个子扇区
flash_n25q_subsector_erase(0x00);
xprintf("start program page...\n");
xprintf("program data: \n");
// 打印读出来的数据
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", program_data[i]);
// 编程第1页
flash_n25q_page_program(program_data, BUFFER_SIZE, 0x01);
xprintf("start read page...\n");
// 读第1页
flash_n25q_read_data(read_data, BUFFER_SIZE, N25Q_PAGE_TO_ADDR(1));
xprintf("read data: \n");
// 打印读出来的数据
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", read_data[i]);
// 使能N25Q QSPI模式
flash_n25q_enable_quad_mode(1);
// 使能SPI控制器QSPI模式
spi0_set_spi_mode(SPI_MODE_QUAD);
xprintf("read ID through QUAD SPI mode\n");
id = flash_n25q_multi_io_read_id();
xprintf("manf id = 0x%2x\n", id.manf_id);
xprintf("mem type = 0x%2x\n", id.mem_type);
xprintf("mem cap = 0x%2x\n", id.mem_cap);
// 失能N25Q QSPI模式
flash_n25q_enable_quad_mode(0);
/*
flash_n25q_set_dummy_clock_cycles(DUMMY_CNT_4_4_4 << 1);
flash_n25q_enable_quad_mode(1);
spi0_set_spi_mode(SPI_MODE_QUAD);
flash_n25q_quad_fast_read(N25Q_PAGE_TO_ADDR(1), read_data, BUFFER_SIZE);
xprintf("fast read data: \n");
for (i = 0; i < BUFFER_SIZE; i++)
xprintf("0x%x\n", read_data[i]);
flash_n25q_enable_quad_mode(0);
*/
while (1);
}