API GUIDE / SPI Slave / OVERVIEW
G32S10 SPI Slave API 概述
模块概述:本文档描述 G32S10 SPI_SLV 模块当前 SDK 中对外提供的 HAL 层与 LL 层正式接口, 包括公开类型、接口行为、参数约束、返回值约定、寄存器语义、典型使用流程以及当前 实现限制。
1. 文档范围
本文档描述 G32S10 SPI_SLV 模块当前 SDK 中对外提供的 HAL 层与 LL 层正式接口, 包括公开类型、接口行为、参数约束、返回值约定、寄存器语义、典型使用流程以及当前 实现限制。
本文档基于以下文件编写:
code/include/drivers/g32s10/spi_slv/spi_slv_regs.hcode/include/drivers/g32s10/spi_slv/ll_spi_slv.hcode/include/drivers/g32s10/spi_slv/hal_spi_slv.hcode/drivers/g32s10/spi_slv/hal_spi_slv.c
2. 分层关系
| 层级 | 文件 | 职责 |
|---|---|---|
| 寄存器定义 | spi_slv_regs.h | 定义寄存器结构体、实例宏和位域宏 |
| LL 层 | ll_spi_slv.h | 提供寄存器字段级静态内联访问,不维护软件状态 |
| HAL 层头文件 | hal_spi_slv.h | 定义 HAL 公开宏、类型、句柄和函数原型 |
| HAL 层实现 | hal_spi_slv.c | 完成参数检查、模块时钟管理、复位、FIFO、IRQ 和回调处理 |
HAL 面向应用、BSP 和 middleware 使用;LL 面向寄存器级控制、底层适配和调试使用。 通常应优先使用 HAL。直接使用 LL 时,调用方必须自行保证实例、参数、时序和并发访问 合法。
3. 资源模型与公开类型
3.1 模块实例与基地址
当前 HAL/LL 支持两个 SPI_SLV 实例。
| 实例 | 基地址宏 | 基地址 |
|---|---|---|
SPI_SLV0 | SPI_SLV0_IOBASE | 0x100CC000 |
SPI_SLV1 | SPI_SLV1_IOBASE | 0x1000E000 |
spi_slv_regs.h 中提供如下实例宏:
#define SPI_SLV0 ((spi_slv_regs_t *)(uintptr_t)SPI_SLV0_IOBASE) #define SPI_SLV1 ((spi_slv_regs_t *)(uintptr_t)SPI_SLV1_IOBASE)
3.2 硬件能力摘要
| 项目 | 说明 |
|---|---|
| 实例数量 | 2,SPI_SLV0 和 SPI_SLV1 |
| 角色 | SPI 从机,只能响应外部主机提供的 CS 和 SCLK |
| 数据通道 | 单线、双线、四线;实际可用通道还取决于 BSP 引脚复用 |
| 帧位宽 | 4 至 32 bit |
| FIFO 深度 | TX 128 entry,RX 128 entry;每个 entry 通过 32 bit 数据寄存器访问 |
| 传输计数 | RX/TX 各有一个 32 bit 总帧数/剩余帧数寄存器 |
| 中断 | RX/TX 阈值、空/满和 FIFO 错误状态汇总为模块聚合 IRQ |
| DMA | RX_RDFLAG 可产生 RX DMA 请求,TX_WRFLAG 可产生 TX DMA 请求 |
| 环回 | 支持内部环回,但从机仍不能自行产生 CS 和 SCLK |
3.3 状态标志
hal_spi_slv_status_get() 返回由 hal_spi_slv_status_flag_t 组成的逻辑 bitmask。
| 状态 | bit | 说明 |
|---|---|---|
HAL_SPI_SLV_STATUS_TX_READ_FLAG | 0 | TX read flag |
HAL_SPI_SLV_STATUS_TX_WRITE_FLAG | 1 | TX write flag |
HAL_SPI_SLV_STATUS_TX_READ_EMPTY_ERR | 2 | TX FIFO 读空错误 |
HAL_SPI_SLV_STATUS_TX_WRITE_FULL_ERR | 3 | TX FIFO 写满错误 |
HAL_SPI_SLV_STATUS_TX_EMPTY | 4 | TX FIFO 空 |
HAL_SPI_SLV_STATUS_TX_FULL | 5 | TX FIFO 满 |
HAL_SPI_SLV_STATUS_RX_READ_FLAG | 6 | RX read flag |
HAL_SPI_SLV_STATUS_RX_WRITE_FLAG | 7 | RX write flag |
HAL_SPI_SLV_STATUS_RX_READ_EMPTY_ERR | 8 | RX FIFO 读空错误 |
HAL_SPI_SLV_STATUS_RX_WRITE_FULL_ERR | 9 | RX FIFO 写满错误 |
HAL_SPI_SLV_STATUS_RX_EMPTY | 10 | RX FIFO 空 |
HAL_SPI_SLV_STATUS_RX_FULL | 11 | RX FIFO 满 |
HAL_SPI_SLV_STATUS_IRQ | 12 | 模块聚合 IRQ 待处理 |
HAL 状态 bit 与 SSLVCTRL[24:13] 的原始位位置不同。需要寄存器原始位时使用ll_spi_slv_get_raw_status();应用侧应使用 HAL 状态定义。
3.4 HAL 返回值约定
| 返回值 | SPI_SLV HAL 中的典型含义 |
|---|---|
IM_OK | 操作成功 |
IM_ERR_INVALID_PARAM | 句柄、实例、输出指针、枚举、bitmask 或配置范围非法 |
IM_ERR_BUSY | 重复初始化、TX FIFO 已满,或设置传输计数时 RX/TX 已使能 |
IM_ERR_NOT_READY | RX FIFO 为空,或复位所需系统 tick 尚未初始化 |
IM_ERR_TIMEOUT | 等待硬件复位完成超过内部超时 |
IM_ERR_UNSUPPORTED | 寄存器 dump 功能未编译 |
hal_spi_slv_init() 和 hal_spi_slv_deinit() 还会透传 CPM 接口返回的错误码。
4. 典型用法
4.1 轮询式全双工从机准备
以下代码只展示 HAL 调用顺序。BSP 引脚初始化和主机启动应由系统在相应位置完成。
hal_spi_slv_handle_t hspi_slv;
hal_spi_slv_fifo_level_t level;
uint32_t rx_word;
error_code_t ret;
ret = hal_spi_slv_handle_init(&hspi_slv, SPI_SLV1);
if (ret != IM_OK) {
return ret;
}
hspi_slv.init.cpol = HAL_SPI_SLV_CLOCK_POLARITY_LOW;
hspi_slv.init.cpha = HAL_SPI_SLV_CLOCK_PHASE_FIRST_EDGE;
hspi_slv.init.rx_channel = HAL_SPI_SLV_CHANNEL_SINGLE;
hspi_slv.init.tx_channel = HAL_SPI_SLV_CHANNEL_SINGLE;
hspi_slv.init.rx_bitwidth = 8U;
hspi_slv.init.tx_bitwidth = 8U;
ret = hal_spi_slv_init(&hspi_slv);
if (ret != IM_OK) {
return ret;
}
ret = hal_spi_slv_transfer_count_set(&hspi_slv, 64U, 64U);
if (ret != IM_OK) {
goto out_deinit;
}
(void)hal_spi_slv_irq_clear(&hspi_slv);
ret = hal_spi_slv_enable(&hspi_slv, HAL_SPI_SLV_DIRECTION_TX_RX);
if (ret != IM_OK) {
goto out_deinit;
}
/* 在主机开始 CS/SCLK 前,按 TX 可用水位写入待发 frame。 */
ret = hal_spi_slv_fifo_level_get(&hspi_slv, &level);
if ((ret == IM_OK) && (level.tx_available_count != 0U)) {
ret = hal_spi_slv_fifo_write(&hspi_slv, 0x5AU);
}
/* 主机开始传输后,轮询 RX 水位并读取。 */
if (ret == IM_OK) {
ret = hal_spi_slv_fifo_level_get(&hspi_slv, &level);
}
if ((ret == IM_OK) && (level.rx_fill_count != 0U)) {
ret = hal_spi_slv_fifo_read(&hspi_slv, &rx_word);
}
(void)hal_spi_slv_disable(&hspi_slv, HAL_SPI_SLV_DIRECTION_TX_RX);
out_deinit:
(void)hal_spi_slv_deinit(&hspi_slv);
return ret;实际轮询流程应增加超时、循环填充/读取、错误状态检查和完整帧数校验。仓库中的code/examples/hal/spi_slv_hal_example.c 提供 SPI_SLV1 与 SSI1 互收发的完整示例。
4.2 IRQ 回调配置
static void spi_slv_rx_ready(hal_spi_slv_handle_t *hspi_slv,
void *user_data)
{
uint32_t word;
(void)user_data;
while (hal_spi_slv_fifo_read(hspi_slv, &word) == IM_OK) {
/* 将 word 放入非阻塞软件队列。 */
}
}
static void spi_slv_error(hal_spi_slv_handle_t *hspi_slv,
void *user_data)
{
uint32_t status;
(void)user_data;
(void)hal_spi_slv_status_get(hspi_slv, &status);
}
(void)hal_spi_slv_callback_register(&hspi_slv,
HAL_SPI_SLV_CALLBACK_RX_READY,
spi_slv_rx_ready);
(void)hal_spi_slv_callback_register(&hspi_slv,
HAL_SPI_SLV_CALLBACK_ERROR,
spi_slv_error);
(void)hal_spi_slv_irq_config(
&hspi_slv,
HAL_SPI_SLV_IRQ_READ_FLAG |
HAL_SPI_SLV_IRQ_READ_EMPTY_ERR |
HAL_SPI_SLV_IRQ_WRITE_FULL_ERR,
HAL_SPI_SLV_IRQ_READ_EMPTY_ERR |
HAL_SPI_SLV_IRQ_WRITE_FULL_ERR,
1U);SoC IRQ 入口仍需由上层注册,并在入口中调用:
hal_spi_slv_irq_handler(&hspi_slv);
5. 使用检查表
BSP 已为目标实例配置 CLK、CS 和所需数据线;dual/quad 模式配置了足够的数据引脚。
已在使用 HAL 前完成系统 tick 初始化,以便 HAL 硬件复位超时逻辑工作。
主机和 SPI_SLV 的 CPOL、CPHA、位宽、端序及通道模式一致。
在 RX/TX 均关闭时设置 RXN/TXN,并在主机开始 SCLK 前将 SPI_SLV armed。
FIFO 访问前检查 fill/unfill 水位,避免读空和写满。
HAL IRQ enable mask 与 LL 硬件 mask 的相反语义没有混用。
IRQ 回调只执行短小、非阻塞操作;任务间共享句柄和 FIFO 时有明确同步。
DMA 模式同时正确配置 request、数据寄存器地址、宽度、长度和固定外设地址。
传输结束或异常退出时关闭 RX/TX,并按生命周期调用 reset 或 deinit。