QSPI LCD 驱动

基于 lisa_device 框架的 QSPI LCD 设备驱动,为 ARCS 平台提供统一的 QSPI 接口,用于驱动 LCD 显示屏等外设。

功能特性

  • 设备支持: QSPI LCD 控制器(qspilcd0)

  • 传输模式: 支持 PIO(轮询)和 DMA(直接内存访问)两种传输方式

  • 数据线模式: 支持单线(Single)、双线(Dual)和四线(Quad)传输

  • CS 控制: 支持硬件自动 CS 控制,也支持通过 GPIO 进行手动 CS 控制

  • 灵活配置: 提供 control 接口配置总线速度、时钟模式、位序等参数

  • 线程安全: 内部使用互斥锁保护,支持多线程并发访问

配置选项

prj.conf 中启用驱动:

CONFIG_LISA_QSPILCD=y

# 配置 QSPI 使用的 GPDMA 通道号
CONFIG_LISA_QSPILCD_GPDMA_CH=0

API 接口

数据传输

int lisa_qspilcd_transfer(lisa_device_t *dev, const lisa_qspilcd_xfer_t *xfer);
int lisa_qspilcd_wait_done(lisa_device_t *dev, uint32_t timeout_ms);

模式配置

int lisa_qspilcd_set_lane(lisa_device_t *dev, lisa_qspilcd_lane_num_t lane);
int lisa_qspilcd_set_data_bits(lisa_device_t *dev, uint8_t data_bits);

CS 控制

int lisa_qspilcd_cs_configure(lisa_device_t *dev, lisa_device_t *gpio_dev, uint32_t cs_pin);
void lisa_qspilcd_cs_control(lisa_device_t *dev, bool level);

高级控制

int lisa_qspilcd_control(lisa_device_t *dev, uint32_t control, uint32_t arg);

控制码组合说明

control 参数是一个 32 位控制码,由多个字段按位或组合而成:

uint32_t control = LISA_QSPILCD_TXIO_PIO |      /* TX I/O 模式 */
                   LISA_QSPILCD_CPOL0_CPHA0 |   /* 时钟极性和相位 */
                   LISA_QSPILCD_MSB_LSB |       /* 位序 */
                   LISA_QSPILCD_MODE_MASTER |   /* 主从模式 */
                   LISA_QSPILCD_DATA_BITS(8);   /* 数据位宽 */

lisa_qspilcd_control(qspi, control, 50*1000*1000);  /* arg 为总线速度 */

控制码字段定义

字段

位域

宏定义

说明

主从模式

[3:0]

LISA_QSPILCD_MODE_MASTER

主机模式

LISA_QSPILCD_MODE_SLAVE

从机模式

TX I/O 模式

[5:4]

LISA_QSPILCD_TXIO_PIO

CPU 轮询发送

LISA_QSPILCD_TXIO_DMA

DMA 发送

LISA_QSPILCD_TXIO_AUTO

自动选择

RX I/O 模式

[7:6]

LISA_QSPILCD_RXIO_PIO

CPU 轮询接收

LISA_QSPILCD_RXIO_DMA

DMA 接收

LISA_QSPILCD_RXIO_AUTO

自动选择

时钟极性/相位

[11:8]

LISA_QSPILCD_CPOL0_CPHA0

Mode 0

LISA_QSPILCD_CPOL0_CPHA1

Mode 1

LISA_QSPILCD_CPOL1_CPHA0

Mode 2

LISA_QSPILCD_CPOL1_CPHA1

Mode 3

数据位宽

[17:12]

LISA_QSPILCD_DATA_BITS(n)

n = 1~32

位序

[19:18]

LISA_QSPILCD_MSB_LSB

高位优先

LISA_QSPILCD_LSB_MSB

低位优先

命令阶段

[20]

LISA_QSPILCD_CMD_PHASE_ENABLE

启用命令阶段

LISA_QSPILCD_CMD_PHASE_DISABLE

禁用命令阶段

地址阶段

[21]

LISA_QSPILCD_ADDR_PHASE_ENABLE

启用地址阶段

LISA_QSPILCD_ADDR_PHASE_DISABLE

