Edit online

设计说明

3 Dec 2024
Read time: 6 minute(s)

源码说明

1.
相关模块 源码路径
SPI Driver framework kernel/rt-thread/components/drivers/spi
Driver bsp/artinchip/drv/qspi
HAL bsp/artinchip/hal/qspi

模块架构


spi_kernel_arch

1. Luban-Lite 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 层进行对接。


spi_hal

2. HAL and 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);
  • 添加 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);
  • 初始化流程
    当 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);
  • 中断处理流程

    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);

    中断发生时,QSPI DRV 层的中断处理函数,调用 HAL 层的中断处理函数进行处理。

    qspi_irq_handler(); p/artinchip/drv/qspi/drv_qspi.c
    |-> hal_qspi_master_irq_handler(h);

数据结构

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;
};
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;
};
struct qspi_transfer {
    uint8_t *tx_data;
    uint8_t *rx_data;
    uint32_t data_len;
};
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;
};

接口设计

RT-Thread 中的 QSPI 接口设计,在 RT-Thread 的文档中已经有详细说明。 此处介绍 QSPI HAL 层的接口设计。

2. 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 的空间由使用者负责分配和释放
3. hal_qspi_master_deinit
函数原型 int hal_qspi_master_deinit(qspi_master_handle *h)
功能说明 QSPI 控制器的反初始化函数,在 QSPI 控制器关闭时使用
参数定义
qspi_master_handle *h
QSPI 控制器 Handle
返回值
0: 成功
其他: 失败
注意事项 -
4. 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: 成功
其他: 失败
注意事项 -
5. 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() 调用时配置
6. 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: 成功
其他: 失败
注意事项 -
7. 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。
8. 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: 成功
其他: 失败
注意事项 -
9. 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: 成功
其他: 失败
注意事项 该函数启动硬件传输即返回,具体是否完成,需要检查硬件状态,或者等待回调函数
10. 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: 成功
其他: 失败
注意事项 该函数为同步函数,阻塞式调用,数据传输完成或者出错才返回。
11. 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 中的定义
注意事项 -
12. hal_qspi_master_irq_handler
函数原型 void hal_qspi_master_irq_handler(qspi_master_handle *h)
功能说明 QSPI 中断处理接口
参数定义
qspi_master_handle *h
QSPI 控制器 Handle
返回值
注意事项 使用者需要向系统注册中断,并且在中断回调函数中调用本 API 进行中断处理