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_MAX24 位周期字段最大值。0x00FF_FFFF。
HAL_TPC_SHIFT_SETUP_HOLD_CYCLE_MAX移位 setup/hold 字段最大值。3。
HAL_TPC_WDT_CLOCK_DIV_MAXWDT 有效分频字段最大值。5;6、7 为保留值。
HAL_TPC_DMA_UNIT_SIZEFIFO/DMA 基本访问粒度。4 字节。
HAL_TPC_MODULE_COUNTHAL 软件活动状态跟踪的模块数。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_SHIFTSHIFT_FINISH;另有 SHIFT_FIFO_UNDERRUN(独立一次调用)
HAL_TPC_CALLBACK_LATCHLATCH_FINISH
HAL_TPC_CALLBACK_HEATHEAT_FINISH;另有 HEAT_FIFO_UNDERRUN、HEAT_OVERTIME(各独立一次调用)
HAL_TPC_CALLBACK_MOTOR0MOTOR0_FINISH / MOTOR0_START_STEP / MOTOR0_REPEAT_STEP 合并为一次调用;另有 MOTOR0_FIFO_UNDERRUN、MOTOR0_OVERTIME 各独立一次调用
HAL_TPC_CALLBACK_MOTOR1同 Motor0,事件前缀为 MOTOR1_*
HAL_TPC_CALLBACK_SYNCPRINT_HEAD_FINISH 与 AUTO_ALIGN_FINISH 合并为一次调用;另有 SYNC_ERROR 独立一次调用
HAL_TPC_CALLBACK_WDTWDT_HALF / WDT_FULL 合并为一次调用

2.3 事件标志

HAL_TPC_EVENT_* 与 TPC_INT_* 的位值一一对应:

事件位
HAL_TPC_EVENT_NONE0
HAL_TPC_EVENT_PRINT_HEAD_FINISHbit0
HAL_TPC_EVENT_SHIFT_FINISHbit1
HAL_TPC_EVENT_LATCH_FINISHbit2
HAL_TPC_EVENT_HEAT_FINISHbit3
HAL_TPC_EVENT_SHIFT_FIFO_UNDERRUNbit4
HAL_TPC_EVENT_HEAT_FIFO_UNDERRUNbit5
HAL_TPC_EVENT_HEAT_OVERTIMEbit6
HAL_TPC_EVENT_MOTOR0_FINISH / HAL_TPC_EVENT_MOTOR0_START_STEP / HAL_TPC_EVENT_MOTOR0_REPEAT_STEPbit8 / bit9 / bit10
HAL_TPC_EVENT_MOTOR0_FIFO_UNDERRUN / HAL_TPC_EVENT_MOTOR0_OVERTIMEbit11 / bit12
HAL_TPC_EVENT_MOTOR1_FINISH / HAL_TPC_EVENT_MOTOR1_START_STEP / HAL_TPC_EVENT_MOTOR1_REPEAT_STEPbit16 / bit17 / bit18
HAL_TPC_EVENT_MOTOR1_FIFO_UNDERRUN / HAL_TPC_EVENT_MOTOR1_OVERTIMEbit19 / bit20
HAL_TPC_EVENT_AUTO_ALIGN_FINISH / HAL_TPC_EVENT_SYNC_ERRORbit24 / bit25
HAL_TPC_EVENT_WDT_HALF / HAL_TPC_EVENT_WDT_FULLbit30 / bit31

聚合宏便于判定错误:

宏组成
HAL_TPC_EVENT_SHIFT_ERRORHAL_TPC_EVENT_SHIFT_FIFO_UNDERRUN
HAL_TPC_EVENT_HEAT_ERRORHAL_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_ERRORTPC_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 前置条件

  1. 使能 TPC 模块时钟与门控(CPM),必要时先做一次 TPC 软件复位;

  2. 初始化 SDK 时间基准(systick),启动/停止 API 会用到 im_time_*;

  3. 若使用回调或中断驱动路径,注册并使能 IRQ_TPC,并在中断服务函数里调用hal_tpc_irq_handler();纯轮询路径不需要注册该 IRQ;

  4. 确认 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()