禁用地址阶段

地址长度

[23:22]

LISA_QSPILCD_ADDR_PHASE_1BYTES

1 字节地址

LISA_QSPILCD_ADDR_PHASE_2BYTES

2 字节地址

LISA_QSPILCD_ADDR_PHASE_3BYTES

3 字节地址

LISA_QSPILCD_ADDR_PHASE_4BYTES

4 字节地址

独占操作

[27:24]

LISA_QSPILCD_SET_BUS_SPEED

设置总线速度

LISA_QSPILCD_GET_BUS_SPEED

获取总线速度

LISA_QSPILCD_ABORT_TRANSFER

中止传输

LISA_QSPILCD_RESET_FIFO

复位 FIFO

DMA 控制

[29:28]

LISA_QSPILCD_DMA_ENABLE

启用 DMA

LISA_QSPILCD_DMA_DISABLE

禁用 DMA

参数说明

  • dev: QSPI LCD 设备句柄

  • control: 控制码,由上述宏按位或组合

  • arg: 附加参数,含义取决于控制码:

    • 设置总线速度时为频率值(Hz)

    • 复位 FIFO 时为 FIFO 类型(1=TX, 2=RX, 3=Both)

    • 其他情况通常为 0

返回值

  • LISA_DEVICE_OK: 操作成功

  • LISA_DEVICE_ERR_INVALID: 参数无效

  • LISA_DEVICE_ERR_IO: 底层操作失败

使用示例

1. 基础 PIO 传输

#include "lisa_qspilcd.h"

lisa_device_t *qspi = lisa_device_get("qspilcd0");
if (!lisa_device_ready(qspi)) {
    return -1;
}

// 准备传输数据
const uint8_t command[] = {0x2A}; // 示例命令
const uint8_t data[] = {0x00, 0x01, 0x02, 0x03}; // 示例数据

lisa_qspilcd_xfer_t xfer_cmd = {
    .buf = command,
    .size_bytes = sizeof(command),
    .lane = LISA_QSPILCD_LANE_SINGLE,
    .data_bits = 8,
    .use_dma = false, // 使用 PIO
};

lisa_qspilcd_xfer_t xfer_data = {
    .buf = data,
    .size_bytes = sizeof(data),
    .lane = LISA_QSPILCD_LANE_QUAD, // 使用四线传输数据
    .data_bits = 8,
    .use_dma = false, // 使用 PIO
};

// 发送命令 (单线)
lisa_qspilcd_transfer(qspi, &xfer_cmd);
lisa_qspilcd_wait_done(qspi, 1000);

// 发送数据 (四线)
lisa_qspilcd_transfer(qspi, &xfer_data);
lisa_qspilcd_wait_done(qspi, 1000);

2. DMA 传输

#include "lisa_qspilcd.h"

// ... 获取设备 ...

// 大块数据适合 DMA 传输
static uint8_t frame_buffer[1024];

lisa_qspilcd_xfer_t dma_xfer = {
    .buf = frame_buffer,
    .size_bytes = sizeof(frame_buffer),
    .lane = LISA_QSPILCD_LANE_QUAD,
    .data_bits = 8,
    .use_dma = true, // 启用 DMA
};

// 启动 DMA 传输
int ret = lisa_qspilcd_transfer(qspi, &dma_xfer);
if (ret == LISA_DEVICE_OK) {
    // 等待 DMA 完成,信号量机制,低功耗
    ret = lisa_qspilcd_wait_done(qspi, 5000);
    if (ret == LISA_DEVICE_OK) {
        printf("DMA transfer complete\n");
    }
}

3. 手动 CS 控制

#include "lisa_qspilcd.h"
#include "lisa_gpio.h"

// ... 获取 qspi 设备 ...
lisa_device_t *gpio = lisa_device_get("gpio0");
const uint32_t cs_pin = 20; // 假设 CS 在 PA20

// 1. 关联 GPIO 和 CS 引脚
lisa_qspilcd_cs_configure(qspi, gpio, cs_pin);

// 2. 手动拉低 CS
lisa_qspilcd_cs_control(qspi, false);

