API GUIDE / TPC / OVERVIEW

G32S10 TPC API 概述

模块概述:本文档描述 G32S10 SDK 的 TPC(热敏打印头控制器)HAL 与 LL 接口。

1. 文档范围

本文档描述 G32S10 SDK 的 TPC(热敏打印头控制器)HAL 与 LL 接口。TPC 同时驱动打印头 移位、锁存、加热、步进电机和内部 WDT;一次完整打印通常由这些子模块按确定顺序协同完成。

1.1 先认识几个概念

TPC 的典型分层关系如下。MID 是整图打印编排层;应用也可以跳过 MID,直接调用 HAL:

APPLICATION  Application / BSP / Example  业务代码、板级支持与示例入口
↓
OPTIONAL MIDDLEWARE  MID TPC  文件打印、循环 DMA、事件与超时策略
DIRECT HAL  HAL TPC  直接面向业务模块的 TPC 能力接口
↓
HAL  HAL TPC  模块配置、DMA 通道与中断分发
↓
LL  LL TPC / Registers  寄存器访问与字段级控制
概念在本模块中的含义
TPCSoC 内的热敏打印头时序控制器。它输出移位、锁存、加热和电机控制信号,不生成 bitmap
LLll_tpc.h 中的内联函数,直接读写寄存器和位域;不校验参数,不维护运行时状态
HALhal_tpc.h 中的有状态驱动。负责配置校验、模块活动状态、中断分发、DMA 生命周期和 FIFO 启动/停止时序
MIDim_tpc 中间件。负责 bitmap 行组织、打印窗口滚动、DMA 描述符、进度和完成策略
DMA / FIFODMA 把 32 位数据字搬入 TPC FIFO;TPC 再按移位、加热或电机时序消费 FIFO 数据
Shift / Latch / Heat打印头数据依次经历移位、锁存、加热三个阶段
Motor步进电机按重复步和周期推进打印纸;自动对齐模式用对齐步把打印与走纸串联

1.2 本文边界

HAL 只在“句柄、实例、参数范围、模块当前状态”这一层做校验。它不判断一次打印是否完整, 也不替应用决定错误后是否重试或停机。

不属于 HAL/LL 的职责:

事项归属
TPC 模块时钟门控、时钟分频、软件复位CPM / 板级(HAL_CPM_ID_CLK_CGU_TPC、HAL_CPM_ID_GATE_TPC、SRBC_TPC_SR_BIT)
IRQ_TPC 在 SoC 中断控制器里的注册、使能和优先级PLIC 与中断框架(im_irq_*)
打印数据流的行/窗口管理、bitmap 语义、超时与重试、命令队列TPC middleware im_tpc
打印头、电机、加热驱动板的电气连接与 pinmux板级 BSP 与硬件设计

1.3 源码依据

本文按以下源码核对编写;当代码、板级配置与外部规范不一致时,以当前 SDK 源码为准, 并在硬件联调时核对实际 SoC 地址表:

类型路径
HAL 公开接口code/include/drivers/g32s10/tpc/hal_tpc.h
HAL 实现code/drivers/g32s10/tpc/hal_tpc.c
LL 公开接口code/include/drivers/g32s10/tpc/ll_tpc.h
寄存器定义code/include/drivers/g32s10/tpc/tpc_regs.h
构建配置code/drivers/g32s10/tpc/Kconfig、code/drivers/g32s10/tpc/CMakeLists.txt
HAL 示例code/examples/hal/

2. 构建配置与文件组织

直接使用 HAL/LL 时需要使能:

CONFIG_DRIVER_TPC=y

DRIVER_TPC 会自动选择 DRIVER_DMA(HAL 依赖 DMA HAL)。它不会选择 OS、中断框架 或 TPC middleware。

应用程序通常直接包含:

#include "hal_tpc.h"

开始调用启动、停止 API 前,板级初始化必须已经完成以下事项:

前置资源原因
TPC 功能时钟、模块门控和必要的软件复位HAL 不管理 CPM
TPC 引脚 pinmuxHAL 不管理 GPIO
SDK systickHAL 等待 FIFO 非空和 Flush 完成时使用 im_time_*
IRQ_TPC handler 与使能只有使用回调/中断驱动路径时才必需;纯轮询路径不需要
共享 PDMA 中断 owner若系统需要 DMA 完成回收或 DMA 故障明细,应由统一 DMA owner 管理;TPC 不注册 PDMA IRQ

可选的寄存器 dump 助手(hal_tpc_regs_dump())需要同时使能两个选项,缺一不可:

CONFIG_SDK_ENABLE_DEBUG_HELPERS=y
CONFIG_TPC_ENABLE_DEBUG_HELPERS=y

未同时使能时,hal_tpc_regs_dump() 保留公开符号但返回 IM_ERR_UNSUPPORTED,不会读取 或打印寄存器。