需要区分三个时刻:

  1. 带 DMA 的 shift/heat/motor/sync_write 启动返回成功,只表示 DMA 已启动、FIFO 已 装入首批数据且硬件启动命令已发出,不表示本次传输或打印过程已经结束。Latch 不使用 DMA,成功只表示锁存事件已启动。

  2. 使用中断路径时,应以对应回调或 hal_tpc_status_get() 的 active 状态判断结束; 使用轮询路径时,不能仅凭 *_start() 成功就调用下一次启动。

  3. 只有活动模块都停止后才能 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
Shifthal_tpc_shift_config()hal_tpc_shift_start()hal_tpc_shift_stop()需要(HAL_DMA_REQUEST_TPC_SHIFT_TX)
Latchhal_tpc_latch_config()hal_tpc_latch_start()hal_tpc_latch_stop()不需要
Heathal_tpc_heat_config()hal_tpc_heat_start()hal_tpc_heat_stop()需要(HAL_DMA_REQUEST_TPC_DEST_TX)
Motor0/1hal_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() 的行为:

  1. 读取 (PINTS & ~PINTM0) & HAL_TPC_INTERRUPT_MASK_ALL 得到受支持的未屏蔽挂起位, 为 0 立即返回;

  2. 用 PINTS = pending 清掉本次处理的挂起位(RW1C);

  3. 按模块分发回调;FINISH 且同模块没有错误位时把该模块从活动掩码清除,活动掩码 清空后 state 回到 READY;

  4. 错误事件只上报:不自动停机、不清活动掩码。恢复策略由应用决定,且*_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 接口规范

本章每个接口统一按以下顺序说明:

  1. 函数原型;

  2. 功能说明;

  3. 参数表;

  4. 返回值表;

  5. 补充说明。

无参数接口仍保留参数表并明确写“无”;无失败返回值的接口在返回值表中写“无返回值”。 除特别说明外,空句柄、空必需指针或非法枚举/索引均返回 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),不访问硬件。

参数表:

参数类型方向说明
confighal_tpc_shift_config_t *输出待填充的移位配置,不能为 NULL

返回值表:

返回值说明
IM_OK默认配置已填入
IM_ERR_INVALID_PARAMconfig == 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),不访问硬件。

参数表:

参数类型方向说明
confighal_tpc_latch_config_t *输出待填充的锁存配置,不能为 NULL

返回值表:

返回值说明
IM_OK默认配置已填入
IM_ERR_INVALID_PARAMconfig == 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),不访问硬件。

参数表:

参数类型方向说明
confighal_tpc_heat_config_t *输出待填充的加热配置,不能为 NULL

返回值表:

返回值说明
IM_OK默认配置已填入
IM_ERR_INVALID_PARAMconfig == 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),不访问硬件。

参数表:

参数类型方向说明
confighal_tpc_motor_config_t *输出待填充的电机配置,不能为 NULL

返回值表:

返回值说明
IM_OK默认配置已填入
IM_ERR_INVALID_PARAMconfig == 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),不访问硬件。

参数表:

参数类型方向说明
confighal_tpc_wdt_config_t *输出待填充的 WDT 配置,不能为 NULL

返回值表:

返回值说明
IM_OK默认配置已填入
IM_ERR_INVALID_PARAMconfig == 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_cycleuint32_t输入本单元到下一单元的等待周期,有效范围 0 ~ 0x00FFFFFF
next_triggerhal_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_cycleuint32_t输入该通道加热周期,有效范围 0 ~ 0x00FFFFFF
outputhal_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 实例和内部空回调。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输出待初始化的 HAL 句柄,不能为 NULL
instancetpc_regs_t *输入TPC 寄存器块,必须是 TPC

