API GUIDE / SPI Slave / HAL
G32S10 SPI Slave HAL 接口
HAL 层接口:内部模块时钟用于寄存器逻辑、复位计数和模块运行,不是 SPI 总线上的 SCLK。
1. 资源模型与公开类型
1.1 HAL 公开宏
| 宏 | 当前值 | 说明 |
|---|---|---|
HAL_SPI_SLV_FIFO_DEPTH | 128 | TX/RX FIFO 深度 |
HAL_SPI_SLV_BITWIDTH_MIN | 4 | 最小帧位宽 |
HAL_SPI_SLV_BITWIDTH_MAX | 32 | 最大帧位宽 |
HAL_SPI_SLV_RESET_COUNT_MAX | 63 | SSLVCTRL.RESET 最大计数值 |
HAL_SPI_SLV_THRESHOLD_MAX | 127 | HAL 接受的最大有效 FIFO 阈值 |
HAL_SPI_SLV_DEFAULT_RESET_COUNT | 63 | 默认复位计数 |
HAL_SPI_SLV_DEFAULT_BITWIDTH | 8 | 默认 RX/TX 帧位宽 |
HAL_SPI_SLV_MODULE_CLOCK_PARENT | HAL_CPM_ID_CLK_SCLK_A | 默认内部模块时钟父源 |
HAL_SPI_SLV_MODULE_CLOCK_HZ | 100000000 | 默认请求的内部模块时钟频率,单位 Hz |
HAL_SPI_SLV_DEFAULT_MODULE_CLOCK_HZ | HAL_SPI_SLV_MODULE_CLOCK_HZ | 模块时钟频率宏的兼容别名 |
HAL_SPI_SLV_CLOCK_POLARITY_LOW | 0 | SCLK 空闲低 |
HAL_SPI_SLV_CLOCK_POLARITY_HIGH | 1 | SCLK 空闲高 |
HAL_SPI_SLV_CLOCK_PHASE_FIRST_EDGE | 0 | 第一个边沿采样 |
HAL_SPI_SLV_CLOCK_PHASE_SECOND_EDGE | 1 | 第二个边沿采样 |
HAL_SPI_SLV_RX_IRQ_SOURCE_MASK | 方向相关 mask | HAL 支持的 RX IRQ 源集合 |
HAL_SPI_SLV_TX_IRQ_SOURCE_MASK | 方向相关 mask | HAL 支持的 TX IRQ 源集合 |
HAL_SPI_SLV_IRQ_SOURCE_MASK_ALL | 全部 HAL IRQ 标志 | HAL IRQ 源符号并集 |
HAL_SPI_SLV_STATUS_ERROR_MASK | 四个 FIFO 错误状态 | HAL 错误状态并集 |
内部模块时钟用于寄存器逻辑、复位计数和模块运行,不是 SPI 总线上的 SCLK。SPI_SLV
不会根据 HAL_SPI_SLV_MODULE_CLOCK_HZ 对外输出时钟。
1.2 传输方向
typedef enum {
HAL_SPI_SLV_DIRECTION_NONE = 0U,
HAL_SPI_SLV_DIRECTION_RX = (1UL << 0U),
HAL_SPI_SLV_DIRECTION_TX = (1UL << 1U),
HAL_SPI_SLV_DIRECTION_TX_RX =
HAL_SPI_SLV_DIRECTION_RX | HAL_SPI_SLV_DIRECTION_TX,
} hal_spi_slv_direction_t;| 枚举 | 说明 |
|---|---|
HAL_SPI_SLV_DIRECTION_NONE | 不选择任何方向;不能传给 enable() 或 disable() |
HAL_SPI_SLV_DIRECTION_RX | RX 路径 |
HAL_SPI_SLV_DIRECTION_TX | TX 路径 |
HAL_SPI_SLV_DIRECTION_TX_RX | 同时选择 RX 和 TX 路径 |
1.3 数据通道模式
typedef enum {
HAL_SPI_SLV_CHANNEL_SINGLE = 0U,
HAL_SPI_SLV_CHANNEL_DUAL = 1U,
HAL_SPI_SLV_CHANNEL_QUAD = 2U,
} hal_spi_slv_channel_t;| 枚举 | 字段编码 | 说明 |
|---|---|---|
HAL_SPI_SLV_CHANNEL_SINGLE | 0 | 标准单线数据模式 |
HAL_SPI_SLV_CHANNEL_DUAL | 1 | 双线数据模式 |
HAL_SPI_SLV_CHANNEL_QUAD | 2 | 四线数据模式 |
原始字段编码 3 保留。HAL 会拒绝大于 HAL_SPI_SLV_CHANNEL_QUAD 的值。四线模式需要
BSP 同时将 D0 至 D3 配置为 SPI_SLV 功能;HAL 只配置控制器寄存器,不申请 GPIO。
1.4 数据端序
typedef enum {
HAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_MSB = 0U,
HAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_LSB = 1U,
HAL_SPI_SLV_ENDIAN_WORD_LSB_BYTE_LSB = 2U,
HAL_SPI_SLV_ENDIAN_WORD_LSB_BYTE_MSB = 3U,
} hal_spi_slv_endian_t;| 枚举 | Word 顺序 | Byte 内顺序 |
|---|---|---|
HAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_MSB | Big-endian | MSB-first |
HAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_LSB | Big-endian | LSB-first |
HAL_SPI_SLV_ENDIAN_WORD_LSB_BYTE_LSB | Little-endian | LSB-first |
HAL_SPI_SLV_ENDIAN_WORD_LSB_BYTE_MSB | Little-endian | MSB-first |
RX 和 TX 可独立配置端序。主机与从机的位宽、采样模式和位序必须匹配。
1.5 IRQ 源
typedef enum {
HAL_SPI_SLV_IRQ_READ_FLAG = (1UL << 2U),
HAL_SPI_SLV_IRQ_WRITE_FLAG = (1UL << 3U),
HAL_SPI_SLV_IRQ_READ_EMPTY_ERR = (1UL << 4U),
HAL_SPI_SLV_IRQ_WRITE_FULL_ERR = (1UL << 5U),
} hal_spi_slv_irq_source_t;| HAL IRQ 源 | RX 方向可用 | TX 方向可用 | 说明 |
|---|---|---|---|
HAL_SPI_SLV_IRQ_READ_FLAG | 是 | 否 | RX FIFO 达到可读阈值 |
HAL_SPI_SLV_IRQ_WRITE_FLAG | 否 | 是 | TX FIFO 达到可写阈值 |
HAL_SPI_SLV_IRQ_READ_EMPTY_ERR | 是 | 是 | 对应 FIFO 发生读空错误 |
HAL_SPI_SLV_IRQ_WRITE_FULL_ERR | 是 | 是 | 对应 FIFO 发生写满错误 |
HAL 的 *_irq_enable_mask 入参采用“1 表示启用”的逻辑语义。LL 和硬件寄存器中的*_IRQ_MASK 位采用相反语义:“1 表示屏蔽,0 表示不屏蔽”。HAL 会完成这层转换。
1.6 初始化配置
typedef struct {
uint8_t cpol;
uint8_t cpha;
uint8_t loop_enable;
uint8_t reset_count;
uint8_t rx_channel;
uint8_t tx_channel;
uint8_t rx_endian;
uint8_t tx_endian;
uint8_t rx_bitwidth;
uint8_t tx_bitwidth;
uint8_t rx_read_threshold;
uint8_t rx_write_threshold;
uint8_t tx_read_threshold;
uint8_t tx_write_threshold;
hal_cpm_id_t module_clock_parent;
uint32_t module_clock_hz;
} hal_spi_slv_init_config_t;| 成员 | 合法范围 | 说明 |
|---|---|---|
cpol | 0 或 1 | SPI SCLK 极性 |
cpha | 0 或 1 | SPI SCLK 相位 |
loop_enable | 0 或 1 | 初始化完成后是否保持内部环回 |
reset_count | 0 至 63 | 复位计数;复位时间约为 reset_count / module_clock_hz |
rx_channel | 0 至 2 | RX 单线、双线或四线模式 |
tx_channel | 0 至 2 | TX 单线、双线或四线模式 |
rx_endian | 0 至 3 | RX 数据端序 |
tx_endian | 0 至 3 | TX 数据端序 |
rx_bitwidth | 4 至 32 | RX 每帧有效 bit 数 |
tx_bitwidth | 4 至 32 | TX 每帧有效 bit 数 |
| 四个 threshold | 0 至 127 | 对应寄存器阈值字段的 HAL 有效原始值 |
module_clock_parent | 0 或有效 hal_cpm_id_t | 内部模块时钟父源;0 表示使用 HAL_SPI_SLV_MODULE_CLOCK_PARENT |
module_clock_hz | 0 或有效频率 | 请求的模块时钟频率;0 表示使用 HAL_SPI_SLV_MODULE_CLOCK_HZ |
默认配置如下。
| 字段 | 默认值 |
|---|---|
cpol | HAL_SPI_SLV_CLOCK_POLARITY_LOW |
cpha | HAL_SPI_SLV_CLOCK_PHASE_FIRST_EDGE |
loop_enable | 0 |
reset_count | 63 |
rx_channel / tx_channel | HAL_SPI_SLV_CHANNEL_SINGLE |
rx_endian / tx_endian | HAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_MSB |
rx_bitwidth / tx_bitwidth | 8 |
| 四个 threshold | 0 |
module_clock_parent | 0 |
module_clock_hz | 0 |
1.7 FIFO 水位快照
typedef struct {
uint32_t tx_fill_count;
uint32_t tx_available_count;
uint32_t rx_fill_count;
uint32_t rx_available_count;
} hal_spi_slv_fifo_level_t;| 成员 | 说明 |
|---|---|
tx_fill_count | TX FIFO 中已有 entry 数 |
tx_available_count | TX FIFO 中可继续写入的 entry 数 |
rx_fill_count | RX FIFO 中可读取的 entry 数 |
rx_available_count | RX FIFO 中尚未占用的 entry 数 |
应直接使用硬件提供的 fill/unfill 字段,不建议用 128 - fill_count 推算可用空间。
1.8 回调与句柄
typedef void (*hal_spi_slv_callback_t)(hal_spi_slv_handle_t *hspi_slv, void *user_data);
struct hal_spi_slv_handle {
spi_slv_regs_t *instance;
hal_spi_slv_init_config_t init;
uint32_t module_clock_hz;
uint32_t rx_irq_enable_mask;
uint32_t tx_irq_enable_mask;
hal_spi_slv_callback_t tx_ready_callback;
hal_spi_slv_callback_t rx_ready_callback;
hal_spi_slv_callback_t error_callback;
void *user_data;
bool aggregate_irq_enabled;
bool is_initialized;
};| 成员 | 说明 |
|---|---|
instance | 绑定的 SPI_SLV0 或 SPI_SLV1 |
init | hal_spi_slv_init() 使用的硬件配置 |
module_clock_hz | HAL 初始化后读取到的内部模块时钟频率;反初始化后为 0 |
rx_irq_enable_mask | 当前启用的 RX HAL IRQ 源 |
tx_irq_enable_mask | 当前启用的 TX HAL IRQ 源 |
| 三个 callback | TX ready、RX ready 和错误回调 |
user_data | 调用方私有指针,HAL 只保存并原样传给回调 |
aggregate_irq_enabled | 模块聚合 IRQ 是否未屏蔽 |
is_initialized | hal_spi_slv_init() 是否成功完成 |
回调可能在 SPI_SLV IRQ 上下文中执行,不得阻塞、休眠、等待锁或执行重日志操作。
回调没有携带状态参数;错误回调如需定位错误,应调用 hal_spi_slv_status_get()。
2. HAL 接口规范
2.1 HAL 实现边界
HAL 负责:
识别
SPI_SLV0和SPI_SLV1实例并校验配置范围。选择并使能 SPI_SLV 内部模块时钟和门控,初始化后记录实际频率。
屏蔽中断、复位 FIFO/传输状态并应用静态配置。
提供 RX/TX 路径使能、FIFO 单 entry 访问、计数和阈值配置。
将 HAL 的 IRQ 启用语义转换为硬件 active-high mask。
分发 TX ready、RX ready 和 FIFO error 回调。
提供 DMA 数据寄存器地址,不负责 DMA 通道配置和搬运。
HAL 不负责:
配置 CLK、CS、D0 至 D3 的 GPIO 复用。
产生 SPI SCLK 或控制主机侧 CS。
注册、设置优先级或使能 CPU/SoC 中断控制器。
在 HAL 内完成阻塞式整包收发或 DMA 通道编排。
2.2 默认配置与生命周期
2.2.1 hal_spi_slv_init_config_default
error_code_t hal_spi_slv_init_config_default(hal_spi_slv_init_config_t *init);
功能:向 init 写入第 3.10 节列出的 SDK 默认配置。
| 参数 | 说明 |
|---|---|
init | 输出初始化配置,不得为空 |
| 返回值 | 说明 |
|---|---|
IM_OK | 默认配置写入成功 |
IM_ERR_INVALID_PARAM | init == NULL |
该接口只填写软件结构体,不访问硬件。
2.2.2 hal_spi_slv_handle_init
error_code_t hal_spi_slv_handle_init(hal_spi_slv_handle_t *hspi_slv, spi_slv_regs_t *instance);
功能:清零 HAL 句柄、绑定实例、装入默认配置和默认空回调。
| 参数 | 说明 |
|---|---|
hspi_slv | HAL 句柄,不得为空 |
instance | 必须为 SPI_SLV0 或 SPI_SLV1 |
| 返回值 | 说明 |
|---|---|
IM_OK | 句柄初始化成功 |
IM_ERR_INVALID_PARAM | 句柄为空或实例不受支持 |
该接口不使能模块时钟,也不访问 SPI_SLV 寄存器。调用成功后is_initialized == false,应按需修改 hspi_slv->init 后再调用hal_spi_slv_init()。
2.2.3 hal_spi_slv_init
error_code_t hal_spi_slv_init(hal_spi_slv_handle_t *hspi_slv);
功能:校验 hspi_slv->init,使能内部模块时钟,复位控制器并应用静态配置。
| 返回值 | 说明 |
|---|---|
IM_OK | 硬件初始化成功 |
IM_ERR_INVALID_PARAM | 句柄未绑定合法实例,或 init 字段越界 |
IM_ERR_BUSY | 该句柄已经初始化 |
IM_ERR_NOT_READY | 系统 tick 未初始化,无法执行带超时的硬件复位 |
IM_ERR_TIMEOUT | RESET 字段未在 10 us 内自动清零 |
| 其他错误码 | CPM 设置父时钟、频率或使能时钟失败 |
主要执行顺序:
清空 HAL IRQ 启用快照并安装缺失的默认回调。
若
module_clock_parent非 0 则使用该父源,否则使用HAL_SPI_SLV_MODULE_CLOCK_PARENT;若module_clock_hz非 0 则请求该频率,否则 使用HAL_SPI_SLV_MODULE_CLOCK_HZ。配置父源和频率后依次使能模块时钟和门控。屏蔽聚合 IRQ,屏蔽全部 RX/TX 子中断并清除聚合 IRQ 标志。
关闭 RX/TX,临时使能 loop,写入 RESET 计数并等待其自动归零。
根据
loop_enable决定初始化后是否保留 loop。配置 SEL 保持、CPOL、CPHA、通道、端序、位宽和阈值。
将
is_initialized置为true。
初始化不会设置 SSLVRXN/SSLVTXN,也不会使能 RX/TX 路径。
2.2.4 hal_spi_slv_reset
error_code_t hal_spi_slv_reset(hal_spi_slv_handle_t *hspi_slv);
功能:在保持 HAL 句柄打开的前提下,复位 FIFO 和传输状态并重新应用初始化配置。
| 返回值 | 说明 |
|---|---|
IM_OK | 复位成功 |
IM_ERR_INVALID_PARAM | 句柄非法或尚未初始化 |
IM_ERR_NOT_READY | 系统 tick 未初始化 |
IM_ERR_TIMEOUT | 硬件复位超时 |
该接口会:
关闭 RX/TX。
屏蔽聚合 IRQ 和全部子中断,清空 HAL IRQ 启用快照。
执行硬件复位并重新应用
hspi_slv->init。将
SSLVRXN和SSLVTXN清零。保留已注册回调和
user_data。
复位成功后仍处于已初始化状态,但传输方向和 IRQ 均未启用。
2.2.5 hal_spi_slv_deinit
error_code_t hal_spi_slv_deinit(hal_spi_slv_handle_t *hspi_slv);
功能:关闭 SPI_SLV 数据路径和中断,关闭内部模块时钟并使句柄失效。
| 返回值 | 说明 |
|---|---|
IM_OK | 反初始化成功 |
IM_ERR_INVALID_PARAM | 句柄非法或未初始化 |
| 其他错误码 | CPM 关闭门控或模块时钟失败 |
调用后 is_initialized == false、module_clock_hz == 0。如需重新开始,先再次调用hal_spi_slv_init();如需恢复整个句柄默认内容,可重新调用hal_spi_slv_handle_init()。
2.3 RX/TX 路径控制
2.3.1 hal_spi_slv_enable
error_code_t hal_spi_slv_enable(hal_spi_slv_handle_t *hspi_slv, uint32_t direction);
功能:在本地关中断临界区内,使能所选 RX/TX 路径。
| 参数 | 说明 |
|---|---|
direction | RX、TX 或 TX_RX,不能为 NONE 或包含未知 bit |
| 返回值 | 说明 |
|---|---|
IM_OK | 所选路径已使能 |
IM_ERR_INVALID_PARAM | 句柄未初始化或方向 mask 非法 |
调用该接口只使控制器进入待传输状态。必须由外部 SPI 主机拉动有效 CS 并提供 SCLK, 真正的数据收发才会发生。
2.3.2 hal_spi_slv_disable
error_code_t hal_spi_slv_disable(hal_spi_slv_handle_t *hspi_slv, uint32_t direction);
功能:在本地关中断临界区内,关闭所选 RX/TX 路径。
参数和返回值约束与 hal_spi_slv_enable() 相同。修改传输计数前必须确保 RX 和 TX
两条路径都处于关闭状态。
2.4 FIFO 直接访问
2.4.1 hal_spi_slv_fifo_write
error_code_t hal_spi_slv_fifo_write(hal_spi_slv_handle_t *hspi_slv, uint32_t data);
功能:向 SSLVTXD 写入一个 32 bit FIFO entry。
| 参数 | 说明 |
|---|---|
data | 待写数据;有效 bit 数由 tx_bitwidth 决定 |
| 返回值 | 说明 |
|---|---|
IM_OK | 写入成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化 |
IM_ERR_BUSY | TX FIFO 没有可用 entry |
这是非阻塞单 entry 接口,不等待 FIFO 空间。
2.4.2 hal_spi_slv_fifo_read
error_code_t hal_spi_slv_fifo_read(hal_spi_slv_handle_t *hspi_slv, uint32_t *data_out);
功能:从 SSLVRXD 弹出一个 32 bit FIFO entry。
| 参数 | 说明 |
|---|---|
data_out | 输出数据,不得为空 |
| 返回值 | 说明 |
|---|---|
IM_OK | 读取成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化或输出指针为空 |
IM_ERR_NOT_READY | RX FIFO 当前为空 |
这是非阻塞单 entry 接口,不等待主机产生新数据。
2.5 阈值与传输计数
2.5.1 hal_spi_slv_threshold_config
error_code_t hal_spi_slv_threshold_config(hal_spi_slv_handle_t *hspi_slv, uint8_t rx_read_threshold, uint8_t rx_write_threshold, uint8_t tx_read_threshold, uint8_t tx_write_threshold);
功能:更新四个 FIFO 阈值,并同步更新 hspi_slv->init 中的配置快照。
| 参数 | 合法范围 | 对应字段 |
|---|---|---|
rx_read_threshold | 0 至 127 | SSLVRXC.RDTHR |
rx_write_threshold | 0 至 127 | SSLVRXC.WRTHR |
tx_read_threshold | 0 至 127 | SSLVTXC.RDTHR |
tx_write_threshold | 0 至 127 | SSLVTXC.WRTHR |
| 返回值 | 说明 |
|---|---|
IM_OK | 配置成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化或任一阈值大于 127 |
当前实现不检查 RX/TX 是否已使能。为避免传输中阈值突变导致状态和 DMA/IRQ 请求立即 变化,建议在使能数据路径前配置阈值。
2.5.2 hal_spi_slv_transfer_count_set
error_code_t hal_spi_slv_transfer_count_set(hal_spi_slv_handle_t *hspi_slv, uint32_t rx_count, uint32_t tx_count);
功能:分别写入 SSLVRXN 和 SSLVTXN,设置本次传输的 RX/TX 帧数。
| 参数 | 说明 |
|---|---|
rx_count | RX 帧数;0 表示写入 0 |
tx_count | TX 帧数;0 表示写入 0 |
| 返回值 | 说明 |
|---|---|
IM_OK | 两个计数已写入 |
IM_ERR_INVALID_PARAM | 句柄未初始化 |
IM_ERR_BUSY | RX_EN 或 TX_EN 任一已置位 |
该接口在本地关中断临界区内同时检查 RX_EN 和 TX_EN。必须先关闭两个方向,再设置两个
计数;设置成功后才能重新使能传输。读取 SSLVRXN/SSLVTXN 得到的是硬件当前剩余
计数。
2.6 IRQ、状态与 FIFO 水位
2.6.1 hal_spi_slv_irq_config
error_code_t hal_spi_slv_irq_config(hal_spi_slv_handle_t *hspi_slv, uint32_t rx_irq_enable_mask, uint32_t tx_irq_enable_mask, uint8_t aggregate_irq_enable);
功能:配置 HAL 支持的 RX/TX 子中断,并决定是否放开模块聚合 IRQ。
| 参数 | 说明 |
|---|---|
rx_irq_enable_mask | READ_FLAG、READ_EMPTY_ERR、WRITE_FULL_ERR 的组合 |
tx_irq_enable_mask | WRITE_FLAG、READ_EMPTY_ERR、WRITE_FULL_ERR 的组合 |
aggregate_irq_enable | 0 屏蔽聚合 IRQ,1 放开聚合 IRQ |
| 返回值 | 说明 |
|---|---|
IM_OK | 配置成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化、方向 mask 含非法源,或聚合开关不是 0/1 |
HAL 始终屏蔽 RX write flag、TX read flag 以及 RX/TX empty/full 子中断,因为当前hal_spi_slv_irq_handler() 不分发这些事件。配置模块 IRQ 不等于注册或使能 SoC IRQ;
后者由 BSP、middleware 或应用完成。
2.6.2 hal_spi_slv_irq_clear
error_code_t hal_spi_slv_irq_clear(hal_spi_slv_handle_t *hspi_slv);
功能:清除 SSLVCTRL.IRQ_FLAG 聚合 IRQ 标志。
| 返回值 | 说明 |
|---|---|
IM_OK | 已执行清除 |
IM_ERR_INVALID_PARAM | 句柄未初始化 |
该接口只清除聚合标志,不清除 SSLVCTRL[24:13] 中的独立只读状态源。只要源条件仍然
成立,聚合 IRQ 可能再次出现。
2.6.3 hal_spi_slv_status_get
error_code_t hal_spi_slv_status_get(const hal_spi_slv_handle_t *hspi_slv, uint32_t *status_out);
功能:将硬件原始状态转换为第 3.9 节定义的 HAL 逻辑状态 bitmask。
| 返回值 | 说明 |
|---|---|
IM_OK | 状态读取成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化或输出指针为空 |
该接口不清除状态,也不访问 FIFO 数据寄存器。
2.6.4 hal_spi_slv_fifo_level_get
error_code_t hal_spi_slv_fifo_level_get(const hal_spi_slv_handle_t *hspi_slv, hal_spi_slv_fifo_level_t *level_out);
功能:读取 SSLVFLR 中的 TX/RX fill 和 unfill 字段。
| 返回值 | 说明 |
|---|---|
IM_OK | 水位快照读取成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化或输出指针为空 |
这是瞬时快照。硬件或中断处理可能在函数返回后立即改变 FIFO 水位。
2.7 DMA 数据寄存器地址
2.7.1 hal_spi_slv_tx_dma_address_get
error_code_t hal_spi_slv_tx_dma_address_get(const hal_spi_slv_handle_t *hspi_slv, uintptr_t *address_out);
功能:返回 &instance->sslvtxd 的外设地址,供 DMA 目标地址配置使用。
2.7.2 hal_spi_slv_rx_dma_address_get
error_code_t hal_spi_slv_rx_dma_address_get(const hal_spi_slv_handle_t *hspi_slv, uintptr_t *address_out);
功能:返回 &instance->sslvrxd 的外设地址,供 DMA 源地址配置使用。
两个接口的共同返回值如下。
| 返回值 | 说明 |
|---|---|
IM_OK | 地址返回成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化或输出指针为空 |
接口只取得寄存器地址,不读取或写入数据寄存器,不配置 DMA request、通道、宽度、增量 模式或传输长度。
2.8 回调与 IRQ 入口
2.8.1 hal_spi_slv_callback_register
error_code_t hal_spi_slv_callback_register(hal_spi_slv_handle_t *hspi_slv, hal_spi_slv_callback_id_t callback_id, hal_spi_slv_callback_t callback);
功能:注册 TX ready、RX ready 或 error 回调。
callback_id | 目标成员 | 触发条件 |
|---|---|---|
HAL_SPI_SLV_CALLBACK_TX_READY | tx_ready_callback | TX write flag 已启用并置位 |
HAL_SPI_SLV_CALLBACK_RX_READY | rx_ready_callback | RX read flag 已启用并置位 |
HAL_SPI_SLV_CALLBACK_ERROR | error_callback | 任一已启用 FIFO 错误状态置位 |
| 返回值 | 说明 |
|---|---|
IM_OK | 注册成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化或 callback ID 非法 |
callback == NULL 表示恢复为 HAL 默认空回调,不是保留原回调。
2.8.2 hal_spi_slv_user_data_set
error_code_t hal_spi_slv_user_data_set(hal_spi_slv_handle_t *hspi_slv, void *user_data);
功能:保存调用方上下文指针,IRQ handler 调用回调时原样传入。user_data 可以为NULL。
| 返回值 | 说明 |
|---|---|
IM_OK | 保存成功 |
IM_ERR_INVALID_PARAM | 句柄未初始化 |
2.8.3 hal_spi_slv_irq_handler
void hal_spi_slv_irq_handler(hal_spi_slv_handle_t *hspi_slv);
功能:SPI_SLV 模块 IRQ 服务入口,读取一次状态、清除聚合 IRQ,并分发本次快照中 已启用的事件。
处理顺序:
校验句柄;非法时直接返回。
读取全部 HAL 状态并清除聚合 IRQ。
若聚合 IRQ 未启用,则返回,不分发回调。
汇总已启用的 RX/TX FIFO 错误;存在错误时调用一次 error callback。
TX write flag 已启用且置位时调用 TX ready callback。
RX read flag 已启用且置位时调用 RX ready callback。
同一次 IRQ 中可能先后调用 error、TX ready 和 RX ready 三类回调。上层 SoC IRQ 入口 应直接调用本函数,并传入对应实例的 HAL 句柄。连续传输的 FIFO 推进、尾部重检和 完成状态机由 middleware callback 负责,HAL handler 不维护传输循环。
2.9 调试寄存器 dump
2.9.1 hal_spi_slv_regs_dump
error_code_t hal_spi_slv_regs_dump(const hal_spi_slv_handle_t *hspi_slv);
功能:通过公共日志后端输出 SSLVCTRL、SSLVRXC、SSLVTXC、SSLVRXN、SSLVTXN 和 SSLVFLR。
| 返回值 | 说明 |
|---|---|
IM_OK | debug helper 已启用且 dump 成功 |
IM_ERR_INVALID_PARAM | debug helper 已启用,但句柄非法或未初始化 |
IM_ERR_UNSUPPORTED | 任一编译开关未启用 |
公开函数原型始终存在。仅内部实现受以下两个 Kconfig 宏共同控制:
CONFIG_SDK_ENABLE_DEBUG_HELPERS CONFIG_SPI_SLV_ENABLE_DEBUG_HELPERS
3. 当前实现约束与时序说明
3.1 内部模块时钟与 SPI SCLK
SPI_SLV 同时涉及两类时钟:
HAL 通过 CPM 配置的内部模块时钟/PCLK,用于寄存器逻辑、FIFO、复位计数和状态机。
外部 SPI 主机提供的 SCLK,用于串行数据移位和采样。
前者不能替代后者。hal_spi_slv_init() 成功只说明从机模块可以被 CPU 配置;从机在
主机拉动 CS 并产生 SCLK 前不会开始线上的数据传输。
3.2 推荐传输配置顺序
遵循以下顺序可满足 RXN/TXN 必须在使能前设置的要求:
hal_spi_slv_handle_init()。修改
hspi_slv.init中的 CPOL、CPHA、通道、端序、位宽和阈值。hal_spi_slv_init()。确保 RX/TX 均关闭。
hal_spi_slv_transfer_count_set()写入本次 RX/TX 帧数。清除旧聚合 IRQ,按需配置 IRQ。
hal_spi_slv_enable()使从机进入 armed 状态,并准备 TX FIFO 数据。最后启动主机传输,让主机产生 CS 和 SCLK。
收集 RX FIFO、检查状态,完成后关闭 RX/TX。
不能在 RX_EN 或 TX_EN 已置位后改写传输总量。需要开始下一次传输时,先关闭两个 方向,再写入新的 RXN/TXN。
3.3 IRQ 与 DMA
模块 IRQ 包含子源 mask 和一个聚合 IRQ mask,两层都需要正确配置。
HAL IRQ handler 只服务 RX read flag、TX write flag 和四类方向错误。
hal_spi_slv_irq_clear()清除聚合 IRQ,不会人为清除仍然成立的 FIFO 条件。DMA 地址 getter 只返回
SSLVTXD/SSLVRXD地址。DMA request 映射、通道申请、源/目的宽度、长度和完成中断由 DMA 层或 middleware 负责。
4. 典型用法
4.1 DMA 地址获取
uintptr_t tx_reg; uintptr_t rx_reg; (void)hal_spi_slv_tx_dma_address_get(&hspi_slv, &tx_reg); (void)hal_spi_slv_rx_dma_address_get(&hspi_slv, &rx_reg);
TX DMA 使用 tx_reg 作为固定外设目的地址;RX DMA 使用 rx_reg 作为固定外设源
地址。具体 DMA request ID 和通道参数由 DMA 驱动或 middleware 配置。