跳转至

SPI 主机应用开发入门指南

本文档以 spi_master.c 为例,带你在 HiDiTing V100 开发板上快速跑通第一个 SPI 主机通信应用,并了解如何基于它构建自己的应用。


SPI 主机驱动背景知识

SPI 工作原理

SPI(Serial Peripheral Interface)是一种高速、全双工、同步的串行通信总线,主机通过以下信号线与从设备通信:

信号线 说明 方向
SCLK 时钟信号,由主机产生 主机→从机
MOSI 主机输出,从机输入 主机→从机
MISO 主机输入,从机输出 从机→主机
CS 片选信号(低有效) 主机→从机

SPI主机驱动主要实现以下功能:

  • 初始化SPI控制器硬件
  • 配置通信参数(时钟频率、模式等)
  • 管理数据传输过程
  • 处理错误和中断

通信模式配置

SPI通信有四种工作模式,由时钟极性(CPOL)和时钟相位(CPHA)决定:

模式 CPOL CPHA 说明
0 0 0 时钟空闲低电平,数据在第一个边沿采样
1 0 1 时钟空闲低电平,数据在第二个边沿采样
2 1 0 时钟空闲高电平,数据在第一个边沿采样
3 1 1 时钟空闲高电平,数据在第二个边沿采样

操作流程

  • SPI 初始化:通过 uapi_spi_init() 对 SPI 进行初始化。
  • 读数据:使用 uapi_spi_master_read() 读取数据。
  • 写数据:使用 uapi_spi_master_write() 写入数据。
  • 全双工读写数据:使用 uapi_spi_master_writeread() 同时读写数据
  • 去初始化:通过 uapi_spi_deinit() 释放资源。

数据传输机制

基础传输特性

  • 同步传输:完全由主设备时钟控制,决定通信速率和时序。从机必须严格遵循主机时钟边沿采样数据。
  • 全双工:可同时收发数据,主机通过MOSI发送数据的同时,通过MISO接收从机返回的数据(同一时钟周期内完成)。
  • 从动模式:主机通过拉低SS/CS片选信号启动通信,无需等待从设备请求(从机无法主动触发通信)。

数据传输模式对比

模式 触发条件 优点 缺点 适用场景
轮询 主动查询 实现简单 CPU占用高 低速简单应用
中断 CS信号/数据就绪 实时响应 需处理中断嵌套 中等速率常规应用
DMA 硬件自动触发 解放CPU 配置复杂 高速大数据量传输

快速跑通 SPI_master Demo

功能说明

SPI master Demo 支持通过 AT 指令进行 SPI_master 的配置和传输功能,相应的 AT 指令如下:

AT+SPIMASTER=50

AT指令参数说明

参数 默认值 说明 范围
loop_count 50 需要执行数据传输的次数 1 - 250

编译

完成一站式 CLI 环境配置后执行:

# 编译固件,编译生成的固件从 output/3322/fwpkggt 中获取 diting-community.fwpkg
fbb set-target pack_diting_community
fbb build

构建成功后,使用一站式 CLI 烧写固件并打开 UART2 串口监视器。以下为 Windows USB DFU 示例;将 COM3 替换为实际日志串口,其他平台和串口烧写参数参见一站式 CLI 开发环境使用指南

fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000

使用方式

在使用该 demo 之前要正确的连接 SPI 的主机和 SPI 从机 SPI接线图如下所示:

在使用该 demo 之前要正确的连接 SPI 的主机和 SPI 从机 SPI接线图如下所示

连接说明:

  • MOSI(主出从入):
  • 主设备的MOSI → 从设备的MOSI(数据由主设备发送到从设备)
  • MISO(主入从出):
  • 主设备的MISO ← 从设备的MISO(数据由从设备返回主设备)
  • SCLK(时钟线):
  • 主设备的SCLK → 从设备的SCLK(主设备控制时钟同步)
  • SS/CS(片选线):
  • 主设备的CS → 从设备的CS(低电平时激活从设备)
  • 若从设备无需片选,可接地(始终激活);多从机时需独立CS线。

烧录固件并启动设备