返回值表:

返回值说明
IM_OK软件句柄已初始化
IM_ERR_INVALID_PARAMhtpc == 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 管理的打印头和电机使能。

参数表:

参数类型方向说明
htpchal_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。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄

返回值表:

返回值说明
IM_OK清理完成,state = HAL_TPC_STATE_RESET
IM_ERR_INVALID_PARAM句柄或实例无效
IM_ERR_BUSYactive_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 通道。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
configconst 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 打印头功能。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
configconst 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 通道。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
configconst 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 通道。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
configconst 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);

功能说明:配置同步/自动打印流程,并选择是否启用电机自动对齐。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
motor_enableuint8_t输入0 = 仅打印头自动流程;1 = 打印头与电机自动对齐
motor_iduint8_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_BUSYSync 模块正在运行

补充说明:要求 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 有数据后启动移位硬件。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
buffervoid *输入源缓冲区,必须 4 字节对齐
lenuint32_t输入字节数,必须同时是 4 和 line_bytes 的整数倍
modehal_tpc_dma_mode_t输入SINGLE 或 CYCLIC
descriptor_countuint32_t输入仅 CYCLIC 使用;0 表示默认 2 个描述符

返回值表:

返回值说明
IM_OKDMA 已启动、FIFO 已非空且移位硬件已启动
IM_ERR_INVALID_PARAM缓冲区、长度、模式或描述符配置非法
IM_ERR_NOT_READYHAL 或 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 有数据后启动加热硬件。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
buffervoid *输入PDDTF 字流源缓冲区,必须 4 字节对齐
lenuint32_t输入字节数,必须同时是 4 和 (channel_count + 1) * 4 的整数倍
modehal_tpc_dma_mode_t输入SINGLE 或 CYCLIC
descriptor_countuint32_t输入仅 CYCLIC 使用;0 表示默认 2 个描述符

返回值表:

返回值说明
IM_OKDMA 已启动、FIFO 已非空且加热硬件已启动
IM_ERR_INVALID_PARAM缓冲区、长度、模式或描述符配置非法
IM_ERR_NOT_READYHAL 或 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 模块标记为活动。

参数表:

参数类型方向说明
htpchal_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 有数据后启动电机硬件。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
motor_iduint8_t输入电机索引,0/1
buffervoid *输入电机周期字源缓冲区,必须 4 字节对齐
lenuint32_t输入字节数,必须同时是 4 和 repeat_step_count * 4 的整数倍
modehal_tpc_dma_mode_t输入SINGLE 或 CYCLIC
descriptor_countuint32_t输入仅 CYCLIC 使用;0 表示默认 2 个描述符

返回值表:

返回值说明
IM_OKDMA 已启动、FIFO 已非空且电机硬件已启动
IM_ERR_INVALID_PARAM句柄、电机索引、缓冲区、长度、模式或描述符配置非法
IM_ERR_NOT_READYHAL 或 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 装入首批数据。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
shift_buffer / shift_lenvoid * / uint32_t输入移位窗口及字节长度,约束同 hal_tpc_shift_start()
heat_buffer / heat_lenvoid * / uint32_t输入加热窗口及字节长度,布局同 hal_tpc_heat_start()
motor_buffer / motor_lenvoid * / uint32_t输入电机窗口;未启用同步电机时必须为 NULL / 0

返回值表:

返回值说明
IM_OK三路窗口已装入,并把对应模块标记为活动
IM_ERR_INVALID_PARAM句柄、缓冲区、长度或电机窗口组合非法,描述符容量不足,或任一路窗口无法拆成 2 ~ 128 个等长描述符
IM_ERR_NOT_READYHAL 或 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 窗口的同步硬件流程。

参数表:

