TI 16xx MCU外部时钟输出配置:EXTCLKDIV、EXTCLKSRCSEL与EXTCLKCTL详解

TI 16xx MCU外部时钟输出配置:EXTCLKDIV、EXTCLKSRCSEL与EXTCLKCTL详解
1. 项目概述与核心价值在嵌入式系统尤其是汽车电子和工业控制这类对可靠性和实时性要求近乎苛刻的领域微控制器MCU的底层行为控制是项目成败的基石。很多工程师在项目初期往往把精力集中在应用逻辑和算法实现上却容易忽视一个事实如果芯片的电源、复位和时钟简称PRC这三大基础没配置好再精妙的代码也如同建立在流沙上的城堡随时可能因为一次意外的电压波动、一个不稳定的时钟源或者一次不彻底的复位而崩塌。我经历过不止一次这样的深夜调试系统在实验室跑得好好的一到现场就偶发性死机最后追根溯源问题往往就出在这些最基础的寄存器配置上。德州仪器TI的16xx系列MCU作为其面向高性能实时控制的主力产品线其PRC管理机制设计得非常精细和强大。它不像一些简单的8位MCU上电就能跑。16xx系列提供了一个名为“Power, Reset, Clock Management and Control Registers (IWR)”的寄存器模块你可以把它理解为芯片的“总控制台”。这个控制台不直接处理你的业务逻辑但它决定了芯片以何种状态、何种节奏来执行你的逻辑。今天我们就来深入拆解这个IWR模块中的几个关键角色EXTCLKDIV外部时钟分频、EXTCLKSRCSEL外部时钟源选择和EXTCLKCTL外部时钟控制。它们共同掌管着MCU_CLKOUT和PMIC_CLKOUT这两个至关重要的时钟输出引脚是连接芯片内部精密时钟网络与外部世界的桥梁。理解并熟练配置这些寄存器意味着你获得了以下能力第一精准的功耗控制你可以通过门控和分频在不需要高速时钟时将其关闭或降低频率直接降低动态功耗第二灵活的系统同步你可以为外部PMIC电源管理芯片或其它协处理器提供一颗与MCU核心时钟严格同步或成特定比例关系的“心跳”确保整个板级系统步调一致第三强大的调试与监控能力将内部时钟引到引脚上用示波器一量很多棘手的时序问题就无所遁形。这不仅仅是阅读数据手册更是将芯片数据手册中的静态描述转化为你手中动态、可操控的系统能力。2. 核心寄存器功能解析与设计逻辑在动手写代码之前我们必须先搞明白这三个寄存器各自扮演什么角色以及TI的设计师为何要这样设计。如果把MCU_CLKOUT/PMIC_CLKOUT的输出路径比作一条自来水管道那么这三个寄存器就分别控制了水源、水阀和出水口的粗细。### 2.1 EXTCLKDIV决定“出水流量”的分频器EXTCLKDIV寄存器偏移地址0x10复位值0x0。它的功能非常纯粹分频。寄存器分为高8位EXTCLK2DIV控制PMIC_CLKOUT和低8位EXTCLK1DIV控制MCU_CLKOUT。每个字段都是一个8位无符号整数代表分频系数。这里有一个关键细节也是新手最容易栽跟头的地方分频值的计算是“N1”模式。寄存器值0x00代表1分频即不分频输出频率等于输入频率0x01代表2分频以此类推直到0xFF代表256分频。所以如果你需要4分频应该写入的值是0x03而不是0x04。这个设计在硬件中很常见因为计数器是从0开始计数的写0意味着计数值为0触发第一次翻转从而实现1分频。为什么需要如此宽的分频范围1-256这源于实际应用的多样性。例如你的主芯片跑在200MHz但外部连接的PMIC可能只需要一个32.768kHz的慢速时钟作为参考这时你就需要大约6000倍的分频。虽然256倍不够但你可以通过组合时钟源比如先选择低频的RC时钟和分频器来达成目标。分频器的存在让你不必为每一个目标频率去寻找一个完美的时钟源大大增加了设计的灵活性。 注意数据手册中特别强调“One Should change the divide value before switching to New clock.” 这是一个至关重要的操作顺序你必须先配置好新的分频系数然后再去切换时钟源通过EXTCLKSRCSEL。如果顺序反过来在切换到一个高速时钟源的瞬间分频器还是旧的低分频值甚至是不分频可能会导致输出时钟频率瞬间飙高超过下游器件的承受能力造成不可预知的问题。### 2.2 EXTCLKSRCSEL选择“水源”的调度员EXTCLKSRCSEL寄存器偏移地址0x14复位值0x0。它负责为两个输出时钟选择“水源”。高4位EXTCLK2SRCSEL选择PMIC_CLKOUT的源低4位EXTCLK1SRCSEL选择MCU_CLKOUT的源。可供选择的时钟源列表是理解16xx系列时钟架构的窗口000: CPUCLK。这是来自模拟模块ANA的时钟可以是外部晶振XTAL支持40/50/80/100MHz或者在“Wake-Up Limp”模式下的RCCLK。这是最常用、最稳定的主时钟源。001/100/101/111: RCCLK (10MHz)。这是片内RC振荡器精度不如晶振但启动快功耗低。多个编码指向同一个源可能是为了兼容性或预留。010: 600MHz PLL分频时钟。来自高性能锁相环用于需要极高频率输出的场景。011: 240MHz PLL分频时钟。另一个PLL输出选项。110: REFCLK from ANA。来自模拟模块的参考时钟同样是40/50/80/100MHz的晶振频率。选择时钟源的本质是在精度、速度、功耗和启动时间之间做权衡。在系统刚上电、晶振还未稳定的阶段你可以先用RCCLK输出一个时钟让外部PMIC先工作起来等晶振稳定后再无缝切换到更精确的CPUCLK。这种灵活性对于满足汽车电子的功能安全启动序列至关重要。### 2.3 EXTCLKCTL掌管“水阀”的门卫EXTCLKCTL寄存器偏移地址0x18复位值0xADAD。它的功能是门控Gating也就是开关。和分频寄存器类似它用高8位EXTCLK2GATE控制PMIC_CLKOUT低8位EXTCLK1GATE控制MCU_CLKOUT。门控的位置很讲究是“Pre clock divider gate”即在分频器之前进行门控。这意味着当你关闭门控时不仅输出没了连分频器电路的翻转都停止了这能实现最大程度的功耗节省。它的操作逻辑有点特别要关断时钟需要向对应字段写入0xAD。注意这个字段是8位但手册说明“either 3:0 should be 0xD or 7:4 should be 0xA”。这实际上是一种简单的“魔法数字”保护机制防止因误写而意外关断时钟。你可以写入0x0A高4位是A也可以写入0x0D低4位是D或者直接写入0xAD都能触发关断。要重新开启时钟则写入0x00。这种设计在关键的安全控制寄存器中很常见增加了误操作的门槛。### 2.4 寄存器间的协同工作流程理解了单个寄存器后我们将其串联起来看一个完整的配置流程。假设我们要为PMIC_CLKOUT输出一个25MHz的时钟源自主晶振100MHz。计算分频值目标频率25MHz源频率100MHz分频比 100 / 25 4。根据“N1”规则分频寄存器值 4 - 1 3 (0x03)。配置分频寄存器向EXTCLKDIV寄存器的EXTCLK2DIV字段位[15:8]写入0x03。此时先不要动EXTCLKSRCSEL。配置时钟源向EXTCLKSRCSEL寄存器的EXTCLK2SRCSEL字段位[11:8]写入0x0选择CPUCLK即100MHz晶振。可选门控控制如果需要先关闭输出检查EXTCLKCTL的EXTCLK2GATE如果不是0x00则写入0x00开启门控。我们的场景是使能输出所以确保它是0x00。这个顺序——先分频后切源——必须遵守。在实际代码中我们通常会封装成一个函数确保原子性操作。3. 实操配置与代码实现详解理论清楚了我们来看怎么用代码操作。这里以常见的C语言嵌入式开发环境为例假设我们已经有了访问内存映射寄存器的宏或函数。### 3.1 寄存器地址定义与访问宏首先我们需要根据数据手册定义这些寄存器的基地址和偏移量。通常IWR模块是挂在某个外设总线上的。/* 假设 IWR 模块基地址 */ #define IWR_BASE_ADDR (0xFFFFF800UL) /* 寄存器偏移量定义 (来自数据手册) */ #define EXTCLKDIV_OFFSET (0x10UL) #define EXTCLKSRCSEL_OFFSET (0x14UL) #define EXTCLKCTL_OFFSET (0x18UL) #define SOFTSYSRST_OFFSET (0x1CUL) // 顺便定义软复位寄存器 /* 方便操作的指针定义 */ #define REG_EXTCLKDIV (*(volatile uint32_t *)(IWR_BASE_ADDR EXTCLKDIV_OFFSET)) #define REG_EXTCLKSRCSEL (*(volatile uint32_t *)(IWR_BASE_ADDR EXTCLKSRCSEL_OFFSET)) #define REG_EXTCLKCTL (*(volatile uint32_t *)(IWR_BASE_ADDR EXTCLKCTL_OFFSET)) #define REG_SOFTSYSRST (*(volatile uint32_t *)(IWR_BASE_ADDR SOFTSYSRST_OFFSET))### 3.2 配置函数实现以PMIC_CLKOUT为例我们来编写一个配置PMIC_CLKOUT的函数。这个函数要处理时钟源选择、分频设置并严格遵守操作顺序。/** * brief 配置 PMIC_CLKOUT 输出时钟 * param source: 时钟源选择参见 ref EXTCLK_Source_Definitions * param div: 分频值 (实际分频比 div 1)。范围: 0-255 (对应1-256分频) * param enable: 是否立即使能输出 (控制门控) * retval 无 */ void PMIC_CLKOUT_Config(uint8_t source, uint8_t div, bool enable) { uint32_t tempReg; /* 1. 安全起见先关闭时钟输出操作门控 */ tempReg REG_EXTCLKCTL; tempReg ~(0xFFUL 8); // 清除EXTCLK2GATE字段[15:8] tempReg | (0xADUL 8); // 写入魔法数字0xAD关闭PMIC_CLKOUT REG_EXTCLKCTL tempReg; /* 2. 配置分频系数 (EXTCLK2DIV) */ tempReg REG_EXTCLKDIV; tempReg ~(0xFFUL 8); // 清除[15:8]位 tempReg | ((uint32_t)div 8); // 设置新的分频值 REG_EXTCLKDIV tempReg; /* 3. 配置时钟源 (EXTCLK2SRCSEL) */ tempReg REG_EXTCLKSRCSEL; tempReg ~(0x0FUL 8); // 清除[11:8]位 tempReg | ((uint32_t)source 8); // 设置时钟源 REG_EXTCLKSRCSEL tempReg; /* 4. 根据参数决定是否打开时钟门控 */ tempReg REG_EXTCLKCTL; tempReg ~(0xFFUL 8); // 再次清除EXTCLK2GATE字段 if (enable) { tempReg | (0x00UL 8); // 写入0x00使能时钟输出 } else { tempReg | (0xADUL 8); // 保持关闭状态 } REG_EXTCLKCTL tempReg; } /* 时钟源定义方便调用 */ #define EXTCLK_SRC_CPUCLK 0x0U /* CPUCLK from ANA (XTAL) */ #define EXTCLK_SRC_RCCLK_10M 0x1U /* RCCLK 10MHz */ #define EXTCLK_SRC_PLL_600M 0x2U /* 600MHz PLL divided clock */ #define EXTCLK_SRC_PLL_240M 0x3U /* 240MHz PLL divided clock */ #define EXTCLK_SRC_REFCLK 0x6U /* REFCLK from ANA */### 3.3 系统初始化中的集成调用在实际的系统初始化函数如SystemInit()或board_init()中你可能会这样调用void Board_Clock_Init(void) { /* 假设系统主晶振已配置为100MHz且PLL已锁定 */ /* 配置PMIC_CLKOUT输出25MHz源自主晶振并立即使能 */ /* 分频值计算: 100MHz / 25MHz 4分频 - div 4-1 3 */ PMIC_CLKOUT_Config(EXTCLK_SRC_CPUCLK, 3, true); /* 配置MCU_CLKOUT输出10MHz同样来自主晶振用于调试初始关闭 */ /* 100MHz / 10MHz 10分频 - div 10-1 9 */ // 类似地需要实现MCU_CLKOUT_Config函数操作EXTCLK1DIV和EXTCLK1SRCSEL // MCU_CLKOUT_Config(EXTCLK_SRC_CPUCLK, 9, false); }### 3.4 动态时钟切换与低功耗场景示例更高级的应用是动态切换。例如系统进入低功耗模式前需要将给外部PMIC的时钟从高速晶振切换到低速RC以降低噪声和功耗。void Enter_LowPowerMode(void) { /* 1. 将PMIC_CLKOUT切换到低功耗、低频的RCCLK (10MHz)并做2分频输出5MHz */ /* 注意先改分频目标5MHz源10MHz分频比2 - div 1 */ uint32_t temp REG_EXTCLKDIV; temp ~(0xFFUL 8); temp | (1UL 8); // EXTCLK2DIV 1 (2分频) REG_EXTCLKDIV temp; /* 再切换时钟源 */ temp REG_EXTCLKSRCSEL; temp ~(0x0FUL 8); temp | (EXTCLK_SRC_RCCLK_10M 8); // 切换为RC 10MHz REG_EXTCLKSRCSEL temp; /* 2. 关闭MCU_CLKOUT输出以省电 */ temp REG_EXTCLKCTL; temp ~(0xFFUL); temp | 0xADUL; // EXTCLK1GATE 0xAD 关闭MCU_CLKOUT REG_EXTCLKCTL temp; /* 3. 执行进入低功耗模式的指令 (如WFI) */ __WFI(); } void Exit_LowPowerMode(void) { /* 唤醒后将PMIC_CLKOUT切换回高性能时钟源 */ /* 先恢复分频到25MHz配置 (div3) */ uint32_t temp REG_EXTCLKDIV; temp ~(0xFFUL 8); temp | (3UL 8); REG_EXTCLKDIV temp; /* 再切换回主晶振 */ temp REG_EXTCLKSRCSEL; temp ~(0x0FUL 8); temp | (EXTCLK_SRC_CPUCLK 8); REG_EXTCLKSRCSEL temp; /* 重新开启MCU_CLKOUT如果需要 */ temp REG_EXTCLKCTL; temp ~(0xFFUL); temp | 0x00UL; // EXTCLK1GATE 0x00 开启 REG_EXTCLKCTL temp; }4. 关联寄存器深度解析与系统级应用IWR模块远不止这三个时钟控制寄存器。围绕PRC管理TI设计了一整套相互关联的寄存器理解它们才能进行真正的系统级设计。### 4.1 复位管理与状态捕获复位是系统可靠性的最后防线。IWR模块提供了精细的复位控制与原因查询。SOFTSYSRST(偏移 0x1Ch)软件触发热复位。向该寄存器写入0xAD会立即触发一次芯片的热复位Warm Reset。热复位会复位大部分逻辑但可能保留某些寄存器和内存的内容取决于具体型号比上电复位Power-On Reset更快。这在程序跑飞、看门狗失效的极端情况下提供了一种由应用软件自我修复的最后手段。WDRSTEN(偏移 0x20h)看门狗复位使能。写入0xAD后当MSS主子系统看门狗超时复位时会触发一个热复位而不是通常的局部复位。这确保了看门狗超时能引发更彻底的系统恢复。SYSRSTCAUSE(偏移 0x24h)复位原因寄存器。这是调试死机、重启问题的关键寄存器。它记录了上一次复位的原因1001: 系统退出NRESET上电或冷复位。1010: 由于MSS看门狗触发的热复位。1100: 由于软件写SOFTSYSRST触发的热复位。1000: 外部热复位。重要提示数据手册明确指出ROM引导加载程序Bootloader在运行时会清除这个寄存器。所以你的应用程序读它永远是0。真正的复位原因被保存在TOPRCM_SPARE9寄存器中。在调试时你必须去读SPARE9的相应位段才能获取历史信息。这个“坑”我踩过花了半天时间才在手册角落里找到这条说明。SYSRSTCAUSECLR(偏移 0x28h)向此寄存器写入0xAD可以清除SYSRSTCAUSE的内容尽管会被Bootloader再次清除。### 4.2 安全与访问控制在汽车和工业领域安全性至关重要。USERMODEEN/USERMODEEN2(偏移 0x48h, 0x180h)这两个是用户模式写使能寄存器。IWR模块的许多关键寄存器默认可能只在特权模式如芯片初始化阶段下可写。为了在应用程序用户模式中也能动态配置时钟或触发复位你需要先向这两个寄存器写入特定的魔法数字0xADADADAD来解锁写权限。USERMODEEN解锁偏移地址0x00-0xFF的区域USERMODEEN2解锁0x100-0x1FF的区域仅受上电复位影响。这相当于一把软件钥匙。SECURECFGREG1-4(偏移 0x1C4h 等)这一组寄存器配置硬件防火墙。例如你可以禁用JTAG接口、保护加密引擎Crypto的密钥区、保护安全RAM或跟踪Trace模块的访问。防火墙的使能/禁用通常通过写入特定的非111值来实现例如000。STICKYBIT相关的寄存器则用于设置“粘滞”位一旦防火墙因违规访问触发粘滞位会锁死状态直到下一次复位这用于记录安全事件。### 4.3 内存初始化与共享内存控制对于包含大型共享RAM或TCM紧耦合存储器的系统正确的内存初始化是稳定性的前提。MEMINITSTARTSHMEM/MEMINITDONESHMEM(偏移 0x2A8h, 0x2ACh)这两个寄存器控制共享内存的初始化。MEMINITSTARTSHMEM的每一个位对应一个内存Bank0-7写1会触发对应Bank的初始化该位会自动清除。MEMINITDONESHMEM的对应位则用于查询该Bank的初始化是否完成。在访问任何共享内存之前必须确保其初始化完成。DSSMEMTAB0,TCMAMEMTAB,TCMBMEMTAB(偏移 0x2B0h, 0x2BCh, 0x2C0h)这些是内存地址重映射表。它们定义了逻辑地址到物理内存Bank的映射关系。例如DSS可能是显示或信号处理子系统看到的连续逻辑地址空间可以通过DSSMEMTAB0寄存器映射到8个物理Bank中的任意顺序。这提供了极大的灵活性允许软件根据访问模式优化内存布局减少Bank冲突提升性能。### 4.4 其他实用寄存器SYSTICK(偏移 0x18Ch)一个运行在32kHz源自RC时钟上的32位自由递增计数器。它不受系统主时钟关断的影响非常适合用作低功耗模式下的长时间基准定时或时间戳。UID31TO0~UID119TO96(偏移 0x200h 等)芯片唯一标识符UID读取寄存器。从EFUSE中读取用于软件加密、设备识别或生产追溯。SPARE0_3,SPARE4_9备用寄存器。这些寄存器的内容在热复位后能够保持SPARE9部分被Bootloader使用。你可以用来存储跨复位周期的状态信息比如记录异常发生的次数、系统运行模式等对于现场问题诊断极其有用。5. 常见问题、调试技巧与避坑指南基于这些年的项目经验我总结了一些在配置和使用TI 16xx系列IWR模块时最容易遇到的问题和解决方法。### 5.1 时钟输出无信号或频率不对这是最高频的问题排查思路如下检查时钟源是否就绪你配置了使用CPUCLK晶振但晶振起振了吗PLL锁定了吗在配置EXTCLKSRCSEL之前务必通过读取时钟状态寄存器如PLLSTS确认时钟源有效。确认引脚复用MCU_CLKOUT和PMIC_CLKOUT是复用引脚。你需要检查对应的PINMUX寄存器确保该引脚功能已正确设置为时钟输出而不是普通的GPIO或其他外设功能。验证分频计算牢记“N1”规则。想要2分频写0x01想要1分频直通写0x00。写0x04得到的是5分频而不是4分频。遵守配置顺序反复强调先写EXTCLKDIV设置分频再写EXTCLKSRCSEL切换源。错误的顺序可能导致瞬间的尖峰频率。检查门控状态EXTCLKCTL寄存器是否已使能输出默认复位后是0xADAD意味着两个时钟输出都是关闭的。你必须将其对应字段写为0x00才能打开。测量点选择用示波器测量时确保探头接地良好并注意引脚可能驱动能力有限直接测量可能导致信号变形。必要时使用缓冲器或使用芯片提供的专用测试点。### 5.2 软件复位或看门狗复位后行为异常区分热复位与冷复位你的初始化代码是否区分了这两种情况通过读取TOPRCM_SPARE9保存的SYSRSTCAUSE来判断复位原因。对于热复位你可能需要跳过外设的完整重初始化尤其是时钟、PLL而只重置应用状态以加快恢复速度。USERMODEEN锁如果你在应用程序中动态配置时钟后发生了热复位复位后USERMODEEN的写权限可能再次关闭。如果你的应用在复位恢复流程中需要重新配置时钟必须再次写入0xADADADAD解锁。共享内存状态热复位可能不会清除所有共享内存。如果你的应用在复位前正在使用DMA或协处理器访问共享内存复位后这些引擎可能状态错乱。安全的做法是在应用初始化时检查MEMINITDONESHMEM必要时重新触发初始化。### 5.3 低功耗模式下的时钟管理门控 vs. 切换源进入低功耗模式时如果外部设备不需要时钟最省电的方式是使用EXTCLKCTL直接门控关闭输出。如果外部设备需要低频时钟则切换到RCCLK并设置大分频比。前者功耗最低后者兼容性更好。唤醒同步从低功耗模式唤醒切换回高速时钟源时要留出时钟稳定的时间。在切换EXTCLKSRCSEL后添加一个短暂的软件延时几十微秒或查询时钟状态寄存器等待时钟源稳定再执行关键操作。SYSTICK计数器在深度低功耗模式下主时钟可能关闭但SYSTICK基于32kHz RC时钟仍在运行。可以利用它来做唤醒定时但要注意RC时钟的精度误差可能达到百分之几对时间精度要求高的场合需要校准。### 5.4 安全配置的注意事项防火墙一次性配置SECURECFGREG1等安全配置寄存器通常在上电初始化阶段由安全启动代码配置一次之后不应再改动。随意修改可能导致外设如JTAG被永久锁死无法调试。魔法数字保护像SOFTSYSRST、WDRSTEN、USERMODEEN等寄存器都需要写入特定的“魔法数字”如0xAD才能生效。这防止了指针跑飞等意外写操作。在代码中建议将这些魔法数字定义为宏如#define IWR_MAGIC_KEY 0xAD提高可读性和可维护性。寄存器位域操作强烈建议使用位域操作或清晰的掩码宏来操作寄存器避免直接进行简单的赋值这可能会覆盖其他无关位。例如// 推荐做法读-改-写 uint32_t regVal REG_EXTCLKSRCSEL; regVal ~(0xFUL 8); // 仅清除目标位域 regVal | (source 8); REG_EXTCLKSRCSEL regVal; // 风险做法直接赋值假设你知道其他位都是0 // REG_EXTCLKSRCSEL (source 8);### 5.5 调试手段与日志记录活用SPARE寄存器SPARE4_9等寄存器是宝贵的非易失性跨热复位存储资源。可以在代码的关键路径如时钟配置函数、复位处理函数中向这些寄存器写入特定的状态码或序列号。当系统异常复位后通过调试器读取这些寄存器的值就能还原出故障发生前的最后几步操作极大缩小排查范围。时钟输出作为调试信号除了给外设提供时钟MCU_CLKOUT可以配置为输出内部各种总线时钟或内核时钟。在调试复杂的总线交互或性能瓶颈时将其连接到逻辑分析仪可以直观地看到时钟活动情况判断CPU是否挂起、DMA是否在传输等。复位原因诊断流程建立一个标准的复位诊断函数在main()函数最开始调用。void DiagnoseResetCause(void) { uint32_t spare9 *((volatile uint32_t*) (TOPRCM_BASE 0xFC)); // 假设SPARE9地址 uint8_t resetCause (spare9 0) 0xF; // 获取低4位 switch(resetCause) { case 0x9: LOG(Cold Reset/POR); break; case 0xA: LOG(Warm Reset by MSS WDG); break; case 0xC: LOG(Warm Reset by Software); break; case 0x8: LOG(External Warm Reset); break; default: LOG(Unknown Reset Cause: 0x%X, resetCause); } // 可以将本次复位原因记录到另一个SPARE寄存器用于统计 }对TI 16xx系列MCU的PRC寄存器进行深入理解和精准操控是迈向资深嵌入式工程师的必经之路。它不再是把芯片当成一个黑盒而是真正理解了其内部脉搏的跳动。从稳定的时钟输出到可靠的复位管理再到精细的安全控制和内存初始化每一个细节都关乎最终产品的稳健性。我希望这篇结合了手册解读与实战经验的梳理能帮你建立起这套底层控制的思维框架下次当系统出现那些“玄学”问题时你能自信地拿起示波器和调试器从这些最基础的寄存器中寻找答案。记住芯片不会说谎配置寄存器上的每一个比特都决定了它如何运行。