API GUIDE / SPI Slave / HAL

G32S10 SPI Slave HAL 接口

HAL 层接口:内部模块时钟用于寄存器逻辑、复位计数和模块运行,不是 SPI 总线上的 SCLK。

1. 资源模型与公开类型

1.1 HAL 公开宏

宏当前值说明
HAL_SPI_SLV_FIFO_DEPTH128TX/RX FIFO 深度
HAL_SPI_SLV_BITWIDTH_MIN4最小帧位宽
HAL_SPI_SLV_BITWIDTH_MAX32最大帧位宽
HAL_SPI_SLV_RESET_COUNT_MAX63SSLVCTRL.RESET 最大计数值
HAL_SPI_SLV_THRESHOLD_MAX127HAL 接受的最大有效 FIFO 阈值
HAL_SPI_SLV_DEFAULT_RESET_COUNT63默认复位计数
HAL_SPI_SLV_DEFAULT_BITWIDTH8默认 RX/TX 帧位宽
HAL_SPI_SLV_MODULE_CLOCK_PARENTHAL_CPM_ID_CLK_SCLK_A默认内部模块时钟父源
HAL_SPI_SLV_MODULE_CLOCK_HZ100000000默认请求的内部模块时钟频率,单位 Hz
HAL_SPI_SLV_DEFAULT_MODULE_CLOCK_HZHAL_SPI_SLV_MODULE_CLOCK_HZ模块时钟频率宏的兼容别名
HAL_SPI_SLV_CLOCK_POLARITY_LOW0SCLK 空闲低
HAL_SPI_SLV_CLOCK_POLARITY_HIGH1SCLK 空闲高
HAL_SPI_SLV_CLOCK_PHASE_FIRST_EDGE0第一个边沿采样
HAL_SPI_SLV_CLOCK_PHASE_SECOND_EDGE1第二个边沿采样
HAL_SPI_SLV_RX_IRQ_SOURCE_MASK方向相关 maskHAL 支持的 RX IRQ 源集合
HAL_SPI_SLV_TX_IRQ_SOURCE_MASK方向相关 maskHAL 支持的 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_RXRX 路径
HAL_SPI_SLV_DIRECTION_TXTX 路径
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_SINGLE0标准单线数据模式
HAL_SPI_SLV_CHANNEL_DUAL1双线数据模式
HAL_SPI_SLV_CHANNEL_QUAD2四线数据模式

原始字段编码 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_MSBBig-endianMSB-first
HAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_LSBBig-endianLSB-first
HAL_SPI_SLV_ENDIAN_WORD_LSB_BYTE_LSBLittle-endianLSB-first
HAL_SPI_SLV_ENDIAN_WORD_LSB_BYTE_MSBLittle-endianMSB-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;
成员合法范围说明
cpol0 或 1SPI SCLK 极性
cpha0 或 1SPI SCLK 相位
loop_enable0 或 1初始化完成后是否保持内部环回
reset_count0 至 63复位计数;复位时间约为 reset_count / module_clock_hz
rx_channel0 至 2RX 单线、双线或四线模式
tx_channel0 至 2TX 单线、双线或四线模式
rx_endian0 至 3RX 数据端序
tx_endian0 至 3TX 数据端序
rx_bitwidth4 至 32RX 每帧有效 bit 数
tx_bitwidth4 至 32TX 每帧有效 bit 数
四个 threshold0 至 127对应寄存器阈值字段的 HAL 有效原始值
module_clock_parent0 或有效 hal_cpm_id_t内部模块时钟父源;0 表示使用 HAL_SPI_SLV_MODULE_CLOCK_PARENT
module_clock_hz0 或有效频率请求的模块时钟频率;0 表示使用 HAL_SPI_SLV_MODULE_CLOCK_HZ

默认配置如下。

