API GUIDE / TPC / HAL
G32S10 TPC HAL 接口
HAL 层接口:本文档描述 G32S10 SDK 的 TPC(热敏打印头控制器)HAL 与 LL 接口。
1. 文档范围
本文档描述 G32S10 SDK 的 TPC(热敏打印头控制器)HAL 与 LL 接口。TPC 同时驱动打印头 移位、锁存、加热、步进电机和内部 WDT;一次完整打印通常由这些子模块按确定顺序协同完成。
2. HAL 公开宏、类型与结构
2.1 HAL 公开宏
HAL 公开宏用于描述实例、容量上限、DMA 粒度、模块数量和中断 mask:
| 宏 | 使用说明 | 取值或约束 |
|---|---|---|
IS_TPC_ALL_INSTANCE(instance) | 检查实例是否为当前 SDK 支持的 TPC。 | HAL 配置和启动接口最终要求实例为 TPC。 |
HAL_TPC_SHIFT_CHANNEL_MAX | 移位通道数上限。 | 16。 |
HAL_TPC_HEAT_CHANNEL_MAX | 加热通道数上限。 | 4。 |
HAL_TPC_MOTOR_COUNT | 电机控制器数量。 | 2,对应 Motor0/Motor1。 |
HAL_TPC_MOTOR_CHANNEL_COUNT | 每个电机控制器可配置的输出通道数上限。 | 8。Motor1 和 Motor0 的组合场景还有额外约束。 |
HAL_TPC_MOTOR_CHANNEL_MAX | 电机输出通道最大索引。 | 7。 |
HAL_TPC_MOTOR_REPEAT_STEP_MAX | 电机重复步数上限。 | 64。 |
HAL_TPC_CYCLE_24BIT_MAX | 24 位周期字段最大值。 | 0x00FF_FFFF。 |
HAL_TPC_SHIFT_SETUP_HOLD_CYCLE_MAX | 移位 setup/hold 字段最大值。 | 3。 |
HAL_TPC_WDT_CLOCK_DIV_MAX | WDT 有效分频字段最大值。 | 5;6、7 为保留值。 |
HAL_TPC_DMA_UNIT_SIZE | FIFO/DMA 基本访问粒度。 | 4 字节。 |
HAL_TPC_MODULE_COUNT | HAL 软件活动状态跟踪的模块数。 | 6:Shift、Latch、Heat、Motor0、Motor1、Sync。 |
HAL_TPC_CALLBACK_COUNT | 公开回调槽数量。 | 7。 |
HAL_TPC_INTERRUPT_MASK_ALL | 所有受支持的 TPC 中断源 mask。 | 由公开的 TPC_INT_* 位按位或组成。 |
CONFIG_TPC_ENABLE_DEBUG_HELPERS | 可选调试助手开关。 | 未定义时按 0 处理;hal_tpc_regs_dump() 还需要 CONFIG_SDK_ENABLE_DEBUG_HELPERS。 |
2.2 回调 ID
typedef enum {
HAL_TPC_CALLBACK_SHIFT = 0U,
HAL_TPC_CALLBACK_LATCH = 1U,
HAL_TPC_CALLBACK_HEAT = 2U,
HAL_TPC_CALLBACK_MOTOR0 = 3U,
HAL_TPC_CALLBACK_MOTOR1 = 4U,
HAL_TPC_CALLBACK_SYNC = 5U,
HAL_TPC_CALLBACK_WDT = 6U,
} hal_tpc_callback_id_t;hal_tpc_callback_id_t 决定事件分发到哪个回调:
| 回调槽 | 收到的 HAL_TPC_EVENT_* |
|---|---|
HAL_TPC_CALLBACK_SHIFT | SHIFT_FINISH;另有 SHIFT_FIFO_UNDERRUN(独立一次调用) |
HAL_TPC_CALLBACK_LATCH | LATCH_FINISH |
HAL_TPC_CALLBACK_HEAT | HEAT_FINISH;另有 HEAT_FIFO_UNDERRUN、HEAT_OVERTIME(各独立一次调用) |
HAL_TPC_CALLBACK_MOTOR0 | MOTOR0_FINISH / MOTOR0_START_STEP / MOTOR0_REPEAT_STEP 合并为一次调用;另有 MOTOR0_FIFO_UNDERRUN、MOTOR0_OVERTIME 各独立一次调用 |
HAL_TPC_CALLBACK_MOTOR1 | 同 Motor0,事件前缀为 MOTOR1_* |
HAL_TPC_CALLBACK_SYNC | PRINT_HEAD_FINISH 与 AUTO_ALIGN_FINISH 合并为一次调用;另有 SYNC_ERROR 独立一次调用 |
HAL_TPC_CALLBACK_WDT | WDT_HALF / WDT_FULL 合并为一次调用 |
2.3 事件标志
HAL_TPC_EVENT_* 与 TPC_INT_* 的位值一一对应:
| 事件 | 位 |
|---|---|
HAL_TPC_EVENT_NONE | 0 |
HAL_TPC_EVENT_PRINT_HEAD_FINISH | bit0 |
HAL_TPC_EVENT_SHIFT_FINISH | bit1 |
HAL_TPC_EVENT_LATCH_FINISH | bit2 |
HAL_TPC_EVENT_HEAT_FINISH | bit3 |
HAL_TPC_EVENT_SHIFT_FIFO_UNDERRUN | bit4 |
HAL_TPC_EVENT_HEAT_FIFO_UNDERRUN | bit5 |
HAL_TPC_EVENT_HEAT_OVERTIME | bit6 |
HAL_TPC_EVENT_MOTOR0_FINISH / HAL_TPC_EVENT_MOTOR0_START_STEP / HAL_TPC_EVENT_MOTOR0_REPEAT_STEP | bit8 / bit9 / bit10 |
HAL_TPC_EVENT_MOTOR0_FIFO_UNDERRUN / HAL_TPC_EVENT_MOTOR0_OVERTIME | bit11 / bit12 |
HAL_TPC_EVENT_MOTOR1_FINISH / HAL_TPC_EVENT_MOTOR1_START_STEP / HAL_TPC_EVENT_MOTOR1_REPEAT_STEP | bit16 / bit17 / bit18 |
HAL_TPC_EVENT_MOTOR1_FIFO_UNDERRUN / HAL_TPC_EVENT_MOTOR1_OVERTIME | bit19 / bit20 |
HAL_TPC_EVENT_AUTO_ALIGN_FINISH / HAL_TPC_EVENT_SYNC_ERROR | bit24 / bit25 |
HAL_TPC_EVENT_WDT_HALF / HAL_TPC_EVENT_WDT_FULL | bit30 / bit31 |
聚合宏便于判定错误:
| 宏 | 组成 |
|---|---|
HAL_TPC_EVENT_SHIFT_ERROR | HAL_TPC_EVENT_SHIFT_FIFO_UNDERRUN |
HAL_TPC_EVENT_HEAT_ERROR | HAL_TPC_EVENT_HEAT_FIFO_UNDERRUN 与 HAL_TPC_EVENT_HEAT_OVERTIME |
HAL_TPC_EVENT_MOTOR0_ERROR / HAL_TPC_EVENT_MOTOR1_ERROR | 对应的 FIFO_UNDERRUN 与 OVERTIME |
HAL_TPC_EVENT_SYNC_ERROR | TPC_INT_AUTO_ALIGN_ERROR(对应 bit25) |
2.4 HAL 运行状态
typedef enum {
HAL_TPC_STATE_RESET = 0,
HAL_TPC_STATE_READY,
HAL_TPC_STATE_BUSY,
} hal_tpc_state_t;RESET 表示尚未执行 hal_tpc_init() 或已经执行 hal_tpc_deinit();有活动模块时,状态
查询会报告 BUSY。
2.5 TPC 子模块选择
typedef enum {
HAL_TPC_MODULE_SHIFT = 0U,
HAL_TPC_MODULE_LATCH = 1U,
HAL_TPC_MODULE_HEAT = 2U,
HAL_TPC_MODULE_MOTOR0 = 3U,
HAL_TPC_MODULE_MOTOR1 = 4U,
HAL_TPC_MODULE_SYNC = 5U,
} hal_tpc_module_t;枚举值同时表示 configured_module_mask / active_module_mask 的位序。
2.6 DMA 与停止模式
typedef enum {
HAL_TPC_DMA_MODE_SINGLE = 0U,
HAL_TPC_DMA_MODE_CYCLIC = 1U,
} hal_tpc_dma_mode_t;
typedef enum {
HAL_TPC_STOP_MODE_NORMAL = 0U,
HAL_TPC_STOP_MODE_QUICK = 1U,
} hal_tpc_stop_mode_t;HAL_TPC_DMA_MODE_SINGLE使用非描述符传输;HAL_TPC_DMA_MODE_CYCLIC使用调用方 提供的描述符缓冲区。HAL_TPC_STOP_MODE_NORMAL在支持的场景等待当前传输或描述符结束;QUICK立即停止。单模块 start 接口在
CYCLIC且descriptor_count = 0U时默认使用 2 个描述符。
2.7 移位、加热与电平枚举
typedef enum {
HAL_TPC_SHIFT_ENDIAN_BIG = TPC_SHIFT_ENDIAN_BIG,
HAL_TPC_SHIFT_ENDIAN_LITTLE = TPC_SHIFT_ENDIAN_LITTLE,
} hal_tpc_shift_endian_t;
typedef enum {
HAL_TPC_SHIFT_SPI_POLARITY_IDLE_LOW = TPC_SHIFT_SPI_POLARITY_IDLE_LOW,
HAL_TPC_SHIFT_SPI_POLARITY_IDLE_HIGH = TPC_SHIFT_SPI_POLARITY_IDLE_HIGH,
} hal_tpc_shift_spi_polarity_t;
typedef enum {
HAL_TPC_SHIFT_SPI_PHASE_FIRST_EDGE = TPC_SHIFT_SPI_PHASE_FIRST_EDGE,
HAL_TPC_SHIFT_SPI_PHASE_SECOND_EDGE = TPC_SHIFT_SPI_PHASE_SECOND_EDGE,
} hal_tpc_shift_spi_phase_t;
typedef enum {
HAL_TPC_LEVEL_LOW = 0U,
HAL_TPC_LEVEL_HIGH = 1U,
} hal_tpc_level_t;
typedef enum {
HAL_TPC_HEAT_NEXT_TRIGGER_MOTOR = 0U,
HAL_TPC_HEAT_NEXT_TRIGGER_LATCH = 1U,
} hal_tpc_heat_next_trigger_t;
typedef enum {
HAL_TPC_HEAT_OUTPUT_DISABLE = 0U,
HAL_TPC_HEAT_OUTPUT_ENABLE = 1U,
} hal_tpc_heat_output_t;hal_tpc_level_t用于移位、锁存和加热的空闲电平。hal_tpc_heat_next_trigger_t决定一个加热数据单元结束后由电机还是锁存器触发下一单元。hal_tpc_heat_output_t只表示当前加热通道字是否使能输出。
2.8 回调类型
typedef struct hal_tpc_handle hal_tpc_handle_t; typedef void (*hal_tpc_callback_t)(hal_tpc_handle_t *htpc, uint32_t event_mask);
event_mask 使用 HAL_TPC_EVENT_* 位。回调可能运行在 IRQ_TPC 中断上下文,必须短小、
不可阻塞;应用上下文通过 hal_tpc_handle_t::user_data 传递。
2.9 配置结构体通用约定
4.10 至 4.14 的配置结构体建议先用对应的 hal_tpc_*_config_default() 填默认值,再修改
需要的字段。HAL 不保留配置结构体指针,配置完成后结构体可复用或释放;但 dma_desc指向的描述符缓冲区会在首次配置时绑定给 DMA 句柄,生命周期要求见 10.3。
2.10 移位配置
typedef struct {
uint8_t idle_level; /**< 数据线空闲电平,使用 hal_tpc_level_t。 */
uint8_t endian; /**< 移位位序,使用 hal_tpc_shift_endian_t。 */
uint8_t spi_polarity; /**< SPI 时钟极性选择。 */
uint8_t spi_phase; /**< SPI 采样相位选择。 */
uint8_t setup_cycle; /**< 数据建立周期,范围 0 ~ 3。 */
uint8_t hold_cycle; /**< 数据保持周期,范围 0 ~ 3。 */
uint8_t channel_count; /**< 打印头移位通道数,范围 1 ~ 16。 */
uint8_t data_invert; /**< 非 0 表示反转移位数据。 */
uint16_t line_bytes; /**< 一行在全部移位通道上的总字节数。 */
uint8_t clock_div; /**< PDSCD.PRESCALE 原始字段值。 */
void *dma_desc; /**< 循环 DMA 描述符缓冲区,可为 NULL。 */
uint32_t dma_desc_count; /**< dma_desc 容量;dma_desc 为 NULL 时为 0。 */
} hal_tpc_shift_config_t;关键约束:
idle_level、endian、spi_polarity、spi_phase、data_invert必须使用 0/1 或对应枚举。setup_cycle/hold_cycle为 0 ~ 3;channel_count为 1 ~ 16。line_bytes必须非 0 并能被channel_count整除;每通道字节数在 1 ~ 4 通道时最多 256,在 5 ~ 16 通道时最多 128。clock_div是PDSCD.PRESCALE原始值,HAL 不把 Hz 自动换算成该字段。dma_desc与dma_desc_count必须同时为NULL/ 0,或同时提供并满足对齐和数量上限。
默认值:空闲低电平、大端、SPI 空闲低/第一边沿、setup/hold 为 0、1 通道、line_bytes = 4、不反相、clock_div = 0、无描述符。
2.11 锁存配置
typedef struct {
uint8_t idle_level; /**< 锁存线空闲电平,使用 hal_tpc_level_t。 */
uint32_t wait_cycle; /**< 锁存输出前等待周期,范围 0 ~ 0xFFFFFF。 */
uint32_t active_cycle; /**< 锁存有效周期,范围 0 ~ 0xFFFFFF。 */
uint32_t shift_wait_cycle; /**< 同步模式锁存到下次移位的间隔周期。 */
} hal_tpc_latch_config_t;关键约束:idle_level 为 0/1;三个周期字段均为 0 ~ 0x00FFFFFF 个功能时钟周期。shift_wait_cycle 写入 PDSWC,用于锁存到下一次移位的间隔。默认配置全部为 0,
空闲电平为低。
2.12 加热配置
typedef struct {
uint8_t idle_level; /**< 加热线空闲电平,使用 hal_tpc_level_t。 */
uint8_t channel_count; /**< 加热通道数,范围 1 ~ 4。 */
uint32_t wait_cycle; /**< 加热输出前等待周期,范围 0 ~ 0xFFFFFF。 */
uint32_t max_cycle; /**< 单次加热最大有效周期,范围 0 ~ 0xFFFFFF。 */
void *dma_desc; /**< 循环 DMA 描述符缓冲区,可为 NULL。 */
uint32_t dma_desc_count; /**< dma_desc 容量;dma_desc 为 NULL 时为 0。 */
} hal_tpc_heat_config_t;关键约束:
idle_level为 0/1;channel_count为 1 ~ 4。每个加热数据单元包含
channel_count + 1个 32 位字。wait_cycle/max_cycle为 0 ~0x00FFFFFF个功能时钟周期。描述符字段的约束与 4.10 相同。
默认值:空闲低电平、1 通道、等待和最大加热周期均为 0、无描述符。
2.13 电机配置
typedef struct {
uint8_t motor_id; /**< 电机控制器索引,0 或 1。 */
uint8_t channel_count; /**< 电机输出通道数,范围 1 ~ 8。 */
uint8_t idle_level_mask; /**< 每 bit 对应一个通道的空闲电平。 */
uint8_t start_level_mask; /**< 每 bit 对应一个通道的开始步电平。 */
uint8_t end_level_mask; /**< 每 bit 对应一个通道的结束步电平。 */
uint32_t start_step_cycle; /**< 开始步周期数。 */
uint32_t end_step_cycle; /**< 结束步周期数。 */
uint8_t repeat_step_count; /**< 重复步数,范围 1 ~ 64。 */
uint8_t align_step_index; /**< 对齐步索引,范围 1 ~ repeat_step_count。 */
uint64_t repeat_level[HAL_TPC_MOTOR_CHANNEL_COUNT]; /**< 每通道 64 个重复步的输出电平。 */
uint32_t max_step_cycle; /**< 单步最大周期数。 */
void *dma_desc; /**< 循环 DMA 描述符缓冲区,可为 NULL。 */
uint32_t dma_desc_count; /**< dma_desc 容量;dma_desc 为 NULL 时为 0。 */
} hal_tpc_motor_config_t;关键约束:
motor_id为 0/1;channel_count为 1 ~ 8,但 Motor1 最多 4 通道。Motor0 使用 5 ~ 8 通道时会占用 Motor1 的通道,因此 Motor1 不能再配置。
repeat_step_count为 1 ~ 64;align_step_index必须落在1 ~ repeat_step_count,两者都从 1 开始计数。start_step_cycle、end_step_cycle、max_step_cycle为 0 ~0x00FFFFFF。repeat_level[channel]的每个 bit 对应一个重复步输出电平,共使用最多 64 bit。描述符字段的约束与 4.10 相同。
默认值:Motor0、1 通道、电平 mask 为 0、周期为 0、1 个重复步、align_step_index = 1、repeat_level[] 全 0、无描述符。
2.14 WDT 配置
typedef struct {
uint16_t half_threshold; /**< WDT 半阈值字段。 */
uint16_t full_threshold; /**< WDT 满阈值字段。 */
uint8_t clock_div; /**< WDT 时钟分频字段,范围 0 ~ 5。 */
uint8_t rtc_clock_enable; /**< 非 0 表示使用 RTC 时钟输入。 */
} hal_tpc_wdt_config_t;关键约束:
half_threshold/full_threshold可写uint16_t全范围。clock_div的有效值为 0 ~ 5;6、7 为保留编码。rtc_clock_enable为 0/1。
默认值:两个阈值和分频均为 0,使用模块时钟。
2.15 模块状态
typedef struct {
uint8_t configured; /**< 非 0 表示模块已经成功配置。 */
uint8_t active; /**< 非 0 表示 HAL 仍将模块记录为活动。 */
} hal_tpc_status_t;configured非 0 表示该模块已经成功配置。active非 0 表示 HAL 仍把该模块记录为活动状态。状态由
hal_tpc_status_get()读取,应用不应直接修改句柄内部掩码。
2.16 HAL 句柄
typedef struct hal_tpc_handle hal_tpc_handle_t;
struct hal_tpc_handle {
tpc_regs_t *instance; /**< TPC 寄存器块基址,通常为 TPC。 */
hal_tpc_state_t state; /**< HAL 模块级运行状态。 */
uint32_t configured_module_mask; /**< HAL 已配置模块的 mask。 */
uint32_t active_module_mask; /**< HAL 跟踪的活动模块 mask。 */
uint32_t configured_interrupt_mask; /**< HAL 已放行的 TPC 中断 mask。 */
uint32_t unit_size[HAL_TPC_MODULE_COUNT]; /**< 各模块 DMA 逻辑单元大小,单位字节。 */
uint8_t motor_channel_count[HAL_TPC_MOTOR_COUNT]; /**< 两路电机已配置的通道数。 */
uint8_t sync_motor_enable; /**< 非 0 表示同步模式使用电机。 */
uint8_t sync_motor_id; /**< 同步模式使用的电机索引。 */
void *user_data; /**< 应用私有上下文,HAL 不解释。 */
hal_dma_handle_t shift_dma; /**< HAL 持有的移位 DMA handle。 */
hal_dma_handle_t heat_dma; /**< HAL 持有的加热 DMA handle。 */
hal_dma_handle_t motor_dma[HAL_TPC_MOTOR_COUNT]; /**< HAL 持有的电机 DMA handle。 */
hal_tpc_callback_t shift_callback; /**< 移位完成/错误回调。 */
hal_tpc_callback_t latch_callback; /**< 锁存完成回调。 */
hal_tpc_callback_t heat_callback; /**< 加热完成/错误回调。 */
hal_tpc_callback_t motor0_callback; /**< Motor0 完成/重复步/错误回调。 */
hal_tpc_callback_t motor1_callback; /**< Motor1 完成/重复步/错误回调。 */
hal_tpc_callback_t sync_callback; /**< 同步完成/错误回调。 */
hal_tpc_callback_t wdt_callback; /**< WDT 半满/全满回调。 */
};各字段的所有权和用法:
instance由调用方通过hal_tpc_handle_init()绑定,必须是TPC。state、模块 mask、中断 mask、unit_size[]、motor_channel_count[]、sync_motor_enable和sync_motor_id由 HAL 维护,应用只读。user_data归应用使用;HAL 只在初始化时清 0,并在hal_tpc_deinit()时再次清 0。shift_dma、heat_dma、motor_dma[]由 HAL 打开、使用和关闭;应用不要直接操作。DMA descriptor 存储仍由调用方持有,生命周期必须覆盖首次配置、DMA 运行和停止过程。
*_callback通过hal_tpc_callback_register()设置;初始为内部空回调。
3. HAL 使用流程
3.1 前置条件
使能 TPC 模块时钟与门控(CPM),必要时先做一次 TPC 软件复位;
初始化 SDK 时间基准(systick),启动/停止 API 会用到
im_time_*;若使用回调或中断驱动路径,注册并使能
IRQ_TPC,并在中断服务函数里调用hal_tpc_irq_handler();纯轮询路径不需要注册该 IRQ;确认 TPC 引脚已由 BSP pinmux 配置为 TPC 功能;HAL 不管理任何 GPIO。
3.2 初始化与反初始化
static hal_tpc_handle_t s_tpc; hal_tpc_handle_init(&s_tpc, TPC); /* 只准备软件句柄,state = RESET */ hal_tpc_init(&s_tpc); /* 屏蔽中断、清状态、关打印头与电机,state = READY */
hal_tpc_init() 不会做 CPM 复位、不打开 DMA 通道,也不触碰 GPIO。同一次上电内继续
使用 TPC 需要重新 hal_tpc_init():
hal_tpc_deinit(&s_tpc); /* 所有模块必须已停止,否则返回 IM_ERR_BUSY */ hal_tpc_init(&s_tpc); /* deinit 后 instance 仍保留,可直接重新初始化硬件状态 */
hal_tpc_deinit() 会先回收、再关闭已配置模块的 DMA 通道,并把句柄恢复到 RESET。
当前实现会忽略 DMA reap/close 的返回值,因此该 API 在参数有效且没有活动模块时返回IM_OK。公开头文件的通用说明保留了“其它错误码”的描述,但当前 .c 实现不向上传播
这些清理错误;需要严格确认 DMA 资源状态时,应在 deinit 前检查共享 DMA 管理器的状态。
WDT 不参与模块活动掩码,hal_tpc_init() / hal_tpc_deinit() 也不停止 WDT;若启用了
WDT,应按业务要求先调用 hal_tpc_wdt_disable()。
3.3 调用顺序总览
正常 HAL 生命周期如下:
板级准备(CPM、pinmux、systick) -> hal_tpc_handle_init() -> hal_tpc_init() -> *_config_default() + *_config() -> callback_register() + interrupt_enable() + 注册并使能 IRQ_TPC(可选) -> *_start() -> 等待 FINISH 回调,或轮询状态 -> *_stop() -> hal_tpc_deinit()
需要区分三个时刻:
带 DMA 的
shift/heat/motor/sync_write启动返回成功,只表示 DMA 已启动、FIFO 已 装入首批数据且硬件启动命令已发出,不表示本次传输或打印过程已经结束。Latch 不使用 DMA,成功只表示锁存事件已启动。使用中断路径时,应以对应回调或
hal_tpc_status_get()的active状态判断结束; 使用轮询路径时,不能仅凭*_start()成功就调用下一次启动。只有活动模块都停止后才能
hal_tpc_deinit()。错误事件不会自动清活动状态,应用需 选择重试、停止或整体复位。
3.4 手动单模块流程
手动模式指各子模块独立启动,不由 TPC 自动对齐流程串联。典型顺序为 “配置 → 启动 → 等回调或轮询 → 停止”:
static hal_tpc_handle_t s_tpc; static uint32_t s_line_words[12]; /* 48 字节一行 */ hal_tpc_shift_config_t shift; /* 前置:已执行 hal_tpc_handle_init() + hal_tpc_init()(见 5.2) */ hal_tpc_shift_config_default(&shift); shift.channel_count = 1U; shift.line_bytes = 48U; shift.clock_div = 1U; /* 24 MHz 功能时钟 → 12 MHz 移位时钟,见 9.2 */ hal_tpc_shift_config(&s_tpc, &shift); /* 首次调用会打开移位 DMA 通道 */ /* 使用回调时,还必须像 5.6 所示注册 IRQ_TPC 并调用过 hal_tpc_irq_handler() */ hal_tpc_interrupt_enable(&s_tpc, HAL_TPC_EVENT_SHIFT_FINISH); hal_tpc_shift_start(&s_tpc, s_line_words, sizeof(s_line_words), HAL_TPC_DMA_MODE_SINGLE, 0U); /* SHIFT_FINISH 回调或轮询 hal_tpc_status_get() 之后 */ hal_tpc_shift_stop(&s_tpc, HAL_TPC_STOP_MODE_QUICK, NULL);
各模块的对应关系:
| 模块 | 配置 | 启动 | 停止 | DMA |
|---|---|---|---|---|
| Shift | hal_tpc_shift_config() | hal_tpc_shift_start() | hal_tpc_shift_stop() | 需要(HAL_DMA_REQUEST_TPC_SHIFT_TX) |
| Latch | hal_tpc_latch_config() | hal_tpc_latch_start() | hal_tpc_latch_stop() | 不需要 |
| Heat | hal_tpc_heat_config() | hal_tpc_heat_start() | hal_tpc_heat_stop() | 需要(HAL_DMA_REQUEST_TPC_DEST_TX) |
| Motor0/1 | hal_tpc_motor_config() | hal_tpc_motor_start() | hal_tpc_motor_stop() | 需要(HAL_DMA_REQUEST_TPC_STEP_MOTO0_TX / _MOTO1_TX) |
Latch 没有数据负载:hal_tpc_latch_start() 只触发一次锁存脉冲,hal_tpc_latch_stop()固定执行硬件急停。
3.5 同步(自动对齐)流程
同步模式由 TPC 自动对齐流程串联打印头和电机,顺序固定为
“配置 → sync_write 装窗口 → sync_start → 运行中更新窗口 → sync_stream_end 收尾 →sync_stop 清理”:
/* 1. shift / latch / heat(使用电机时再加 motor)必须先配置 */ hal_tpc_sync_config(&s_tpc, 1U, 0U); /* 使用 Motor0 做自动对齐 */ /* 2. 装入循环 DMA 窗口;配置时给出的 descriptor capacity 必须足够 */ hal_tpc_sync_write(&s_tpc, shift_win, shift_len, heat_win, heat_len, motor_win, motor_len); /* 3. 启动硬件流程:有电机走 PAFC 自动对齐,无电机只启动加热流程 */ hal_tpc_sync_start(&s_tpc); /* 4. 运行中由应用负责写位置跟踪和窗口更新(HAL 不跟踪写指针) */ /* 5. 最后一份数据写入后断开循环链接,让 DMA 自然收尾 */ hal_tpc_sync_stream_end(&s_tpc, shift_last, heat_last, motor_last); /* 6. 收到 PRINT_HEAD_FINISH / AUTO_ALIGN_FINISH 后清理 */ hal_tpc_sync_stop(&s_tpc, HAL_TPC_STOP_MODE_QUICK, NULL, NULL, NULL);
要点:
hal_tpc_sync_config()要求 shift、latch、heat 已配置;motor_enable非 0 时还要 求指定电机已配置,否则返回IM_ERR_NOT_READY。hal_tpc_sync_write()固定用循环 DMA 启动各路窗口。HAL 先算逻辑单元数len / unit_size,再由它选择描述符数;每路必须能拆成至少 2 个、不超过HAL_DMA_MAX_DESCRIPTOR_COUNT(128)个等长描述符,调用方提供的dma_desc_count必须覆盖该选择。单描述符窗口会被拒绝。hal_tpc_sync_stream_end()只能用于描述符循环窗口:它依赖描述符的 LINK 位 (hal_dma_stop_after_current_transfer()),并按 Motor → Shift → Heat 断链。断链粒度是描述符,不是逻辑单元。
*_last_mem用于定位包含最后数据的描述符;该 描述符中的剩余单元仍可能被硬件完成。应用应像现有示例一样预留收尾/排空数据,或保证 最后数据位于描述符边界。应用若在循环窗口运行期间改写数据,必须自行维护写位置、避免覆盖尚未被 DMA 读取的 数据,并在写完后自行做 cache clean;HAL 只在
hal_tpc_sync_write()首次启动时清理 传入缓冲区。自动对齐要求对齐步索引与打印头结算节奏匹配:
align_step_index必须落在1 ~ repeat_step_count内,常见做法是取repeat_step_count(一个电机行周期的 最后一步)作为对齐点。
3.6 中断与回调
static void tpc_irq(uint32_t irq_id, void *arg)
{
(void)irq_id;
hal_tpc_irq_handler((hal_tpc_handle_t *)arg);
}
hal_tpc_callback_register(&s_tpc, HAL_TPC_CALLBACK_SHIFT, on_shift_event);
hal_tpc_interrupt_enable(&s_tpc, HAL_TPC_EVENT_SHIFT_FINISH |
HAL_TPC_EVENT_SHIFT_FIFO_UNDERRUN);
(void)im_irq_request((uint32_t)IRQ_TPC, tpc_irq, "tpc", &s_tpc);
(void)im_irq_enable((uint32_t)IRQ_TPC);hal_tpc_irq_handler() 的行为:
读取
(PINTS & ~PINTM0) & HAL_TPC_INTERRUPT_MASK_ALL得到受支持的未屏蔽挂起位, 为 0 立即返回;用
PINTS = pending清掉本次处理的挂起位(RW1C);按模块分发回调;
FINISH且同模块没有错误位时把该模块从活动掩码清除,活动掩码 清空后state回到READY;错误事件只上报:不自动停机、不清活动掩码。恢复策略由应用决定,且
*_stop()可能等待硬件,必要时放到任务上下文执行。
TPC HAL 不注册也不拥有 IRQ_PDMA0 / IRQ_PDMA0_DIP。连续手动请求在对应 TPC
模块已完成、DMA handle 仍为 BUSY 时,由下一次 start 或 deinit 回收该 handle;
若系统需要统一 DMA 完成回调或 DMA 错误明细,应由唯一 DMA owner 注册 PDMA IRQ,
TPC 应用不得再次注册同一共享中断。
回调运行在中断上下文,必须短小、不可阻塞;应用上下文通过hal_tpc_handle_t::user_data 传递。
3.7 WDT 流程
hal_tpc_wdt_config_t wdt; uint32_t counter; hal_tpc_wdt_config_default(&wdt); wdt.half_threshold = 0x0800U; wdt.full_threshold = 0x1000U; hal_tpc_wdt_config(&s_tpc, &wdt); /* WDT 已使能时返回 IM_ERR_BUSY */ hal_tpc_interrupt_enable(&s_tpc, HAL_TPC_EVENT_WDT_HALF | HAL_TPC_EVENT_WDT_FULL); hal_tpc_wdt_enable(&s_tpc); /* 需要时 */ hal_tpc_wdt_counter_clear(&s_tpc); (void)hal_tpc_wdt_counter_get(&s_tpc, &counter); hal_tpc_wdt_disable(&s_tpc);
4. HAL 接口规范
本章每个接口统一按以下顺序说明:
函数原型;
功能说明;
参数表;
返回值表;
补充说明。
无参数接口仍保留参数表并明确写“无”;无失败返回值的接口在返回值表中写“无返回值”。
除特别说明外,空句柄、空必需指针或非法枚举/索引均返回 IM_ERR_INVALID_PARAM。
4.1 默认值与数据构造
4.1.1 hal_tpc_shift_config_default
error_code_t hal_tpc_shift_config_default(hal_tpc_shift_config_t *config);
功能说明:填入移位默认配置(见 4.10),不访问硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
config | hal_tpc_shift_config_t * | 输出 | 待填充的移位配置,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 默认配置已填入 |
IM_ERR_INVALID_PARAM | config == NULL |
补充说明:默认值及字段约束见 4.10。
4.1.2 hal_tpc_latch_config_default
error_code_t hal_tpc_latch_config_default(hal_tpc_latch_config_t *config);
功能说明:填入锁存默认配置(见 4.11),不访问硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
config | hal_tpc_latch_config_t * | 输出 | 待填充的锁存配置,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 默认配置已填入 |
IM_ERR_INVALID_PARAM | config == NULL |
补充说明:默认值及字段约束见 4.11。
4.1.3 hal_tpc_heat_config_default
error_code_t hal_tpc_heat_config_default(hal_tpc_heat_config_t *config);
功能说明:填入加热默认配置(见 4.12),不访问硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
config | hal_tpc_heat_config_t * | 输出 | 待填充的加热配置,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 默认配置已填入 |
IM_ERR_INVALID_PARAM | config == NULL |
补充说明:默认值及字段约束见 4.12。
4.1.4 hal_tpc_motor_config_default
error_code_t hal_tpc_motor_config_default(hal_tpc_motor_config_t *config);
功能说明:填入电机默认配置(见 4.13),不访问硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
config | hal_tpc_motor_config_t * | 输出 | 待填充的电机配置,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 默认配置已填入 |
IM_ERR_INVALID_PARAM | config == NULL |
补充说明:默认选择 Motor0、1 通道、1 个重复步,align_step_index = 1,repeat_level[] 全 0。
4.1.5 hal_tpc_wdt_config_default
error_code_t hal_tpc_wdt_config_default(hal_tpc_wdt_config_t *config);
功能说明:填入 WDT 默认配置(见 4.14),不访问硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
config | hal_tpc_wdt_config_t * | 输出 | 待填充的 WDT 配置,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 默认配置已填入 |
IM_ERR_INVALID_PARAM | config == NULL |
补充说明:两个阈值和分频默认为 0,并使用模块时钟。
4.1.6 hal_tpc_heat_next_word_build
uint32_t hal_tpc_heat_next_word_build( uint32_t wait_cycle, hal_tpc_heat_next_trigger_t next_trigger);
功能说明:构造一个加热数据单元的首字(下一单元触发/等待字)。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
wait_cycle | uint32_t | 输入 | 本单元到下一单元的等待周期,有效范围 0 ~ 0x00FFFFFF |
next_trigger | hal_tpc_heat_next_trigger_t | 输入 | HAL_TPC_HEAT_NEXT_TRIGGER_MOTOR 或 HAL_TPC_HEAT_NEXT_TRIGGER_LATCH |
返回值表:
| 返回值 | 说明 |
|---|---|
uint32_t | 编码后的 FIFO 数据字,不是 error_code_t |
补充说明:该函数不做参数范围校验,并直接按字段 mask 截取 wait_cycle。
4.1.7 hal_tpc_heat_channel_word_build
uint32_t hal_tpc_heat_channel_word_build( uint32_t heat_cycle, hal_tpc_heat_output_t output);
功能说明:构造一个加热数据单元中的通道字。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
heat_cycle | uint32_t | 输入 | 该通道加热周期,有效范围 0 ~ 0x00FFFFFF |
output | hal_tpc_heat_output_t | 输入 | HAL_TPC_HEAT_OUTPUT_DISABLE 或 HAL_TPC_HEAT_OUTPUT_ENABLE |
返回值表:
| 返回值 | 说明 |
|---|---|
uint32_t | 编码后的 FIFO 数据字,不是 error_code_t |
补充说明:该函数不做参数范围校验,只把等于HAL_TPC_HEAT_OUTPUT_ENABLE 的值编码为输出使能。
4.2 生命周期
4.2.1 hal_tpc_handle_init
error_code_t hal_tpc_handle_init( hal_tpc_handle_t *htpc, tpc_regs_t *instance);
功能说明:清零并准备 HAL 软件句柄,绑定 TPC 实例和内部空回调。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输出 | 待初始化的 HAL 句柄,不能为 NULL |
instance | tpc_regs_t * | 输入 | TPC 寄存器块,必须是 TPC |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 软件句柄已初始化 |
IM_ERR_INVALID_PARAM | htpc == NULL 或 instance 不是 TPC |
补充说明:该接口只准备软件句柄,state = HAL_TPC_STATE_RESET;不访问硬件,也不打开 DMA。
4.2.2 hal_tpc_init
error_code_t hal_tpc_init(hal_tpc_handle_t *htpc);
功能说明:初始化 TPC 硬件运行状态,并关闭受 HAL 管理的打印头和电机使能。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | 已通过 hal_tpc_handle_init() 绑定的 HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 硬件运行状态已初始化,state = HAL_TPC_STATE_READY |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
IM_ERR_BUSY | 句柄不处于 HAL_TPC_STATE_RESET |
补充说明:该接口屏蔽全部中断并清 PINTS、关闭自动流程和两路电机、清空 HAL 运行时
状态;不执行 CPM 复位、不打开 DMA、不配置 GPIO,也不停止 WDT。
4.2.3 hal_tpc_deinit
error_code_t hal_tpc_deinit(hal_tpc_handle_t *htpc);
功能说明:关闭 HAL 管理的硬件功能并释放已配置模块的 DMA handle。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清理完成,state = HAL_TPC_STATE_RESET |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
IM_ERR_BUSY | active_module_mask != 0 |
补充说明:该接口回收并关闭已配置模块的 DMA handle,清空 HAL 运行时状态和user_data,恢复内部空回调。当前实现不传播 DMA reap/close 错误,也不关闭 WDT;需要
停止 WDT 时应先调用 hal_tpc_wdt_disable()。
4.3 配置
4.3.1 hal_tpc_shift_config
error_code_t hal_tpc_shift_config( hal_tpc_handle_t *htpc, const hal_tpc_shift_config_t *config);
功能说明:配置移位引擎;首次成功配置时打开移位 DMA 通道。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
config | const hal_tpc_shift_config_t * | 输入 | 移位配置,字段约束见 4.10 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 配置已写入 |
IM_ERR_INVALID_PARAM | 句柄或配置非法 |
IM_ERR_NOT_READY | 尚未执行 hal_tpc_init() |
IM_ERR_BUSY | 移位模块正在运行 |
| DMA 层错误 | 首次打开通道失败时透传 |
补充说明:写入 PDSCD、PDSBC、PDSDFC 并启用 Shift/Manual 打印头功能,FIFO 阈值
固定为 1。DMA 通道和描述符存储只在首次成功配置时确定;之后重新配置不会更换dma_desc 或 dma_desc_count。
4.3.2 hal_tpc_latch_config
error_code_t hal_tpc_latch_config( hal_tpc_handle_t *htpc, const hal_tpc_latch_config_t *config);
功能说明:配置锁存引擎并启用 Latch/Manual 打印头功能。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
config | const hal_tpc_latch_config_t * | 输入 | 锁存配置,字段约束见 4.11 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 配置已写入 |
IM_ERR_INVALID_PARAM | 句柄或配置非法 |
IM_ERR_NOT_READY | 尚未执行 hal_tpc_init() |
IM_ERR_BUSY | 锁存模块正在运行 |
补充说明:写入 PDLBC、PDLWC、PDLAC 和 PDSWC(shift_wait_cycle)。锁存不使用 DMA。
4.3.3 hal_tpc_heat_config
error_code_t hal_tpc_heat_config( hal_tpc_handle_t *htpc, const hal_tpc_heat_config_t *config);
功能说明:配置加热引擎;首次成功配置时打开加热 DMA 通道。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
config | const hal_tpc_heat_config_t * | 输入 | 加热配置,字段约束见 4.12 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 配置已写入 |
IM_ERR_INVALID_PARAM | 句柄或配置非法 |
IM_ERR_NOT_READY | 尚未执行 hal_tpc_init() |
IM_ERR_BUSY | 加热模块正在运行 |
| DMA 层错误 | 首次打开通道失败时透传 |
补充说明:写入 PDDBC、PDDWC、PDDMAC、PDDTFC 并启用 Heat/Manual 打印头功能,
FIFO 阈值固定为 1。DMA 描述符的首次绑定规则与 6.3.1 相同。
4.3.4 hal_tpc_motor_config
error_code_t hal_tpc_motor_config( hal_tpc_handle_t *htpc, const hal_tpc_motor_config_t *config);
功能说明:配置 Motor0 或 Motor1;首次成功配置时打开所选电机的 DMA 通道。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
config | const hal_tpc_motor_config_t * | 输入 | 电机配置,字段约束见 4.13 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 配置已写入 |
IM_ERR_INVALID_PARAM | 句柄或配置非法,包括 channel/repeat/align/descriptor 越界 |
IM_ERR_NOT_READY | 尚未执行 hal_tpc_init() |
IM_ERR_BUSY | 该电机正在运行,或 Motor0/Motor1 通道模式冲突 |
| DMA 层错误 | 首次打开所选电机 DMA 通道失败时透传 |
补充说明:写入 PMnBC、PMnSSC、PMnESC、PMnMSC、PMnTFC、PMCMS、PMCILC、PMCSLC、PMCELC 和 PMCcRLC0/1,最后启用电机自动模式和所选通道。
HAL 默认只放行 align_step_index 对应的重复步中断;如需自定义,可在配置后、启动前
4.3.5 hal_tpc_sync_config
error_code_t hal_tpc_sync_config( hal_tpc_handle_t *htpc, uint8_t motor_enable, uint8_t motor_id);
功能说明:配置同步/自动打印流程,并选择是否启用电机自动对齐。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
motor_enable | uint8_t | 输入 | 0 = 仅打印头自动流程;1 = 打印头与电机自动对齐 |
motor_id | uint8_t | 输入 | motor_enable = 1 时的电机索引,0/1 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 同步配置已写入 |
IM_ERR_INVALID_PARAM | 句柄非法、motor_enable 不是 0/1,或启用电机时 motor_id 非法 |
IM_ERR_NOT_READY | 尚未执行 hal_tpc_init(),或所需模块尚未配置 |
IM_ERR_BUSY | Sync 模块正在运行 |
补充说明:要求 Shift、Latch、Heat 已配置;motor_enable = 1 时还要求所选电机已配置。
配置会关闭 Manual 打印头模式、启用 Auto 模式;带电机时同时启用TPC_MOTOR_AUTO | TPC_MOTOR_AUTO_ALIGN、自动流程控制和TPC_PRINT_HEAD_AUTO_ALIGN。
4.4 启动
4.4.1 hal_tpc_shift_start
error_code_t hal_tpc_shift_start( hal_tpc_handle_t *htpc, void *buffer, uint32_t len, hal_tpc_dma_mode_t mode, uint32_t descriptor_count);
功能说明:启动一次移位 DMA 传输,并在 FIFO 有数据后启动移位硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
buffer | void * | 输入 | 源缓冲区,必须 4 字节对齐 |
len | uint32_t | 输入 | 字节数,必须同时是 4 和 line_bytes 的整数倍 |
mode | hal_tpc_dma_mode_t | 输入 | SINGLE 或 CYCLIC |
descriptor_count | uint32_t | 输入 | 仅 CYCLIC 使用;0 表示默认 2 个描述符 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | DMA 已启动、FIFO 已非空且移位硬件已启动 |
IM_ERR_INVALID_PARAM | 缓冲区、长度、模式或描述符配置非法 |
IM_ERR_NOT_READY | HAL 或 systick 尚未初始化,或移位尚未配置 |
IM_ERR_BUSY | 移位正在运行 |
IM_ERR_TIMEOUT | 等待 FIFO 非空超过 1 s,已停止刚启动的 DMA |
| DMA 层错误 | DMA 启动失败时透传 |
补充说明:启动前先回收旧 DMA handle,并对 buffer 做 cache data clean。函数成功返回时
只表示硬件流程已启动,不表示移位传输已经完成。
4.4.2 hal_tpc_heat_start
error_code_t hal_tpc_heat_start( hal_tpc_handle_t *htpc, void *buffer, uint32_t len, hal_tpc_dma_mode_t mode, uint32_t descriptor_count);
功能说明:启动一次加热 DMA 传输,并在 FIFO 有数据后启动加热硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
buffer | void * | 输入 | PDDTF 字流源缓冲区,必须 4 字节对齐 |
len | uint32_t | 输入 | 字节数,必须同时是 4 和 (channel_count + 1) * 4 的整数倍 |
mode | hal_tpc_dma_mode_t | 输入 | SINGLE 或 CYCLIC |
descriptor_count | uint32_t | 输入 | 仅 CYCLIC 使用;0 表示默认 2 个描述符 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | DMA 已启动、FIFO 已非空且加热硬件已启动 |
IM_ERR_INVALID_PARAM | 缓冲区、长度、模式或描述符配置非法 |
IM_ERR_NOT_READY | HAL 或 systick 尚未初始化,或加热尚未配置 |
IM_ERR_BUSY | 加热正在运行 |
IM_ERR_TIMEOUT | 等待 FIFO 非空超过 1 s,已停止刚启动的 DMA |
| DMA 层错误 | DMA 启动失败时透传 |
补充说明:每个加热数据单元包含 channel_count + 1 个字。word[0] 必须由hal_tpc_heat_next_word_build() 构造,后续通道字必须由hal_tpc_heat_channel_word_build() 构造,且数据中的通道数与配置一致。
4.4.3 hal_tpc_latch_start
error_code_t hal_tpc_latch_start(hal_tpc_handle_t *htpc);
功能说明:触发一次锁存脉冲,并把 Latch 模块标记为活动。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 锁存脉冲已触发 |
IM_ERR_INVALID_PARAM | 句柄非法 |
IM_ERR_NOT_READY | 尚未初始化或锁存尚未配置 |
IM_ERR_BUSY | 锁存正在运行 |
补充说明:锁存不使用 DMA 和 FIFO;成功返回只表示锁存脉冲已启动。
4.4.4 hal_tpc_motor_start
error_code_t hal_tpc_motor_start( hal_tpc_handle_t *htpc, uint8_t motor_id, void *buffer, uint32_t len, hal_tpc_dma_mode_t mode, uint32_t descriptor_count);
功能说明:启动所选电机的 DMA 传输,并在 FIFO 有数据后启动电机硬件。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
motor_id | uint8_t | 输入 | 电机索引,0/1 |
buffer | void * | 输入 | 电机周期字源缓冲区,必须 4 字节对齐 |
len | uint32_t | 输入 | 字节数,必须同时是 4 和 repeat_step_count * 4 的整数倍 |
mode | hal_tpc_dma_mode_t | 输入 | SINGLE 或 CYCLIC |
descriptor_count | uint32_t | 输入 | 仅 CYCLIC 使用;0 表示默认 2 个描述符 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | DMA 已启动、FIFO 已非空且电机硬件已启动 |
IM_ERR_INVALID_PARAM | 句柄、电机索引、缓冲区、长度、模式或描述符配置非法 |
IM_ERR_NOT_READY | HAL 或 systick 尚未初始化,或所选电机尚未配置 |
IM_ERR_BUSY | 所选电机正在运行 |
IM_ERR_TIMEOUT | 等待 FIFO 非空超过 1 s,已停止刚启动的 DMA |
| DMA 层错误 | DMA 启动失败时透传 |
补充说明:每个 DMA 单元包含 repeat_step_count 个“该拍周期”字;该拍输出电平来自先前
配置的 repeat_level[],最终写入 PMCcRLC0/1。
4.4.5 hal_tpc_sync_write
error_code_t hal_tpc_sync_write( hal_tpc_handle_t *htpc, void *shift_buffer, uint32_t shift_len, void *heat_buffer, uint32_t heat_len, void *motor_buffer, uint32_t motor_len);
功能说明:启动各路循环 DMA 窗口,并等待对应 FIFO 装入首批数据。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
shift_buffer / shift_len | void * / uint32_t | 输入 | 移位窗口及字节长度,约束同 hal_tpc_shift_start() |
heat_buffer / heat_len | void * / uint32_t | 输入 | 加热窗口及字节长度,布局同 hal_tpc_heat_start() |
motor_buffer / motor_len | void * / uint32_t | 输入 | 电机窗口;未启用同步电机时必须为 NULL / 0 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 三路窗口已装入,并把对应模块标记为活动 |
IM_ERR_INVALID_PARAM | 句柄、缓冲区、长度或电机窗口组合非法,描述符容量不足,或任一路窗口无法拆成 2 ~ 128 个等长描述符 |
IM_ERR_NOT_READY | HAL 或 systick 尚未初始化,或 hal_tpc_sync_config() 尚未执行 |
IM_ERR_BUSY | 同步流程的任一模块仍在活动 |
IM_ERR_TIMEOUT | 等待任一 FIFO 非空超过 1 s,已停止本次已启动的通道 |
| DMA 层错误 | 启动任一 DMA 通道失败时透传 |
补充说明:该接口固定使用循环 DMA。每路逻辑单元数必须至少为 2;单元数不超过 128 时
直接使用该数量作为描述符数,超过 128 时使用 2 ~ 128 范围内的最大整除数。没有合法
整除数时在启动任何 DMA 前返回 IM_ERR_INVALID_PARAM。调用方首次配置时提供的dma_desc_count 必须覆盖所选数量。启动顺序为 Shift → Heat →(有电机时)Motor,并把
Shift/Latch/Heat(及同步电机)标记为活动。
4.4.6 hal_tpc_sync_start
error_code_t hal_tpc_sync_start(hal_tpc_handle_t *htpc);
功能说明:启动已配置且已装入 DMA 窗口的同步硬件流程。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 同步硬件流程已启动 |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
IM_ERR_NOT_READY | 尚未初始化、同步尚未配置,或同步窗口尚未装入 |
补充说明:启用电机时写 PAFC.START 启动自动对齐;未启用电机时写 PDDMC.START启动打印头自动流程。成功返回不表示打印已经完成。
4.4.7 hal_tpc_sync_stream_end
error_code_t hal_tpc_sync_stream_end( hal_tpc_handle_t *htpc, void *shift_last_mem, void *heat_last_mem, void *motor_last_mem);
功能说明:在最后一份数据写入后清除各循环描述符链的 LINK 位,让 DMA 自然排空并停止。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
shift_last_mem | void * | 输入 | 最后一份移位数据的逻辑单元源地址 |
heat_last_mem | void * | 输入 | 最后一份加热数据的逻辑单元源地址 |
motor_last_mem | void * | 输入 | 最后一份电机数据的逻辑单元源地址;未启用电机时必须为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 已在 Motor → Shift → Heat 顺序完成断链 |
IM_ERR_NOT_READY | 所需 DMA 不是 BUSY,或该 handle 未使用描述符传输 |
IM_ERR_INVALID_PARAM | 必需地址为 NULL,或地址不在本次 DMA 源窗口内 |
补充说明:一个描述符可以覆盖多个逻辑单元。清除 LINK 后硬件仍会完成包含最后数据地址的 描述符,因此停止粒度是描述符而不是单个逻辑单元;应用应预留收尾/排空数据,或保证最后 数据位于描述符边界。
4.5 停止
4.5.1 hal_tpc_shift_stop
error_code_t hal_tpc_shift_stop( hal_tpc_handle_t *htpc, hal_tpc_stop_mode_t stop_mode, void *current_mem);
功能说明:停止移位 DMA,对移位硬件执行急停并 Flush FIFO。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
stop_mode | hal_tpc_stop_mode_t | 输入 | NORMAL 可在描述符模式下按 current_mem 断链;QUICK 立即停止 |
current_mem | void * | 输入 | NORMAL 模式下要断链的源地址;NULL 表示直接停止 DMA |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清理流程已执行 |
IM_ERR_INVALID_PARAM | 句柄或 stop_mode 非法 |
补充说明:停止接口是 best-effort;DMA 停止和 FIFO Flush 的失败不会向上传播。stop_mode 只控制 DMA 停止策略,TPC 硬件始终执行急停和 FIFO Flush,并清除活动状态。
4.5.2 hal_tpc_heat_stop
error_code_t hal_tpc_heat_stop( hal_tpc_handle_t *htpc, hal_tpc_stop_mode_t stop_mode, void *current_mem);
功能说明:停止加热 DMA,对加热硬件执行急停并 Flush FIFO。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
stop_mode | hal_tpc_stop_mode_t | 输入 | NORMAL 或 QUICK |
current_mem | void * | 输入 | NORMAL 模式下要断链的源地址;NULL 表示直接停止 DMA |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清理流程已执行 |
IM_ERR_INVALID_PARAM | 句柄或 stop_mode 非法 |
补充说明:语义与 6.5.1 相同;DMA 停止和 Flush 错误不向上传播。
4.5.3 hal_tpc_latch_stop
error_code_t hal_tpc_latch_stop(hal_tpc_handle_t *htpc);
功能说明:对锁存硬件执行急停,并清除 Latch 活动状态。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 急停命令已发出并清除活动状态 |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
补充说明:锁存不使用 DMA 和 FIFO,因此没有相应的停止或 Flush 错误。
4.5.4 hal_tpc_motor_stop
error_code_t hal_tpc_motor_stop( hal_tpc_handle_t *htpc, uint8_t motor_id, hal_tpc_stop_mode_t stop_mode, void *current_mem);
功能说明:停止所选电机的 DMA 和硬件流程,并 Flush 对应 FIFO。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
motor_id | uint8_t | 输入 | 电机索引,0/1 |
stop_mode | hal_tpc_stop_mode_t | 输入 | NORMAL 或 QUICK |
current_mem | void * | 输入 | NORMAL 模式下要断链的源地址;NULL 表示直接停止 DMA |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清理流程已执行 |
IM_ERR_INVALID_PARAM | 句柄、motor_id 或 stop_mode 非法 |
补充说明:语义与 6.5.1 相同,作用对象为所选电机的 DMA、PMnMC 和 PMnTF FIFO。
4.5.5 hal_tpc_sync_stop
error_code_t hal_tpc_sync_stop( hal_tpc_handle_t *htpc, hal_tpc_stop_mode_t stop_mode, void *shift_current_mem, void *heat_current_mem, void *motor_current_mem);
功能说明:停止同步流程涉及的全部 DMA、硬件流程和 FIFO。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
stop_mode | hal_tpc_stop_mode_t | 输入 | NORMAL 或 QUICK |
shift_current_mem | void * | 输入 | 移位流 NORMAL 模式的断链地址,可为 NULL |
heat_current_mem | void * | 输入 | 加热流 NORMAL 模式的断链地址,可为 NULL |
motor_current_mem | void * | 输入 | 同步电机 NORMAL 模式的断链地址,可为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清理流程已执行 |
IM_ERR_INVALID_PARAM | 句柄或 stop_mode 非法 |
补充说明:DMA 按 Shift → Heat → Motor 停止;带电机时执行 PAFC 自动对齐急停,否则
执行加热急停,随后 Flush FIFO 并清除活动状态。该接口不改变打印头使能、电机自动/自动
对齐使能和自动流程控制配置,这些配置由 hal_tpc_deinit() 清理。停止仍为 best-effort。
4.6 WDT
4.6.1 hal_tpc_wdt_config
error_code_t hal_tpc_wdt_config( hal_tpc_handle_t *htpc, const hal_tpc_wdt_config_t *config);
功能说明:配置 WDT 阈值、时钟源和分频。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
config | const hal_tpc_wdt_config_t * | 输入 | WDT 配置,字段约束见 4.14 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 配置已写入 |
IM_ERR_INVALID_PARAM | 句柄或配置非法 |
IM_ERR_BUSY | WDT 已使能 |
补充说明:写入 PWDTF 和 PWDTC;该接口不自动使能 WDT。
4.6.2 hal_tpc_wdt_enable
error_code_t hal_tpc_wdt_enable(hal_tpc_handle_t *htpc);
功能说明:启动 WDT 计数。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 已写 WDT 使能位 |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
补充说明:当前实现只检查句柄有效性,不检查 hal_tpc_init() 的运行状态。
4.6.3 hal_tpc_wdt_disable
error_code_t hal_tpc_wdt_disable(hal_tpc_handle_t *htpc);
功能说明:停止 WDT 计数。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 已写 WDT 关闭位 |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
补充说明:当前实现只检查句柄有效性,不检查 WDT 此前是否已使能。
4.6.4 hal_tpc_wdt_counter_clear
error_code_t hal_tpc_wdt_counter_clear(hal_tpc_handle_t *htpc);
功能说明:向 WDT 自清零控制位发出计数清零请求。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清零请求已发出 |
IM_ERR_INVALID_PARAM | 句柄或实例无效 |
补充说明:该接口不等待自清零位或 WDT 计数回到 0。
4.6.5 hal_tpc_wdt_counter_get
error_code_t hal_tpc_wdt_counter_get( const hal_tpc_handle_t *htpc, uint32_t *counter_out);
功能说明:读取 PWDTV 当前计数值。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | const hal_tpc_handle_t * | 输入 | HAL 句柄 |
counter_out | uint32_t * | 输出 | 当前计数值,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 计数值已写入 |
IM_ERR_INVALID_PARAM | 句柄或输出指针非法 |
补充说明:该接口只读取 PWDTV,不改变运行状态或计数。
4.7 中断与回调
4.7.1 hal_tpc_interrupt_enable
error_code_t hal_tpc_interrupt_enable( hal_tpc_handle_t *htpc, uint32_t interrupt_mask);
功能说明:清除指定的 PINTS 挂起位,并放行对应 TPC 中断源。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
interrupt_mask | uint32_t | 输入 | 非 0,且只能包含 HAL_TPC_INTERRUPT_MASK_ALL 中的位 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 中断源已放行,并记入 configured_interrupt_mask |
IM_ERR_INVALID_PARAM | 句柄或中断 mask 非法 |
补充说明:该接口先清除指定挂起位再放行中断;SoC 侧的 IRQ_TPC 仍需由应用注册并使能。
4.7.2 hal_tpc_interrupt_disable
error_code_t hal_tpc_interrupt_disable( hal_tpc_handle_t *htpc, uint32_t interrupt_mask);
功能说明:屏蔽指定的 TPC 中断源,并从 configured_interrupt_mask 中清除对应位。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
interrupt_mask | uint32_t | 输入 | 掩码约束与 6.7.1 相同 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 中断源已屏蔽 |
IM_ERR_INVALID_PARAM | 句柄或中断 mask 非法 |
补充说明:该接口只修改 PINTM0 屏蔽和软件 mask,不清除已有 PINTS 挂起位。
4.7.3 hal_tpc_interrupt_status_get
error_code_t hal_tpc_interrupt_status_get( const hal_tpc_handle_t *htpc, uint32_t *status_out);
功能说明:读取 PINTS,并按 HAL_TPC_INTERRUPT_MASK_ALL 过滤。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | const hal_tpc_handle_t * | 输入 | HAL 句柄 |
status_out | uint32_t * | 输出 | 中断状态,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 状态已写入 |
IM_ERR_INVALID_PARAM | 句柄或输出指针非法 |
补充说明:该接口返回原始挂起状态,不按 PINTM0 屏蔽位过滤。
4.7.4 hal_tpc_interrupt_status_clear
error_code_t hal_tpc_interrupt_status_clear( hal_tpc_handle_t *htpc, uint32_t interrupt_mask);
功能说明:向 PINTS 指定位写 1 以清除中断状态。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
interrupt_mask | uint32_t | 输入 | 掩码约束与 6.7.1 相同 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 清除请求已发出 |
IM_ERR_INVALID_PARAM | 句柄或中断 mask 非法 |
补充说明:该接口只写 PINTS,不修改 PINTM0 或 configured_interrupt_mask。
4.7.5 hal_tpc_irq_handler
void hal_tpc_irq_handler(hal_tpc_handle_t *htpc);
功能说明:处理 TPC 挂起中断并分发到已注册回调。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
| 无返回值 | — |
补充说明:有效挂起位会先写 1 清除再分发;完整行为见 5.6。非法句柄直接返回。
4.7.6 hal_tpc_callback_register
error_code_t hal_tpc_callback_register( hal_tpc_handle_t *htpc, hal_tpc_callback_id_t callback_id, hal_tpc_callback_t callback);
功能说明:注册指定回调槽的回调函数。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | hal_tpc_handle_t * | 输入/输出 | HAL 句柄 |
callback_id | hal_tpc_callback_id_t | 输入 | HAL_TPC_CALLBACK_* 中的有效槽位 |
callback | hal_tpc_callback_t | 输入 | 回调函数;为 NULL 时恢复内部空实现 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 回调已注册 |
IM_ERR_INVALID_PARAM | 句柄或 callback_id 非法 |
补充说明:callback == NULL 时恢复为 HAL 内部空回调,不删除槽位。
4.8 状态与调试
4.8.1 hal_tpc_status_get
error_code_t hal_tpc_status_get( const hal_tpc_handle_t *htpc, hal_tpc_module_t module, hal_tpc_status_t *status_out);
功能说明:读取一个模块的 configured / active 状态快照。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | const hal_tpc_handle_t * | 输入 | HAL 句柄 |
module | hal_tpc_module_t | 输入 | 目标模块 |
status_out | hal_tpc_status_t * | 输出 | 模块状态,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 状态已写入 |
IM_ERR_INVALID_PARAM | 句柄、模块号或输出指针非法 |
补充说明:该接口读取 HAL 的软件配置/活动 mask,不直接读取 PFSM 硬件状态。
4.8.2 hal_tpc_active_module_mask_get
error_code_t hal_tpc_active_module_mask_get( const hal_tpc_handle_t *htpc, uint32_t *active_module_mask_out);
功能说明:读取 HAL 认为仍处于活动状态的模块 mask。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | const hal_tpc_handle_t * | 输入 | HAL 句柄 |
active_module_mask_out | uint32_t * | 输出 | 活动模块 mask,位序同 hal_tpc_module_t,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 活动模块 mask 已写入 |
IM_ERR_INVALID_PARAM | 句柄或输出指针非法 |
补充说明:返回值只包含 HAL 正在跟踪的软件活动模块,不包含 WDT。
4.8.3 hal_tpc_state_get
error_code_t hal_tpc_state_get( const hal_tpc_handle_t *htpc, hal_tpc_state_t *state_out);
功能说明:读取 RESET / READY / BUSY 运行状态。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | const hal_tpc_handle_t * | 输入 | HAL 句柄 |
state_out | hal_tpc_state_t * | 输出 | 状态输出,不能为 NULL |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 状态已写入 |
IM_ERR_INVALID_PARAM | 句柄或输出指针非法 |
补充说明:只要 active_module_mask != 0,即使内部状态字段不是 BUSY,查询也会返回HAL_TPC_STATE_BUSY。
4.8.4 hal_tpc_regs_dump
error_code_t hal_tpc_regs_dump(const hal_tpc_handle_t *htpc);
功能说明:通过 SDK 日志打印一组关键 TPC 寄存器。
参数表:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
htpc | const hal_tpc_handle_t * | 输入 | HAL 句柄 |
返回值表:
| 返回值 | 说明 |
|---|---|
IM_OK | 寄存器已输出 |
IM_ERR_INVALID_PARAM | 调试助手已启用,但句柄非法 |
IM_ERR_UNSUPPORTED | CONFIG_SDK_ENABLE_DEBUG_HELPERS 或 CONFIG_TPC_ENABLE_DEBUG_HELPERS 未同时使能 |
补充说明:调试助手未使能时直接返回 IM_ERR_UNSUPPORTED,此时不检查句柄。
5. 参数换算
5.1 移位时钟分频
PDSCD.PRESCALE 是原始字段,移位输出时钟按下面的关系得到:
sft_clk = f_tpc / (PRESCALE + 1) => PRESCALE = f_tpc / sft_clk - 1
分频比因此只能取 1 ~ 256(PRESCALE 为 8 位字段),且 f_tpc 要能被目标时钟整除。
例如 24 MHz / 12 MHz 和 125 MHz / 12.5 MHz 都对应分频比 2,但 PRESCALE 分别是1 和 9。示例源码默认写入 f_tpc=24 MHz、shift_clk=12 MHz,上板工程可通过编译
宏覆盖这两个值。
hal_tpc_shift_config() 只接收 clock_div 原始字段,本身不做换算也不做校验;
Middleware 和示例按上式完成 Hz 到字段值的换算。
6. DMA 与资源所有权
6.1 通道与请求
HAL 按需打开 DMA 通道,一个模块一条通道,共 4 条:
| 模块 | DMA 请求 | 目的寄存器 |
|---|---|---|
| Shift | HAL_DMA_REQUEST_TPC_SHIFT_TX | PDSDF |
| Heat | HAL_DMA_REQUEST_TPC_DEST_TX | PDDTF |
| Motor0 | HAL_DMA_REQUEST_TPC_STEP_MOTO0_TX | PM0TF |
| Motor1 | HAL_DMA_REQUEST_TPC_STEP_MOTO1_TX | PM1TF |
6.2 DMA handle 回收
TPC HAL 自行持有 shift、heat 和 motor 的 DMA handle。没有统一 PDMA IRQ owner 时,
一次传输虽然已在硬件上完成,DMA HAL 的软件 handle 仍可能保持 HAL_DMA_STATE_BUSY。hal_tpc_dma_reap() 在以下位置处理这种状态:
单模块下一次
*_start()前;hal_tpc_sync_write()启动新窗口前;hal_tpc_deinit()关闭 handle 前。
若 handle 仍为 BUSY,reap 调用 hal_dma_stop(),释放该 handle 占用的通道并清除该通道
的 pending 状态;它不会关闭整个 PDMA 控制器,也不会清理其它模块或其它应用的通道。
若统一 DMA owner 已经处理完成中断并把 handle 置为 READY,reap 是空操作。