news 2026/6/15 15:28:56

MSC711x定时器深度解析:从寄存器配置到PWM实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MSC711x定时器深度解析:从寄存器配置到PWM实战

1. 项目概述

在嵌入式系统开发中,定时器模块是驱动一切精确时序逻辑的“心脏”。无论是控制电机的PWM波形、测量传感器脉冲宽度,还是实现多任务操作系统的滴答时钟,都离不开对定时器寄存器的精准操控。很多开发者初次接触芯片手册时,面对动辄几十页的寄存器描述和模式说明,常常感到无从下手,配置起来也容易出错。今天,我就以飞思卡尔(现恩智浦)MSC711x系列芯片的定时器模块为例,结合我过去在电机控制和通信设备开发中的实际踩坑经验,来一次彻底的“庖丁解牛”。我们不仅会看懂手册,更要弄懂每个配置位背后的设计意图,以及如何将它们组合起来,实现从简单的延时到复杂的可变频率PWM生成。这篇文章的目标是让你读完就能动手,配置时心里有底,调试时思路清晰。

2. 定时器核心机制与设计思路拆解

2.1 定时器的本质:一个可编程的“沙漏”

抛开复杂的术语,你可以把MSC711x的一个定时器通道想象成一个16位的“沙漏”。这个沙漏的流速(计数频率)由你选择的“沙子”(时钟源)决定,可以是系统主频,也可以是外部引脚输入的信号。沙漏的容量是固定的65536粒沙子(0x0000到0xFFFF)。你的核心工作,就是告诉这个沙漏:什么时候该翻过来重新开始(重载),以及在沙子流到某一特定数量时,需要举起一面小旗子(输出标志OFLAG)来通知你。

这个“举旗”的机制,就是通过比较寄存器(TMRxCMP1/TMRxCMP2)实现的。当计数器的值与你预设的比较值相等时,硬件会自动触发一个“比较成功”事件。这个事件是定时器所有高级功能的基石——它可以用来翻转一个引脚输出(生成PWM),可以产生一个中断让CPU来处理,甚至可以触发另一个定时器开始工作。

2.2 输出标志(OFLAG):你的万能信号发生器

OFLAG是定时器与外界沟通的核心信号。手册里提到它有两种基本的复位方式:

  1. 比较成功时置位,次输入信号边沿时复位:这非常适合做脉冲宽度测量单次触发。例如,你可以用比较事件启动一个高电平脉冲,然后用一个外部引脚(次输入信号)的上升沿来结束它,这样脉冲宽度就等于外部信号高电平的持续时间。
  2. 比较成功时置位,计数器溢出时复位:这是生成固定占空比方波的经典模式。计数器从0开始向上计数,到达比较值A时OFLAG置位(比如输出高电平),继续计数到65535溢出归零时OFLAG复位(输出低电平),如此循环,就得到了一个占空比为A/65536的PWM波。

OFLAG信号最终会映射到芯片的TOUTx引脚上,成为你可以用示波器测量的物理波形。它的极性(高有效还是低有效)可以通过TMRxSCTL[OPS]位编程,这给了你极大的灵活性去匹配不同外围器件(比如某些电机驱动芯片是高电平使能,有些是低电平)。

实操心得:在初始化定时器输出前,务必先通过TMRxSCR[VAL]TMRxSCR[FORCE]位,手动设置OFLAG的初始状态。这是一个非常容易忽略的步骤。如果没设置,上电后OFLAG可能处于随机状态,导致PWM输出第一个脉冲的宽度异常,可能会引发电机抖动或电源冲击。我的习惯是在使能计数器前,先将其强制设为低电平。

2.3 级联计数器:突破16位限制的艺术

单个16位计数器,在高速时钟下(比如100MHz)的定时分辨率很高,但定时范围很窄(655.36微秒)。为了进行长时间定时(比如1秒),就需要级联。

MSC711x的级联设计得很巧妙。它并非简单地将前一个计数器的溢出作为后一个计数器的时钟(那样是异步的,会有延迟累积)。而是采用了一种特殊的同步高速信号路径,绕过常规的输出标志逻辑。这样,多个计数器在逻辑上就像一个宽位计数器一样同步工作。

