7.9.5. 设计说明

7.9.5.1. 源码说明

相关模块

源码路径

SPI Driver framework

kernel/rt-thread/components/drivers/spi

Driver

bsp/zx/drv/qspi

HAL

bsp/zx/hal/qspi

7.9.5.2. 模块架构

../../../_images/spi_kernel_arch1.png

图 7.25 ZX-RTT QSPI 框图

RT-Thread 透过其定义的 QSPI/SPI 驱动框架,向上提供了 QSPI/SPI 接口,并且通过这一层接口支持各种应用,包括 SPI NAND, SPI NOR。

ZX 提供了 QSPI HAL 层,并且实现了对接 RT-Thread 的驱动层。由于 QSPI 传输需要使用 DMA,因此 DMA HAL 是一个相关模块。

7.9.5.3. HAL 与 DRV

ZX 的 QSPI 驱动按照 HAL 层 + Driver 层的结构进行设计,其中 HAL 层为硬件抽象层,提供系统无关的硬件驱动实现; 在 HAL 层之上,可根据不同 RTOS 的驱动框架,实现对应的 QSPI DRV 层进行对接。

../../../_images/spi_hal.png

图 7.26 HAL and DRV

QSPI HAL 的特点:

  1. 无状态

  2. 支持 sync、async(irq) 模式

  3. 支持 DMA、非 DMA 模式

QSPI HAL 相关的设备操作都需要通过 Handle 的方式进行。 由于 HAL 其内部无状态,不会进行空间分配,因此 Handle 的空间需要外部申请并且传入, 由 HAL 层进行使用。

7.9.5.4. 关键流程

7.9.5.4.1. 添加 QSPI 总线

在 RT-Thread 板级初始化过程中,会调用 rt_hw_qspi_bus_init() 函数,将板子支持的 QSPI 控制器(总线) 添加到系统中。

INIT_BOARD_EXPORT(rt_hw_qspi_bus_init); // bsp/zx/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);

7.9.5.4.2. 添加 QSPI 设备

将 QSPI 设备挂载到总线上。

aic_qspi_bus_attach_device("qspi0", "GD25B127D", 0, 4, RT_NULL, RT_NULL); // bsp/zx/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);

7.9.5.4.3. 初始化流程

当 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/zx/drv/qspi/drv_qspi.c
            |-> hal_qspi_master_init(&qspi->handle, &cfg);

7.9.5.4.4. 中断处理流程

QSPI HAL 层提供了中断处理函数,但是是否使用中断模式由 DRV 层决定。 ZX-RTT SDK 中对接 RT-Thread 时,使能了中断处理模式。

首先在初始化时,注册了对应的中断处理函数。

qspi_configure(); // bsp/zx/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/zx/drv/qspi/drv_qspi.c
|-> hal_qspi_master_irq_handler(h);

7.9.5.5. 数据结构

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

7.9.5.6. 接口设计

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

7.9.5.6.1. 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 的空间由使用者负责分配和释放

7.9.5.6.2. hal_qspi_master_deinit

函数原型

int hal_qspi_master_deinit(qspi_master_handle *h)

功能说明

QSPI 控制器的反初始化函数,在 QSPI 控制器关闭时使用

参数定义

qspi_master_handle *h
QSPI 控制器 Handle

返回值

0: 成功
其他: 失败

注意事项

7.9.5.6.3. 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: 成功
其他: 失败

注意事项

7.9.5.6.4. 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() 调用时配置

7.9.5.6.5. 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.9.5.6.6. 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。

7.9.5.6.7. 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: 成功
其他: 失败

注意事项

7.9.5.6.8. 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: 成功
其他: 失败

注意事项

该函数启动硬件传输即返回,具体是否完成,需要检查硬件状态,或者等待回调函数

7.9.5.6.9. 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: 成功
其他: 失败

注意事项

该函数为同步函数,阻塞式调用,数据传输完成或者出错才返回。

7.9.5.6.10. 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 中的定义

注意事项

7.9.5.6.11. hal_qspi_master_irq_handler

函数原型

void hal_qspi_master_irq_handler(qspi_master_handle *h)

功能说明

QSPI 中断处理接口

参数定义

qspi_master_handle *h
QSPI 控制器 Handle

返回值

注意事项

使用者需要向系统注册中断,并且在中断回调函数中调用本 API 进行中断处理