ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TMS320F28335 DSP开发全流程:从CCS环境搭建到Flash烧写

TMS320F28335 DSP开发全流程:从CCS环境搭建到Flash烧写 提到DSP开发圈子里一直有个绕不开的名字TMS320F28335。很多做电机控制、数字电源、并网逆变器的工程师第一块正经的DSP芯片就是它。甚至有学生朋友跟我说实验室里导师丢来一块28335开发板扔下一句“自己跑通一遍”人就走了——然后一周过去连一个LED都点不亮。这不是个例而是绝大多数初学者都会经历的现实。原因很简单28335的运行机制、开发流程、调试手段和ST的STM32系列完全是两套思路。你用单片机固化的那套“点亮GPIO”的思维去套DSP大概率会卡在工程配置、时钟初始化和内存分配这些最基础的地方。这篇文章我打算以TMS320F28335为主线把DSP开发流程从零到一完整梳理一遍涉及芯片选型、硬件架构、CCS开发环境搭建、工程创建、RAM调试到Flash烧写的全部环节。适合已经有点单片机基础、想正式进入DSP开发领域的人也适合刚拿到28335开发板还在发懵的初学者。1. 为什么入门DSP我推荐先摸熟283351.1 先搞清楚28335在DSP家族里的定位TI的C2000系列覆盖了几代产品早期是F2407后来是F2812再后来就是F28335这一代。如果放在时间轴上28335属于“承前启后”的型号——它既有老一代C28x内核的稳定特性又加入了硬件浮点运算单元、DMA、更强的PWM模块等新特性。这种定位决定了它在今天依然有巨大的存量市场大量已量产的项目里跑的还是这颗芯片。很多学生问要不要直接学更新的F28379D我的建议是作为学习入门28335的资料、例程、网上讨论量都是最多的。你去搜一个问题几乎每个坑都有人踩过而新芯片资料少遇到问题连个问的地方都没有。入门阶段最怕的不是芯片性能不够而是学习成本失控。28335的另外一个优势是价格相对便宜开发板一两百块就能买到性能不错的核心板。对于初学者来说低成本试错本身就是一种竞争力。1.2 28335能做什么解决了什么问题28335的主频是150MHz32位C28x内核带FPU单精度浮点运算单元片内集成256KB Flash和34KB SRAM。这些参数放在今天看不算顶级但在实时控制领域它的外设配置放到现在依然很能打6组ePWM共12路PWM输出、16通道12位ADC、2个CAN模块、3个SCI串口、1个SPI、1个I2C、1个McBSP还带EMIF外部存储器接口。这意味着什么意味着你可以用一片28335完成一套完整的电机控制系统PWM发生器控制功率开关管ADC采集母线电压和相电流eQEP读取编码器位置CAN和上位机通信。数字电源领域更是它的主战场高频PWM配合HRPWM高分辨率模式可以达到几百皮秒级别的脉宽调节精度。对于做毕业设计、竞赛或者小批量产品的工程师来说它是性价比很高的选择。2. 28335的硬件架构核心要点从总线结构到外设地图2.1 内核与总线C28x不只是“跑得快”的32位MCU很多初学者会把DSP等同于高频单片机其实这是理解上的第一个误区。C28x内核采用哈佛总线结构程序存储和数据存储是分开的指令和数据可以在同一个时钟周期内并行访问这是DSP能高效执行循环运算的底层原因。配合片内的流水线机制很多运算在硬件层面就做了加速而不是靠软件优化。内核部分还有一个关键知识点28335的中断系统。它把中断分为三级——外设级、PIE级和CPU级。外设产生中断事件后要先被PIE外设中断扩展模块捕获再由PIE映射到CPU的12条中断线INT1到INT12。实际编程时你必须清楚自己的外设中断被分配到哪一组第几个通道才能在PIE向量表中正确注册中断服务函数。很多人第一次写CAN接收中断进不去问题经常就出在这里。2.2 存储器映射与管理一句话讲清楚CMD文件28335的存储空间是统一编址的程序、数据、外设寄存器都在同一个4M×16位的寻址空间内。Flash从地址0x300000开始SRAM分若干块从0x008000开始。还有Boot ROM区、OTP区以及外设寄存器区。正因为空间是统一规划的芯片本身不区分“这个地址是给程序还是给数据用”而是靠链接文件CMD文件来把编译产物安排到不同区域。CMD文件是28335开发里绕不开的东西。调试阶段用RAM版本的链接文件把所有程序段放到SRAM里运行烧写阶段用Flash版本的链接文件把程序固化到Flash中上电后由Bootloader搬移到RAM中执行。不少初学者把这两个文件搞混在RAM调试好好的程序用Flash链接文件编译下载后反而不运行了原因多半是中断向量表、堆栈指针和程序入口没有正确安排。后面我会专门展开讲。2.3 外设框架哪些外设是实际项目中高频使用的关于28335的外设不需要死记硬背每个寄存器但要建立“外设地图”的概念。以实际项目为例电机控制至少会用上ePWM、ADC、eQEP、CAN数字电源会用到ePWM、ADC、HRPWM数据采集板卡会用到ADC、DMA、SCI、SPI需要外扩存储或并行总线时会用EMIF。ePWM模块在28335上相对复杂一个ePWM由两个输出通道ePWMxA和ePWMxB组成包含时基周期寄存器TBPRD、计数比较寄存器CMPA/CMPB、动作限定寄存器AQCTLA等关键寄存器。你需要理解“时基周期决定PWM频率、比较寄存器决定占空比”这一核心关系。ADC是12位、16通道但内部只有一个转换核心多通道是分时采样实际应用中要注意采样顺序和采样窗口时间的分配。还有GPIO28335的GPIO几乎都承担了复用功能比如ADC的引脚是固定的但SCI、SPI这些可以通过GPIO MUX来选择引脚这个灵活性是好事但配置错了也最折磨人。3. 搭建开发环境CCS版本选择与第一个工程的创建3.1 开发环境怎么选CCS版本到底装哪个28335的开发工具主要是TI官方的CCSCode Composer Studio。老工程师习惯用CCS3.3因为它经典、稳定、上手快但问题是它只支持老旧的XDS510仿真器在Windows 10以上系统里驱动经常出问题。新项目我建议直接用CCS8或更高版本CCS10.0以上版本界面更友好集成了Eclipse框架调试体验也更好。从CCS6开始CCS改成了基于Eclipse的架构工程管理、代码编辑、断点调试都集中在一个界面里习惯之后效率很高。不过要注意CCS版本不同自带的编译器版本也不同。28335的官方例程大多是老编译器如TI v6.4.x或v15.12写的用新版本CCS如CCS12自带的TI v22.6编译时经常会出现语法警告或者头文件兼容问题。解决办法有两个一是安装CCS时勾选老版本编译器二是在工程属性里手动更改编译选项。我的建议是直接装CCS10同时保留TI v18.12和v15.12两套编译器遇到老工程就切换编译器版本。3.2 创建工程实操从新建到编译通过的完整步骤在CCS中为28335创建工程我习惯按以下步骤操作打开CCS设置工作区路径建议不要用默认路径单独建一个workspace目录。点击Project → New CCS ProjectTarget选择“TMS320F28335”编译器选择已安装的TI编译器版本。工程模板选择空工程不要用自带的例程模板方便你自己控制文件结构。新建工程后右键工程名 → Properties在Include Options中添加头文件搜索路径。典型路径是你的工程目录下的“include”文件夹以及TI官方的“DSP2833x_headers”目录。把官方库里的源文件如DSP2833x_GlobalVariableDefs.c、DSP2833x_PieCtrl.c复制到工程src目录或者直接链接进来。编译之前还有一件重要的事检查CMD文件。调试阶段选择“28335_RAM_lnk.cmd”烧写阶段换为“F28335.cmd”。如果工程里同时放了两个CMD编译器会报重复段定义或者地址冲突所以务必确认当前只有一个有效CMD。我第一次用CCS10创建28335工程时编译报了几十个“unresolved symbol”错误排查半天才发现是漏加了全局变量定义文件。TI外设库用了一种“影子变量”机制寄存器映射的全局变量定义必须和头文件配套使用漏掉任何一个都会导致链接失败。如果你也遇到类似问题先检查DSP2833x_GlobalVariableDefs.c是否已经包含在工程里。4. DSP开发的标准流程从初始化套路到Flash烧写4.1 上电初始化为什么必须按固定顺序操作28335的开发流程看似自由实则上电初始化阶段几乎有一套“标准动作”。任何main函数开头常规顺序是关闭看门狗、初始化PLL、初始化Flash等待状态、初始化各外设时钟、初始化GPIO、初始化PIE向量表、使能中断。这步顺序经我实测和TI官方推荐的顺序高度一致也确实是有道理的。关闭看门狗要放在最前面因为看门狗默认是开启状态如果你的初始化代码跑得久了点看门狗超时就会强制复位芯片。PLL配置决定系统主频28335外部晶振一般接30MHz通过PLL倍频到150MHz。典型配置是PLLCR寄存器写0x000A10倍频然后将CLKINDIV设为0这样系统时钟SYSCLKOUT等于30MHz×10/2150MHz。Flash等待状态设置很关键Flash的读取速度跟不上CPU主频因此需要在Flash控制寄存器里配置等待周期否则程序跑飞或者随机死机的概率极高。GPIO初始化属于容易被轻视但返工率很高的环节。28335的引脚默认是通用IO模式要使用SCI、SPI、eCAP这类复用功能必须通过GPxMUX寄存器把引脚切换到外设功能模式。这段时间我见过太多次“我已经配好串口了为什么收发不了数据”的求助一问GPIO MUX没配或者配错了引脚。4.2 ePWMADC实战组合从一个最小电机控制块说起ePWM和ADC是28335应用的核心组合这里拿一个最简单的开环电机控制框架来说。先配置时基——TBPRD寄存器写入7999如果系统时钟150MHz、分频系数1那么PWM频率就是150MHz/(79991)18.75kHz这是电机控制非常常用的频率。然后设置CMPA占空比比如写入4000占空比就是4000/800050%。AQCTLA寄存器设置高电平有效或者低电平有效的逻辑。死区模块用于当ePWMxA和ePWMxB控制同一桥臂时防止上下管直通一般死区时间设置在几百纳秒到几微秒之间。ADC部分28335的ADC是12位输入范围0到3.3V。它的转换结果存放在ADCRESULT0到ADCRESULT15这些寄存器里转换公式为数字量模拟输入电压/3.3V×4095。实际项目中常用软件平均值滤波或者滑动滤波来稳定采样值。一个比较容易忽视的点是ADC的采样窗口时间ACQ_PS位控制采样保持电容的充电时间如果信号源阻抗比较高充电时间不够会导致转换结果偏低。一般的做法是把ACQ_PS设成15也就是最大值虽然转换速率低一些但采样稳定性好很多。也可以把ADC时钟分频降低给更长的转换时间。我调试过一个采样波动明显的板子换上更低阻抗的运放驱动电路后数据立刻稳定。采样电路的前端阻抗设计比在软件里反复滤波的效果更明显。4.3 EMIF外扩存储器位宽匹配是关键28335的EMIF接口可以外扩Flash、SRAM甚至CPLD/FPGA。这个接口的配置里位宽是最先要确认的外部存储器是8位还是16位就必须在EMIF配置寄存器里设置一致。以常见的16位异步SRAM为例28335的EM接口数据线D[15:0]直接连接SRAM的D[15:0]地址线EA[15:1]连接SRAM的A[14:0]这里需要特别注意地址对齐关系——16位模式下系统地址线的最低位EA0不参与连接因为系统按16位字寻址而不是按字节寻址。如果这步接错了读写数据会错位最常见就是读出来的数据所有字节都移了一位。EMIF的读写时序参数包含建立时间、选通时间、保持时间等。配置时建议参考外接器件的数据手册以SRAM为例读写周期时间不能低于手册标称的最小值。很多工程师图省事直接用TI例程里的默认值结果和某些高速SRAM通信时偶发出错排查起来非常浪费时间。我的建议是先读外设手册计算好最小建立时间和保持时间再把这些参数填到EMIF的配置寄存器里宁可稍微宽松一点也不要去卡极限时序。4.4 Boot流程与Flash烧写从RAM调试到脱机运行在调试阶段程序默认在RAM中运行下载快可以随意修改但RAM是易失性存储器掉电程序就没了。要让28335脱机运行必须把程序烧写进片内Flash。烧写过程我实测下来有几个必须注意的坑。第一将链接文件从RAM版本换成Flash版本即替换CMD文件。Flash版本的CMD会调整段布局把程序段分配到Flash区域同时你要检查中断向量表的地址是否与Boot流程匹配。第二烧写前先擦除整片Flash并确认电源稳定。第三烧写完成后要断电重新上电观察程序是否正常自动运行。如果完全没反应优先检查GPIO84和GPIO85上的启动模式引脚配置它们决定芯片从Flash启动还是从SCI/SPI启动很多开发板需要将这两个引脚拉高。我遇到过一个问题程序烧进Flash后能跑但是只要一进中断就复位。排查了很久最后发现是中断服务函数还是存放在Flash里虽然执行了但速度跟不上实时性需求。正确做法是把需要高频调用的中断处理函数、关键算法函数通过#pragma CODE_SECTION放到RAM中执行同时配合MemCopy功能在启动时把代码从Flash复制到RAM。这是28335开发里的经典优化做法也是理解DSP“内存敏感”特性的敲门砖。4.5 CAN通信实战中断进不去的3个隐蔽原因CAN模块在实际项目里使用率非常高特别是在车载和工业控制场景。28335上的CAN是DCAN模块支持CAN 2.0B协议。本来CAN配置是标准操作但“中断进不去”这个问题却反复出现我复盘过几个案例通常有三个隐蔽原因。一是邮箱配置问题。DCAN发送和接收数据都是通过邮箱机制完成的你必须在对用的邮箱控制寄存器里使能该邮箱并且把邮箱的方向设置正确。二是中断使能顺序问题。DCAN的中断使能要分两级设置模块级的中断屏蔽寄存器要允许邮箱产生中断同时PIE级的中断使能也必须打开这两个使能缺一不可。我排查过一位同事的代码他在中断服务函数里加入了清标志的操作但CAN模块要求在读取数据后必须手动清除相应的中断标志位否则同一中断只触发一次之后再无任何反应。三是波特率配置问题。28335 CAN的位时序由BRP、TSEG1、TSEG2参数决定如果这些参数配置不当总线上的节点会一直报错甚至进入Bus-Off状态自然也就无法收到任何数据。官方例程的500kbps配置参数可以直接参考但如果你的系统时钟不是150MHzBRP也要同步调整。5. 那些折磨人的常见问题调试实录与排查技巧5.1 问题速查表现象、分析与解决办法现象排查思路解决办法编译报大量unresolved symbol漏掉DSP2833x_GlobalVariableDefs.c等源文件将官方源文件完整加入工程并配置好include路径链接报“no matching section”或“overlap”CMD文件重复定义或选错版本工程内只保留一个CMD调试用RAM版烧录用Flash版下载时仿真器连接失败JTAG接线、供电、仿真器驱动问题检查复位、TMS/TCK信号确认目标板单独供电优先换短USB线烧录后上电不运行启动模式引脚配置不对检查GPIO84/85电平选择Flash启动模式程序在RAM调试正常、Flash无法运行Flash等待状态未设置在系统初始化配置Flash等待状态寄存器进入中断一次后不再响应中断标志位未清除检查外设级、PIE级中断标志清除逻辑ADC采样值波动大或明显偏低采样窗口时间不足或前端阻抗太高增大ACQ_PS降低ADC时钟增加低阻抗驱动EMIF读写数据错位位宽或地址线连接不匹配确认EMIF数据位宽与实际器件一致核对地址对齐CAN收发超时波特率配置不一致或未使能邮箱使用总线分析仪检查实际波特率核对位时序参数5.2 仿真调试技巧如何更高效地定位问题CCS的调试功能远比很多人用到的强大。我在调试28335时最常用的几个技巧是定义Expression窗口监控变量和寄存器尤其关注外设寄存器的值是否按照预期变化利用CCS的View → Memory Browser直接查看内存区域内容检查数组写入是否越界在关键位置设置断点用Step Over配合Set Next Statement跳过程序中耗时长的初始化段。更高效的一种做法是使用CCS的“Logitech Analytics”功能查看变量波形但日常开发中我更多把变量导出为文本文件配合脚本做二次分析。这种方式做电机电流波形拟合非常方便。另一个容易被忽略的工具是“Disassembly“窗口。如果你怀疑编译器优化导致程序行为和C语言逻辑不一致打开这个窗口逐条查看汇编指令能很快定位问题。特别是28335上做定点运算和浮点运算混合的时候查看汇编能帮你确认CPU到底执行了哪种指令是FPU指令还是软件浮点库函数调用这对排查数值异常很有帮助。5.3 新手最容易忽略的3个基础雷区第一个雷区是忘记初始化外设时钟。28335的片上外设默认时钟是关闭的以降低功耗。你在使用SCI、SPI、ePWM、ADC之前必须在PCLKCR寄存器里打开对应的时钟位。这个操作写在比较靠前的初始化代码里但它太简单实战中反而容易遗漏症状却是千奇百怪的比如ADC偶发不工作SPI数据错乱。第二个雷区是中断向量表没有注册入口。第一次写中断程序时我忘了把中断服务函数的地址写入PIE向量表只在IER里使能了中断结果程序一执行到中断事件就跳进未知地址系统直接复位。正确做法是在初始化里调用PieVectTable.SCIRXINT1 sciRxIsr; 这样的语句把ISR地址赋值给对应的PIE向量表条目。第三个雷区是忽略了上拉电阻配置。28335的GPIO默认状态和外部电路的预期可能不一致比如CAN的收发器需要特定的电平才能正常工作如果你没有配置GPIO内部上拉电阻收发器可能会进入错误状态导致通信不稳定。正确做法是查看原理图确认哪些引脚需要上拉再通过GPxPUD寄存器配置。6. 写在最后的实操心得上面这些内容本质上是我在多年调试28335时反复踩坑后沉淀下来的经验也是DSP开发流程中最基础但最重要的一部分。从一开始在CCS里捣鼓工程配置到后来独立完成电机控制板卡再到帮别人定位各种稀奇古怪的问题我越来越确信一点DSP开发流程的难度并不在于单个知识点有多深而在于从工程环境、初始化代码到调试方法之间的链条非常长任何一环松动整体就跑不起来。所以我不建议初学者一上来就抱着官方几百页的手册死磕。更高效的做法是先照着这篇文章把环境搭好把一个最小的工程跑通用GPIO翻转来验证时序然后再逐步把外设模块加进去。每增加一个外设就验证一个。我个人的习惯是每次上电后先读一下复位寄存器和PLL状态寄存器确认系统正常工作再开始业务逻辑。这个方法看起来麻烦但能帮你把“芯片问题”和“代码问题”分开定位效率能提升不少。后面有时间我打算接着写28335的PWM、ADC和CAN模块的更详细应用也计划再整理一篇关于如何在工程中把中断优先级和实时性处理好的实操文章。留个记号咱们下篇继续。
返回列表