级联的关键配置规则(务必遵守)

  1. 链式时钟:第一个计数器(编号最小)配置为普通计数模式(绝不能CM=111级联模式),并选择系统时钟等作为其主时钟源(PCS)。链中后续的每个计数器,都必须设置为级联模式(CM=111),并且它们的PCS字段必须选择前一个计数器的输出作为时钟源。
  2. 顺序严格:计数器必须按照编号升序级联。例如,你可以将Counter 0, 1, 2级联成一个48位计数器,但不能让Counter 2作为Counter 1的时钟源。这是硬件布线决定的,违反此规则会导致不可预测的行为。
  3. 统一节拍:所有级联的计数器都跟随第一个计数器的计数模式(向上或向下)。整个链作为一个整体进行计数、比较和溢出。

读取级联计数器的正确姿势: 由于你无法原子性地读取一个64位值,MSC711x提供了TMRxHOLD(保持)寄存器来辅助。当你读取级联链中任何一个计数器的TMRxCNTR时,硬件会瞬间将链中所有计数器的当前值锁存到它们各自的TMRxHOLD寄存器中。因此,正确的读取顺序是:

  1. 读取任意一个计数器的TMRxCNTR(触发锁存动作)。
  2. 依次从低编号到高编号,读取所有计数器的TMRxHOLD寄存器,拼合成完整的计数值。

避坑指南:我曾在一个需要精密时间戳的项目中,直接循环读取TMRxCNTR来拼接64位值,结果发现拼接后的值偶尔会“跳变”。这就是因为在两次读取之间,计数器已经递增了。改用HOLD寄存器方案后,时间戳变得非常稳定。记住:读取级联计数器,永远遵循“读CNTR触发,读HOLD取值”的两步法。

3. 核心工作模式详解与配置要点

MSC711x定时器提供了7种计数模式(TMRxCTL[CM]),远不止简单的数时钟。理解每种模式的适用场景,是发挥其威力的关键。

3.1 基础计数模式(CM = 001)

这是最常用的模式,在每个主时钟源(PCS)的上升沿(或下降沿,由IPS位控制)计数器加1。它用于:

  • 通用定时:配合比较寄存器产生周期性中断。
  • 事件计数:将外部引脚信号设为PCS,直接统计脉冲个数。

3.2 双边沿计数(CM = 010)

此模式会计数主时钟源信号的上升沿和下降沿。注意,此时PCS不能选择分频后的内部时钟(即值不能为1000-1111),必须选择外部输入引脚。它的典型应用是测量数字信号的频率,因为一个周期包含两个边沿。这样,计数值直接就是周期数的两倍,无需软件乘2。

3.3 门控计数(CM = 011)

这是一个“条件计数”模式。计数器只在次输入信号为高电平(或低电平)期间,才对主时钟源的边沿进行计数。它完美解决了脉冲宽度测量的问题:

  • PCS设置为高精度内部时钟(如IPBus时钟)。
  • SCS设置为需要测量的外部信号引脚。
  • 计数器累加的值,就是信号高电平期间经过的时钟周期数,乘以时钟周期即得脉冲宽度。

3.4 正交编码计数(CM = 100)

这是连接旋转编码器的专用模式。它需要两个相位差90度的方波信号(A相和B相),分别接入主时钟源和次输入源。硬件内部会自动根据两相的先后关系判断方向(正转加1,反转减1)。这种模式将复杂的边沿检测和方向逻辑全部硬件化,极大减轻了CPU负担,在电机位置反馈中必不可少。

3.5 触发计数(CM = 110)

这是一种“单次触发”或“门控启动”模式。计数器平时停止,只在检测到次输入信号的边沿时,才开始对主时钟源计数,直到发生一次比较事件后停止。它常用于实现可编程的延迟触发。例如,用一个外部按键的上升沿作为触发,计数器开始计数,到达比较值时产生中断,这个中断可以用于在按键事件后延迟一段时间再执行某个动作。

3.6 核心功能衍生:PWM生成模式

手册中基于基础计数模式,衍生出了几种特殊的PWM生成配置,这是定时器最核心的应用之一。