相关源文件:

文件职责
code/include/drivers/g32s10/tpc/hal_tpc.hHAL 公开类型、宏和函数
code/drivers/g32s10/tpc/hal_tpc.cHAL 实现、软件状态机、DMA 通道管理
code/include/drivers/g32s10/tpc/ll_tpc.hLL 内联寄存器和位域接口
code/include/drivers/g32s10/tpc/tpc_regs.h寄存器布局、实例、位域宏
code/drivers/g32s10/tpc/KconfigDRIVER_TPC、TPC_ENABLE_DEBUG_HELPERS
code/drivers/g32s10/tpc/CMakeLists.txt组件 g32s10_tpc 的源文件注册

hal_tpc.h 已经包含 hal_dma.h、ll_tpc.h、im_types.h 和 im_error.h,包含hal_tpc.h 后即可使用 tpc_regs_t、TPC 实例和 LL 接口。

HAL 还依赖两套 SDK 基础设施:

  • 时间基准(im_time_*):启动/停止时等待 FIFO 就绪和 Flush 完成,超时上限 1 s (内部常量 TPC_WAIT_TIMEOUT_US,轮询间隔 10 us)。调用前必须初始化 systick。

  • 数据缓存维护(im_cache_*):每次启动 DMA 前由 HAL 对源缓冲区做 data clean (write-back),应用无需重复调用。

3. 硬件资源

项目值来源
TPC 实例TPC = (tpc_regs_t *)TPC_IOBASE,当前 SDK 中 TPC_IOBASE = 0x1349_0000base.h、tpc_regs.h
TPC 中断号IRQ_TPC = IRQ_PLIC0_START + 14(当前等于 14)irq_table.def
电机控制器数2(Motor0 / Motor1)TPC_MOTOR_COUNT
电机输出通道每个控制器最多 8 路(Motor1 实际使用 4 路)TPC_MOTOR_CHANNEL_COUNT
Motor0 8 通道模式仅当 Motor1 未配置时可用HAL 参数校验
Shift 通道数1 ~ 16TPC_SHIFT_CHANNEL_MAX
Heat 通道数1 ~ 4TPC_HEAT_CHANNEL_MAX
电机重复步数1 ~ 64TPC_MOTOR_REPEAT_STEP_MAX

地址提示:当前 SDK 和所用地址表为 0x1349_0000。应用应使用 TPC/TPC_IOBASE,不要自行硬编码外部规范地址;若板上 访问异常,应先确认所测 SoC 版本和地址表。

4. DMA 与资源所有权

4.1 描述符

项目值
最大描述符数HAL_DMA_MAX_DESCRIPTOR_COUNT = 128
描述符对齐HAL_DMA_DESCRIPTOR_ALIGN = IM_CACHE_MAX_LINE_SIZE_BYTES = 64 字节
缓冲区大小宏HAL_DMA_DESCRIPTOR_BUFFER_SIZE(count)
循环模式默认描述符数2(单模块启动接口 hal_tpc_shift_start() / _heat_start() / _motor_start() 在 descriptor_count = 0 时使用)

描述符在首次成功配置该模块时绑定,之后重新配置不会更换存储地址或容量。若之后 可能需要循环 DMA,必须在首次配置前提供对齐的 dma_desc 和非零 dma_desc_count。

hal_tpc_sync_write() 按每路窗口的逻辑单元数 unit_count = len / unit_size 选择实际 描述符数:

unit_count <= 128  ->  descriptor_count = unit_count
unit_count >  128  ->  descriptor_count = 2 ~ 128 范围内的最大整除数
无法得到 2 ~ 128 的整除数 -> 返回 IM_ERR_INVALID_PARAM

例如 218 个逻辑单元选择 109 个描述符,217 个逻辑单元选择 31 个描述符。配置容量必须 至少覆盖所选数量;逻辑单元数与描述符数并非总是一一对应。一个描述符负责窗口总字节数 / descriptor_count 的连续数据,所谓“共享描述符”不会丢弃其余逻辑单元。

每路逻辑单元数必须至少为 2。若单元数大于 128 且没有 2 ~ 128 的整除数,hal_tpc_sync_write() 返回 IM_ERR_INVALID_PARAM,不会启动任何 DMA,也不会退化为 单个自循环描述符。连续打印时应让窗口单元数具有不超过 128 的合法整除数,并为描述符内 的排空数据保留空间。

4.2 中断所有权

TPC 打印事件使用 IRQ_TPC。应用负责向 SoC 中断框架注册 IRQ_TPC,并在 handler 中 调用 hal_tpc_irq_handler();TPC HAL 本身只处理 TPC 的 PINTS/PINTM0,不注册 PLIC 中断线。

