设计说明
源码说明
相关模块 | 源码路径 |
---|---|
SPI Driver framework | kernel/rt-thread/components/drivers/spi |
Driver | bsp/artinchip/drv/qspi |
HAL | bsp/artinchip/hal/qspi |
模块架构
RT-Thread 透过其定义的 QSPI/SPI 驱动框架,向上提供了 QSPI/SPI 接口,并且通过这一层接口支持各种应用,包括 SPI NAND, SPI NOR。
ArtInChip 提供了 QSPI HAL 层,并且实现了对接 RT-Thread 的驱动层。由于 QSPI 传输需要使用 DMA,因此 DMA HAL 是一个相关模块。
HAL 与 DRV
ArtInChip 的 QSPI 驱动按照 HAL 层 + Driver 层的结构进行设计,其中 HAL 层为硬件抽象层,提供系统无关的硬件驱动实现; 在 HAL 层之上,可根据不同 RTOS 的驱动框架,实现对应的 QSPI DRV 层进行对接。
QSPI HAL 的特点:1.无状态
2.支持 sync、async(irq) 模式
3.支持 DMA、非 DMA 模式
QSPI HAL 相关的设备操作都需要通过 Handle 的方式进行。 由于 HAL 其内部无状态,不会进行空间分配,因此 Handle 的空间需要外部申请并且传入, 由 HAL 层进行使用。
关键流程
添加 QSPI 总线
在 RT-Thread 板级初始化过程中,会调用 rt_hw_qspi_bus_init() 函数,将板子支持的 QSPI 控制器(总线) 添加到系统中。
INIT_BOARD_EXPORT(rt_hw_qspi_bus_init); // bsp/artinchip/drv/qspi/drv_qspi.c
|-> rt_qspi_bus_register(); // kernel/rt-thread/components/drivers/spi/qspi_core.c
|-> rt_spi_bus_register(); kernel/rt-thread/components/drivers/spi/spi_core.c
|-> rt_spi_bus_device_init(); // kernel/rt-thread/components/drivers/spi/spi_dev.c
|-> rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
2
3
4
5
添加 QSPI 设备
将 QSPI 设备挂载到总线上。
aic_qspi_bus_attach_device("qspi0", "GD25B127D", 0, 4, RT_NULL, RT_NULL); // bsp/artinchip/drv/qspi/drv_qspi.c
|-> rt_spi_bus_attach_device(); // kernel/rt-thread/components/drivers/spi/spi_core.c
|-> rt_spidev_device_init(device, name); // kernel/rt-thread/components/drivers/spi/spi_dev.c
|-> rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
2
3
4
初始化流程
当 QSPI 设备需要使用之前,必须进行初始化配置。
rt_sfud_flash_probe_ex();
|-> rt_qspi_configure(qspi_dev, qspi_cfg); // kernel/rt-thread/components/drivers/spi/qspi_core.c
|-> rt_spi_configure(&device->parent, &cfg->parent); // kernel/rt-thread/components/drivers/spi/spi_core.c
|-> device->bus->ops->configure(device, &device->config);
qspi_configure(device, &device->config); // bsp/artinchip/drv/qspi/drv_qspi.c
|-> hal_qspi_master_init(&qspi->handle, &cfg);
2
3
4
5
6
中断处理流程
QSPI HAL 层提供了中断处理函数,但是是否使用中断模式由 DRV 层决定。 Luban-Lite SDK 中对接 RT-Thread 时,使能了中断处理模式。
首先在初始化时,注册了对应的中断处理函数。
qspi_configure(); // bsp/artinchip/drv/qspi/drv_qspi.c
|-> aicos_request_irq(qspi->irq_num, qspi_irq_handler, 0, NULL, (void *)&qspi->handle);
2
中断发生时,QSPI DRV 层的中断处理函数,调用 HAL 层的中断处理函数进行处理。
qspi_irq_handler(); p/artinchip/drv/qspi/drv_qspi.c
|-> hal_qspi_master_irq_handler(h);
2
数据结构
HAL 层主要数据结构。
struct qspi_master_config {
uint32_t idx;
uint32_t clk_in_hz;
uint32_t clk_id;
bool bit_mode;
bool wire3_en;
bool lsb_en;
bool cs_auto;
uint8_t cs_polarity;
uint8_t cpol;
uint8_t cpha;
};
2
3
4
5
6
7
8
9
10
11
12
struct qspi_master_dma_config {
uint32_t port_id;
uint32_t tx_bus_width;
uint32_t tx_max_burst;
uint32_t rx_bus_width;
uint32_t rx_max_burst;
};
2
3
4
5
6
7
struct qspi_transfer {
uint8_t *tx_data;
uint8_t *rx_data;
uint32_t data_len;
};
2
3
4
5
struct qspi_master_state {
uint32_t idx;
qspi_master_async_cb cb;
void *cb_priv;
uint32_t status;
uint32_t clk_id;
uint32_t bus_hz;
uint32_t bus_width;
struct qspi_master_dma_config dma_cfg;
void *dma_tx;
void *dma_rx;
uint8_t *async_tx; /* Used in Async Non-DMA mode */
uint8_t *async_rx; /* Used in Async Non-DMA mode */
uint32_t async_tx_remain; /* Used in Async Non-DMA mode */
uint32_t async_rx_remain; /* Used in Async Non-DMA mode */
uint32_t work_mode;
uint32_t done_mask;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
接口设计
RT-Thread 中的 QSPI 接口设计,在 RT-Thread 的文档中已经有详细说明。 此处介绍 QSPI HAL 层的接口设计。
hal_qspi_master_init
函数原型 | int hal_qspi_master_init(qspi_master_handle *h, struct qspi_master_config *cfg) |
---|---|
功能说明 | QSPI 控制器的初始化函数 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle struct qspi_master_config *cfg QSPI 控制器的初始化配置参数 |
返回值 | 0: 成功 其他: 失败 |
注意事项 | 初始化时,Handle 的空间由使用者负责分配和释放 |
hal_qspi_master_deinit
函数原型 | int hal_qspi_master_deinit(qspi_master_handle *h) |
---|---|
功能说明 | QSPI 控制器的反初始化函数,在 QSPI 控制器关闭时使用 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle |
返回值 | 0: 成功 其他: 失败 |
注意事项 |
hal_qspi_master_set_cs
函数原型 | int hal_qspi_master_set_cs(qspi_master_handle *h, uint32_t cs_num, bool enable) |
---|---|
功能说明 | 设置 SPI 设备的片选信号 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle bool enable CS 信号是否有效 |
返回值 | 0: 成功 其他: 失败 |
注意事项 |
hal_qspi_master_set_bus_freq
函数原型 | int hal_qspi_master_set_bus_freq(qspi_master_handle *h, uint32_t bus_hz) |
---|---|
功能说明 | 设置 QSPI 控制器的接口总线工作时钟 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle uint32_t bus_hz 接口总线的工作时钟 |
返回值 | 0: 成功 其他: 失败 |
注意事项 | QSPI 控制器的模块输入时钟,在 hal_qspi_master_init() 调用时配置 |
hal_qspi_master_set_bus_width
函数原型 | int hal_qspi_master_set_bus_width(qspi_master_handle *h, uint32_t bus_width) |
---|---|
功能说明 | 设置传输所使用的总线位宽 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle uint32_t bus_width 总线位宽,取值可以为 1、2、4 |
返回值 | 0: 成功 其他: 失败 |
注意事项 |
hal_qspi_master_dma_config
函数原型 | int hal_qspi_master_dma_config(qspi_master_handle *h, struct qspi_master_dma_config *cfg) |
---|---|
功能说明 | 配置和使能 DMA |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle struct qspi_master_dma_config *cfg QSPI 控制器使用的 TX、RX DMA 通道配置 |
返回值 | 0: 成功 其他: 失败 |
注意事项 | 需要使能系统 DMA 进行数据传输,则需要在初始化时调用本 API,否则不使用系统 DMA。 |
hal_qspi_master_register_cb
函数原型 | int hal_qspi_master_register_cb(qspi_master_handle *h, qspi_master_async_cb cb, void *priv) |
---|---|
功能说明 | 注册异步传输的回调函数 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle qspi_master_async_cb cb 回调函数指针 void *priv 回调函数的私有数据 |
返回值 | 0: 成功 其他: 失败 |
注意事项 |
hal_qspi_master_transfer_async
函数原型 | int hal_qspi_master_transfer_async(qspi_master_handle *h, struct qspi_transfer *t); |
---|---|
功能说明 | 异步数据传输接口 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle struct qspi_transfer *t 传输的数据信息 |
返回值 | 0: 成功 其他: 失败 |
注意事项 | 该函数启动硬件传输即返回,具体是否完成,需要检查硬件状态,或者等待回调函数 |
hal_qspi_master_transfer_sync
函数原型 | int hal_qspi_master_transfer_sync(qspi_master_handle *h, struct qspi_transfer *t) |
---|---|
功能说明 | 同步数据传输接口 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle struct qspi_transfer *t 传输的数据信息 |
返回值 | 0: 成功 其他: 失败 |
注意事项 | 该函数为同步函数,阻塞式调用,数据传输完成或者出错才返回。 |
hal_qspi_master_get_status
函数原型 | int hal_qspi_master_get_status(qspi_master_handle *h) |
---|---|
功能说明 | 传输状态读取接口 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle |
返回值 | 0: 传输成功完成 其他: 传输失败,具体错误信息可参考 hal_qspi.h 中的定义 |
注意事项 |
hal_qspi_master_irq_handler
函数原型 | void hal_qspi_master_irq_handler(qspi_master_handle *h) |
---|---|
功能说明 | QSPI 中断处理接口 |
参数定义 | qspi_master_handle *h QSPI 控制器 Handle |
返回值 | 无 |
注意事项 | 使用者需要向系统注册中断,并且在中断回调函数中调用本 API 进行中断处理 |