参数类型方向说明
htpchal_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 自然排空并停止。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
shift_last_memvoid *输入最后一份移位数据的逻辑单元源地址
heat_last_memvoid *输入最后一份加热数据的逻辑单元源地址
motor_last_memvoid *输入最后一份电机数据的逻辑单元源地址;未启用电机时必须为 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。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
stop_modehal_tpc_stop_mode_t输入NORMAL 可在描述符模式下按 current_mem 断链;QUICK 立即停止
current_memvoid *输入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。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
stop_modehal_tpc_stop_mode_t输入NORMAL 或 QUICK
current_memvoid *输入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 活动状态。

参数表:

参数类型方向说明
htpchal_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。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
motor_iduint8_t输入电机索引,0/1
stop_modehal_tpc_stop_mode_t输入NORMAL 或 QUICK
current_memvoid *输入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。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
stop_modehal_tpc_stop_mode_t输入NORMAL 或 QUICK
shift_current_memvoid *输入移位流 NORMAL 模式的断链地址,可为 NULL
heat_current_memvoid *输入加热流 NORMAL 模式的断链地址,可为 NULL
motor_current_memvoid *输入同步电机 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 阈值、时钟源和分频。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
configconst hal_tpc_wdt_config_t *输入WDT 配置,字段约束见 4.14

返回值表:

返回值说明
IM_OK配置已写入
IM_ERR_INVALID_PARAM句柄或配置非法
IM_ERR_BUSYWDT 已使能

补充说明:写入 PWDTF 和 PWDTC;该接口不自动使能 WDT。

4.6.2 hal_tpc_wdt_enable

error_code_t hal_tpc_wdt_enable(hal_tpc_handle_t *htpc);

功能说明:启动 WDT 计数。

参数表:

参数类型方向说明
htpchal_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 计数。

参数表:

参数类型方向说明
htpchal_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 自清零控制位发出计数清零请求。

参数表:

参数类型方向说明
htpchal_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 当前计数值。

参数表:

参数类型方向说明
htpcconst hal_tpc_handle_t *输入HAL 句柄
counter_outuint32_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 中断源。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
interrupt_maskuint32_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 中清除对应位。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
interrupt_maskuint32_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 过滤。

参数表:

参数类型方向说明
htpcconst hal_tpc_handle_t *输入HAL 句柄
status_outuint32_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 以清除中断状态。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
interrupt_maskuint32_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 挂起中断并分发到已注册回调。

参数表:

参数类型方向说明
htpchal_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);

功能说明:注册指定回调槽的回调函数。

参数表:

参数类型方向说明
htpchal_tpc_handle_t *输入/输出HAL 句柄
callback_idhal_tpc_callback_id_t输入HAL_TPC_CALLBACK_* 中的有效槽位
callbackhal_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 状态快照。

参数表:

参数类型方向说明
htpcconst hal_tpc_handle_t *输入HAL 句柄
modulehal_tpc_module_t输入目标模块
status_outhal_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。

参数表:

参数类型方向说明
htpcconst hal_tpc_handle_t *输入HAL 句柄
active_module_mask_outuint32_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 运行状态。

参数表:

参数类型方向说明
htpcconst hal_tpc_handle_t *输入HAL 句柄
state_outhal_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 寄存器。

参数表:

参数类型方向说明
htpcconst hal_tpc_handle_t *输入HAL 句柄

返回值表:

返回值说明
IM_OK寄存器已输出
IM_ERR_INVALID_PARAM调试助手已启用,但句柄非法
IM_ERR_UNSUPPORTEDCONFIG_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 请求目的寄存器
ShiftHAL_DMA_REQUEST_TPC_SHIFT_TXPDSDF
HeatHAL_DMA_REQUEST_TPC_DEST_TXPDDTF
Motor0HAL_DMA_REQUEST_TPC_STEP_MOTO0_TXPM0TF
Motor1HAL_DMA_REQUEST_TPC_STEP_MOTO1_TXPM1TF

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 是空操作。