字段默认值
cpolHAL_SPI_SLV_CLOCK_POLARITY_LOW
cphaHAL_SPI_SLV_CLOCK_PHASE_FIRST_EDGE
loop_enable0
reset_count63
rx_channel / tx_channelHAL_SPI_SLV_CHANNEL_SINGLE
rx_endian / tx_endianHAL_SPI_SLV_ENDIAN_WORD_MSB_BYTE_MSB
rx_bitwidth / tx_bitwidth8
四个 threshold0
module_clock_parent0
module_clock_hz0

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_countTX FIFO 中已有 entry 数
tx_available_countTX FIFO 中可继续写入的 entry 数
rx_fill_countRX FIFO 中可读取的 entry 数
rx_available_countRX 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
inithal_spi_slv_init() 使用的硬件配置
module_clock_hzHAL 初始化后读取到的内部模块时钟频率;反初始化后为 0
rx_irq_enable_mask当前启用的 RX HAL IRQ 源
tx_irq_enable_mask当前启用的 TX HAL IRQ 源
三个 callbackTX ready、RX ready 和错误回调
user_data调用方私有指针,HAL 只保存并原样传给回调
aggregate_irq_enabled模块聚合 IRQ 是否未屏蔽
is_initializedhal_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_PARAMinit == 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_slvHAL 句柄,不得为空
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_TIMEOUTRESET 字段未在 10 us 内自动清零
其他错误码CPM 设置父时钟、频率或使能时钟失败

主要执行顺序:

  1. 清空 HAL IRQ 启用快照并安装缺失的默认回调。

  2. 若 module_clock_parent 非 0 则使用该父源,否则使用HAL_SPI_SLV_MODULE_CLOCK_PARENT;若 module_clock_hz 非 0 则请求该频率,否则 使用 HAL_SPI_SLV_MODULE_CLOCK_HZ。配置父源和频率后依次使能模块时钟和门控。

  3. 屏蔽聚合 IRQ,屏蔽全部 RX/TX 子中断并清除聚合 IRQ 标志。

  4. 关闭 RX/TX,临时使能 loop,写入 RESET 计数并等待其自动归零。

  5. 根据 loop_enable 决定初始化后是否保留 loop。

  6. 配置 SEL 保持、CPOL、CPHA、通道、端序、位宽和阈值。

  7. 将 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 路径。

参数说明
directionRX、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_BUSYTX 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_READYRX 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_threshold0 至 127SSLVRXC.RDTHR
rx_write_threshold0 至 127SSLVRXC.WRTHR
tx_read_threshold0 至 127SSLVTXC.RDTHR
tx_write_threshold0 至 127SSLVTXC.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_countRX 帧数;0 表示写入 0
tx_countTX 帧数;0 表示写入 0
返回值说明
IM_OK两个计数已写入
IM_ERR_INVALID_PARAM句柄未初始化
IM_ERR_BUSYRX_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_maskREAD_FLAG、READ_EMPTY_ERR、WRITE_FULL_ERR 的组合
tx_irq_enable_maskWRITE_FLAG、READ_EMPTY_ERR、WRITE_FULL_ERR 的组合
aggregate_irq_enable0 屏蔽聚合 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_READYtx_ready_callbackTX write flag 已启用并置位
HAL_SPI_SLV_CALLBACK_RX_READYrx_ready_callbackRX read flag 已启用并置位
HAL_SPI_SLV_CALLBACK_ERRORerror_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,并分发本次快照中 已启用的事件。

处理顺序:

  1. 校验句柄;非法时直接返回。

  2. 读取全部 HAL 状态并清除聚合 IRQ。

  3. 若聚合 IRQ 未启用,则返回,不分发回调。

  4. 汇总已启用的 RX/TX FIFO 错误;存在错误时调用一次 error callback。

  5. TX write flag 已启用且置位时调用 TX ready callback。

  6. 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_OKdebug helper 已启用且 dump 成功
IM_ERR_INVALID_PARAMdebug 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 必须在使能前设置的要求:

  1. hal_spi_slv_handle_init()。

  2. 修改 hspi_slv.init 中的 CPOL、CPHA、通道、端序、位宽和阈值。

  3. hal_spi_slv_init()。

  4. 确保 RX/TX 均关闭。

  5. hal_spi_slv_transfer_count_set() 写入本次 RX/TX 帧数。

  6. 清除旧聚合 IRQ,按需配置 IRQ。

  7. hal_spi_slv_enable() 使从机进入 armed 状态,并准备 TX FIFO 数据。

  8. 最后启动主机传输,让主机产生 CS 和 SCLK。

  9. 收集 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 配置。