API GUIDE / SPI / HAL
G32S10 SPI HAL 接口
HAL 层接口:重要边界:
1. 分层关系与文件组织
| 层次 | 负责内容 | 不负责内容 |
|---|---|---|
| Platform/Application | GPIO pinmux、控制器选择、SoC IRQ 申请和路由 | SPI 寄存器细节和 HAL 内部状态 |
| HAL SPI | CPM module clock/gate、参数校验、寄存器组合、FIFO、状态、控制器 IRQ source、DMA request 语义和 callback 分发 | SoC im_irq_request()、板级 pinmux、完整传输状态机和 timeout |
| LL SPI | 寄存器位级读写 | 参数保护、软件状态、传输流程和并发保护 |
重要边界:
hal_spi_init()要求平台已准备 GPIO pinmux;HAL 配置并使能对应 CPM module clock/gate,但保持 SPI 控制器 disabled。hal_spi_irq_config()只控制 SPI 模块内部中断源,不申请或使能 SoC IRQ。hal_spi_dma_request_config()只维护 DMA request 语义,不申请 DMA 通道,也不通过 TIE/RIE 模拟 DMA enable。HAL 只记录 TX underrun 和 RX overrun 等硬件错误,不表达完整传输的 busy、timeout 或完成状态机。
1.1 Kconfig
| 选项 | 默认值 | 说明 |
|---|---|---|
DRIVER_SPI | n | 编译 G32S10 SPI HAL,并选择 CPM 依赖 |
SPI_ENABLE_DEBUG_HELPERS | n | 构建 hal_spi_regs_dump();需要同时开启全局 debug helper |
仅使用 HAL 时启用:
CONFIG_DRIVER_SPI=y
2. 硬件能力与资源模型
2.1 串行时钟
规格书定义:
SPI_CLK = module_clock_hz / (2 * (CGV + 1))
hal_spi_init() 在 config.module_clock_parent 非 0 时使用该父时钟,否则使用 HAL_SPI_MODULE_CLOCK_PARENT;在 config.module_clock_hz 非 0 时请求该频率,否则请求 HAL_SPI_MODULE_CLOCK_HZ。随后 HAL 尝试读取 CPM module clock,回读失败或返回 0 时使用刚请求的 module clock 作为有效值。CGV 范围为 0x00..0xFF,hal_spi_handle_t.module_clock_hz 和 actual_clock_hz 分别保存用于计算的有效 module clock 与计算得到的 SPI clock。
CGV = 0 表示 module clock 二分频,不表示不分频。例如 module clock 为 60 MHz 时,CGV = 0 得到 30 MHz SPI clock。
HAL 根据有效 module clock 计算 CGV;若所需 divider 超出字段编码范围,则将 CGV 饱和到字段边界,并通过 actual_clock_hz 记录最终 SPI clock。
3. 公共宏和返回状态
3.1 HAL 公开宏
| 宏 | 值 | 说明 |
|---|---|---|
HAL_SPI_INSTANCE_COUNT | 2U | HAL 支持的控制器数量 |
HAL_SPI_FIFO_DEPTH | 128U | TX/RX FIFO 深度 |
HAL_SPI_BITS_PER_WORD_MIN | 2U | 最小帧长 |
HAL_SPI_BITS_PER_WORD_MAX | 32U | 最大帧长 |
HAL_SPI_CLOCK_DIVIDER_MAX | 0xFFU | CGV 最大值 |
HAL_SPI_HARDWARE_CHIP_SELECT_NONE | 0xFFFFFFFFU | 不使用硬件 CS |
HAL_SPI_HARDWARE_CHIP_SELECT_MAX | 0x1U | 最大硬件 CS 编号 |
HAL_SPI_INTERVAL_TIME_MAX | 0x7FFFU | IVLTM 最大值 |
HAL_SPI_INTERVAL_FRAME_COUNT_MAX | 0x7U | ICC 最大字段值 |
HAL_SPI_RECEIVE_COUNT_MAX | 0xFFFFU | RCNT 最大值 |
HAL_SPI_DEFAULT_CLOCK_HZ | 1000000U | HAL 默认请求时钟 |
HAL_SPI_MODULE_CLOCK_PARENT | HAL_CPM_ID_CLK_SCLK_A | 默认 CPM module clock 父源 |
HAL_SPI_MODULE_CLOCK_HZ | 80000000U | HAL init 默认请求的 CPM module clock |
HAL_SPI_DEFAULT_MODULE_CLOCK_HZ | HAL_SPI_MODULE_CLOCK_HZ | HAL_SPI_MODULE_CLOCK_HZ 的兼容别名 |
4. 公开类型
4.1 HAL 枚举类型
4.1.1 协议格式
| 枚举 | 值 | 说明 |
|---|---|---|
HAL_SPI_FRAME_FORMAT_SPI | 0 | Motorola SPI |
HAL_SPI_FRAME_FORMAT_SSP | 1 | TI SSP;不允许 2 bit frame |
HAL_SPI_FRAME_FORMAT_NM1 | 2 | National Microwire 1 |
HAL_SPI_FRAME_FORMAT_NM2 | 3 | National Microwire 2 |
4.1.2 Endian
| 枚举 | 说明 |
|---|---|
HAL_SPI_ENDIAN_MSB_FIRST | MSB first |
HAL_SPI_ENDIAN_MSB_FIRST_BYTE_SWAP | MSB first 并交换 byte |
HAL_SPI_ENDIAN_LSB_FIRST | LSB first |
HAL_SPI_ENDIAN_LSB_FIRST_BYTE_SWAP | LSB first 并交换 byte |
4.1.3 CPOL、CPHA 和 CS
| 类型 | 枚举 | 说明 |
|---|---|---|
hal_spi_clock_polarity_t | LOW / HIGH | SPI clock 空闲电平 |
hal_spi_clock_phase_t | FIRST_EDGE / SECOND_EDGE | 第一个边沿采样或驱动 |
hal_spi_cs_active_level_t | ACTIVE_LOW / ACTIVE_HIGH | CS 有效电平 |
4.1.4 状态、错误、IRQ 和 DMA
| 类型 | 成员 |
|---|---|
hal_spi_status_t | TX half empty、RX half full、TX underrun、RX overrun、END、BUSY、TX full、RX empty |
hal_spi_error_t | TX underrun、RX overrun |
hal_spi_irq_source_t | TX threshold、RX threshold、TX underrun、RX overrun、END |
hal_spi_dma_request_t | TX、RX |
hal_spi_callback_id_t | TX ready、RX ready、ERROR、END |
IRQ mask 与 DMA request mask 是独立语义。PDMA request 由 DMA 控制器 request source 选择,DMA 使用方不应通过 TIE/RIE 模拟 DMA enable。
4.2 hal_spi_config_t 默认值和约束
| 字段 | HAL 默认值 | 约束/说明 |
| --- | --- | --- | --- |
| instance | SPI0 | 必须为 SPI0/SPI1 |
| clock_hz | 1 MHz | init 配置中 0 表示默认 1 MHz |
| bits_per_word | 8 | 2..32 |
| frame_format | SPI | SPI/SSP/NM1/NM2 |
| clock_polarity | LOW | SPI 格式有效 |
| clock_phase | FIRST_EDGE | SPI 格式有效 |
| tx_endian | MSB first | 四种模式之一 |
| rx_endian | MSB first | 四种模式之一 |
| hardware_chip_select | 0 | SPI1 不支持硬件 CS1 |
| hardware_cs_active_level | active low | 使用硬件 CS 时生效 |
| continue_on_tx_underrun | false | SSP 不允许 true |
| interval_enable | false | true 时 interval_time 必须非零 |
| interval_count_32k | false | interval 使用 32K 计数时钟 |
| interval_keep_cs | false | interval gap 是否保持 CS |
| interval_time | 0 | 0..0x7FFF |
| interval_frame_count | 0 | ICC 原始值 0..7;实际每组帧数为值 + 1 |
| loopback | false | 内部回环 |
| tx_threshold | 1 | TTRG 原始值 0..15 |
| rx_threshold | 1 | RTRG 原始值 0..15;传输层可以在空闲时通过 HAL 接口调整 |
| module_clock_parent | 0 | 0 表示使用 HAL_SPI_MODULE_CLOCK_PARENT;init 后保存实际选择的父源 |
| module_clock_hz | 0 | 0 表示使用 HAL_SPI_MODULE_CLOCK_HZ;init 后保存请求频率 |
4.3 hal_spi_handle_t
| 分区 | 字段 | 说明 |
|---|---|---|
| 配置快照 | instance、config | init 成功后只读 |
| 内部状态 | error_code | sticky 的 HAL 硬件错误位 |
| 内部状态 | irq_enable_mask | 当前 HAL IRQ source mask |
| 内部状态 | dma_request_mask | 当前 HAL DMA request 语义 mask |
| 内部状态 | actual_clock_hz | 实际 SPI clock |
| 内部状态 | module_clock_hz | HAL 用于分频计算的有效 SPI module clock |
| 内部状态 | callback slots / user_data | 通过注册接口维护 |
| 内部状态 | is_initialized | HAL 生命周期标志 |
应用不应直接写入 HAL handle 内部状态。
5. HAL 接口规范
5.1 HAL 实现边界
HAL 是无 timeout、无完整 transfer busy 状态机的硬件积木层。它保留硬件相关错误 TX_UNDERRUN 和 RX_OVERRUN,但不表达上层传输的 BUSY/ERROR/TIMEOUT 状态机。
HAL init 不处理 GPIO pinmux、SoC IRQ request 或 DMA 通道打开;SPI 实例固定对应的 CPM module clock/gate 由 HAL 管理。
5.2 初始化与生命周期
| 接口 | 原型摘要 | 行为 |
|---|---|---|
hal_spi_config_struct_init | void (...config) | 填充 HAL 默认配置 |
hal_spi_init | error_code_t (handle, config) | 配置并使能 CPM clock/gate,配置寄存器并保持 disabled,初始化 no-op callbacks |
hal_spi_deinit | error_code_t (handle) | 关闭 IRQ/DMA 语义、disable、flush,并关闭 CPM clock/gate |
hal_spi_enable | error_code_t (handle) | 使能控制器 |
hal_spi_disable | error_code_t (handle) | 禁用控制器 |
hal_spi_init() 的时钟和寄存器配置顺序为:
根据 SPI0/SPI1 取得固定的 CPM module clock、gate 和默认 parent。
按配置选择 parent 并设置请求的 module clock,enable module clock 和 gate;回读有效时更新缓存,否则保留请求值。
根据请求 SPI clock 和缓存的有效 module clock 计算
CGV。disable SPI 和所有内部 IRQ source。
选择新 TX FIFO empty 判定模式。
配置接收、RCNT、endian、loopback 和硬件 CS。
配置协议、位宽、CPHA/CPOL、threshold、interval 和
CGV。保持 SPI disabled,等待传输层准备 FIFO/RCNT/IRQ/DMA 后 enable。
5.3 时钟
error_code_t hal_spi_set_clock(hal_spi_handle_t *handle, uint32_t clock_hz);
clock_hz必须非零;当请求不能被CGV精确表达时,应通过actual_clock_hz获取最终 SPI clock。只能在 SPI disabled、传输空闲时调用;控制器 enabled 时返回
IM_ERR_BUSY。HAL 使用 handle 中缓存的有效 module clock 计算并更新
CGV,不要求 CPM 再次提供频率回读。config.clock_hz和actual_clock_hz更新;module_clock_hz保持初始化时的有效 module clock 不变。
5.4 FIFO
| 接口 | 主要返回 | 说明 |
|---|---|---|
hal_spi_fifo_flush | IM_OK | flush TX/RX,并清 TUNDR、ROVER、END |
hal_spi_fifo_write | IM_ERR_BUSY | TX full 时不写,否则写一个 32 bit frame word |
hal_spi_fifo_read | IM_ERR_NOT_READY | RX empty 时不读,否则读一个 word |
hal_spi_fifo_level_get | IM_OK | 返回 TX count、RX count 和 TX free space |
hal_spi_threshold_config | IM_ERR_INVALID_PARAM | 配置原始 TTRG/RTRG 0..15,并更新快照 |
hal_spi_receive_count_config | IM_ERR_INVALID_PARAM | 0 禁用 RCNT;1..0xFFFF 配置并使能 |
5.5 状态
error_code_t hal_spi_status_get(const hal_spi_handle_t *handle, uint32_t *status_out); error_code_t hal_spi_status_clear(hal_spi_handle_t *handle, uint32_t status_mask);
status_get 单次读取 SSISR,映射为 HAL_SPI_STATUS_*。status_clear 只对 TUNDR、ROVER 和 END 执行 clear;level 类型的 TX/RX threshold 状态不能靠 clear 接口消除。
5.6 IRQ
error_code_t hal_spi_irq_config(hal_spi_handle_t *handle, uint32_t irq_enable_mask); error_code_t hal_spi_callback_register(hal_spi_handle_t *handle, hal_spi_callback_id_t callback_id, hal_spi_callback_t callback); error_code_t hal_spi_user_data_set(hal_spi_handle_t *handle, void *user_data); void hal_spi_irq_handler(hal_spi_handle_t *handle);
说明:
irq_config接收HAL_SPI_IRQ_*mask;0 表示 mask 所有 SPI 内部 IRQ source。callback 传 NULL 会恢复 HAL 默认 no-op callback。
user_data由四类 callback 共享。handler 先处理并 clear TUNDR/ROVER,再分发 RX/TX level callback,最后处理并 clear END。
handler 不 request、enable、disable 或 release SoC IRQ。
5.7 DMA 辅助
error_code_t hal_spi_dma_request_config(hal_spi_handle_t *handle, uint32_t request_mask); error_code_t hal_spi_tx_dma_address_get(const hal_spi_handle_t *handle, uintptr_t *address_out); error_code_t hal_spi_rx_dma_address_get(const hal_spi_handle_t *handle, uintptr_t *address_out);
hal_spi_dma_request_config() 记录 TX/RX DMA request 语义,不打开 DMA channel,也不切换 TIE/RIE。TX/RX 地址接口当前都返回 SSIDR 地址。
5.8 Debug dump
error_code_t hal_spi_regs_dump(const hal_spi_handle_t *handle);
仅当 CONFIG_SDK_ENABLE_DEBUG_HELPERS 和 CONFIG_SPI_ENABLE_DEBUG_HELPERS 同时启用时输出 SPI 寄存器;否则返回 IM_ERR_UNSUPPORTED。dump 跳过读取会消耗 RX FIFO 数据的 SSIDR,也跳过只写的 SSITLOAD。
6. 行为约束与规格书流程
6.1 软件配置流程对齐
规格书要求在使能 SPI 前完成 GPIO、时钟、IRQ mask、错误清除、FIFO flush、协议、时钟、阈值、帧宽、interval 和 RCNT 等配置。
当前分层关系如下:
| 规格书步骤 | 负责方 |
|---|---|
| GPIO pinmux | BSP/平台 |
| CPM module clock/gate | HAL init/deinit |
| SoC IRQ request/enable | HAL 上层调用方 |
| SPI 内部 IRQ source | HAL hal_spi_irq_config() |
| 清 TUNDR/ROVER/END 和 flush FIFO | HAL 接口及上层传输流程 |
| SPI serial clock、协议、位宽、interval | HAL init/hal_spi_set_clock() |
| RCNT 和传输期 threshold | HAL 上层调用方 |
| FIFO CPU/DMA 搬运 | HAL 上层调用方 |
| enable/disable | HAL 上层调用方通过 HAL 接口控制 |
hal_spi_init() 完成静态配置后保持控制器 disabled。上层应在 FIFO、RCNT、IRQ 或 DMA 等传输资源准备完成后再调用 hal_spi_enable()。