3.6.1 固定频率PWM模式这是最基础的PWM,频率固定,占空比可调。

  • 配置核心
    • CM = 001(基础计数)
    • LEN = 0(溢出回滚,而非比较后重载)
    • ONCE = 0(重复计数)
    • OFLM = 110(比较成功时置位,溢出时复位)
  • 工作原理:计数器从0累加到65535后溢出归零,循环往复。当计数值等于TMRxCMP1时,OFLAG置位;当计数值溢出时,OFLAG复位。
  • 参数计算
    • PWM频率 = 输入时钟频率 / 65536
    • 占空比 =TMRxCMP1/ 65536
  • 特点与局限:频率由时钟和计数器位数固定死,改变频率必须换时钟源。占空比分辨率高达16位(65536级)。

3.6.2 可变频率PWM模式此模式功能强大,可以独立调节PWM的频率和占空比。

  • 配置核心
    • CM = 001
    • LEN = 1(计数到比较值后重载)
    • ONCE = 0
    • OFLM = 100(使用交替比较寄存器切换输出)
  • 工作原理:计数器在0和TMRxCMP1TMRxCMP2两个边界之间交替计数。假设向上计数,从0开始,到达TMRxCMP2时,OFLAG翻转一次,计数器继续向上;到达TMRxCMP1时,OFLAG再次翻转,同时计数器重载回0,开始下一个周期。
  • 参数计算
    • PWM周期 = (TMRxCMP1值) * 时钟周期
    • 高电平时间 = (TMRxCMP2值) * 时钟周期
    • 占空比 =TMRxCMP2/TMRxCMP1
    • 频率 = 1 / (PWM周期)
  • 核心优势:频率和占空比均可自由编程,且互不影响。TMRxCMP1决定周期,TMRxCMP2决定高电平时间。

注意事项:在可变频率PWM模式下,计数器是单向计数(通常向上)。TMRxCMP2必须小于TMRxCMP1。如果设置TMRxCMP2大于TMRxCMP1,计数器永远达不到TMRxCMP2OFLAG将不会翻转,输出保持恒定。

4. 可变频率PWM与比较预加载实战

可变频率PWM模式虽然灵活,但有一个挑战:如何在PWM周期运行中,动态、无毛刺地更新下一个周期的比较值?如果直接在计数器运行时写入TMRxCMP1/2,若写入时机不当(计数器已越过新值),会导致当前周期异常,输出产生毛刺。MSC711x的比较预加载寄存器(TMRxCMPLD1/2)比较控制状态寄存器(TMRxCOMSC)就是为了优雅地解决这个问题而设计的。

4.1 比较预加载机制详解

这套机制的精髓在于“影子寄存器”和“交替加载”。

  1. 影子寄存器TMRxCMPLD1TMRxCMPLD2是预加载寄存器,你可以随时安全地向它们写入新的比较值,而不会影响当前正在使用的TMRxCMP1TMRxCMP2
  2. 交替加载:通过配置TMRxCOMSC[CL1][CL2]位,可以设置在特定的比较事件发生时,自动将预加载寄存器的值更新到实际比较寄存器中。

典型的可变频率PWM带预加载的配置流程

  1. 初始化寄存器
    • TMRxCTL:CM=001,PCS=1000(IPBus时钟),ONCE=0,LEN=1,OFLM=100
    • TMRxSCTL: 根据需要设置OPSOEN,使能输出。
    • TMRxCOMSC: 这是关键!
      • TCF2EN = 1(使能比较2中断)
      • TCF1EN = 0(通常只需一个中断源)
      • CL1 = 10(当TCF2置位时,用TMRxCMPLD1加载TMRxCMP1)
      • CL2 = 01(当TCF1置位时,用TMRxCMPLD2加载TMRxCMP2)
    • 写入初始的TMRxCMP1,TMRxCMP2,TMRxCMPLD1,TMRxCMPLD2值。
  2. 启动计数器:最后配置TMRxCTL,计数器开始运行。
  3. 中断服务程序(ISR)中的操作
    • 当计数器达到TMRxCMP2(第一个比较点)时,TCF2置位,触发中断。
    • 在ISR中,首先清除TCF2TCF1标志位。
    • 然后,计算下一个PWM周期所需的CMP1_newCMP2_new值。
    • 最后,将新值写入TMRxCMPLD1TMRxCMPLD2
    • 此时,硬件会在下一个加载点自动将新值载入实际比较寄存器,实现无缝切换。