// 3. 执行一系列传输
lisa_qspilcd_transfer(qspi, &xfer1);
lisa_qspilcd_wait_done(qspi, 1000);

lisa_qspilcd_transfer(qspi, &xfer2);
lisa_qspilcd_wait_done(qspi, 1000);

// 4. 手动拉高 CS
lisa_qspilcd_cs_control(qspi, true);

硬件配置

引脚复用配置

QSPI 驱动在初始化时会自动调用板型目录中定义的 lisa_qspilcd_pinmux() 函数,用于配置 QSPI 的 CLK, CS, IO0-IO3 引脚复用。

  • 定义: boards/<板型名>/pinmux.c 中实现 lisa_qspilcd_pinmux() 函数。

  • 声明: boards/<板型名>/pinmux.h 中声明 void lisa_qspilcd_pinmux()

示例 (参考 boards/arcs_evb/pinmux.c):

void lisa_qspilcd_pinmux()
{
    // 配置 PA18, PA19, PA20, PA21, PA22, PA23 为 QSPI 功能
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 18, 12); // CLK
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 19, 12); // CS
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 20, 12); // IO0
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 21, 12); // IO1
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 22, 12); // IO2
    IOMuxManager_PinConfigure(CSK_IOMUX_PAD_A, 23, 12); // IO3
}

注意: 功能码需根据芯片手册确定。

参数说明

数据线模式

模式

枚举值

说明

单线

LISA_QSPILCD_LANE_SINGLE

使用 IO0 进行数据传输

双线

LISA_QSPILCD_LANE_DUAL

使用 IO0, IO1 进行数据传输

四线

LISA_QSPILCD_LANE_QUAD

使用 IO0, IO1, IO2, IO3 进行数据传输

control 接口常用控制码

控制码

参数 arg

说明

LISA_QSPILCD_SET_BUS_SPEED

uint32_t 频率 (Hz)

设置 QSPI 总线时钟频率

LISA_QSPILCD_GET_BUS_SPEED

uint32_t* 指针

获取当前总线频率

LISA_QSPILCD_DMA_ENABLE

0

启用 DMA 模式

LISA_QSPILCD_DMA_DISABLE

0

禁用 DMA 模式 (切换到 PIO)

LISA_QSPILCD_CPOL0_CPHA0CPOL1_CPHA1

0

设置 SPI 时钟极性与相位

LISA_QSPILCD_MSB_LSB / LSB_MSB

0

设置位序

LISA_QSPILCD_RESET_FIFO

3 (TX & RX)

复位硬件 FIFO

返回值说明

返回值

说明

LISA_DEVICE_OK (0)

操作成功

LISA_DEVICE_ERR_INVALID

参数无效(如 xfer 为空)

LISA_DEVICE_ERR_NOT_READY

设备未初始化

LISA_DEVICE_ERR_IO

底层 HAL 操作失败

LISA_DEVICE_ERR_TIMEOUT

等待传输完成超时

LISA_DEVICE_ERR_NOT_SUPPORT

不支持的操作

注意事项

  1. 引脚配置: 使用 QSPI 前必须通过板型 pinmux 配置将对应引脚切换为 QSPI 功能

  2. DMA 通道: 需通过 Kconfig 正确配置 GPDMA 通道号,确保没有与其他外设冲突

  3. 传输同步: lisa_qspilcd_transfer() 是异步接口,必须调用 lisa_qspilcd_wait_done() 等待传输完成

  4. CS 管理: 默认使用 QSPI 控制器内置 CS 引脚;如需手动控制,需先调用 lisa_qspilcd_cs_configure() 配置 GPIO

  5. 参数切换: 切换数据线模式或数据位宽应在总线空闲时进行

  6. 线程安全: 驱动 API 内部使用互斥锁保护,可在多线程环境中安全调用

  7. DMA 缓冲区: 使用 DMA 传输时,缓冲区地址需满足 DMA 对齐要求

文件说明

  • lisa_qspilcd.h - 驱动头文件,包含所有 API 和类型定义

  • lisa_qspilcd_arcs.c - ARCS 平台适配实现

  • Kconfig - 配置选项

  • CMakeLists.txt - 构建配置