DSP28335 SCI串口回传实验:FIFO配置与中断实现详解
简介本资源是面向嵌入式开发工程师与高校电类专业学生的TMS320F28335 DSP串行通信实战项目聚焦SCI模块在RS232标准下的16位字符双向传输实现重点解决实时控制场景中高效、稳定串口通信的中断驱动与FIFO管理难题。压缩包含139个文件涵盖41个头文件.h定义寄存器与接口、38个依赖文件.d支撑编译依赖、9个C源码如main.c、DSP2833x_Sci.c实现SCI初始化、中断服务例程及FIFO收发逻辑以及汇编启动代码、链接命令文件.cmd、工程配置.ccsproject等完整构建要素总大小315KB。已有1484人学习下载提供可直接导入CCS的完整工程结构包含SCI中断使能、16位数据打包/解析、发送/接收FIFO阈值触发机制及回传验证逻辑代码注释详实便于理解TI底层外设驱动设计思想与实时系统中断响应流程。 拿到一块新的DSP28335开发板我通常第一件事不是点灯而是先把SCI串口打通。干这行的人都清楚后续不管调试变量、看运行状态还是跟上位机做联调串口永远是最快的那条路。而串口调试里最基础也最直观的验证实验就是“回传”echoPC通过RS-232发一个字符DSP的SCI模块收到后原样发回来。链路通没通、波特率配没配准、电平转换芯片有没有接错一次回传全都能暴露出来。这篇文章我会把TMS320F28335的SCIA外设配合RS-232电平转换、利用SCI内置16级FIFO做发送与回传的完整过程讲清楚包括寄存器怎么配、代码怎么写、实测会遇到哪些坑、以及从echo Demo如何升级成一个可用的通信框架。内容偏向实操适合刚开始接触28335串口、或者被SCI各种寄存器位搞晕的朋友。1. “发送与回传”到底要打通什么先把硬件链路理清楚回传Demo从代码量上看很简单但它背后是一条完整的硬件链路。很多朋友代码写完发现收不到数据问题往往不在软件而在硬件链路某一环断了。1.1 从SCI到RS-232两套电平标准别混淆DSP28335的SCI模块本质上是UART通用异步收发器它输出的是3.3V TTL电平。而PC的串口DB9接口遵循的是RS-232标准逻辑电平是负逻辑高电平在-3V到-15V低电平在3V到15V。两者不能直接相连中间必须经过电平转换芯片常见的有MAX32323.3V供电和MAX2325V供电。28335是3.3V器件所以优选MAX3232。市面上很多DSP28335开发板已经把MAX3232电路集成在了板子上引出一个DB9公头或者排针。如果你用的是核心板底板的组合需要确认底板上SCIA的TXD/RXD是否已经通过电平转换芯片接到了串口插座。接线逻辑并不复杂DSP的SCITXDA引脚连接MAX3232的TTL侧输入端比如T1INMAX3232的RS-232侧输出比如T1OUT连接DB9的第2脚PC发送过来的RS-232信号从DB9第3脚进入MAX3232的R1IN再从R1OUT输出到DSP的SCIRXDA引脚。DB9的5脚GND必须和DSP开发板的GND连在一起。信号通路可以这样看PC串口发送 → DB9第3脚 → MAX3232 R1IN → R1OUT → DSP的SCIRXDA DSP的SCITXDA → MAX3232 T1IN → T1OUT → DB9第2脚 → PC串口接收如果你用的是USB转RS-232线或者USB转TTL模块需要先搞清楚线序。USB转TTL模块输出的已经是3.3V或5V TTL电平如果直接接DSP的TTL引脚可以绕过板载MAX3232但要注意模块是3.3V还是5V电平5V电平直连3.3V的DSP有风险。稳妥起见优先使用板载的RS-232通道。1.2 回传Demo的实际价值为什么先做echo而不是直接写业务回传这个实验虽然看起来“玩具”但它能一次性验证三件事电气链路是否连通TXD/RXD有没有接反GND是否共地MAX3232是否正常工作波特率配置是否正确波特率错了回传回来的字符会变成乱码这是最直接的反馈FIFO和中断配置是否正确触发级别、标志位清除、PIE中断使能任何一个环节出错数据要么丢要么卡死我自己的习惯是新板子到手先用回传Demo把SCI链路验证通过再在这个基础上叠加帧协议、环形缓冲区、上位机联调。否则一上来就写一堆逻辑出问题时分不清是硬件故障还是软件bug排查成本成倍增加。2. SCI外设与16级FIFO关键寄存器和工作机制这一节把28335的SCI模块内部结构讲清楚。很多Datasheet把寄存器表格堆在一起看着头大但实际用到的就那么几个寄存器一个个拆开看逻辑非常清晰。2.1 发送通道和接收通道FIFO帮你缓冲数据28335的每个SCI模块SCIA和SCIB都有独立的发送器和接收器各自带一个16级深度的FIFO。所谓16级就是硬件上能缓存16个字符每个字符按SCICCR配置的位数决定默认8位。在没有FIFO的传统UART模式里CPU发送一个字节必须等移位寄存器把这一位一位地发完才能写下一个接收也一样每收到一字节CPU就得立刻读走否则下一个字节来了就会覆盖。数据量一上来CPU就卡死在等待上。FIFO模式解决了这个问题。发送路径变成CPU写SCITXBUF → 发送FIFO最多缓存16字节 → 发送移位寄存器 → SCITXD引脚接收路径变成SCIRXD引脚 → 接收移位寄存器 → 接收FIFO最多缓存16字节 → CPU读SCIRXBUF这样CPU可以一次性把16个字节塞进发送FIFO然后去做别的事硬件慢慢发接收时哪怕CPU没来得及读FIFO也能先存着最多16个字节不至于立刻丢数据。2.2 核心寄存器速查SCICCR、SCICTL1、SCICTL2先记住三个最基础的配置寄存器。SCICCRSCI通信控制寄存器主要管通信格式bit 2-0SCICHAR字符长度0001位0012位一直到1118位bit 2STOP停止位数量01个停止位12个停止位bit 4POLINT奇偶校验使能0不使能bit 5LOOPBKENA环回测试使能1内部环回调试用非常方便SCICTL1SCI控制寄存器1主要管发送器接收器的使能和复位状态bit 0RXENA接收器使能bit 1TXENA发送器使能bit 5SWRESET软件复位0SCI处于复位状态配置完成后置1启动工作SCICTL2SCI控制寄存器2主要管中断和状态标志bit 0TXINTENA发送FIFO中断使能bit 6RXBKINTENA接收缓冲器中断使能bit 1TXRDY、bit 3TXEMPTY发送器状态标志2.3 16级FIFO的状态与控制SCIFFTX和SCIFFRXFIFO寄存器是配置的重点SCIFFTX管发送FIFOSCIFFRX管接收FIFO。SCIFFTX各位的作用bit 15SCIRSTSCI复位控制1正常运行bit 14SCIFFENAFIFO增强功能使能1使用FIFObit 13TXFIFORESET发送FIFO复位1正常运行0复位bit 11-8TXFFST只读当前发送FIFO中待发送的字符个数bit 7TXFFINTCLR写1清除发送FIFO中断标志bit 4-0TXFFIL发送FIFO中断触发级别当TXFFST小于等于这个值时触发中断SCIFFRX各位的作用bit 15RXFIFORESET接收FIFO复位1正常运行bit 14-13RXFFOVF只读接收FIFO溢出标志bit 11-8RXFFST只读当前接收FIFO中已接收的字符个数bit 7RXFFINTCLR写1清除接收FIFO中断标志bit 5RXFFIENA接收FIFO中断使能bit 4-0RXFFIL接收FIFO中断触发级别当RXFFST大于等于这个值时触发中断注意一个容易混淆的点发送FIFO的中断触发条件是“FIFO深度小于等于触发级别”因为发送FIFO空了才需要CPU继续填数据接收FIFO的中断触发条件是“FIFO深度大于等于触发级别”因为接收到足够数据才需要CPU取走。方向相反别搞混。2.4 “16位字符”到底是什么意思标题里的“16位字符”需要澄清一下避免误解。DSP28335的SCI外设数据位最长只能配到8位也就是一个标准字节。所谓“16”其实指的是FIFO深度是16级外设寄存器按16位组织SCITXBUF和SCIRXBUF都是16位寄存器。至于SCIRXBUF的高8位在某些型号上会携带错误标志位比如奇偶校验错误、溢出标志等但在28335上通常我们只用低8位取数据。如果你确实需要传输一个“16位数据类型”比如16位ADC采样值、16位温度值也不能靠SCICHAR配到16正确做法是拆成两个8位字节发送接收端再拼接。这个后面扩展部分会提到。3. 初始化代码逐行解析GPIO、波特率、FIFO一个都不能错下面进入正题。我用SCIA作为示例完整写一遍初始化代码并逐段解释每一行在做什么、为什么这么写。3.1 GPIO复用配置把引脚切换成SCI功能28335的GPIO口默认是通用数字IO要切换成SCI功能需要配置GPAMUX寄存器。SCIA的功能引脚有两个映射位置我默认用GPIO28和GPIO29这也是绝大多数开发板的设计。EALLOW; // GPIO28 - SCIRXDAGPIO29 - SCITXDA GpioCtrlRegs.GPAMUX2.bit.GPIO28 1; GpioCtrlRegs.GPAMUX2.bit.GPIO29 1; // 使能内部上拉防止空闲时电平悬空 GpioCtrlRegs.GPAPUD.bit.GPIO28 0; GpioCtrlRegs.GPAPUD.bit.GPIO29 0; EDIS;GPAMUX2中每个GPIO占用2位01代表外设功能1对GPIO28/29来说就是SCI功能我直接使用bit域操作不用去手动算移位。另外配置为外设功能后引脚方向由硬件自动管理不需要再配置GPADIR。如果开发板把SCIA接到了GPIO35/36上配置改成GpioCtrlRegs.GPBMUX1.bit.GPIO35 1; // SCIRXDA GpioCtrlRegs.GPBMUX1.bit.GPIO36 1; // SCITXDA无论用哪组引脚关键是查原理图确认信号方向GPIO28/35是接收引脚连的是MAX3232的R1OUTGPIO29/36是发送引脚连的是MAX3232的T1IN。接反了数据就“只进不出”或者“只出不进”。3.2 波特率计算BRR公式和实际误差波特率寄存器是16位的分高8位SCHIBAUD和低8位SCILBAUD两部分。计算公式如下BRR LSPCLK / (波特率 × 8) - 1LSPCLK是低速外设时钟。在28335默认配置下系统时钟SYSCLKOUT为150MHzLSPCLK SYSCLKOUT / 4 37.5MHz。以115200波特率为例BRR 37500000 / (115200 × 8) - 1 37500000 / 921600 - 1 40.69 - 1 39.69取整BRR40。由于BRR只能取整数实际波特率为实际波特率 37500000 / (8 × (401)) 37500000 / 328 114329跟115200的误差约0.756%在UART通信允许的误差范围通常±2%内可以正常工作。再看9600波特率BRR 37500000 / (9600 × 8) - 1 37500000 / 76800 - 1 487.28 - 1 486.28取整整487实际波特率 37500000 / (8 × 488) 9602误差约0.025%更精确。初始化代码如下// 115200波特率LSPCLK 37.5MHzBRR 40 SciaRegs.SCIHBAUD 0x0000; SciaRegs.SCILBAUD 0x0028; // 40 // 如果是9600波特率BRR 487 0x01E7 // SciaRegs.SCIHBAUD 0x0001; // SciaRegs.SCILBAUD 0x00E7;这里有个经验之谈如果你发现上位机收到的全是乱码优先怀疑波特率有没有算对。尤其是有人会拿150MHz直接代入公式忘记除以4算出来的BRR差了4倍必然乱码。3.3 标准初始化流程顺序很重要FIFO和SCI的初始化顺序有讲究混乱的配置顺序会导致某些寄存器写入不生效。我习惯按下面这个顺序void SCI_Init(void) { // 第1步配置GPIO复用 EALLOW; GpioCtrlRegs.GPAMUX2.bit.GPIO28 1; GpioCtrlRegs.GPAMUX2.bit.GPIO29 1; GpioCtrlRegs.GPAPUD.bit.GPIO28 0; GpioCtrlRegs.GPAPUD.bit.GPIO29 0; EDIS; // 第2步配置通信格式 // 8位字符长度1个停止位无校验 SciaRegs.SCICCR.all 0x0007; // 第3步使能发送和接收但保持SWRESET0软件复位状态 SciaRegs.SCICTL1.all 0x0003; // 第4步配置波特率 SciaRegs.SCIHBAUD 0x0000; SciaRegs.SCILBAUD 0x0028; // 115200 // 第5步配置FIFO // 发送FIFOSCIRST1SCIFFENA1TXFIFORESET1 SciaRegs.SCIFFTX.all 0xE000; // 接收FIFORXFIFORESET1 SciaRegs.SCIFFRX.all 0x8000; // 接收FIFO中断触发级别配置为1即每收到1个字符触发中断 SciaRegs.SCIFFRX.bit.RXFFIL 1; // 字符间发送延迟为0 SciaRegs.SCIFFCT.all 0x0000; // 第6步解除软件复位SCI开始工作 SciaRegs.SCICTL1.all 0x0023; // 第7步使能接收FIFO中断 SciaRegs.SCIFFRX.bit.RXFFIENA 1; }为什么要在SWRESET0的状态下先做配置因为SCI处于复位状态时配置寄存器可以被修改一旦解除复位某些位就锁定为运行状态修改无效。最后一步把SWRESET置10x0023中bit5就是SWRESETSCI才真正开始收发。4. 回传逻辑实现查询模式和FIFO中断模式初始化搞定后回传逻辑本身很简单。但有两条路可以走各有适用场景我分别说明。4.1 查询模式最直接的验证方式查询模式不涉及中断主循环里不断检查接收FIFO的状态位有数据就读取并转发到发送FIFOvoid SCI_Echo_Loop(void) { Uint16 rxData; while(1) { // 检查接收FIFO是否有数据 if(SciaRegs.SCIFFRX.bit.RXFFST 0) { // 读取接收数据低8位有效 rxData SciaRegs.SCIRXBUF.all 0x00FF; // 等待发送FIFO有空位不为16 while(SciaRegs.SCIFFTX.bit.TXFFST 16); // 写回发送FIFO SciaRegs.SCITXBUF.all rxData; } } }查询模式的优点是代码简单、逻辑一目了然非常适合第一次验证链路是否通畅。缺点是CPU全程占用主循环不能干别的。对于回传Demo来说完全够用但放到实际项目中不现实。4.2 FIFO中断模式每收到1个字符就自动回传中断模式让硬件在接收到指定数量的字符后自动触发中断在中断服务程序里完成读取和回传。先配置PIE中断向量// 在main函数中注册中断服务函数 EALLOW; PieVectTable.SCIRXINTA sciaRxFifoIsr; EDIS; // 使能PIE第9组第1个中断SCIA接收中断 PieCtrlRegs.PIEIER9.bit.INTx1 1; // 使能CPU中断第9组 IER | M_INT9; // 开总中断 EINT;中断服务函数的完整写法__interrupt void sciaRxFifoIsr(void) { Uint16 rxData; // 读取接收FIFO数据低8位是有效字符 rxData SciaRegs.SCIRXBUF.all 0x00FF; // 等待发送FIFO有空间 while(SciaRegs.SCIFFTX.bit.TXFFST 16); // 把收到的字符写入发送FIFO实现回传 SciaRegs.SCITXBUF.all rxData; // 清除接收FIFO中断标志否则会不停进中断 SciaRegs.SCIFFRX.bit.RXFFINTCLR 1; // 应答PIE控制器允许同组后续中断 PieCtrlRegs.PIEACK.all PIEACK_GROUP9; }这段代码有几个细节必须注意RXFFINTCLR必须在中断处理完成后写1清掉中断标志否则中断标志一直有效CPU会反复进中断表现为系统卡死。PIEACK的应答不能漏。28335的PIE控制器同一组内多个中断共享一个CPU中断入口处理完一个必须向PIEACK写1才能继续响应同组其他中断。否则即使有新的SCI接收中断CPU也不会响应。中断函数里尽量别做耗时操作回传这种“读一个字节、写一个字节”的简单操作没问题千万不要在中断里做大数据处理或打印。4.3 两种发送方式的取舍上面回传是“收一个回一个”。但实际项目中经常需要主动发送字符串或数据块。发送FIFO的使用有两种思路逐字节等待发送void SCI_SendByte(Uint16 data) { // 等待发送FIFO有空间深度小于16 while(SciaRegs.SCIFFTX.bit.TXFFST 16); SciaRegs.S p a hrefhttps://download.csdn.net/download/qq_38948179/75681588 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p

相关新闻

最新新闻

日新闻

周新闻

月新闻