1. 项目概述:深入MC68349的集成世界
在嵌入式系统开发的早期,尤其是基于Motorola 68000系列处理器的时代,系统设计者常常面临一个核心挑战:如何用最少的芯片、最低的成本和最高的可靠性,将CPU、内存、外设和必要的控制逻辑连接成一个高效运行的整体。那个年代,一块典型的单板计算机上,除了CPU和内存,往往还需要大量的74系列逻辑芯片(如地址译码器、锁存器、缓冲器)来“粘合”各个部件,这不仅增加了布板的复杂性、功耗和成本,更引入了潜在的信号完整性和时序匹配问题。MC68349,作为M68300家族中的一员,其核心价值就在于将大量这类“胶合逻辑”集成到了芯片内部,特别是其强大的系统集成模块(SIM49),为设计者提供了一个高度可配置、高度集成的片上系统雏形。
今天,我们就来深入拆解SIM49模块中两个最基础也最关键的硬件抽象层功能:芯片选择(Chip Select)和时钟控制。这不仅仅是阅读一份二十多年前的用户手册,更是理解一个经典嵌入式架构如何通过精妙的寄存器设计,将复杂的硬件行为转化为软件可编程的配置项。对于从事底层驱动开发、Bootloader编写或老旧系统维护的工程师来说,理解这些原理,就如同掌握了一套与硬件直接对话的“内功心法”。即便在今天,许多现代MCU的存储器控制器、时钟树管理、低功耗模式等概念,其设计思想依然能在这里找到源头。我将结合手册中的寄存器描述,补充大量实际配置时的考量和避坑经验,让你不仅能看懂表格,更能真正用起来。
2. 芯片选择(Chip Select)功能深度解析
2.1 核心价值与设计哲学
在传统的微处理器系统中,CPU通过地址总线发出一个地址,这个地址需要经过外部逻辑电路(通常是PAL或GAL)进行译码,才能产生一个有效的片选信号(CS#)去选中特定的存储器或外设芯片。MC68349的芯片选择模块,本质上就是把这块外部译码器搬到了芯片内部,并且做得更加灵活和强大。
它的核心设计是一对寄存器:基地址寄存器(Base Address Register)和地址掩码寄存器(Address Mask Register)。每个芯片选择信号(CS0# - CS3#)都对应这样一对寄存器。你可以把基地址寄存器想象成你为某个外设划定的“领地”的起始坐标,而地址掩码寄存器则定义了这块“领地”的大小和形状(是256字节的小院子,还是4GB的广阔平原)。这种设计的精妙之处在于,它通过掩码位(Mask Bits)实现了可变大小的地址块,并且起始地址只需对齐到块大小的整数倍即可,这比固定边界的译码方式灵活得多。
2.2 寄存器对详解与配置实战
2.2.1 基地址寄存器(BAR)—— 划定疆域
基地址寄存器是一个32位寄存器,其关键字段决定了访问的基本规则:
- BA31-BA8 (24位基地址):这是你为外设分配的地址空间起始地址的高24位。低8位(A7-A0)在寄存器中不体现,因为最小的地址块是256字节(2^8),起始地址自然就是256字节对齐的。例如,你设置
BA31-BA8 = 0x000400,那么实际的起始地址就是0x00040000。 - BFC3-BFC0 (4位基功能码):68000系列处理器不仅有32位地址总线,还有4位功能码(FC3-FC0)总线,用于区分不同的地址空间类型,如用户程序、用户数据、管理程序、管理数据、CPU空间等。这个字段让你可以指定该片选信号只在访问特定类型的地址空间时才有效。例如,设置
BFC=0101(管理数据空间),那么只有当CPU以管理权限访问数据时,这个CS#才会被拉低。 - WP (写保护位):这是一个非常实用的安全特性。当WP=1时,对该地址范围内的任何写操作都会被SIM49模块阻止,并产生总线错误(BERR#)信号。这对于保护只读存储器(如Boot ROM)或关键配置寄存器区域非常有用。
- EDS (扩展延迟选择位):此位与地址掩码寄存器中的DD1、DD0位共同作用,用于控制内部生成的等待状态数或选择快速终止模式。这是实现与不同速度外设时序匹配的关键。
- NCS (非CPU空间位):当NCS=1时,该片选在CPU空间访问周期(FC=0111或1111)时将被抑制。这通常用于确保在CPU执行特殊操作(如中断响应)时,不会误触发对外部存储器的访问。
- V (有效位):这是最重要的“开关”。无论你如何精心配置BAR和AMR,只有在将对应BAR的V位设置为1后,该芯片选择配置才会生效。系统复位后,所有V位默认为0,确保了配置完成前系统的安全。
2.2.2 地址掩码寄存器(AMR)—— 定义规则
地址掩码寄存器与BAR配对,定义了地址块的匹配规则和访问属性:
- AM31-AM8 (24位地址掩码):这是实现可变大小地址块的核心。它的工作原理是:任何被设置为1的掩码位,其对应的基地址位(BAx)在比较时将被忽略(视为“无关位”)。地址块的大小计算公式为:
块大小 = 2^(n),其中n = (掩码位中设置为1的位数) + 8。 举个例子最容易理解:假设你需要为一个128KB(0x20000字节)的SRAM配置片选。128KB = 2^17 字节。根据公式,n=17,那么掩码位中设置为1的位数应为 17 - 8 = 9。我们需要让地址的高24位中,有9位在比较时被忽略。通常,我们让这些位从低位开始忽略。假设起始地址定为0x00000000。- 128KB的地址范围是
0x00000000~0x0001FFFF。地址位A24-A31都是0,A23-A17在变化。 - 为了匹配这个范围,我们需要忽略A23-A17这7位(因为128KB内这些位会变),同时,由于块大小是2的幂,且起始地址必须对齐,我们还需要忽略决定块对齐的更高位吗?不,这里的关键是,我们通过忽略A23-A17,已经定义了一个从
0x00000000开始,持续2^(7+8)=2^15=32KB的块?不对,这里有个常见的理解误区。 - 正确算法:要覆盖128KB,我们需要地址总线中连续的低17位(A16-A0)用于片内寻址,高15位(A31-A17)用于片选。因此,在AMR中,我们希望A31-A17这15位与BAR中的值严格比较,而A16-A8这9位被忽略。所以,
AM31-AM8中,对应A31-A17的位应设为0(参与比较),对应A16-A8的位应设为1(忽略)。即AM31-AM8 = 0xFFFFFE00(二进制:...1111 1111 1111 1111 1110 0000 0000)。这样,当CPU地址的A31-A17全为0时,无论A16-A8是什么值,都会命中这个片选,正好覆盖了从0x00000000开始的2^9个256字节块,即128KB。
- 128KB的地址范围是
- FCM3-FCM0 (4位功能码掩码):这是对BAR中BFC字段的补充。如果BFC指定了只响应“管理数据空间”(0101),但你希望该片选也能响应“用户数据空间”(0001),则可以通过设置FCM位来屏蔽功能码的某些位,实现多空间匹配。例如,设置
BFC=0001(用户数据),同时设置FCM=0100(屏蔽FC2位),那么当FC2位不同(即0101管理数据)时,由于FC2被屏蔽,比较仍会成功,从而同时响应两种空间。 - DD1, DD0 (DSACK延迟位):与BAR中的EDS位共同编码,决定插入的等待状态数(0-6)或启用快速终止。具体编码见手册Table 4-11。例如,
EDS=0, DD1=1, DD0=0表示插入2个等待状态。 - PS1, PS0 (端口大小位):定义外部设备的端口宽度,以控制数据总线宽度和内部DSACK#信号的生成。
00=32位,01=16位,10=8位。当设置为11时,表示依赖外部设备返回的DSACK#信号,此时EDS和DDx位无效。
实操心得一:地址掩���计算的“笨”方法手动计算掩码容易出错。我常用的“笨”方法是:先确定块大小(Size)和起始地址(Base)。计算
n = log2(Size)。则需要忽略的地址位是A[(n-1):8]。在AMR中,将这些位对应的AMx设为1,其余高位置0。例如,Size=64KB=65536,n=16。忽略的位是A15-A8(共8位)。所以AM31-AM8中,AM15-AM8=1,其余为0,即0x0000FF00。务必确保Base是Size的整数倍。
2.3 全局芯片选择(Global Chip Select)—— 系统启动的钥匙
在系统上电或复位后,CPU开始从特定地址(通常是高地址区域,如0x00000000或0xFFFFFFF0,取决于CPU型号和配置)取指令执行。但此时,芯片选择寄存器的V位都是0,所有内部片选逻辑都未启用。那么CPU如何读取第一条指令呢?答案就是全局芯片选择。
这是一个特殊的、无需软件初始化即可工作的片选逻辑。它在复位后立即生效,专门用于连接系统的引导ROM(Boot ROM)。其块大小由复位时数据总线D31和D30引脚的电平状态决定(见手册Table 4-4)。例如,D31=0, D30=0,则全局片选配置为32位端口,用于连接一个32位的Flash或ROM。全局片选的地址范围通常是固定的(例如从0x00000000开始的一块区域),它确保了CPU在最开始的时刻就能访问到初始化代码。
注意事项:全局片选与常规片选的过渡在你的启动代码(Bootloader)中,必须在跳转到主程序或启用其他片选之前,先正确初始化常规片选寄存器,并禁用或重新配置全局片选。否则,当你的程序访问到全局片选与其他片选重叠的地址区域时,会发生不可预测的总线冲突。通常的做法是,在启动代码的早期,就将引导ROM的内容复制到RAM中,然后配置一个新的、独立的片选给RAM,并关闭全局片选,最后跳转到RAM中执行。
2.4 端口复用与外部总线接口(EBI)
MC68349的引脚是复用的,尤其是Port B引脚,它们可以在芯片选择(CS0#-CS3#)、中断请求(IRQ1#-IRQ7#)和通用I/O(PORTBx)之间切换。这是通过模块配置寄存器(MCR)中的FIRQ位和端口B引脚分配寄存器(PPARB)共同控制的。
- FIRQ=0:Port B引脚配置为4个中断请求线(IRQ1#-IRQ4#)和4个芯片选择线(CS0#-CS3#),以及一个自动向量(AVEC)引脚。这是最常用的模式,提供了基本的中断和片选能力。
- FIRQ=1:Port B引脚配置为7个中断请求线(IRQ1#-IRQ7#),不提供芯片选择信号。当你的系统需要更多外部中断源,且片选信号可以通过其他方式(例如使用剩余的Port A地址线进行译码)实现时,可以使用此模式。
配置的灵活性带来了设计的复杂性。你需要仔细规划引脚功能,并在软件初始化时正确设置MCR和PPARB寄存器。一个常见的坑是:即使某个Port B引脚被配置为IRQ#或I/O功能,其对应的芯片选择寄存器中编程的等待状态数仍然会作用于该引脚。这意味着,如果你将一个引脚用作IRQ输入,并希望为其附加等待状态(例如用于连接慢速中断控制器),你仍然需要“虚拟地”配置对应的CS#寄存器,设置好EDS和DDx位,即使这个CS#信号永远不会被驱动到引脚上。
3. 时钟控制与低功耗管理
3.1 时钟合成器控制寄存器(SYNCR)—— 系统心跳的调节器
MC68349通常使用一个低频的、稳定的外部晶体(如32.768kHz)作为参考,通过内部锁相环(PLL)倍频产生更高的系统时钟(如8.39MHz, 16.78MHz等)。SYNCR寄存器就是控制这个PLL的核心。
- 频率控制位(W, X, Y5-Y0, Z):这些位通过一个复杂的公式
Fsys = Fxtal * [2^(2W+X+3Z-1)] * (Y+1)来决定最终的系统频率。调整这些位(尤其是W, Y, Z)会导致VCO需要重新锁相,在此期间系统时钟可能不稳定。因此,改变频率应在系统初始化时一次性完成,并插入足够的延时等待锁相稳定(查阅手册获取具体延时时间,通常需要数毫秒)。位X比较特殊,它控制反馈环外的分频器,改变它可即时改变频率而无须重新锁相。 - SLIMP(跛行模式)与SLOCK(锁相状态):SLOCK位指示PLL是否已锁定到目标频率。SLIMP位在输入参考时钟丢失时被置位,此时VCO会以一个内部电压参考产生的降频时钟运行,保证系统不至于完全死机。这是一个重要的可靠性特性。
- RSTEN(复位使能):当RSTEN=1且检测到参考时钟丢失时,SIM49会产生一个系统复位。这可以防止系统在时钟异常时运行在错误的状态下。
- STSIM与STEXT(低功耗停止模式时钟控制):这是实现低功耗的关键。
3.2 低功耗停止(LPSTOP)模式实战
执行LPSTOP指令是MC68349进入低功耗状态的主要方式。此时,CPU核心和大部分外设模块的时钟被停止,只有SIM49模块的部分电路(如周期性中断定时器PIT)可以保持活动,功耗大幅降低。
进入LPSTOP模式前,软件需要做一系列准备工作:
- 配置SYNCR:根据你对唤醒后时钟源的需求,设置STSIM和STEXT位。
STSIM=0, STEXT=0:最省电模式。SIM49时钟来自外部晶体,VCO关闭,CLKOUT引脚输出低电平。唤醒后系统时钟从外部晶体重新启动。STSIM=1, STEXT=1:快速唤醒模式。SIM49时钟和CLKOUT都来自VCO。VCO保持运行,功耗稍高,但唤醒后无需等待PLL重新锁相,响应最快。
- 停止外设模块:在DMA、串口等片上模块的模块配置寄存器(MCR)中,设置STP位。这会停止该模块的内部时钟(来自IMB的时钟除外),进一步降低功耗。
- 处理周期性中断定时器(PIT):如果希望用PIT定时唤醒,需确保PIT的中断级别高于CPU当前的中断屏蔽级别。如果不想在LPSTOP期间产生中断,则需在进入LPSTOP前将PITR寄存器清零以关闭它。
- 注意软件看门狗:LPSTOP指令会停止软件看门狗的时钟。这与
STOP指令不同,STOP指令下看门狗仍会运行。如果你的系统依赖看门狗复位,需要特别注意这一点。
退出LPSTOP模式通常由外部中断、复位或周期性中断触发。唤醒后,CPU从LPSTOP指令后的下一条指令开始执行,软件需要根据RSR(复位状态寄存器)判断唤醒源,并重新初始化可能需要的模块(特别是如果之前关闭了VCO,需要等待SLOCK置位)。
实操心得二:LPSTOP模式下的功耗测量与调试调试低功耗系统时,一个常见的误区是只关注CPU电流。实际上,即使CPU进入LPSTOP,外部电路(如未关闭的上拉电阻、保持活动的LED、无效电平下的IO口漏电流)可能仍是耗电大户。务必使用
STEXT=0关闭CLKOUT输出。在测量功耗前,将所有未使用的IO口配置为输出低电平或带上拉电阻的输入模式(根据硬件设计),并确保所有外部设备处于其最低功耗状态。使用高精度电流表,观察执行LPSTOP指令瞬间的电流跌落,可以验证软件配置是否正确。
4. 关键系统模块配置与编程示例
4.1 模块基地址寄存器(MBAR)—— 内部世界的门户
在能够访问SIM49的任何功能寄存器之前,你必须先告诉CPU这些寄存器在内存地图中的位置。这就是MBAR的作用。MBAR本身位于一个固定的CPU空间地址($0003FF00),需要通过MOVEC等特权指令访问。
MBAR的高20位(BA31-BA12)定义了SIM49寄存器块4KB空间的基地址。例如,设置BA31-BA12 = 0xFFFFF,则SIM49的寄存器将从物理地址0xFFFFF000开始映射。MBAR的AS8-AS0位(地址空间屏蔽位)��允许你将SIM49的访问限制在特定的地址空间。例如,如果你设置AS6=1(屏蔽管理程序空间),那么当CPU在管理程序空间访问0xFFFFFxxx时,这个访问将不会被SIM49响应,而是作为一个外部总线周期处理。这为系统设计提供了额外的灵活性。最后,别忘了设置V位为1,否则整个SIM49寄存器块都无法访问。
4.2 系统保护与监控机制
SIM49集成了几个关键的监控功能,增强了系统的鲁棒性:
- 软件看门狗(Software Watchdog):由SYPCR寄存器的SWE位使能。你需要定期向SWSR寄存器依次写入
$55和$AA来“喂狗”。超时时间由SYPCR中的SWT1、SWT0和PITR中的SWP位共同决定,范围从几十微秒到数百秒。超时后可以触发复位(SWRI=1)或不可屏蔽的7级中断(SWRI=0)。注意:修改超时配置后,必须立即执行一次完整的喂狗序列,新超时周期才会生效。 - 总线监视器(Bus Monitor):监控外部总线访问。如果一个外部总线周期(例如,访问一个不存在或未响应的设备)超过了BMT1/BMT0设定的时间(64-512个系统时钟),总线监视器将终止该周期并报告错误。这对于检测总线挂起至关重要。
- 双总线故障监视器(Double Bus Fault Monitor):在CPU连续遇到两个总线错误时触发系统复位,防止系统在严重错误状态下失控。
4.3 完整配置流程与代码示例
假设我们要为MC68349设计一个最小系统,包含一片256KB的SRAM(16位数据总线,位于地址0x00040000,需要2个等待状态)和一片UART外设(8位数据总线,位于地址0x20000000,需要1个等待状态)。我们将使用CS0#和CS1#,并启用软件看门狗。
; 首先,设置MBAR,将SIM49寄存器映射到0xFFFFF000 MOVE.L #7, D0 ; 设置CPU空间功能码 MOVEC.L D0, DFC ; 设置目的功能码寄存器 LEA.L $0003FF00, A0 ; MBAR的CPU空间地址 MOVE.L #$FFFFF101, D0 ; 基地址=0xFFFFF000, AS7=1(屏蔽CPU空间访问),V=1 MOVES.L D0, (A0) ; 写入MBAR ; 现在可以通过MBAR的基地址访问SIM49寄存器了 MOVE.L #$FFFFF000, A6 ; A6作为SIM49寄存器基址指针 ; 1. 配置CS0# 用于 256KB SRAM @ 0x00040000, 16-bit, 2 wait states, Supervisor/User Data ; 基地址寄存器 (CS0 BAR @ offset $044) ; BA31-BA8 = 0x000400 (高24位起始地址) ; BFC3-BFC0 = 0101 (Supervisor Data) 或 0001 (User Data),这里我们设为0001,并通过FCM屏蔽 ; WP = 0 (允许读写) ; EDS = 0 (与DDx配合) ; NCS = 1 (抑制CPU空间访问) ; V = 1 (有效) ; 假设我们配置为响应管理数据和用户数据空间:BFC=0001, FCM=0100 (屏蔽FC2) ; 寄存器值计算:高16位=0x0004,低16位=0x0013 (BFC=0001, WP=0, EDS=0, NCS=1, V=1) MOVE.W #$0004, $044(A6) ; 写入BAR高字 (BA31-BA16) MOVE.W #$0013, $046(A6) ; 写入BAR低字 (BA15-BA8=0x00, BFC=0001, WP=0, EDS=0, NCS=1, V=1) ; 地址掩码寄存器 (CS0 AMR @ offset $040) ; 块大小 256KB = 2^18 bytes -> n=18, 忽略的位 = A17-A8 (10位) ; AM31-AM8: 对应A17-A8的位为1,其余为0。即 AM31-AM24=0, AM23-AM17=0, AM16-AM8=1。 ; 计算:忽略A17-A8,即AM17-AM8=1。高16位(AM31-AM16): AM17=1, AM31-AM18=0 -> 0x0002 ; 低16位(AM15-AM0): AM15-AM8=0xFF, FCM=0100, DD1/DD0=10 (2 wait states), PS1/PS0=01 (16-bit) ; FCM=0100, DD1/DD0=10, PS1/PS0=01 合并为二进制 0100 10 01 = 0x49 ; 寄存器值:高16位=0x0002, 低16位=0xFF49 MOVE.W #$0002, $040(A6) ; 写入AMR高字 MOVE.W #$FF49, $042(A6) ; 写入AMR低字 (AM15-AM8=0xFF, FCM=4, DD=2, PS=1) ; 2. 配置CS1# 用于 UART @ 0x20000000, 8-bit, 1 wait state, Supervisor Data only ; 假设UART只有8个寄存器,我们分配一个256字节的最小块。 ; 基地址寄存器 (CS1 BAR @ offset $04C) ; BA31-BA8 = 0x200000 ; BFC = 0101 (Supervisor Data only) ; WP = 0, EDS=0, NCS=1, V=1 ; 高16位=0x2000, 低16位=0x0053 (BFC=0101, WP=0, EDS=0, NCS=1, V=1) MOVE.W #$2000, $04C(A6) MOVE.W #$0053, $04E(A6) ; 地址掩码寄存器 (CS1 AMR @ offset $048) ; 块大小 256 bytes = 2^8 -> n=8, 忽略的位 = A7-A8? 不对,最小块就是256字节,由A7-A0寻址。 ; 对于256字节块,我们不需要忽略任何AM31-AM8位(即所有位都参与比较)。 ; 所以 AM31-AM8 = 0x000000 (但寄存器是16+16位) ; 实际上,对于精确的256字节块,AM31-AM8应全为0,表示所有高24位地址都必须严格匹配。 ; 低16位: AM15-AM8=0x00, FCM=0000 (不屏蔽),DD1/DD0=01 (1 wait state), PS1/PS0=10 (8-bit) ; FCM=0, DD=1, PS=2 -> 二进制 0000 01 10 = 0x06 MOVE.W #$0000, $048(A6) ; AMR高字 MOVE.W #$0006, $04A(A6) ; AMR低字 ; 3. 配置软件看门狗 (超时时间约250ms @ 16.777MHz) ; 根据手册Table 4-8,对于16.777MHz,要得到~250ms,需要SWP=0, SWT1=1, SWT0=0 ; SYPCR (@offset $021) : SWE=1, SWRI=0(中断), SWT1=1, SWT0=0, DBFE=1, BME=1, BMT1=0, BMT0=0(512 clocks) ; 即 1001 1100 = $9C MOVE.B #$9C, $021(A6) ; 4. 配置周期性中断定时器 (PIT) 用于定时喂狗或任务调度 ; 假设我们设置PIT每10ms产生一次中断 (时钟频率16.777MHz,预分频PTP=0) ; 计数值 = 时间间隔 * 频率 = 0.01s * 16.777e6 Hz = 167770 ; 但PITR是8位计数器,最大255。所以必须使用预分频。 ; 设置PTP=1 (预分频512),则输入时钟 = 16.777MHz / 512 = 32768 Hz (与32.768kHz晶振同频) ; 10ms间隔需要的计数值 = 0.01s * 32768 Hz = 327.68 -> 取整328 (0x148) ; 但PITR只有8位,最大255。所以我们需要设置一个更长的周期,或者使用更短的间隔。 ; 改为1ms间隔:计数值 = 0.001 * 32768 = 32.768 -> 33 (0x21) ; PICR (@offset $022): 设置中断级别和向量号 ; 假设使用中断级别2,向量号0x40 MOVE.W #$0240, $022(A6) ; PIRQL=010 (Level 2), PIV=0x40 ; PITR (@offset $024): SWP=0 (看门狗不预分频,与之前SYPCR设置一致), PTP=1, PITR=33 MOVE.W #$0121, $024(A6) ; 高字节: SWP=0, PTP=1 -> 0x01; 低字节: PITR=33 -> 0x21 ; 5. 配置端口功能 (例如,将Port B配置为4个中断+4个片选) ; MCR (@offset $000) : FIRQ=0 (4中断+4片选模式) ; 假设其他位保持复位值: FRZ1=1, FRZ0=1, SHEN1=0, SHEN0=0, SUPV=0, IARB=1111 MOVE.W #$C00F, $000(A6) ; 复位值 0xC00F ; 6. 最后,别忘了定期喂狗!通常在周期性中断服务程序或主循环中执行。 ; 喂狗序列: 先写$55,再写$AA到SWSR (@offset $027) WATCHDOG_SERVICE: MOVE.B #$55, $027(A6) MOVE.B #$AA, $027(A6) RTS5. 常见问题排查与调试技巧
5.1 芯片选择不生效或地址映射错误
- 症状:访问配置好的地址范围,CS#信号没有产生,或访问了错误的内存/设备。
- 排查步骤:
- 检查V位:这是最常被忽略的一步。确认对应基地址寄存器的V位已设置为1。
- 验证地址对齐:确保基地址是块大小的整数倍。计算
Base Address % Block Size == 0。 - 核对掩码计算:使用前面提到的“笨方法”重新计算AMR值。可以用一个简单测试:写一个循环,遍历你期望的地址范围,读取某个固定位置(如0x55AA),看CS#信号是否在每个地址都正常触发。如果只在部分地址触发,说明掩码设置可能过宽或过窄。
- 检查功能码(FC)匹配:确认你的访问是用户模式还是管理模-式,是程序访问还是数据访问。使用调试器或逻辑分析仪捕获总线周期,查看FC3-FC0引脚的实际值,并与BFC/FCM设置对比。
- 优先级冲突:如果多个片选的地址范围重叠,编号小的CS#(如CS0#)优先级最高。确保没有意外的重叠。
5.2 总线访问异常或系统挂起
- 症状:系统在访问外部设备时触发总线错误(BERR#)或完全挂起。
- 排查步骤:
- 等待状态配置:这是最常见的原因。如果外部设备速度慢,而EDS/DDx设置的等待状态不足,CPU会在设备准备好前就尝试读取数据,导致失败。增加等待状态数。使用逻辑分析仪测量CS#、DS#、DTACK#/DSACK#的时序关系。
- 端口大小不匹配:如果设备是8位,而PS位配置为16或32位,CPU会尝试进行16/32位访问(可能伴随UDS#/LDS#信号),而设备可能无法正确响应。确保PS位设置与硬件连接一致。
- 总线监视器超时:如果BME已启用,且外部设备无法在超时时间内返回DSACK#,总线监视器会终止周期并可能引发异常。检查BMT超时设置是否合理,或检查外部设备是否已正确连接并上电。
- 使用示波器/逻辑分析仪:这是最直接的硬件调试手段。观察地址线、数据线、控制线(AS#、DS#、R/W#)和片选/应答信号。确认时序符合MC68349和外部设备的数据手册要求。
5.3 低功耗模式无法进入或唤醒异常
- 症状:执行LPSTOP后电流下降不明显,或系统无法从LPSTOP模式唤醒。
- 排查步骤:
- 检查STSIM/STEXT配置:如果希望CLKOUT停止输出以省电,确保
STEXT=0。 - 确认中断源:LPSTOP模式只能被中断或复位唤醒。确保你期望的唤醒中断(如外部中断、PIT中断)已使能,并且其优先级高于CPU状态寄存器(SR)中的中断屏蔽位。
- 关闭外设时钟:进入LPSTOP前,确认所有片上模块(如DMA、串口)的MCR中的STP位已设置。
- PIT配置:如果使用PIT唤醒,确保PITR不为零,且PICR中设置的中断级别足够高。同时,在LPSTOP期间,只有SIMCLK(由STSIM位决定来源)会运行PIT,确认时钟源配置正确。
- 测量唤醒时间:从唤醒事件发生到第一条指令执行,存在延迟。如果唤醒后立即访问依赖稳定时钟的外设(如需要PLL锁定的快速存储器),可能需要插入软件延时。
- 检查STSIM/STEXT配置:如果希望CLKOUT停止输出以省电,确保
5.4 软件看门狗误触发
- 症状:系统频繁被看门狗复位,即使你认为已经定期“喂狗”。
- 排查步骤:
- 喂狗序列必须精确:必须是先写
$55,再写$AA到SWSR寄存器。顺序错误、写入别的值、或者两次写入之间被中断打断,都可能失败。 - 检查超时周期:根据EXTAL频率和SWP/SWT位设置,重新计算超时时间。确保你的喂狗间隔远小于超时时间(例如,小于一半)。
- 修改配置后的喂狗:任何对SYPCR中SWE、SWT、SWP位的修改,都必须紧随其后立即执行一次完整的喂狗序列,否则新的超时周期不会生效,可能立即导致超时复位。
- 在中断服务程序(ISR)中喂狗:这是一个好习惯,可以防止主程序跑飞后看门狗失效。但要确保ISR的执行频率足够高。
- 喂狗序列必须精确:必须是先写
调试MC68349这类老式芯片,一份完整的数据手册、一个能捕获总线周期的逻辑分析仪,以及耐心细致的寄存器检查,是解决问题的关键。每次配置后,通过读取回寄存器值来确认写入成功,是一个值得坚持的好习惯。这些看似繁琐的底层操作,正是构建稳定嵌入式系统的基石。