共享 PDMA 中断遵循以下边界:

  • TPC HAL/MID 不注册 IRQ_PDMA0 / IRQ_PDMA0_DIP;

  • 系统已有统一 DMA owner 时,由该 owner 处理 PDMA IRQ,勿在 TPC 应用里重复注册;

  • 没有 PDMA IRQ owner 时,TPC 依靠下一次启动或 deinit 做 handle reap,DMA 故障不会 自动转换为 TPC HAL 错误码,通常表现为进度停滞、等待超时或后续 IM_ERR_BUSY;

  • 需要 DMA 错误明细时,应通过统一的 DMA 管理接口读取状态,不要从 TPC IRQ 里抢接 PDMA 中断线。

4.3 并发与实例

  • TPC 只有一个寄存器块实例,HAL 句柄不是可重入的:同一句柄不能并发调用,多任务 共享时需要外部串行化。

  • hal_tpc_init() / hal_tpc_deinit() 成对使用;重复 hal_tpc_init() 返回IM_ERR_BUSY。

  • 模块正在运行时再次配置或启动该模块都会返回 IM_ERR_BUSY,需要先停止。

5. 错误码

HAL 自身会返回:

错误码常见原因
IM_OK成功
IM_ERR_INVALID_PARAM句柄/实例非法、配置字段越界、缓冲区未对齐或长度不匹配、描述符与个数不匹配、掩码包含未知中断位
IM_ERR_NOT_READY未调用 hal_tpc_init()、模块尚未配置、同步流程所需模块或窗口未就绪
IM_ERR_BUSY模块正在运行、重复初始化、hal_tpc_deinit() 时仍有模块活动、WDT 已使能
IM_ERR_TIMEOUT启动时等待 FIFO 非空超过 1 s
IM_ERR_UNSUPPORTED调试助手未使能时调用 hal_tpc_regs_dump()

打开或启动 DMA 时,HAL 会透传 DMA HAL 的错误码(例如无可用通道、控制器未就绪); 停止接口按 6.5 所述执行 best-effort 清理,不向上传播 DMA 停止或 Flush 失败。

6. 示例与参考实现

参考内容
code/examples/hal/tpc_manual_mode_example.c手动模式整图打印:Shift→Latch→Heat→Motor0 事件链
code/examples/hal/tpc_auto_mode_print_example.cHAL 单次打印:自动对齐与自动非对齐两种模式,含 sync_write / sync_stream_end 用法
code/middleware/tpc/include/im_tpc.hMID 公共配置、状态和 API,适合产品级整幅打印流程
code/middleware/tpc/example/main/im_tpc_example_single_print.cMID 单次打印和非对齐路径
code/middleware/tpc/example/main/im_tpc_example_single_print_sync.cMID 单次打印和自动对齐路径
code/middleware/tpc/example/main/im_tpc_example_multi_print.cMID 连续多次打印及资源复用
code/middleware/tpc/example/README.mdMID 示例的构建、切换和上板说明

建议按“HAL 单模块 → HAL 整图 → MID 单次打印 → MID 多打印”的顺序阅读。只做接口查询时 可直接转到第 7、8 章。

7. 已知限制与注意事项

  1. HAL 不管 CPM:模块时钟门控和软件复位由应用/板级完成;hal_tpc_init() 只做 寄存器层面的复位。

  2. 错误事件不自动停机:各 *_FIFO_UNDERRUN、*_OVERTIME、AUTO_ALIGN_ERROR只通过回调上报,活动掩码不会自动清除,停机策略由应用选择。

  3. 停止接口是 best-effort:DMA 停止和 Flush 的失败不会传播,只保证流程走完; 需要严格确认时自行读寄存器核对(PFCEN、PDEN、PMnEN、PINTS、PFFS、PFSM)。

  4. sync_stream_end() 依赖 LINK 和描述符范围:只能用于由 2 ~ 128 个描述符组成的 循环窗口;单描述符或无法等长分片的窗口会被 hal_tpc_sync_write() 拒绝。传入的是最后 一份数据所在逻辑单元的源地址,HAL 会映射到一个或多个逻辑单元共用的描述符。LINK 清除 后仍会完成当前描述符,应用需预留收尾/排空数据。

  5. WDT 分频字段只有 0 ~ 5 有效,6、7 为保留值,HAL 配置时校验。

  6. 电机通道模式互斥:Motor0 使用 8 通道时 Motor1 不可配置;反之 Motor0 通道数 不能超过 4。

  7. hal_tpc_deinit() 要求先停机:任何模块仍活动都会返回 IM_ERR_BUSY。正常顺序是 先 *_stop() 再 hal_tpc_deinit();当前 deinit 对 DMA reap/close 采用 best-effort 清理,不向上传播这些错误。WDT 不受 active mask 管理,也不会由 deinit 自动关闭。

  8. 实例基址以 SDK/地址表为准:见第 3 章,当前值为 0x1349_0000;不要按外部规范 地址硬编码。