
决定把这次调 TMS32F28P550 的经历写成一份实录也是给自己留个档。这块芯片看名字跟普通 32 位 MCU 差别不大真正上手才发现光是“能连上仿真器”这一关就能把人卡掉一层皮。仿真器报 -1135、程序烧进 Flash 不跑、串口打印乱码、一运行就进非法中断……每一个问题单独拎出来都有十几种可能而“调试问题实录”这类内容最怕的就是只记录表象不分析根因。所以这篇文章我会把调试环境搭建、JTAG 连接原理、Flash 烧写步骤、串口联调配合、常见问题排查全部走一遍主要面向正在用 F28P55 系列做电机控制或数字电源的朋友也适合所有 C2000 平台的新手直接对照排错。1. 调试环境与工具链搭建——事情能不能成一半看这里1.1 为什么选 XDS110 仿真器而不是 J-Link我第一次拿到 TMS32F28P550 开发板时下意识就是想用 J-Link因为以前调 Cortex-M 用习惯了。但 J-Link 官方并不直接支持 TI C2000 平台就算用第三方转接也麻烦识别出来的内核是错的根本没法下程序。最后老老实实换成 TI 官方的 XDS110 调试器。XDS110 在 TI 生态里属于低成本但功能够用的型号支持 JTAG 和 cJTAG也可以当串口工具用。它通过 USB 连接到电脑另一端是标准的 20 针 JTAG 座或者 10 针转接座。F28P55 这类 C2000 器件本身带标准的 JTAG 接口所以硬件连线并不复杂TCK、TMS、TDI、TDO、TRST、GND 这六根是必须的如果板子面积紧张只拉这六根也能工作但我建议把 EMU0 和 EMU1 也引出来后续排查低速连接问题会方便很多。还有一个容易踩的坑是线缆长度。我第一次打样为了布线方便把 JTAG 座放得离芯片很远中间走了二十多厘米的排线结果 CCS 连接时频繁超时。后来把线裁到十厘米以内问题立刻消失。XDS110 的 JTAG 信号本身不算特别娇气但 TDO 和 TCK 是时序关键路径线太长、地线不干净都会造成回读不稳定。1.2 CCS 版本与组件选择Code Composer Studio 版本建议直接用 12.x 以上安装时一定要勾选 C2000 相关的组件。我同事装了默认配置打开后新建 Target Configuration 时Device 列表里根本没有 TMS32F28P550 这个型号排查了半天最后重新安装并勾选了 C2000 编译工具链和器件支持包才解决。另外如果你需要配合 SysConfig 做外设初始化记得在 CCS 里安装对应的 SysConfig 插件。C2000 的新工程向导可以自动生成基础代码但 F28P55 系列在外设初始化上依然保留了大量寄存器级别的配置工作别指望完全图形化。我的建议是工程尽量用 CCS 的向导建编译器版本固定一个不要在一台电脑上同时混用 CCS 12 和 CCS 6两个版本生成的工程文件格式不同打开时会自动迁移迁移后编译选项可能出现差异这种问题最难查。1.3 首次连接前的板级检查清单先别急着插仿真器。拿万用表把这几组电源量一遍VDDIO 是否在 3.3VDVDD 内核电压是否正常AVDD 模拟电源是否和 VDDIO 一致。F28P55 内部有 LDO很多人以为只供一个 3.3V 就完事但如果板子焊接短路或者 LDO 配置不对内核电压可能偏到 1V 以下现象就是仿真器能识别到器件但一连接就报错。复位引脚也要检查。C2000 的复位脚是低有效正常工作时应该为高电平。如果外部接了看门狗芯片或者 RC 复位电路里的电容用得太大会导致复位释放太慢CCS 连接时芯片还没从复位状态出来自然连不上。我手上有一块板子的复位电容用了 10uF每次上电都要等好几秒才能连上后来换成 100nF 才正常。还有一个特殊的地方C2000 有代码安全模块 DCSM如果芯片之前被烧过程序并且安全区被锁定那 CCS 连接时会提示无法访问目标。首次拿到的新芯片一般不会锁但二手板子或返修板特别容易碰到后面我会单独讲怎么处理。2. JTAG与仿真器连接的底层原理2.1 “连接时出现 -1135”到底是什么情况CCS 最常见的连接错误就是弹窗提示 “Error connecting to the target: Device is held in reset” 或者错误号 -1135。我第一次看到 -1135 以为是什么高深问题实际上它对应的是 JTAG 链路握手失败也就是仿真器没有从 TDO 引脚收到预期的数据回包。换句话说目标板没有正常工作或者 JTAG 链路本身不通。排查顺序应该是先点 CCS 里的 “Test Connection” 按钮XDS110 会自检并尝试建立 JTAG 通信测试结果会明确告诉你“扫描到 1 个 TAP”还是“没有发现器件”。如果扫描不到检查 JTAG 排针是否插反、TMS 和 TCK 是否接反、GND 是否共地。尤其是共地问题电脑通过 USB 给仿真器供电目标板是独立电源两者之间必须有一条可靠的 GND 连接否则 TDO 回读永远是高阻态错误码就是 -1135。还有一种情况是芯片被外部看门狗拉住了复位。有些电源板会配外部看门狗上电后看门狗开始计时而调试器连接时目标芯片要先从复位状态释放如果看门狗不断触发复位JTAG 就没法稳定完成握手。调试阶段最简单粗暴的办法是把外部看门狗芯片断电或者把喂狗引脚用杜邦线拉到一个固定电平先把连接问题解决再说。2.2 Boot 引脚与上电时序的坑C2000 的启动过程跟 ARM 芯片不太一样它会根据 Boot 引脚的状态在复位释放时决定进入哪种 boot 模式比如从 Flash 启动、从 SCI 启动、从并行 IO 启动等。这些问题在调试时经常被忽略却可能导致一个很诡异的现象CCS 里在线调试一切正常但一旦断电重新上电程序就是跑不起来。原因在于仿真器连接时TRST 信号处于有效状态目标芯片会进入调试模式并不完全按照 Boot 引脚走。但拔掉仿真器重新上电后Boot 引脚的电平就决定了一切。如果这些引脚悬空受到噪声干扰芯片可能进到 UART Boot 或者其他怪异模式而不是执行 Flash 里的程序。解决办法就是对照数据手册里的 Boot Configuration 表把对应的 Boot 引脚用上拉或下拉电阻固定成“从 Flash 启动”。比如在 Boot 引脚上装拨码开关或者跳线帽调试时任意切换量产时固定成 Flash 模式。另外复位时序也很重要。F28P55 上电后内部 LDO 要稳定输出时钟要起振然后复位脚释放Boot ROM 开始跑。如果外部复位信号释放得太早芯片内部的电源还没稳定启动就会失败。严格来说应该用电源监控芯片控制复位释放但在调试板上只要保证 3.3V 正常后延时几十毫秒再释放复位一般也没问题。2.3 供电、时钟与连接成功率的关系很多人觉得 JTAG 连接失败就是接线问题但供电和时钟同样会卡脖子。特别好笑的是头一天还能连上的板子第二天怎么都连不上最后发现是 USB 供电的仿真器跟目标板共用了一个纹波很大的电源适配器。仿真器输出 JTAG 逻辑电平的参考电压来自目标板如果目标板电压在 3.0V 到 3.6V 之间抖动通信波形就会畸形。时钟这边的问题更隐蔽。F28P55 内部有 INTOSC理论上不接外部晶振也能跑但很多硬件工程师习惯性放一颗外部晶振并且在软件里配置成外部时钟模式。如果晶振没起振或者型号不对芯片上电后 Boot ROM 引导用户程序时在时钟切换这一步就可能死掉。表现就是仿真器能连上也能擦除 Flash但一运行就进非法中断或者直接停在复位向量附近。排查时钟的办法很简单示波器探头直接点 XTAL 引脚。如果芯片供电正常、复位已经释放晶振引脚上应该能看到稳定的正弦波。如果完全没有波形先查晶振两端的负载电容是否过大或过小。我遇到过把 12pF 电容焊成 100nF 的晶振完全不起振折腾了整整一个下午。3. 在线调试与程序下载的实战拆解3.1 目标配置文件与 GEL 脚本到底改什么CCS 里连接芯片必须有一个 Target Configuration 文件.ccxml这里面要填正确的器件型号。TMS32F28P550 在 CCS 的器件列表里应该能找到对应版本注意别选成了 TMS320F28335 这类老芯片虽然内核都是 C28x但寄存器地址和外设映射完全不同连上也是乱七八糟。配置里还可以指定 GEL 脚本。GEL 文件的作用是在连接目标后执行一段初始化代码比如初始化时钟、PLL、外设等相当于把芯片带到一个已知状态。TI 官方会在 CCS 安装目录下提供对应器件的 GEL 文件路径一般在ccs_base/emulation/boards/下面。新手不用自己写直接用默认的就行。但要注意GEL 脚本并不是万能的。如果工程里已经初始化了 PLL而 GEL 又把 PLL 改成另一组参数连接后可能出现时钟已经变了但外设没跟着变的情况。我的习惯是 GEL 只用来让芯片保持在一个可调试的基础状态剩下的外设初始化全部交给用户程序自己的初始化函数。3.2 把程序烧进 Flash 的正确姿势用 CCS 在线调试 RAM 里的程序很简单编译下载就能跑。但产品最终要从 Flash 启动这一步坑最多。首先链接脚本要切换成 Flash 版本的 .cmd 文件。如果你继续用 RAM 版本的链接脚本烧录时虽然不报错但复位后芯片根本找不到程序入口。其次代码运行时的复制问题。F28P55 的 Flash 读取速度慢于 CPU 主频所以一般把时序敏感的代码放到 RAM 里运行比如 ADC 中断服务函数、PWM 中断服务函数。这需要把函数的ramfunc段链接到 RAM并且在启动代码里用memcpy从 Flash 复制到 RAM。很多人的程序跑飞其实不是逻辑问题而是ramfunc没复制完整函数指针跳到了一个还没拷贝完的地址上。烧录之前最好在工程初始化里先把看门狗关掉。虽然烧录本身由仿真器控制但烧完后如果代码里有看门狗在不断复位你根本来不及检查运行结果。另一个要点是 Flash 等待状态如果 CPU 频率比较高必须在初始化里调用 Flash 等待状态配置函数否则读指令会出错。TI 的例程里通常会有F28P55x_InitFlash()这类函数烧录前确认工程把它调用到了。3.3 断点、单步和实时变量窗的坑一切顺利连上芯片后接着会碰到断点失效的问题。C2000 的硬件断点数量有限在 Flash 中运行代码时如果你打了超过硬件限制数量的断点CCS 会静默忽略多余的断点。特别是打断点在中断服务函数里有时候怎么都触发不了可能就是断点资源不够用。解决办法很粗暴减少断点数量或者把要调试的函数放到 RAM 里运行让断点通过软件方式实现。我在调 PWM 中断里的一段 PID 算法时就在函数前面加上#pragma CODE_SECTION(func, ramfuncs)把这段代码放 RAM再用软件断点体验立刻提升。变量窗口读不到值也很常见。C2000 编译器默认可能开启优化一个局部变量在优化后被放到寄存器而不是内存里Expressions 窗口当然读不到。要么调低优化等级要么给变量加volatile。另外实时调试模式下CS 可以单步执行外设中断但要注意实时模式会占用 JTAG 一部分带宽如果变量刷新太快反而会把仿真器拖死。正常情况下不用一直开着实时刷新只有在需要观察电机控制里的动态电流值时再打开。4. 串口调试助手配合联调4.1 串口打印输出配置程序调通了之后下一步就是数据交互。F28P55 上的 SCI 模块就是传统 UART通常用一颗 USB 转 TTL 芯片CH340、CP2102 之类接到电脑再用 XCOM 或 SSCOM 这类串口调试助手看数据。SCI 的波特率配置要稍微算一下因为它是基于外设时钟 LSPCLK 分频出来的。比如系统主频 SYSCLK 是 120MHzLSPCLK 默认是 SYSCLK 的 1/4也就是 30MHz。目标波特率 115200计算公式是BRR LSPCLK / (8 * 波特率) - 1算出来大概是 31.5取整后实际波特率偏差约 1.4%完全没问题。代码里一般这么写#define LSPCLK 30000000UL #define BAUDRATE 115200UL #define BRR_VALUE ((LSPCLK / (8UL * BAUDRATE)) - 1UL)然后在初始化时把这个值写进 SCIHBAUD 和 SCILBAUD 寄存器。注意如果 LSPCLK 配置得不对或者工程里改了时钟树而没同步更新 LSPCLK串口打印就是乱码。4.2 乱码、无数据和丢数据问题排查串口出现乱码的原因基本就几个波特率不对、电平不匹配、共地不良、时钟基准不同步。USB 转 TTL 模块和 F28P55 之间必须共地这一点特别容易忽略。我遇到过用笔记本电脑调试时数据有时对有时错后来发现是 USB 模块的 GND 通过电脑电源地和目标板地形成回路回路里有压降换一根短线直接连 GND 后问题消失。无数据的情况也不少见。C2000 的 SCI 引脚不带 5V 容忍如果你用 5V 的 USB 转串口模块长期会损坏引脚短期则可能出现读不到数据的问题。检查 TXD/RXD 是否接反很基础但也总有人搞混。更隐蔽的是引脚复用F28P55 的 SCI 引脚可能默认被配置成 GPIO需要在初始化代码里通过寄存器切换为外设功能。丢数据的问题则多出现在接收侧。如果压力测试时连续发几百帧上位机偶尔丢一帧先看串口调试助手的接收缓冲区设置很多助手默认缓冲区太小数据一多就丢。我习惯用 XCOM 并关闭“自动滚屏”同时把缓冲区调大能显著降低丢帧。还有一个技巧是使用十六进制接收先确认每个字节都对再去解析协议里带的关键参数不然你以为是丢数据实际上是报文长度解析错了。4.3 上位机与 MCU 的握手技巧联调时不要一上来就跑完整协议。我习惯先在 MCU 里写一段测试代码循环发送 0x55、0xAA 这两个字节。如果串口助手里能看到规整的 55 AA 55 AA说明物理链路完全通然后才进入真正的数据帧联调。调试助手尽量用十六进制收发避免 ASCII 模式下的编码干扰。如果上位机是基于 Python 或 Qt 自己写的接收时要注意超时机制不要在阻塞式读串口里等一帧永远不来的数据。给协议帧加上帧头、长度和校验这样就算丢一帧也能通过校验发现。我曾经踩过一个大坑MCU 发出来的一帧数据在串口助手里少了一个字节怎么查都查不到原因后来发现是上位机把\r\n当成了消息结束符遇到数据里面的 0x0D 就提前截断。所以帧协议设计时要注意定界符的选择不要用可能出现在数据内容里的字节作为边界最稳妥的是用固定长度帧加上校验和。5. 调试问题实录与解决案例5.1 程序跑到一半就进非法中断 illegal ISR这个现象很有代表性。程序上电能跑但运行几秒钟后突然跳进interrupt void illegalISR()单步走也看不出所以然。发生在 TMS32F28P550 上最常见的两个原因一是中断向量表没初始化或者没有复制到 RAM二是某个外设的中断没有映射到正确的 PIE 向量。C2000 的中断架构和串口大片机不太一样它有一个外设中断扩展 PIE 模块所有外设中断都要通过 PIE 映射到 CPU 中断。如果代码里用memcpy把 Flash 里的 PIE 向量表复制到 RAM但复制长度不对或者工程链接脚本里 PIE 向量表段的位置有误一旦对应外设触发中断CPU 就会跳到一个错乱的地址进而进入非法中断。排查办法是在非法中断里点亮一个 LED 或者翻转一个 GPIO然后看现象是不是周期性的。如果周期性出现优先怀疑看门狗复位或者某种定时器中断如果完全不固定优先查中断向量表。调试时把INT1到INT14的中断服务函数逐个屏蔽二分法找到是哪一路中断在捣乱。5.2 断电解锁后程序“神秘消失”的经典场景还有一类问题在线调试明明正常Flash 也烧进去了但一断电再上电板子就跟砖一样串口没输出仿真器重新连接也连不上甚至报目标被锁。这种十有八九是代码安全模块 DCSM 被配置成了锁定状态而你自己忘了这件事。C2000 出厂时 DCSM 默认不锁定但很多评估板例程里会包含安全区设置代码如果你没注释掉直接烧了再把某些区域设成只读或者禁止调试访问下次仿真器就进不去了。解决办法是使用 CCS 的 On-Chip Flash 工具选择解锁操作前提是密码没有被改掉。如果密码丢了就比较麻烦只能通过 JTAG 的 ERASE 命令做全片擦除但部分型号在锁死状态下连擦除都不允许这时候只能换芯片。所以我的经验是产品阶段再用 DCSM调试阶段一律不碰。你觉得自己只是设置了一个安全位实际上等于往芯片上装了一把锁。5.3 Flash 校验失败的经典原因烧录 Flash 时进度条走到一半突然报校验失败这类问题我也遇到过好多次。先从最简单的入手目标板供电是否稳定。Flash 写入需要较高的电流如果 3.3V 电源带载能力不足电压跌落超过 5%编程就会出错。换一个独立电源或者查看一下电源纹波有时候就能解决。然后是时钟配置。如果芯片连接后用户程序的 PLL 配置和烧录工具预期的不一致Flash 写入的时序判断就会偏差。比如连接时 GEL 脚本把系统时钟设成 120MHz但芯片实际外接晶振是 8MHz烧录工具认为的 120MHz 其实没起来Flash 控制器内部等待周期不够校验自然失败。现象通常是 CCS 报错误停在同一位置重启后又能擦除但烧不进去。最后一个隐蔽原因Flash 擦除后没有完全清干净。新芯片不会有这个问题但反复烧录的芯片如果某次写入被中断扇区里残留了一些旧数据再烧录时校验就会失败。处理方式是先做整片擦除Full Erase等它彻底完成后再烧不要选 Erase Only Modified Sectors。量产时如果一片板子反复维修多次这个操作能救回来不少芯片。6. 新板调试检查表——把踩过的坑提前避开6.1 上电后按这个顺序查一遍拿到一块全新的 TMS32F28P550 板子我现在的习惯是固定按几个步骤来一步步排除效率比抓到什么查什么高得多。首先万用表量电源轨VDDIO 3.3V、DVDD 内核电压、AVDD 模拟电压三组都在正常范围再继续。然后用示波器看复位脚确认是高电平而不是被外部电路拉低。接着量晶振引脚最好能看到振荡波形。确认这些之后再连接 XDS110。连接成功后不要急着烧程序先在 CCS 的 Registers 窗口看一下 DEV_CFG 寄存器里的器件 ID确认仿真器识别到的型号和实际芯片一致。然后打开 Disassembly 窗口看 PC 寄存器停在哪如果是 0x3FFFFF 之类的非法地址说明芯片没有进入 Flash 引导如果停在 0x000000很可能卡在复位向量此时再去查启动引脚。6.2 把“低级错误”扼杀在制板阶段回头看我这次调试浪费最多时间的反而不是芯片本身而是一些非常初级的硬件问题。比如 JTAG 座 1 脚方向画反、TCK/TMS 在网络连接时对调、地线没有接全这些都是制板阶段就能避免的坑。调试接口建议用标准 14 针或者 20 针母座同时把 EMU0/EMU1 和 TRST 都引出来方便以后用高速仿真器或做边界扫描测试。电源部分给内核、模拟、数字分别加滤波电容尽量靠近芯片引脚。复位脚上拉电阻和电容的取值要参考数据手册推荐。外部晶振不要选太冷门的频率8MHz、10MHz、20MHz 这类常见频率在软件配置时有现成模板非要选个 12.288MHz不仅计算分频费劲而且容易写错。最后再说一个很多人忽视的经验调试 C2000 时如果只是验证某个外设功能先在 RAM 里把整个流程跑通再进 Flash。我每调一个新外设都会开一个单独的 RAM 调试工程只保留最小配置文件这样就算程序写炸了重新上电还是一条好汉。确认逻辑没问题之后再合入 Flash 工程做烧录验证。这套“先 RAM 后 Flash”的顺序能帮你把调试问题和芯片本身的问题隔离开来。