这个过程形成了一个稳定的流水线:当前周期输出 -> 中断中计算下一周期参数 -> 预加载寄存器更新 -> 下一周期开始自动应用新参数

4.2 一个具体的配置案例:生成1kHz,占空比50%的PWM

假设IPBus时钟频率为100MHz (周期10ns)。

  1. 计算参数
    • 期望周期 T = 1 / 1kHz = 1ms = 1,000,000 ns。
    • 所需计数值 N = T / (时钟周期) = 1,000,000 ns / 10 ns = 100,000。
    • 由于LEN=1模式下,计数器从0计数到CMP1,所以TMRxCMP1应设置为100,000。
    • 占空比50%,则高电平时间应为0.5ms,对应计数值为50,000。所以TMRxCMP2设置为50,000。
    • 注意:计数值不能超过65535(16位限制)。100,000 > 65535,因此单通道无法直接实现,必须使用级联模式或降低时钟频率。
  2. 改用级联方案:将两个定时器通道级联成一个32位计数器。
    • 时钟源频率可先经过预分频。例如,选择PCS=1011(输入时钟128分频),则计数时钟频率为100MHz/128 ≈ 781.25kHz,周期约为1.28μs。
    • 此时,1ms周期需要的计数值约为781。这个值远小于65535,单通道即可实现。
    • TMRxCMP1= 781,TMRxCMP2= 390 (占空比50%)。
  3. C语言配置代码片段
// 假设使用Timer A Channel 0 // 1. 配置为可变频率PWM模式,带预加载 TMR0CTL = (0x1 << 13) | // CM = 001: 基础计数模式 (0xB << 9) | // PCS = 1011: 时钟128分频 (781.25kHz) (0x0 << 6) | // ONCE = 0: 重复计数 (0x1 << 5) | // LEN = 1: 计数到比较值后重载 (0x4 << 0); // OFLM = 100: 交替比较寄存器模式 TMR0SCTL = (0x1 << 0); // OEN = 1: 使能输出 TMR0COMSC = (0x1 << 7) | // TCF2EN = 1: 使能比较2中断 (0x2 << 0) | // CL1 = 10: TCF2时加载CMPLD1到CMP1 (0x1 << 2); // CL2 = 01: TCF1时加载CMPLD2到CMP2 // 2. 写入初始比较值 TMR0CMP1 = 781; // 周期值 TMR0CMP2 = 390; // 高电平时间值 TMR0CMPLD1 = 781; // 预加载值初始化 TMR0CMPLD2 = 390; // 3. 使能定时器中断(需根据具体中断控制器配置) // 4. 最后,如果需要立即开始,可以给LOAD寄存器写入初始计数值(如0),但通常计数器从0开始即可。

实操心得:动态调整PWM:在电机控制中,我们经常需要平滑改变PWM频率或占空比。利用预加载机制,你可以在一个PWM周期的中断里,计算下一个周期的新值并写入预加载寄存器。关键是要确保计算和写入操作在下一个加载事件(TCF1或TCF2)发生前完成。如果计算量很大,可能导致来不及更新。这时有两种策略:一是提前计算好一组值存入缓冲区;二是使用更快的时钟或优化算法。我曾遇到因计算耗时导致PWM更新慢一拍的问题,后来改用查表法预先计算正弦波PWM值,问题迎刃而解。

5. 关键寄存器精讲与配置陷阱

手册给出了完整的寄存器列表,但开发中我们最需要关注的是几个控制类寄存器。理解每个位的含义,是避免配置错误的前提。

5.1 定时器控制寄存器(TMRxCTL)