通过串口发送 AT 命令,使用方法参照如下:

通过串口发送 AT 命令,使用方法参照如下

# SPI_master 设置使用示例:启动 SPI demo开始进行 SPI 的配置、初始化以及验证数据传输功能
AT+SPIMASTER=50

注意: 先启动从设备,后启动主设备, 如果顺序相反大概率会导致主设备系统复位。

预期结果

SPI 主设备配置结果(AT+SPIMASTER)

SPI 主设备配置结果(AT+SPIMASTER)

SPI 数据传输结果

SPI 数据传输结果

文件结构与代码走读

文件职责

文件 作用
samples/native_samples/spi/CMakeLists.txt 将 SPI Master、Slave 源文件构建为同一 Sample 组件。
samples/native_samples/spi/spi_master.h 定义主机串口测试参数和命令表。
samples/native_samples/spi/spi_master.c 实现主机引脚、总线属性、DMA 和收发流程。
samples/native_samples/spi/README.md 给出主从连接、命令和预期数据。

核心数据与常量

名称 作用 开发注意事项
spi_attr_t 配置主从角色、总线时钟、工作频率、CPOL、CPHA、帧格式和帧长。 主从两端的时序、帧格式和帧长必须一致。
spi_extra_attr_t 配置 DMA 选择及 QSPI 扩展字段。 普通 SPI 场景仍应显式初始化未使用字段,避免未定义值。
spi_xfer_data_t 描述收发缓冲区和字节数。 缓冲区生命周期必须覆盖同步传输调用。
spi_dma_config_t 配置 DMA 宽度、突发长度和优先级。 DMA 宽度应与帧宽、地址对齐和缓冲区长度匹配。
CONFIG_SPI_MASTER_BUS_ID / CONFIG_SPI_TRANSFER_LEN 选择总线并限定 Sample 收发长度。 改动前核对板级引脚和从设备协议。

spi_master_task_args_t 仅承载 AT 测试的循环次数,自定义应用可直接使用业务配置,不需要保留 AT 参数结构。

核心业务流程

  1. 配置 CLK、MOSI、MISO、CS 引脚复用,填写主机模式的 spi_attr_tspi_extra_attr_t
  2. 清理可能的旧状态后调用 uapi_spi_init();启用 DMA 时使用与数据宽度匹配的 spi_dma_config_t
  3. 填写 spi_xfer_data_t,调用主机同步收发接口;按返回值和实际协议校验接收数据,而不是只打印缓冲区。
  4. 完成全部传输后关闭 DMA 并调用 uapi_spi_deinit();超时和传输失败也进入同一清理路径。

AT 命令只负责输入循环次数并触发此流程。完整引脚配置、属性值和错误处理见 Sample 源文件;下一节保留面向应用开发的 app_run 入口,不重复 AT 实现。

基于 SPI_master Demo 开发自己的应用

上面的demo是使用AT指令触发运行,HiDiTing还支持app_run方式触发应用在系统启动时自动运行,
以下示例将以app_run的方式开发一个开发者自己的应用

  • app_run(func) 是HiDiTing中应用层注册应用函数的宏,基于 GCC 编译器属性和自定义段区(section)自动注册来实现集中调用应用函数,
    系统启动时会自动遍历所有用 app_run 注册过的函数并执行,无需在系统 main 函数里逐个调用函数。

代码清单

新建一个 SPI 主设备应用(以 my_spi_master 为例)通常需要以下改动:

  • 新建 my_spi_master.c 源文件
  • 新建 my_spi_master.h 头文件
  • 新建 CMakeLists.txt 源文件
  • my_spi_master.c 中实现 SPI master 操作函数
  • my_spi_master.h 中定义宏常量和函数声明
  • CMakeLists.txt 源文件编译规则

my_spi_master文件结构:

samples/native_samples/my_spi_demo/
├── my_spi_master.c
├── my_spi_master.h
├── my_spi_slave.c
├── my_spi_slave.h
└── CMakeLists.txt

CMakeLists.txt 示例

# 在新建的 CMakeLists.txt 中添加应用的源文件
set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/my_spi_master.c
    ${CMAKE_CURRENT_SOURCE_DIR}/my_spi_slave.c
)

