TMS320F280013x eQEP模块深度解析:从原理到伺服控制实战
1. 项目概述:为什么eQEP是运动控制的核心
在伺服电机、机器人关节或者任何需要精确位置反馈的工业设备里,工程师们绕不开一个核心问题:如何实时、准确地知道电机转轴“在哪”以及“跑多快”。十多年前,我们还在用光电开关或者霍尔传感器做粗略的位置判断,精度和实时性都难以满足高性能伺服的需求。如今,几乎所有的数字信号处理器(DSP)和高端微控制器(MCU)都集成了专门处理这个问题的硬件模块——正交编码器脉冲接口,而在德州仪器(TI)的C2000系列微控制器中,它的增强版被称为eQEP。
简单来说,你可以把eQEP模块想象成一个极其专业和高效的“脉冲翻译官”。它直接连接在电机同轴安装的旋转编码器上,这个编码器会输出两路名为A相和B相的方波信号。这两路信号的神奇之处在于,它们的相位差是精确的90度。eQEP模块的核心任务,就是实时解读这两路信号的边沿变化,不仅数出有多少个脉冲(从而知道转了多少角度),还能根据A、B相谁先跳变来判断电机是正转还是反转。
但eQEP的“增强”之处远不止于此。以TMS320F280013x这款芯片为例,它的eQEP模块集成了三大法宝:一个32位的位置计数器(QPOSCNT),一个用于高精度低速测量的边沿捕获单元,以及一个灵活的位置比较单元。这意味着,你不再需要写复杂的软件算法去滤波、去计算速度,硬件已经帮你把最耗时、最要求实时性的活都干了。你只需要配置好寄存器,它就能自动给你提供位置值、计算出的速度值,甚至能在你指定的精确位置点(比如每转1000个脉冲)产生一个同步信号,去精准触发ADC采样或者另一个PWM动作。
这篇文章,我就结合自己多年在伺服驱动器开发上的踩坑经验,带你彻底拆解TMS320F280013x的eQEP模块。我不会只给你罗列寄存器手册,而是会重点讲清楚:在不同应用场景下(比如高精度定位、宽范围速度测量),你该如何配置那一大堆令人眼花缭乱的寄存器位域;硬件自动完成的那些操作,底层到底是怎么跑的;以及最关键的,那些手册里可能不会写,但实际调试中一定会遇到的“坑”该如何避开。无论你是正在评估C2000芯片,还是已经在项目中被eQEP困扰,相信这篇近万字的深度解析都能给你带来直接的帮助。
2. eQEP模块整体架构与核心功能拆解
要玩转eQEP,首先得在脑子里建立起它的整体架构图。这个模块不是一个简单的计数器,而是一个由多个协同工作的子单元构成的精密系统。理解数据流和控制流,是进行正确配置的前提。
2.1 信号链与解码逻辑
编码器的A、B相信号首先经过输入极性控制(QDECCTL[QAP], [QBP]),你可以在这里对信号进行取反,以适应不同的硬件接线或编码器输出逻辑。之后,信号进入核心的解码器。
解码器的工作模式由QDECCTL[QSRC]位决定,这是第一个关键配置点:
- 正交计数模式(Quadrature Count Mode):这是最常用的模式。eQEP模块会同时检测A、B两相的上升沿和下降沿。对于一个线数为N的编码器(每转产生N个A/B相脉冲对),在此模式下,每个机械周期会产生4N个计数脉冲(即4倍频),从而将分辨率提高4倍。方向由A、B相的相位关系判定。
- 方向计数模式(Direction-Count Mode):在此模式下,A相被当作时钟信号(CLK),B相被当作方向信号(DIR)。A相的每个上升沿(或根据配置的边沿)会使计数器递增或递减,具体由B相的电平决定。这种模式适用于某些只有单时钟加方向信号输出的设备。
- 向上/向下计数模式:将A相直接作为时钟,并固定计数方向为向上或向下。这常用于简单的频率测量或事件计数。
实操心得:绝大多数旋转编码器应用都应选择正交计数模式以获取最高分辨率。只有在处理特定的直线编码器或某些定制传感器时,才需要考虑方向计数模式。
QDECCTL[XCR]位可以让你选择是使用每个边沿(2倍频)还是仅上升沿(1倍频),在正交模式下,为了最大化分辨率,通常保持默认的“2x分辨率”即可。
解码后产生的“正交时钟”(QCLK)和“方向”(QDIR)信号,是整个eQEP模块后续所有功能的源头。QCLK驱动位置计数器,也作为边沿捕获单元的基准之一。
2.2 核心子单元功能与协作关系
解码后的信号流会分发到三个核心子单元,它们各司其职:
位置计数器单元(Position Counter):这是最核心的单元,包含32位的
QPOSCNT寄存器。每个QCLK事件都会使其根据QDIR进行加1或减1操作。它本质上是一个积分器,其值直接代表了从某个参考点开始的累积位移。它支持多种复位/初始化方式(通过索引、选通或软件),并可以设置最大计数值(QPOSMAX)实现循环计数。边沿捕获单元(Edge Capture Unit):这是实现高精度低速测量的关键。它包含一个独立的16位定时器
QCTMR(由系统时钟分频驱动)和一个锁存器QCPRD。它的工作原理是:不是去数固定时间内的脉冲数(这在低速时误差大),而是去测量产生固定数量脉冲所花费的时间。你可以通过QCAPCTL[UPPS]设置一个“单位位置事件”(例如,每64个QCLK为一个事件)。每当发生一个单位位置事件,QCTMR的当前值就会被锁存到QCPRD,然后QCTMR清零重启。这样,QCPRD中锁存的值就是产生这“单位位移”所花费的时钟周期数,从而可以非常精确地计算出低速。位置比较单元(Position-Compare Unit):用于产生同步事件。你可以设置一个目标位置值到
QPOSCMP寄存器。当QPOSCNT计数到与该值匹配时,硬件会自动产生一个同步脉冲输出(PCSOUT),并可以触发中断。这个功能在需要位置同步触发的场景中不可或缺,例如,在电机转到特定角度时精确触发ADC采样以测量电流,实现磁场定向控制(FOC)的同步性。
这三个单元并非孤立。例如,边沿捕获单元锁存的时间值,需要结合位置计数器锁存的位移值(通过单位超时事件或读取QPOSCNT时自动锁存到QPOSLAT,QCTMRLAT,QCPRDLAT)才能计算速度。而位置比较单元的同步输出,又可以作为ADC的启动信号。整个模块由统一的中断系统管理,包括位置比较匹配、单位定时器超时、捕获完成、看门狗超时等十多种事件,都可以配置为触发CPU中断,让你能够及时处理关键事件。
3. 核心寄存器配置详解与实战策略
手册上的寄存器描述往往很零散,我们需要从功能目标出发,把它们串联起来。下面我以最常见的“正交编码器位置与速度测量”为例,梳理一套完整的配置流程和关键点。
3.1 初始化配置:搭建工作舞台
在使能任何功能之前,必须先完成GPIO引脚复用配置,将对应的引脚(如GPIO6/7/8/9 for eQEP1)设置为eQEP功能。这一步通常通过SysConfig图形工具或直接写GPyGMUX/GPyMUX寄存器完成,这里不赘述。
接下来是eQEP模块本身的初始化,顺序很重要:
软件复位与基本使能:首先,通过清除
QEPCTL[QPEN]位来禁用位置计数器,这相当于一个软件复位,可以安全地配置其他寄存器。配置完成后,再将其置1使能。// 1. 禁用eQEP,进行安全配置 EQep1Regs.QEPCTL.bit.QPEN = 0; // 2. 配置解码控制寄存器 QDECCTL EQep1Regs.QDECCTL.bit.QSRC = 0; // 00: 正交计数模式 EQep1Regs.QDECCTL.bit.XCR = 0; // 0: 2倍频(计数上升和下降沿),获取最高分辨率 EQep1Regs.QDECCTL.bit.SWAP = 0; // 0: 不交换A/B相输入(根据实际接线调整) EQep1Regs.QDECCTL.bit.QAP = 0; // A相输入极性,0为不反向 EQep1Regs.QDECCTL.bit.QBP = 0; // B相输入极性 EQep1Regs.QDECCTL.bit.QIP = 0; // 索引信号极性 EQep1Regs.QDECCTL.bit.QSP = 0; // 选通信号极性位置计数器设置:设置位置计数器的初始值和计数范围。
EQep1Regs.QPOSINIT = 0; // 位置计数器初始化值,通常设为0 EQep1Regs.QPOSMAX = 0xFFFFFFFF; // 32位最大值,实现单向无限计数。也可设为编码器线数*4,实现循环计数。 EQep1Regs.QEPCTL.bit.PCRM = 0; // 00: 位置计数器在索引事件复位。如果编码器带Z信号,这非常有用。索引与选通事件配置:如果编码器有索引(Z)信号,可以配置其在特定边沿初始化或锁存位置值,实现机械零点的绝对定位。
// 索引事件初始化:在Z信号上升沿将QPOSCNT重置为QPOSINIT的值 EQep1Regs.QEPCTL.bit.IEI = 2; // 10: 上升沿初始化 // 索引事件锁存:在Z信号边沿将当前位置锁存到QPOSILAT,可用于“软件索引标记” EQep1Regs.QEPCTL.bit.IEL = 1; // 01: 上升沿锁存
3.2 速度测量方案选择与配置
这是eQEP最精髓的部分。速度测量本质上就是 Δ位置/Δ时间。eQEP提供了两种主流的硬件辅助方案,分别针对高速和低速优化。
方案一:单位定时器法(高频/高速测量)此方法原理简单粗暴:在一个固定的、较短的时间窗口(例如10ms)内,统计位置计数器的变化量。速度 = (Δ位置 / 单位时间)。这种方法在高速时精度高,但在低速时,由于Δ位置可能很小甚至为0,会导致计算误差大或无法计算。
配置步骤:
- 配置单位定时器周期
QUPRD。该定时器由系统时钟SYSCLKOUT驱动。例如,系统时钟为100MHz,想要10ms的周期,则QUPRD = 100e6 * 0.01 = 1,000,000。 - 使能单位定时器:
QEPCTL[UTE] = 1。 - 配置捕获锁存模式:
QEPCTL[QCLM] = 1。这样,当单位定时器超时(UTO事件)时,硬件会自动将此刻的QPOSCNT,QCTMR,QCPRD分别锁存到QPOSLAT,QCTMRLAT,QCPRDLAT中。这个自动锁存机制至关重要,它确保了你在中断服务程序中读取的位置和时间值是同一时刻的“快照”,避免了因先后读取而引入的误差。 - 使能单位超时中断:
QEINT[UTO] = 1。
// 单位定时器法配置示例 (SYSCLKOUT = 100MHz, 单位周期T = 10ms) Uint32 unit_period = 100000000L / 100; // 100Hz -> 10ms EQep1Regs.QUPRD = unit_period; EQep1Regs.QEPCTL.bit.UTE = 1; // 使能单位定时器 EQep1Regs.QEPCTL.bit.QCLM = 1; // 锁存模式:单位超时时锁存 EQep1Regs.QEINT.bit.UTO = 1; // 使能单位超时中断- 配置单位定时器周期
方案二:边沿捕获法(低频/低速测量)此方法反其道而行之:它测量产生一个固定位置变化(例如,128个QCLK)所需要的时间。速度 = (固定位置变化 / Δ时间)。这种方法在低速时精度极高,因为测量的是较长时间间隔,对时钟分辨率更敏感;但在高速时,时间间隔太短,可能超过捕获定时器的量程。
配置步骤:
- 配置单位位置事件预分频
QCAPCTL[UPPS]。这个值决定了多少个QCLK边沿产生一个“单位位置事件”(UPEVNT)。例如,UPPS=5表示每32个QCLK为一个事件。 - 配置捕获定时器时钟预分频
QCAPCTL[CCPS]。捕获定时器QCTMR由SYSCLKOUT分频而来。分频系数的选择需要确保在最低速测量时,定时器不会在两次单位位置事件间溢出(超过65535)。这是配置的难点和关键。 - 使能捕获单元:
QCAPCTL[CEN] = 1。 - 同样,设置
QEPCTL[QCLM] = 1,让单位超时事件来锁存捕获值。或者,你也可以设置QCLM=0,然后在每次需要计算速度时,通过读取QPOSCNT寄存器来触发一次锁存(硬件自动将QCTMR和QCPRD锁存到QCTMRLAT和QCPRDLAT)。
// 边沿捕获法配置示例 (编码器1000线,最低速10 RPM, SYSCLKOUT=100MHz) // 1. 计算最低速下的QCLK频率 // 电机转速 = 10 RPM = 10/60 RPS // 编码器每转脉冲数 = 1000线 * 4倍频 = 4000 QCLK/rev // QCLK_freq_low = (10/60) * 4000 ≈ 666.67 Hz // 2. 计算单位位置事件间隔时间 (以UPPS=5,即32个QCLK为一个事件为例) // UPEVNT_period = 32 / 666.67 Hz ≈ 0.048秒 // 3. 选择CAPCLK分频,使定时器计数不超过65535 // 需要的计时器计数 = 0.048秒 * SYSCLKOUT = 0.048 * 100e6 = 4.8e6 // 这远大于65535,所以必须分频。选择CCPS=7,即128分频。 // CAPCLK = 100MHz / 128 = 781.25 kHz // 在0.048秒内,CAPCLK的计数 = 0.048 * 781.25e3 ≈ 37500, 在16位计数器范围内。 EQep1Regs.QCAPCTL.bit.UPPS = 5; // 00101b: 单位位置事件 = QCLK/32 EQep1Regs.QCAPCTL.bit.CCPS = 7; // 0111b: CAPCLK = SYSCLKOUT/128 EQep1Regs.QCAPCTL.bit.CEN = 1; // 使能捕获单元 // 使用单位超时事件锁存,与方案一兼容 EQep1Regs.QEPCTL.bit.QCLM = 1; EQep1Regs.QEINT.bit.UTO = 1;- 配置单位位置事件预分频
核心避坑指南:在实际项目中,我强烈推荐同时配置并使用这两种方案,并在软件中根据当前速度进行智能切换。在单位定时器中断里,你可以读取锁存的位置差
DeltaPos。如果DeltaPos过小(例如小于某个阈值),说明速度较低,此时应信任并采用由边沿捕获单元计算出的速度(Speed_low = (固定位置单位) / (QCPRDLAT * CAPCLK周期));反之,则采用单位定时器法计算的速度(Speed_high = DeltaPos / (单位定时器周期))。TI提供的官方库函数EQEP_getVelocity()内部就实现了类似的逻辑。
3.3 位置比较与同步输出配置
位置比较功能常用于生成与机械位置严格同步的触发信号。
- 配置位置比较值:向
QPOSCMP寄存器写入目标位置值。例如,想让电机每转1000个QCLK(对应250线编码器)产生一个同步脉冲,就设置QPOSCMP = 1000。 - 配置同步输出:
EQep1Regs.QPOSCTL.bit.PCE = 1; // 使能位置比较单元 EQep1Regs.QPOSCTL.bit.PCSHDW = 1; // 使能影子寄存器(可选,用于同步更新) EQep1Regs.QPOSCTL.bit.PCPOL = 0; // 同步输出脉冲极性:0-高有效 EQep1Regs.QPOSCTL.bit.PCSPW = 10; // 同步脉冲宽度 = (PCSPW+1)*4个SYSCLKOUT周期 EQep1Regs.QDECCTL.bit.SOEN = 1; // 使能同步输出 EQep1Regs.QDECCTL.bit.SPSEL = 0; // 选择索引引脚作为同步输出引脚(也可选选通引脚) - 使能中断:如果需要在该位置点进行软件处理,使能位置比较匹配中断
QEINT[PCM] = 1。
当QPOSCNT计数到与QPOSCMP匹配时,硬件会在指定的引脚上产生一个宽度可编程的脉冲(PCSOUT),并置位QFLG[PCM]标志。
3.4 看门狗与中断配置
看门狗定时器用于监测运动是否停止。如果超过QWDPRD设定的时间没有收到QCLK边沿,QFLG[WTO]标志会被置位。这可以用来检测电机堵转或编码器故障。
EQep1Regs.QWDPRD = 0xFFFF; // 设置看门狗超时周期 EQep1Regs.QEPCTL.bit.WDE = 1; // 使能看门狗 EQep1Regs.QEINT.bit.WTO = 1; // 使能看门狗超���中断(可选)中断配置是使系统灵活响应的关键。eQEP有丰富的中断源。通常,我们需要在初始化时使能所需的中断,并在中断服务程序(ISR)中及时清除标志位。
// 使能常用的中断 EQep1Regs.QEINT.bit.UTO = 1; // 单位超时(用于速度计算) // EQep1Regs.QEINT.bit.PCM = 1; // 位置比较匹配 // EQep1Regs.QEINT.bit.IEL = 1; // 索引事件 // EQep1Regs.QEINT.bit.WTO = 1; // 看门狗超时 // 在PIE模块中配置eQEP中断向量并启用中断最后,别忘了使能位置计数器,让整个模块开始运行:
EQep1Regs.QEPCTL.bit.QPEN = 1; // 使能eQEP位置计数器4. 实战应用:从配置到速度计算的全流程
让我们结合一个具体的场景:使用一个1000线(每转1000个A/B脉冲对)的增量式编码器,测量电机转速,并在特定位置触发ADC采样。
4.1 硬件连接与初始化
假设编码器A、B、Z信号分别接到GPIO6, GPIO7, GPIO8。
- 使用SysConfig或直接写寄存器,将GPIO6/7/8配置为eQEP1A, eQEP1B, eQEP1I功能。
- 执行第3.1节的初始化代码,配置解码模式、极性等。
4.2 双模式速度测量实现
在全局变量中定义速度计算结构体,并在单位超时中断服务程序中实现算法。
typedef struct { int32_t rawPos; // 原始位置计数 int32_t oldPos; // 上次位置 int32_t deltaPos; // 位置差 float speed_rpm_high; // 单位定时器法计算的速度 (RPM) float speed_rpm_low; // 边沿捕获法计算的速度 (RPM) float speed_rpm; // 最终输出的速度 Uint32 capPeriod; // 捕获的周期值 Uint32 unitTimeoutPeriod;// 单位定时器周期 (对应时间) } SPEED_MEAS; SPEED_MEAS gSpeed; // 初始化 void SpeedMeas_Init(void) { gSpeed.oldPos = 0; gSpeed.speed_rpm = 0.0; // 假设编码器1000线,4倍频后为4000 counts/rev // 单位定时器周期设为10ms (100Hz),对应QUPRD值需根据SYSCLKOUT计算 // 例如 SYSCLKOUT=100MHz, QUPRD = 100e6 / 100 = 1,000,000 EQep1Regs.QUPRD = 1000000L; gSpeed.unitTimeoutPeriod = 1000000L; // 存储用于计算 // 配置捕获单元:每128个QCLK为一个单位位置事件,CAPCLK = SYSCLKOUT/64 EQep1Regs.QCAPCTL.bit.UPPS = 6; // QCLK/64 EQep1Regs.QCAPCTL.bit.CCPS = 6; // SYSCLKOUT/64 EQep1Regs.QCAPCTL.bit.CEN = 1; EQep1Regs.QEPCTL.bit.QCLM = 1; // 单位超时锁存 EQep1Regs.QEPCTL.bit.UTE = 1; EQep1Regs.QEINT.bit.UTO = 1; EQep1Regs.QEPCTL.bit.QPEN = 1; } // eQEP单位超时中断服务程序 __interrupt void eQEP1_ISR(void) { // 1. 读取锁存的位置值 gSpeed.rawPos = EQep1Regs.QPOSLAT; // 单位超时时刻锁存的位置 gSpeed.deltaPos = gSpeed.rawPos - gSpeed.oldPos; // 计算位置差 gSpeed.oldPos = gSpeed.rawPos; // 更新旧位置 // 2. 单位定时器法(高速)速度计算 // 位置差是QCLK数。每转的QCLK数 = 编码器线数 * 4 // 速度 (RPM) = (deltaPos / (counts_per_rev)) / (unitPeriod / SYSCLKOUT) * 60 float deltaRev_high = (float)gSpeed.deltaPos / (1000.0 * 4.0); // 转数 float timeSec_high = (float)gSpeed.unitTimeoutPeriod / 100000000.0; // 假设SYSCLKOUT=100MHz gSpeed.speed_rpm_high = (deltaRev_high / timeSec_high) * 60.0; // 3. 边沿捕获法(低速)速度计算 // 读取锁存的捕获周期值 gSpeed.capPeriod = EQep1Regs.QCPRDLAT; if(gSpeed.capPeriod != 0 && gSpeed.capPeriod != 0xFFFF) { // 固定位置变化 = UPPS定义的单位事件对应的QCLK数,本例为64个QCLK float deltaRev_low = 64.0 / (1000.0 * 4.0); // 单位事件对应的转数 // 捕获周期对应的时间 = capPeriod * (CAPCLK周期) // CAPCLK周期 = (2^CCPS) / SYSCLKOUT, 本例CCPS=6, 分频系数=64 float capClkPeriod = 64.0 / 100000000.0; // 秒 float timeSec_low = (float)gSpeed.capPeriod * capClkPeriod; gSpeed.speed_rpm_low = (deltaRev_low / timeSec_low) * 60.0; } else { // 捕获溢出或方向错误,数据无效 gSpeed.speed_rpm_low = 0.0; } // 4. 速度融合(简单阈值切换) if(abs(gSpeed.deltaPos) > 5) { // 阈值可调,例如位置变化大于5个计数则认为速度较高 gSpeed.speed_rpm = gSpeed.speed_rpm_high; } else { gSpeed.speed_rpm = gSpeed.speed_rpm_low; } // 注意:这里应处理方向,deltaPos的符号即代表方向 // 5. 清除中断标志 EQep1Regs.QCLR.bit.UTO = 1; // 清除单位超时中断标志 EQep1Regs.QCLR.bit.INT = 1; // 清除全局中断标志 // 必须同时清除PIE应答位 PieCtrlRegs.PIEACK.all = PIEACK_GROUP4; }4.3 位置同步触发ADC采样
假设我们需要在电机每转一圈(4000个QCLK)的零点(索引位置)和半圈(2000个QCLK)处触发ADC采样。
void Setup_PositionCompare_Sync(void) { // 配置位置比较单元 EQep1Regs.QPOSCTL.bit.PCE = 1; EQep1Regs.QPOSCTL.bit.PCSHDW = 1; // 使用影子寄存器,避免写入时产生毛刺 EQep1Regs.QPOSCTL.bit.PCPOL = 0; EQep1Regs.QPOSCTL.bit.PCSPW = 99; // 脉冲宽度 = (99+1)*4 = 400个SYSCLK周期 EQep1Regs.QDECCTL.bit.SOEN = 1; EQep1Regs.QDECCTL.bit.SPSEL = 0; // 使用索引引脚作为同步输出 // 设置第一个比较点(半圈) EQep1Regs.QPOSCMP = 2000; // 使能位置比较匹配中断,以便在中断中更新下一个比较点 EQep1Regs.QEINT.bit.PCM = 1; } // 位置比较匹配中断服务程序 __interrupt void eQEP1_PCM_ISR(void) { // 读取当前匹配的位置比较值,并设置下一个比较值 // 例如,实现一个在2000和4000之间交替的比较点 static Uint32 nextCompare = 4000; if(EQep1Regs.QPOSCMP == 2000) { nextCompare = 4000; } else { nextCompare = 2000; } // 更新影子寄存器(如果使能了影子模式,写入QPOSCMP会先到影子寄存器) // 需要在下一个加载事件(如计数器归零或匹配)时生效 // 这里为了简单,直接加载。更安全的做法是配置PCLOAD在匹配时加载。 EQep1Regs.QPOSCMP = nextCompare; // 在这里可以触发ADC采样序列,例如通过软件强制启动SOC AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1; // 清除中断标志 EQep1Regs.QCLR.bit.PCM = 1; EQep1Regs.QCLR.bit.INT = 1; PieCtrlRegs.PIEACK.all = PIEACK_GROUP4; }5. 调试技巧与常见问题排查
即使配置看起来正确,在实际硬件调试中也可能遇到各种问题。以下是我总结的几个典型场景和排查思路。
5.1 位置计数器不计数或计数异常
- 现象:
QPOSCNT寄存器值不变化,或变化规律与预期不符(例如只增不减)。 - 排查步骤:
- 信号层面:首先用示波器检查编码器的A、B相信号是否正常接入芯片引脚,幅值、频率是否符合要求,相位差是否为90度。这是最基本也最常被忽略的一步。
- GPIO复用:确认GPIO的MUX配置是否正确设置为eQEP功能,而非普通的GPIO输入。
- 输入极性:检查
QDECCTL[QAP], [QBP]配置。如果编码器是推挽输出高电平有效,而你的配置是低电平有效,或者接反了,会导致计数方向错误或不计数。可以尝试翻转极性位测试。 - 解码模式:确认
QDECCTL[QSRC]设置为正确的模式(00-正交计数)。 - 计数器使能:最后检查
QEPCTL[QPEN]是否已置1。
5.2 速度测量值不准或不稳定
- 现象:计算出的速度跳动大,或者在高低速切换时出现跳变。
- 排查步骤:
- 单位定时器法(高速):
- 检查
QUPRD值计算是否正确。确保单位定时器中断周期T_unit是准确的。 - 在中断中读取的
DeltaPos是否使用了锁存值QPOSLAT?直接读QPOSCNT可能在两次读取之间其值已变化,导致计算错误。务必使用QCLM=1模式,让硬件在UTO事件时自动锁存QPOSLAT。 - 处理
DeltaPos的符号(方向)。QEPSTS[QDF]位指示当前方向。
- 检查
- 边沿捕获法(低速):
- 最关键:检查捕获定时器是否溢出。读取
QEPSTS[COEF]标志。如果置位,说明QCTMR在两次单位位置事件间计数值超过了65535。这意味着QCAPCTL[CCPS]分频系数设置得太小,需要增大分频比以降低CAPCLK频率。 - 检查方向变化错误
QEPSTS[CDEF]。如果置位,说明在两次单位位置事件间电机改变了方向,此时QCPRDLAT会被置为0xFFFF,数据无效。在低速反转频繁的场景下,这可能频繁发生,需要考虑软件滤波或使用其他测量方法。 - 验证
QCAPCTL[UPPS]和[CCPS]的计算。确保在最低速时,QCTMR的计数值既不会溢出(<65535),也不要太小(>几十个计数),以保证测量精度。
- 最关键:检查捕获定时器是否溢出。读取
- 通用问题:
- 中断延迟:确保eQEP中断的优先级足够高,中断服务程序执行时间尽可能短。长时间关中断会导致锁存的数据不是严格的周期末数据。
- 数据类型与计算:速度计算涉及浮点运算,在ISR中大量浮点计算可能耗时。考虑使用TI的IQMath库进行定点数运算以提升效率。
- 单位定时器法(高速):
5.3 位置比较同步输出无信号
- 现象:配置了位置比较和同步输出,但对应引脚没有脉冲产生。
- 排查步骤:
- 输出使能与引脚选择:确认
QDECCTL[SOEN]=1,并且[SPSEL]选择了正确的引脚(0-索引引脚,1-选通引脚)。同时,该引脚可能还需要在GPIO模块中配置为外设输出功能,而不仅仅是eQEP输入功能,具体需查阅芯片数据手册。 - 比较值:确认
QPOSCMP的值是合理的,并且QPOSCNT能够计数到该值。可以先将比较值设为一个很小的数(如10)进行测试。 - 影子寄存器:如果设置了
PCSHDW=1(影子模式),需要检查PCLOAD的配置。PCLOAD=0时在QPOSCNT=0加载,PCLOAD=1时在比较匹配时加载。如果你在运行时更新了QPOSCMP,但加载条件未触发,新值不会生效。对于简单的单次比较,可以先将PCSHDW设为0(立即加载模式)进行测试。 - 脉冲宽度:
PCSPW设置的是脉冲宽度的参数,公式为(PCSPW+1)*4*SYSCLKOUT周期。如果SYSCLKOUT频率很高(如100MHz),而PCSPW设置很小(如0),则脉冲宽度仅为40ns,可能太窄以至于示波器难以捕捉。可以适当调大PCSPW。
- 输出使能与引脚选择:确认
5.4 索引(Z)信号相关功能异常
- 现象:期望在Z信号边沿复位或锁存位置,但未发生。
- 排查步骤:
- 信号与极性:用示波器确认Z信号是否正常,并检查
QDECCTL[QIP]极性设置是否正确。 - 索引门控:注意
QDECCTL[IGATE]位。如果此位置1,则索引信号会被选通(Strobe)信号门控。在不需要门控的场合,确保此位为0。 - 初始化/锁存边沿选择:
QEPCTL[IEI]控制初始化边沿,[IEL]控制锁存边沿。确认你配置的是上升沿(2)还是下降沿(3)。IEL=3是特殊的“软件索引标记”模式,会将方向也锁存到QEPSTS[QDLF]。 - 首次索引标记:
QEPSTS[FIMF]位在第一个索引事件后置位,并锁存该时刻的方向到QEPSTS[FIDF]。可以通过检查这些状态位来调试索引事件是否被正确识别。
- 信号与极性:用示波器确认Z信号是否正常,并检查
通过以上系统的配置解析、实战代码和问题排查指南,你应该能够驾驭TMS320F280013x的eQEP模块,构建出稳定可靠的高性能位置与速度检测系统。记住,理解硬件模块的数据流和控制流,结合示波器观察实际信号,是调试此类外设的不二法门。