这是定时器的“大脑”,决定了其基本行为。

  • CM[15:13](计数模式):如前所述,选择7种基本模式。特别注意:模式010(双边沿计数)下,PCS不能选择分频时钟(1000-1111),必须用外部输入。
  • PCS[12:9](主时钟源):选择计数脉冲的来源。从外部引脚(0000-0011)、其他计数器输出(用于级联,0100-0111)到内部时钟分频(1000-1111)。致命陷阱:一个定时器不能选择自己的输出作为时钟源,否则计数器将停止。
  • LEN[5](计数长度):这是区分“溢出模式”和“比较重载模式”的关键。
    • LEN=0(溢出模式):计数器自由运行,从0到0xFFFF循环。用于固定频率PWM或自由运行定时。
    • LEN=1(比较重载模式):计数器到达比较值(CMP1CMP2)后,立即重载到LOAD寄存器的值(通常为0)。用于可变频率PWM或精确周期定时。
  • OFLM[2:0](输出模式):控制OFLAG的行为。模式100(交替比较寄存器)是可变频率PWM的专属模式。模式101(比较置位,次输入边沿复位)非常适合测量脉冲:用比较事件启动定时器输出高电平,用外部信号边沿结束它,那么高电平的持续时间就是外部脉冲的宽度。

5.2 定时器状态与控制寄存器(TMRxSCTL)

这个寄存器管理标志位、中断和输入/输出控制。

  • TCF, TOF, IEF:分别是比较成功、溢出、输入边沿标志位。它们是“粘性”的,一旦置位,除非软件写0清除,否则一直保持。常见错误:在中断服务程序中忘了清除这些标志,导致中断连续触发,系统卡死。
  • IPS[9](输入极性选择):非常实用的位。它可以将输入信号反向。例如,你的外部信号是低电平有效,但你想在上升沿触发捕获,那么设置IPS=1,硬件就会在外部信号的下降沿(经反向后变为上升沿)触发。
  • VAL[3] & FORC[2]:用于在计数器禁用时,强制OFLAG输出特定电平。这是一个安全的初始化输出状态的方法。

5.3 比较控制状态寄存器(TMRxCOMSC)

这是实现高级PWM和预加载功能的核心。

  • TCF1EN/TCF2EN:使能特定比较事件的中断。在可变频率PWM中,通常只需使能一个(如TCF2EN),在周期中点进行新参数计算和加载。
  • CL1[1:0], CL2[3:2]预加载控制位。这是实现无毛刺PWM切换的灵魂。
    • 00: 从不预加载。
    • 01: 当TCF1置位时(与CMP1比较成功),加载对应的预加载寄存器。
    • 10: 当TCF2置位时(与CMP2比较成功),加载对应的预加载寄存器。
    • 11: 保留。
  • 配置示例:要实现CMP1CMP2在各自比较事件后自动更新,应设置CL1=10(TCF2时加载CMPLD1CMP1),CL2=01(TCF1时加载CMPLD2CMP2)。这样,两个比较值在周期中交替更新,互不干扰。

6. 高级应用与问题排查实录

6.1 主从广播模式(Broadcast Mode)

这是一个强大的同步功能。你可以指定一个定时器通道为“主”(Master),将其比较事件广播给模块内的其他“从”(Slave)定时器。

  • 配置方法
    1. 在主定时器的TMRxSCTL寄存器中,设置MSTR=1
    2. 在从定时器的TMRxCTL寄存器中,设置EIN=1(允许外部初始化)。
    3. 在从定时器的TMRxSCTL寄存器中,可选设置EEOF=1(允许外部强制输出)。
  • 触发效果:当主定时器发生比较事件时,所有配置了EIN=1的从定时器会立即将其计数器重载为各自LOAD寄存器的值。如果从定时器还设置了EEOF=1,那么其输出标志OFLAG也会被强制为主定时器比较事件发生时VAL位的状态。
  • 应用场景:需要多个PWM输出严格同步的场景。例如,三相电机控制中,三个桥臂的PWM需要同时更新占空比,以避免电流冲击。你可以配置一个主定时器,三个从定时器。主定时器比较事件触发时,三个从定时器同时重载新的比较值,从而实现PWM的同步更新。

6.2 输入捕获功能

虽然手册在比较预加载章节简要提到了捕获寄存器TMRxCAP,但其功能非常独立且实用。通过配置TMRxSCTL[CM](输入捕获模式),可以让定时器在检测到次输入信号边沿时,瞬间将当前计数器的值锁存到CAP寄存器中。

  • 模式00禁用,01上升沿捕获,10下降沿捕获,11双边沿捕获。
  • 应用高精度脉冲宽度测量。启动定时器自由运行(LEN=0)。信号上升沿触发捕获,记录值T1;下降沿再次触发,记录值T2。脉冲宽度 =(T2 - T1) * 时钟周期。这种方法比门控计数模式精度更高,因为它直接捕获时间戳,避免了门控计数中可能存在的±1个时钟的误差。
  • 注意:捕获事件会设置IEF标志。读取捕获值后,必须写0清除IEF,才能等待下一次捕获。