set(PUBLIC_HEADER
    ${CMAKE_CURRENT_SOURCE_DIR}
)

set(PRIVATE_HEADER
    ${ROOT_DIR}/src/include/driver
)

set(PUBLIC_DEFINES
    MY_SPI_MASTER_DEMO_ENABLE
    MY_SPI_SLAVE_DEMO_ENABLE
)

build_component()

关键代码片段

#include "spi.h"
#include "app_init.h"

void my_spi_master_entry(void)
{
    osal_printk("my_spi_app start\n");

    // step1:参数配置
    spi_attr_t config = { 0 };
    config.is_slave = false;
    config.bus_clk = 1000000; // 1 MHz
    config.freq_mhz = 1;
    config.clk_polarity = 0;
    config.clk_phase = 0;
    config.frame_format = 0;
    config.frame_size = 0x1f;

    // step2:初始化
    uapi_spi_init(MY_SPI_BUS_ID, &config, NULL);

    // step3:数据传输缓冲区配置
    uint8_t tx_data[] = {0x01, 0x02, 0x03};
    uint8_t rx_data[3] = {0};
    spi_xfer_data_t data = {
        .tx_buff = tx_data,
        .tx_bytes = sizeof(tx_data),
        .rx_buff = rx_data,
        .rx_bytes = sizeof(rx_data),
    };

    // step4:数据传输
    if (uapi_spi_master_writeread(MY_SPI_BUS_ID, &data, 0xFFFFFFFF) == ERRCODE_SUCC) {
        osal_printk("SPI transaction success\n");
        for (int i = 0; i < sizeof(rx_data); i++) {
            osal_printk("rx_data[%d] = %x\n", i, rx_data[i]);
        }
    }

    osal_printk("my_spi_master_app done\n");
}

app_run(my_spi_master_entry);

测试验证

完成一站式 CLI 环境配置后执行:

# 编译固件,编译生成的固件从 output/3322/fwpkggt 中获取 diting-community.fwpkg
fbb set-target pack_diting_community
fbb build
1. 烧录固件并启动设备 2. 通过串口观察输出日志:

新demo完成后,逐项验收:

  • 设备启动后串口输出 my_spi_master_app start
  • 能够正确发送和接收数据
  • 发送的数据内容为 0x01 到 0x03
  • 接收到的数据正确显示

app_run运行配置

app_run应用默认是关闭的,如需启用此应用,需用户手动在acore.prelds文件中添加 KEEP (*(SORT(.zinitcall.app_run*.init)))
具体参考示意图如下:

apprun运行配置

acore.prelds

注意事项

引脚配置注意事项:

  • 确保选择的 DI、DO、CLK 和 CS 引脚正确连接
  • 引脚模式需要与硬件匹配

时钟频率注意事项:

  • 主从设备必须使用相同的时钟频率
  • 常见频率:1MHz、2MHz、5MHz、16MHz

中断模式注意事项:

  • 中断模式需要正确注册回调函数
  • 中断处理函数应尽量简短

QSPI 模式注意事项:

  • QSPI 模式需要额外配置 D2 和 D3 引脚
  • 需要确保硬件支持 QSPI 模式

资源说明:

  • 使用 DMA 模式需要额外配置 DMA 相关参数

常见错误

错误现象 原因 解决方法
undefined reference to 'uapi_spi_init' 未链接 SPI 驱动库 检查 CMakeLists.txt 中是否正确添加了源文件
undefined reference to 'uapi_at_cmd_table_register' 未链接 AT 命令库 检查 CMakeLists.txt 中是否正确添加了 AT 相关头文件路径
编译报 at_ret_t 未定义 未包含 at.h 头文件 添加 #include "at.h"
串口无输出 AT 命令未注册 确认调用了 at_diting_spi_master_example_cmd_register() 或 AT参数指令和参数是否正确
SPI 通信失败 引脚配置错误或时钟频率不匹配 检查引脚配置和时钟频率设置
DMA 模式报错 DMA 配置错误 检查 DMA 相关配置参数