MC68349串口驱动与JTAG边界扫描实战:嵌入式通信与硬件调试核心技术解析
1. 项目概述:MC68349的通信与测试双核心
在嵌入式系统开发,尤其是基于经典微控制器(MCU)如摩托罗拉(后飞思卡尔)MC68349的系统中,有两项底层技术是开发者必须啃下的硬骨头:一是稳定可靠的串行通信,二是用于硬件调试与测试的边界扫描。串行通信是设备与外界对话的“嘴巴”和“耳朵”,而边界扫描(JTAG)则是深入芯片内部、诊断硬件连接问题的“听诊器”。很多人只关注应用层逻辑,却对支撑这些逻辑的硬件机制一知半解,导致调试时问题定位困难,效率低下。
MC68349作为一款集成度较高的32位微控制器,其内置的串行通信模块(Serial Module)和完全兼容IEEE 1149.1标准的测试访问端口(TAP),为我们提供了一个绝佳的学习范本。本文将从一个资深嵌入式工程师的视角,手把手拆解MC68349的串行模块编程细节,并深入其边界扫描架构的内部逻辑。我会结合手册中的寄存器描述和流程图,补充大量实际编程中才会遇到的“坑”和技巧,让你不仅能看懂手册,更能写出稳定、高效的驱动代码,并理解如何利用边界扫描进行硬件故障排查。无论你是正在维护老式工控设备,还是单纯想深入理解微控制器外设与测试原理,这篇文章都将提供直接的、可复现的实践指南。
2. 串行模块深度解析:从FIFO状态机到驱动编写
MC68349的串行模块是一个全双工、双通道(Channel A和B)的通用异步收发器(UART)。它的核心价值在于通过硬件FIFO(First In, First Out)缓冲区和精细的状态机,将CPU从繁重的字节级I/O管理中解放出来。理解其内部状态流转,是编写健壮驱动程序的前提。
2.1 核心寄存器与状态机:FFULL与RxRDY的博弈
手册中提到的FFULL(FIFO满)和RxRDY(接收器就绪)位,是理解接收流程的关键。它们位于通道的状态寄存器(SR)中,共同描绘了接收FIFO的三种状态。
接收FIFO的三种状态与编程策略:
- 空状态:
FFULL = 0,RxRDY = 0。FIFO中无数据,接收移位寄存器也空闲。此时CPU应等待或处理其他任务。 - 数据待读状态:
FFULL = 0,RxRDY = 1。FIFO中有1到2个字符(未满),可以安全读取。这是最常规的轮询或中断触发状态。 - FIFO满状态:
FFULL = 1,RxRDY = 1。3级FIFO已全部占满。这是一个危险信号。此时如果第四个字符接收完成,它会停留在接收移位寄存器中,无法进入FIFO,存在数据覆盖或丢失的风险。
实操心得:FIFO满状态的处理很多新手驱动只检查
RxRDY,忽略了FFULL。在高速或突发数据传输时,这可能导致“静默”的数据丢失——数据到了移位寄存器但进不了FIFO,而状态位没有额外的溢出错误指示(某些UART有)。稳健的做法是:在读取数据的中断服务例程或轮询循环中,如果检测到FFULL=1,除了读取数据清空FIFO外,还应考虑是否需要提高CPU的读取频率,或检查通信波特率与处理负载是否匹配。手册中提到的“当FIFO有空位时,移位寄存器中的字符会立即移入”正是为了避免这种丢失,但前提是你的程序得及时把数据读走。
发送端相对简单,核心是TxRDY(发送器就绪)位。它位于发送保持寄存器(THR)就绪时被置位。写入发送缓冲区(TB)会清除TxRDY,直到字符从保持寄存器转移到移位寄存器并开始发送后,TxRDY才会重新置位,表明可以接受下一个字符。这里有一个关键细节:手册明确指出,当TxRDY为0(发送器忙)或发送器被禁用时,写入TB是无效的。这意味着在发送函数中,必须严格检查TxRDY位,否则写入操作会被静默忽略,导致数据发送不完整。
2.2 模块初始化:不仅仅是配置寄存器
手册第8.5节给出了一个推荐的初始化序列,但仅仅照搬代码是不够的。我们需要理解每个步骤背后的意图。
初始化流程的深层逻辑:
- 复位收发器(CR寄存器):这是第一步,用于将收发器状态机置于已知的静止状态。在配置任何参数前先复位,可以避免残留状态导致的不确定行为。
- 配置模块级寄存器(MCR, IVR, ILR, IER):这设定了串行模块的全局工作环境。例如,
MCR中的STP位必须清零以启用模块;IARB位设置中断仲裁级别,在多中断源系统中至关重要,设置不当可能导致串口中断无法被响应。 - 等待晶体稳定(轮询ISR的XTAL_RDY):这是极易忽略但至关重要的一步。如果波特率发生器使用的时钟源不稳定,配置的波特率将不准确。必须轮询
XTAL_RDY位直到其清零,表明时钟已稳定。 - 配置通道特定寄存器(CSR, MR1, MR2):这里决定了通信的具体格式。
MR1和MR2需要配合设置:MR1的B/Cx位决定数据位(5-8位),PM/PT位决定奇偶校验,ERR位选择错误模式(字符/块),R/F位决定是RxRDY还是FFULL触发中断。MR2的SBx位决定停止位长度(1, 1.5, 2位),CMx位选择操作模式(正常、自动回环、远程回环等)。自动回环模式常用于驱动自测试。
- 最后使能收发器(CR寄存器):在所有参数配置妥当后,最后一步才通过
CR命令使能接收器和发送器。这个顺序避免了在配置过程中产生意外的发送或接收动作。
手册中的示例代码将通道A配置为9600波特、8位数据、无校验、1位停止位。我们来看一个关键配置行的解读:
MOVE.B #$93, MR1A(A0) ; MR1A = 1001 0011Bit7 (R/F): 1 = 使用RxRDY(而非FFULL)作为接收中断/状态源。Bit6 (ERR): 0 = 字符错误模式(每个字符后更新错误状态)。Bit5-4 (PM): 00 = 无奇偶校验。Bit3 (PT): 0 = 偶校验(当启用校验时有效,此处因PM=00而无作用)。Bit2-0 (B/C): 011 = 8位数据位。 这个配置是终端通信的常见设置。
3. 驱动编程实战:流程图与代码的逐行精讲
手册图8-10的流程图是理解官方驱动框架的蓝图。我们将它转化为更贴近实战的编程思路。
3.1 初始化例程(SINIT与CHCHK):自检的艺术
SINIT例程的精髓在于自动回环(Local Loopback)自检。它并非简单地配置寄存器,而是主动验证硬件通路是否完好。
- 进入回环模式:通过配置
MR2的CMx位,将发送器输出内部连接到接收器输入。这样,发送的数据会被自己接收到,无需外部连线。 - 发送测试字符:驱动发送器发送一个已知的字符(例如
0x55,其二进制01010101,具有交替的01模式,对检测位错误敏感)。 - 接收与验证:等待并读取接收到的字符。需要检查:
- 发送器永不就绪(Transmitter Never Ready):在超时时间内
TxRDY始终不为1。 - 接收器永不就绪(Receiver Never Ready):发送后,在超时时间内
RxRDY始终不为1。 - 奇偶校验错误(Parity Error):如果启用了校验,则检查状态寄存器。
- 帧错误(Framing Error):停止位检测错误。
- 字符不匹配(Incorrect Character):收到的字符与发送的不符。
- 发送器永不就绪(Transmitter Never Ready):在超时时间内
避坑指南:超时机制的实现手册流程图中的“WAITED TOO LONG?”判断,在实际编程中必须实现。绝对避免使用死循环等待。一个稳健的做法是使用一个递减计数器,该计数器由系统定时器或指令循环来递减。例如:
MOVE.W #TIMEOUT_VALUE, D0 ; 加载超时计数 TxPollLoop: BTST #TxRDY_BIT, SRA(A0) ; 检查TxRDY BNE TxReady ; 就绪则跳出 DBRA D0, TxPollLoop ; 计数减1,不为零则循环 ; 超时处理:设置错误标志,进行错误恢复或报告 TxReady: ... ; 继续发送
TIMEOUT_VALUE需要根据系统时钟和波特率仔细计算,确保给予硬件足够的响应时间,又不会让系统无响应。
3.2 I/O驱动例程(INCH, OUTCH, POUTCH):阻塞与非阻塞的权衡
手册给出的INCH,OUTCH,POUTCH是典型的阻塞式驱动。它们会持续轮询状态位,直到操作完成。
OUTCH(发送字符到通道A):循环检查TxRDY,未就绪则等待,就绪后写入数据。它还贴心地处理了“回车(CR)”后自动补“换行(LF)”的常见终端需求。INCH(从通道A读取字符):循环检查RxRDY,有数据则读取。它在中断处理流程中被调用。POUTCH(发送字符到通道B):逻辑同OUTCH,但面向通道B。
在实际系统中,这种阻塞式轮询会独占CPU,效率低下。更常见的做法是中断驱动:
- 中断驱动发送:维护一个发送软件缓冲区(队列)。
OUTCH函数将字符放入缓冲区,并尝试启动发送(如果发送器空闲则直接写入第一个字符,并启用发送空中断)。当发送移位寄存器变空(触发中断),中断服务程序(ISR)从缓冲区取出下一个字符写入,直到缓冲区为空,再禁用发送空中断。 - 中断驱动接收:使能接收数据就绪中断。当数据到达时,ISR读取字符并存入接收环形缓冲区。
INCH函数则从该环形缓冲区中取数据,如果缓冲区为空,则可以选择阻塞等待或返回空状态。
手册流程图中的SIRQ例程展示了如何处理特定的“Break信号变化”中断,这是一种更高级的中断处理,用于检测通信线路上的Break条件(长低电平)。这提醒我们,一个完整的UART驱动可能需要处理多种中断源:接收就绪、发送就绪、接收错误(帧错误、奇偶错误、溢出错误)、Break信号变化等,需要在中断使能寄存器(IER)中合理配置,并在状态寄存器(SR)中准确区分中断源。
4. IEEE 1149.1边界扫描技术详解
当你的电路板焊接好后,如何快速验证所有芯片引脚与PCB走线的连接是否正确?这就是IEEE 1149.1,即JTAG边界扫描技术的用武之地。MC68349完整集成了这一功能。
4.1 TAP控制器:边界扫描的“大脑”
TAP控制器是一个独立的16状态有限状态机(FSM),其状态转移完全由TMS(测试模式选择)信号在TCK(测试时钟)上升沿的值决定。它不依赖于系统主时钟,是独立运行的。
核心状态与操作:
- Test-Logic-Reset:上电或通过
TMS保持高电平进入。此状态禁用测试逻辑,芯片功能正常。 - Run-Test/Idle:测试逻辑空闲状态。
- 数据寄存器(DR)操作路径:
Capture-DR->Shift-DR->Update-DR。这是扫描测试数据(如引脚状态)的路径。 - 指令寄存器(IR)操作路径:
Capture-IR->Shift-IR->Update-IR。这是加载测试指令(如EXTEST,SAMPLE)的路径。
驱动TAP控制器,本质上就是按照图9-2的状态机,在TCK的配合下,通过TMS输入特定的比特流。例如,要从Test-Logic-Reset进入到Shift-DR状态以扫描数据,需要输入TMS序列:1->0->0->0->0(对应状态转移:Test-Logic-Reset->Run-Test/Idle->Select-DR-Scan->Capture-DR->Shift-DR)。
4.2 边界扫描寄存器(BSR):141位的芯片“数字镜像”
MC68349的BSR长达141位,它像一条串行的“数字探针链”,穿过了芯片所有重要的数字引脚。表9-2是这份探针链的“地图”。
理解BSR位定义表是关键:
- Bit Number:位在扫描链中的顺序。Bit 0是最靠近TDO,最先被移出的位。这一点至关重要,在编写扫描向量时必须注意位的顺序。
- Cell Type:定义了该位对应硬件的结构。
IO.Cell:双向引脚的数据单元。它存储从引脚采样到的值,或将要输出到引脚的值。IO.Ctl1/IO.Ctl0:双向引脚的方向控制单元。IO.Ctl1为高电平时使能输出驱动,IO.Ctl0为低电平时使能输出驱动。它们控制着与之关联的一组IO.Cell的输入/输出方向。O.Latch:专用输出引脚的数据单元。I.Pin:专用输入引脚的数据单元。
- Output CTL Cell:对于
IO.Cell,这一列指明了控制其方向的IO.Ctlx单元在BSR中的位置。例如,地址总线A31(Bit 103,类型IO.Cell)受ab31.ctl(Bit 104,类型IO.Ctl0)控制。
一个典型操作示例——读取所有引脚状态(SAMPLE指令):
- 通过IR路径加载
SAMPLE/PRELOAD指令(二进制001)。 - 进入
Capture-DR状态。在TCK上升沿,芯片所有引脚上的当前逻辑电平被瞬间捕获(采样)到对应的BSR位中。 - 进入
Shift-DR状态。在141个TCK周期内,通过TDI输入无关数据(通常为0),同时从TDO读出这141位的引脚状态快照。 - 分析读出的数据流,对照表9-2,即可知道每个引脚在采样时刻的电平。
4.3 核心指令解析与应用场景
MC68349支持4条指令,由3位指令寄存器解码。
EXTEST (000):外部测试。这是最强大的测试指令。当执行
EXTEST时:- 芯片的系统逻辑被内部复位,进入一种“安静”状态,避免干扰测试。
- BSR完全控制引脚行为。你可以通过扫描链:
- 向输出引脚灌入特定值:在
Update-DR阶段,BSR中O.Latch和IO.Cell(当对应IO.Ctlx设置为输出时)的值会被应用到物理引脚上。 - 控制双向引脚方向:通过设置
IO.Ctlx的值。 - 捕获输入引脚的值:在
Capture-DR阶段。
- 向输出引脚灌入特定值:在
- 应用:测试PCB上MC68349与其他芯片之间的连线(开路、短路)。例如,可以配置MCU所有引脚为输出并输出特定模式,然后用另一台JTAG设备或万用表检测下游芯片的输入引脚是否符合预期。
SAMPLE/PRELOAD (001):采样/预加载。这是一个“非侵入式”指令。
- 采样:在不干扰系统正常运行的情况下,偷偷捕获引脚状态。用于实时调试,观察总线活动。
- 预加载:在切换到
EXTEST前,预先设置BSR输出单元的值。这确保了从SAMPLE切换到EXTEST的瞬间,输出引脚不会产生毛刺或不确定状态,而是输出一个已知的、安全的值。
BYPASS (X1X, 101):旁路。该指令选择1位的旁路寄存器。当一块复杂板卡上有多颗支持JTAG的芯片时,为了测试其中某一颗,可以将其他芯片设置为
BYPASS模式。这样,测试数据流可以快速穿过这些芯片(仅1位延迟),大大提高了测试效率。HI-Z (100):高阻态。这是MC68349特有的、非常实用的指令。它使芯片所有输出驱动器进入高阻态。这在以下场景非常有用:
- 在线编程(ISP):当需要通过JTAG对板卡上的其他Flash或CPLD进行编程时,将MCU置于
HI-Z模式��以防止其总线争用。 - 总线冲突排查:当怀疑总线冲突时,可以将MCU置为
HI-Z,看总线问题是否消失,从而隔离问题。
- 在线编程(ISP):当需要通过JTAG对板卡上的其他Flash或CPLD进行编程时,将MCU置于
重要警告:非IEEE 1149.1操作手册第9.6节(非输入内容部分)通常会强调,在正常系统运行时,必��确保TAP控制器处于
Test-Logic-Reset或Run-Test/Idle状态,并且TMS和TDI引脚被上拉或驱动到确定电平(通常为高)。如果让TAP控制器意外进入测试状态,可能会干扰芯片正常功能,导致系统行为异常。因此,在硬件设计上,必须妥善处理这四个JTAG引脚(TCK, TMS, TDI, TDO),即使你不打算使用JTAG功能。
5. 实战:结合串口与边界扫描的板级调试
假设你设计了一块基于MC68349的板卡,焊接后串口无法通信。如何系统性地排查?
第一步:电源与时钟检查使用万用表和示波器检查电源电压、复位信号和主时钟(EXTAL/CLKOUT)。这是基础。
第二步:利用边界扫描检查物理连接
- 连接JTAG调试器(如Segger J-Link配合支持MC68349的软件,或开源OpenOCD)。
- 通过JTAG将MC68349置于
EXTEST模式。 - 测试串口引脚连接:查看表9-2,找到串口相关引脚。例如,
TxDA是Bit 29 (O.Latch),RxDA是Bit 28 (I.Pin),RTSA是Bit 30 (O.Latch),CTSA是Bit 31 (I.Pin)。- 输出测试:在
EXTEST下,通过扫描链向TxDA位写入高电平(1)。用万用表或示波器测量物理TxDA引脚,应为高电平(约VCC)。写入低电平(0),应测量到低电平(约0V)。这验证了MCU引脚到PCB焊盘的连接是好的。 - 输入测试:在
EXTEST下,将RxDA对应的BSR单元配置为输入(对于I.Pin,它总是输入)。然后在外围,用杜邦线将RxDA引脚拉到高电平或低电平。执行SAMPLE操作,捕获BSR值,检查Bit 28 (RxDA)是否与你施加的电平一致。这验证了PCB走线从连接器回到MCU引脚的连通性。
- 输出测试:在
- 检查电平转换芯片:如果使用了RS-232或RS-485电平转换芯片,继续用
EXTEST控制MCU侧引脚,同时测量转换芯片的输入输出,可以快速定位是MCU侧问题,还是转换芯片损坏,或是转换芯片后的线路问题。
第三步:软件初始化与诊断如果硬件连接确认无误,则问题很可能在软件。
- 确认初始化代码:严格对照手册8.5.1节的步骤。最容易出错的地方:
- 忘记等待
XTAL_RDY。 MR1和MR2的配置值与预期不符(例如,想配8N1却配成了7E1)。- 使能收发器(
CR命令)的时机不对,或在配置中途意外使能。
- 忘记等待
- 使用回环模式自检:在初始化代码中,像
SINIT例程那样,将通道配置为本地回环模式(MR2的CMx位),然后发送一个测试字符(如0x55),再接收并比较。如果回环测试通过,说明MCU内部的串口模块是好的,问题可能出在外部电平转换电路或对方设备上。 - 利用状态寄存器诊断:在通信失败时,读取状态寄存器(
SR),检查是否有帧错误(FE)、溢出错误(OE)、奇偶错误(PE)等。这些错误位能提供重要线索。例如,持续的帧错误可能意味着波特率不匹配。
第四步:信号完整性分析如果以上步骤都正常,但高速通信时仍有误码,则需要用示波器观察TxDA和RxDA信号波形。检查上升/下降沿是否陡峭,是否有过冲、振铃或毛刺。这可能是PCB布局不当、阻抗不匹配或终端电阻问题导致的。
通过这种从硬件(JTAG)到软件(初始化、自检)、从静态(连通性)到动态(信号质量)的层层递进的排查方法,绝大多数串口通信问题都能被准确定位和解决。掌握MC68349的这两项核心技术,你就能真正驾驭这颗经典的微控制器,在嵌入式系统开发与调试中游刃有余。