6.3 常见问题排查速查表

在实际调试中,定时器不出波形或波形不对是家常便饭。下面是我总结的排查清单:

现象可能原因排查步骤
完全没有波形输出1. 定时器未使能(CM=000)。
2. 输出未使能(OEN=0)。
3. 引脚复用功能未配置为定时器输出。
4. 时钟源未正确配置或未使能。
1. 检查TMRxCTL[CM]不为0。
2. 检查TMRxSCTL[OEN]=1
3. 查阅芯片数据手册,确认对应引脚的IOMUX配置为TOUTx功能。
4. 检查系统时钟树,确认定时器模块的时钟已打开。
PWM频率不对1.PCS时钟源选择或分频系数错误。
2. 在可变频率模式下,LEN位设置错误(应为1)。
3. 比较寄存器CMP1计算错误。
1. 核对TMRxCTL[PCS]字段,计算实际输入时钟频率。
2. 确认TMRxCTL[LEN]设置与模式匹配(固定频率用0,可变频率用1)。
3. 重新计算:频率 = 时钟频率 / (CMP1 + 1) (LEN=1时)。
PWM占空比不对或不变1. 在可变频率模式下,CMP2大于等于CMP1
2.OFLM模式设置错误。
3. 比较值在运行时被意外修改。
1. 确保CMP2<CMP1
2. 固定频率PWM用OFLM=110,可变频率用OFLM=100
3. 检查是否有其他代码或DMA错误地写入了比较寄存器。使用预加载寄存器可避免此问题。
级联计数器读数错误直接读取CNTR寄存器拼接,未使用HOLD寄存器。严格按照“读CNTR触发,读HOLD取值”的顺序读取所有级联通道。
中断疯狂触发中断标志位(TCF,TOF,IEF)未在中断服务程序中清除。在ISR开始处,立即读取并清除相关标志位(写0)。
输出极性反了OPS位设置与预期相反。检查TMRxSCTL[OPS]位,0为正常(比较成功输出高),1为反向。

最后分享一个调试技巧:在复杂定时器应用初始调试阶段,可以先将OFLM模式设置为000(计数器活动时输出有效)。这样,只要计数器在跑,引脚上就应该有持续的高或低电平输出。用这个简单的方法可以快速验证:定时器时钟是否正确、计数器是否在计数、输出路径是否畅通。等这个基本功能通了,再切换到复杂的PWM模式,就能分步定位问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 15:28:01

DHTMLX Gantt 10.0 闪耀登场

DHTMLX Gantt is a comprehensive JavaScript Gantt chart library designed to simplify project planning, automate scheduling, visualize critical paths, and manage resources efficiently for teams of any size. 10.0 2026年6月11日。主要版本发布 本次更新对甘特图…

作者头像 李华
网站建设 2026/6/15 15:20:00

如何快速转换3D视频到2D格式:VR-Reversal的完整使用指南

如何快速转换3D视频到2D格式&#xff1a;VR-Reversal的完整使用指南 【免费下载链接】VR-reversal VR-Reversal - Player for conversion of 3D video to 2D with optional saving of head tracking data and rendering out of 2D copies. 项目地址: https://gitcode.com/gh_…

作者头像 李华
网站建设 2026/6/15 15:17:56

VisualCppRedist AIO:一站式解决Windows软件运行库问题的终极指南

VisualCppRedist AIO&#xff1a;一站式解决Windows软件运行库问题的终极指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 当您在Windows系统中遇到软件无法启…

作者头像 李华
网站建设 2026/6/15 15:17:55

如何修复RPFM构建三国全面战争Startpos文件失败的5个实用方案

如何修复RPFM构建三国全面战争Startpos文件失败的5个实用方案 【免费下载链接】rpfm Rusted PackFile Manager (RPFM) is a... reimplementation in Rust and Qt6 of PackFile Manager (PFM), one of the best modding tools for Total War Games. 项目地址: https://gitcode…

作者头像 李华