1. McBSP仿真模式、复位机制与寄存器详解
在嵌入式DSP开发中,尤其是使用TI的TMS320系列芯片时,多通道缓冲串行端口(McBSP)是一个功能强大且复杂的模块。它不仅是连接音频编解码器、ADC/DAC、数字传感器等外部器件的桥梁,更是实现复杂通信协议(如SPI、I2S、TDM)的核心。然而,很多工程师在初次接触McBSP时,往往会被其繁多的寄存器、复杂的配置流程以及调试时遇到的诡异问题所困扰。今天,我就结合自己多年在工业控制和音频处理项目中的实际经验,来深入聊聊McBSP的两个关键但容易被忽视的方面:仿真模式与复位机制,并顺带把相关的核心寄存器掰开揉碎了讲清楚。理解透了这些,你不仅能写出更健壮的驱动代码,在调试时也能更快地定位问题,避免在数据丢失或时序错乱上浪费大量时间。
2. McBSP仿真模式深度解析
在嵌入式开发中,调试是家常便饭。但当你用JTAG或类似的高阶语言调试器(High-Level Language Debugger)对DSP进行单步或断点调试时,一个现实的问题就摆在了面前:McBSP这个负责实时数据流收发的模块,该怎么办?是让它跟着CPU一起暂停,还是继续运行?不同的选择会带来截然不同的调试体验和结果。McBSP的设计者早就考虑到了这一点,并在SPCR2寄存器中提供了两个专门的位来控制其在调试断点下的行为:FREE和SOFT位。
2.1 FREE与SOFT位的协同工作机制
这两个位共同决定了McBSP遇到调试器断点时的“生存状态”。我们可以把它们想象成汽车在自动驾驶时遇到紧急情况的处理策略。
FREE位是最高优先级的总开关。当FREE被设置为1时,意味着“自由运行”模式。此时,无论调试器是否命中断点,McBSP的发送和接收时钟(CLKX, CLKR)都会继续运行,数据照常移位进出。这就像自动驾驶汽车无视了“靠边停车”的指令,继续按原计划行驶。在这种模式下,SOFT位变成了“无关项”(Don‘t care),它的值不会产生任何影响。这种模式适用于那些绝对不能中断的实时数据流场景,比如正在录制或播放的音频,一旦中断就会产生可闻的爆音或数据丢失。但风险在于,如果程序停在断点处时间过长,而McBSP仍在接收数据,就极易导致接收缓冲区溢出(Overrun)错误。
当FREE位为0时,SOFT位才真正发挥作用,它决定了“刹车”的柔和程度。
SOFT = 0:立即停止模式(Immediate Stop)。这是最“粗暴”的方式。一旦遇到断点,McBSP的时钟立即停止,正在进行的传输会被立刻中止(Abort)。这好比一脚急刹车,车子瞬间停住。对于发送端,当前正在移出的数据字会不完整;对于接收端,正在移入的数据也会被截断。这种模式虽然能最快地冻结现场,便于观察某一时刻的精确状态,但会破坏当前数据帧的完整性,通常用于非实时性的配置检查或当数据错误无关紧要时。
SOFT = 1:软停止模式(Soft Stop)。这是一种更“文明”的停止方式。遇到断点时,McBSP不会立即刹车,而是会等待当前正在传输的整个数据字完成后,再停止时钟。例如,如果你正在传输一个32位的字,即使在第8个时钟周期遇到断点,McBSP也会坚持把剩下的24位传完才停下。这就像司机看到停车标志后,平稳地将车滑行到停止线再停稳。对于发送器,这能保证当前字的完整性;但对于接收器,需要注意:如果断点时间过长,接收器虽然完成了当前字的接收,但后续数据仍会持续到来(如果外部时钟源未停),这同样可能导致后续的接收缓冲区溢出。
为了更直观,我将这三种模式总结如下:
| FREE | SOFT | 仿真模式 | 发送器行为 | 接收器行为 | 适用场景 |
|---|---|---|---|---|---|
| 1 | X | 自由运行 (Free Run) | 时钟继续,数据继续发送 | 时钟继续,数据继续接收,可能溢出 | 绝对不能中断的实时流(如音频播放) |
| 0 | 0 | 立即停止 (Immediate Stop) | 时钟立即停止,传输中止 | 时钟立即停止,接收中止 | 非实时配置检查,或允许数据损坏的调试 |
| 0 | 1 | 软停止 (Soft Stop) | 完成当前字后停止 | 完成当前字后停止,但后续可能溢出 | 需要观察完整数据字且允许短暂暂停的调试 |
实操心得一:调试模式的选择策略在实际项目中,我的习惯是:在初始化阶段和配置验证时,将FREE和SOFT都设为0(即复位默认值),采用立即停止模式。因为此时还没有开始关键数据传输,快速冻结状态有利于检查寄存器配置是否正确。进入主循环,开始实时数据流处理(比如启动音频Codec)之前,我一定会根据应用需求重新配置它们。如果我的应用对数据连续性要求极高(如专业音频处理),我会在确保有足够缓冲区和处理速度的前提下,冒险使用FREE=1。但更常见的做法是使用SOFT=1模式,并务必在调试器中设置条件断点或观察点,而不是简单的行断点,以尽量减少程序暂停的时间,降低溢出风险。同时,在中断服务程序(ISR)中,要妥善处理RFULL(接收满)和XEMPTY(发送空)等状态位,即使是在调试暂停期间触发的错误也要能安全恢复。
2.2 仿真模式对调试的影响
理解这些模式,能帮你解释调试时的一些“灵异现象”。比如,你可能会发现,在某个断点停下后,再次运行程序,McBSP收发的数据对不上了,或者直接产生了同步错误(RSYNCERR/XSYNCERR)。这很可能是因为你用了“立即停止”模式,破坏了数据帧的边界,导致发送/接收移位寄存器(XSR/RSR)与帧同步信号(FSX/FSR)失去了同步。
另一个常见问题是溢出(Overrun)。在FREE=1或SOFT=1模式下,如果调试暂停时间超过了一个或多个数据字的传输时间,而外部设备仍在发送数据,接收缓冲寄存器(RBR)在填满后,新数据就会覆盖未及时读取的旧数据,触发溢出错误。因此,在调试涉及McBSP的代码时,养成先检查SPCR2中FREE和SOFT位状态的习惯,能让你少走很多弯路。
3. McBSP复位机制全解
复位是让模块从一个确定、已知的状态开始工作的必要操作。McBSP的复位比想象中要复杂一些,它分为几个层次:整个DSP的设备复位、McBSP模块自身的复位、以及其内部采样率发生器的复位。每种复位对引脚和内部状态的影响各不相同。
3.1 不同复位源下的引脚状态
这是硬件连接时最容易出错的地方。很多工程师误以为只要程序里对McBSP进行了复位,其引脚就会变成高阻态或已知状态,其实不然。McBSP引脚(MDR、MCLK、MFS)的状态取决于具体的复位方式。
当整个DSP设备被复位(例如上电复位或看门狗复位,XRS信号拉低)时,所有McBSP引脚都会被强制设置为通用输入/输出(GPIO)模式,且默认方向为输入。这是因为在芯片层面,复位后所有多功能引脚(MUX)都回归到最安全的默认状态——GPIO输入,防止意外输出损坏外部电路或产生总线冲突。此时,McBSP模块的时钟是关闭的。
当通过软件单独复位McBSP的接收器(RRST=0)或发送器(XRST=0),而采样率发生器已启动(GRST=1)时,引脚状态则取决于其配置:
- 接收器复位(RRST=0, GRST=1):数据接收引脚(MDRx)变为输入状态。接收时钟(MCLKRx)和接收帧同步(MFSRx)��脚,如果被配置为输入,则保持输入状态(外部信号决定其电平);如果被配置为输出,则MCLKRx会继续由内部采样率发生器时钟(CLKG)驱动运行,MFSRx则输出其非活动状态(通常为低电平)。
- 发送器复位(XRST=0, GRST=1):数据发送引脚(MDXx)变为高阻态(High-Z)。这一点至关重要!如果你在发送器复位期间,外部电路指望该引脚有确定电平(比如上拉或下拉),可能会因为高阻态导致不确定状态,引发逻辑错误。发送时钟(MCLKXx)和发送帧同步(MFSXx)引脚的状态逻辑与接收端类似。
简单来说,设备复位把引脚“没收”成了GPIO,而模块局部复位则是在已分配的McBSP功能下,将特定引脚置于安全状态。发送数据引脚在局部复位时变为高阻,是为了避免在发送器未就绪时向总线输出垃圾数据。
3.2 采样率发生器复位(GRST)的微妙之处
采样率发生器是McBSP内部时钟和帧同步信号的心脏。通过GRST位可以单独复位它。但这里有一条黄金法则:只有当发送器和接收器都不使用采样率发生器产生的CLKG和FSG时,你才能将GRST清零(复位采样率发生器)。
为什么?想象一下,采样率发生器就像一个乐队的指挥。如果指挥(GRST)突然停下(复位),而乐手(发送器/接收器)还在按照之前的节拍演奏,整个乐队(数据流)必然乱套。具体来说,如果GRST=0,内部时钟CLKG和帧同步FSG会被强制拉低(非活动状态)。此时,任何依赖CLKG或FSG进行工作的发送或接收逻辑都会因为失去时钟或同步信号而失败。
手册里还提到了一个有趣的细节:当采样率发生器不在复位状态(GRST=1)时,即使接收器或发送器单独复位(RRST=0或XRST=0),只要对应的帧同步引脚被配置为由FSG驱动输出,那么该帧同步引脚仍会输出FSG的非活动状态(通常是低电平)。这保证了当McBSP只有一部分在工作时(例如仅接收),另一部分(发送)的帧同步引脚不会悬空或产生干扰信号。
3.3 标准初始化与复位流程详解
TI手册给出了一个标准的McBSP初始化序列,这个序列看似简单,但每一步背后都有其道理。我结合自己的踩坑经验,把它细化成一个更健壮、可复用的流程:
进入全面复位状态:
SpiaRegs.SPCR2.bit.XRST = 0; // 发送器复位 SpiaRegs.SPCR1.bit.RRST = 0; // 接收器复位 SpiaRegs.SPCR2.bit.GRST = 0; // 采样率发生器复位 // 如果是刚退出设备复位,此步可省略,因为硬件已完成目的:将McBSP的所有活动部分置于一个静止、确定的状态。这是配置寄存器的基础,就像在一张白纸上作画。
配置寄存器(关键步骤): 在复位状态下,配置除了数据寄存器(DXR, DRR)以外的所有配置寄存器。这包括:
- 引脚控制寄存器(PCR):决定时钟和帧同步是输入还是输出,极性如何。
- 接收/发送控制寄存器(RCR1/2, XCR1/2):设置字长、帧长、数据延迟、压缩扩展模式等。
- 采样率发生器寄存器(SRGR1/2):配置内部时钟分频和帧同步周期。
- 多通道控制寄存器(MCR1/2)和使能寄存器(RCER, XCER):如果使用多通道模式。
- 串口控制寄存器(SPCR1/2)中的部分位,如中断模式、时钟停止模式等(但FREE、SOFT、复位位等动态控制位先不动)。为什么必须在复位状态下配置?因为McBSP的许多配置逻辑是边沿敏感或依赖于稳定状态的。如果在模块运行时动态更改这些配置(比如字长),很可能导致内部状态机混乱,产生不可预知的数据错位。手册明确警告:“必须在受影响部分处于复位状态时,才能修改其配置寄存器。”
等待内部同步(至少两个时钟周期): 在写配置和启动模块之间,需要插入一个短暂的延迟。手册建议等待“两个时钟周期”。这个时钟周期指的是该部分McBSP所使用的主时钟源周期。对于发送器,是CLKX的周期;对于接收器,是CLKR的周期;如果使用内部采样率发生器,则是CLKG的周期。实操做法:通常用一个小型软件延时循环,或者插入几条NOP指令。更严谨的做法是,在配置完时钟源后,根据已知的CPU频率或外部时钟频率,计算出一个微秒级的延时并执行。这一步是为了让刚才写入寄存器的配置值,在McBSP内部逻辑中完全稳定和生效。
(可选)预装发送数据: 如果需要发送器一启动就发送数据,可以在使能发送器之前,向数据发送寄存器(DXR1, DXR2)写入初始值。注意:对于字长大于16位的情况(如24/32位),必须先写DXR2(高16位),再写DXR1(低16位)。因为DXR1的写入操作会触发DXR到XSR的拷贝动作。如果顺序反了,会导致一个不完整的数据字(旧的高位+新的低位)被发送出去。
使能模块(退出复位):
SpiaRegs.SPCR2.bit.XRST = 1; // 使能发送器 SpiaRegs.SPCR1.bit.RRST = 1; // 使能接收器 // 注意:在设置XRST/RRST时,不要意外改变SPCR1/2中的其他位!技巧:通常使用“读-修改-写”或直接赋值整个寄存器的方式来确保不干扰其他位。例如:
SpiaRegs.SPCR2.all |= 0x0001;来只设置XRST位。(如果需要)启动内部帧同步: 如果帧同步信号是由内部采样率发生器产生的(FSXM=1且FSGM=1),则需要启动帧同步逻辑:
SpiaRegs.SPCR2.bit.FRST = 1; // 使能帧同步生成这一步必须在采样率发生器已启动(GRST=1)后进行。
再次等待激活: 使能发送器和接收器后,再等待两个时钟周期,确保它们已经完全进入工作状态。
一个常见的进阶场景是:如何在接收器运行时,单独复位并重新配置发送器?手册给出了示例代码(Example 15-1)。其核心思想是:只操作发送器相关的复位位(XRST)和配置寄存器(XCR, SRGR中与发送相关的部分),同时保持接收器运行(RRST=1)。操作顺序依然是:先置XRST=0复位发送器,然后在发送器复位状态下修改其配置,等待同步,最后置XRST=1重新使能。这在进行动态协议切换(例如从I2S切换到TDM)时非常有用。
4. 核心寄存器精讲与配置实战
McBSP的寄存器数量众多,但理解了它们的分组和功能后,配置起来就有章可循。下面我挑出最核心、最容易出错的几个寄存器组,结合实例讲解。
4.1 数据寄存器(DRR, DXR)与字长陷阱
数据寄存器是CPU/DMA与McBSP数据缓冲区交互的窗口。
- DRR1/DXR1:总是用于数据的低16位。
- DRR2/DXR2:当字长大于16位(如20, 24, 32位)时,用于数据的高位部分。
这里有一个至关重要的硬件机制,也是新手最容易栽跟头的地方:对于接收,当RBR(接收缓冲寄存器)中的数据准备就绪,会被拷贝到DRR中。这个拷贝动作是由读取DRR1触发的。这意味着,如果你要接收一个32位字,你必须先读DRR2(高16位),再读DRR1(低16位)。如果你先读���DRR1,硬件会立即启动下一次RBR到DRR的拷贝,导致你还没读取的DRR2中的旧数据被新数据覆盖,从而丢失高位数据。
同理,对于发送,数据从DXR拷贝到XSR(发送移位寄存器)是由写入DXR1触发的。所以,发送一个32位字时,必须先写DXR2(高16位),再写DXR1(低16位)。如果顺序错了,会导致XSR中是一个由旧DXR2数据和新DXR1数据拼凑而成的错误字。
实操心得二:数据存取顺序铁律无论你的CPU是32位还是16位架构,只要McBSP配置的字长超过16位,就必须严格遵守“高位先,低位后”的存取顺序。在编写DMA描述符或中断服务程序时,务必检查数据缓冲区的排列顺序是否与这一硬件行为匹配。我曾在一次音频项目中,因为DMA配置错误(先传输了低字地址的数据),导致左、右声道数据错位,产生了奇怪的立体声效果,排查了整整一天。
4.2 串口控制寄存器(SPCR1, SPCR2)—— 控制核心
这两个寄存器是McBSP的大脑。
SPCR2我们前面已经重点讨论了它的仿真控制位(FREE, SOFT)和复位位(XRST, GRST, FRST)。此外,它还有:
- XINTM:发送中断模式。可以配置为在发送准备好(XRDY)、帧同步到来、同步错误(XSYNCERR)或每发送完一个16通道块时产生中断。合理配置可以高效利用CPU资源。
- XRDY:发送就绪位。当DXR中的数据已拷贝到XSR,可以写入新数据时,此位为1。这是查询式发送的判据。
- XEMPTY:发送空标志。当XSR中的数据已全部移出,且DXR中无新数据时,此位为0。这在判断发送队列是否完全清空时有用。
SPCR1则更多地控制接收端和特殊模式:
- DLB:数字回环模式。置1后,发送端的输出直接连接到接收端的输入,同时时钟和帧同步也内部连接。这是测试McBSP自身功能是否正常的绝佳工具,无需连接外部硬件。在驱动开发初期,我强烈建议先开启回环模式,自发自收,验证基本的数据通路和配置是否正确。
- RJUST:接收数据对齐和符号扩展。决定接收到的数据在放入DRR时,是右对齐(LSB对齐)还是左对齐(MSB对齐),高位是补零还是进行符号扩展。必须与发送端的数据格式严格匹配,否则你收到的数据值会是错的。
- CLKSTP:时钟停止模式。用于支持SPI协议。当与SPI设备通信时,需要根据设备是主模式还是从模式,配置CLKSTP和CLKXP/CLKRP(时钟极性)等位。
- RINTM/RRDY/RSYNCERR:与SPCR2中的发送中断部分类似,控制接收中断和状态。
4.3 接收/发送控制寄存器(RCR1/2, XCR1/2)—— 协议定义者
这组寄存器定义了通信的“语法”。
- (R/X)PHASE:帧相位。单相位帧还是双相位帧?双相位帧允许一帧内包含两种不同字长和数量的数据块,非常灵活。
- (R/X)FRLEN1/2:帧长度。定义了一帧中包含多少个数据字。注意:写入的值是“字数-1”。例如,想要一帧有8个字,则需要写入7。
- (R/X)WDLEN1/2:字长。定义每个数据字有多少位(8, 12, 16, 20, 24, 32)。
- (R/X)DATDLY:数据延迟。指定在帧同步信号有效后,延迟几个时钟周期才开始传输第一位数据。通常用于兼容那些数据在帧同步后不是立即有效的设备。0位延迟最常见。
- (R/X)FIG:帧同步忽略位。这是一个提升总线效率的关键位。如果置1,McBSP会在当前帧传输完成前,忽略后续到来的额外帧同步脉冲。这在将多个短帧“打包”成一个长帧连续传输时非常有用(见下文数据打包例子),可以避免不必要的帧同步中断,减少总线开销。
4.4 采样率发生器寄存器(SRGR1/2)—— 时钟引擎
当McBSP需要自己产生时钟(CLKG)和帧同步(FSG)时,就靠它。
- CLKGDV(在SRGR1中):时钟分频值。
CLKG频率 = 输入时钟频率 / (CLKGDV + 1)。输入时钟源由CLKSM和SCLKME位选择(可以是CPU时钟LSPCLK或外部引脚MCLKX/R)。 - FWID:帧同步脉冲宽度。定义了FSG信号有效电平的持续时间,单位是CLKG周期数。
脉冲宽度 = (FWID + 1)个CLKG周期。 - FPER:帧同步周期。定义了FSG脉冲之间的间隔,单位也是CLKG周期数。
脉冲周期 = (FPER + 1)个CLKG周期。 - FSGM:帧同步生成模式。当FSXM=1(内部帧同步)时,此位决定FSX信号是由DXR到XSR的拷贝事件触发(FSGM=0),还是由采样率发生器产生的FSG信号驱动(FSGM=1)。
- GSYNC:时钟同步模式。仅在外部输入时钟(CLKSM=0)时有效。当GSYNC=1时,CLKG和FSG会与外部输入到FSR引脚上的帧同步信号同步。这在作为从设备与一个外部主设备同步时非常关键。
5. 数据打包实战:提升总线效率的技巧
McBSP的数据打包功能是其强大灵活性的体现,目的是减少CPU或DMA搬运数据的次数,从而提升总线利用率和系统整体性能。手册里举了两个经典例子,我用自己的话再解释一下。
场景:你需要连续传输四个8位的数据字(比如四个音频采样点)。
方法一:常规传输(低效)
- 配置:单相位帧(PHASE=0),每帧4个字(FRLEN1=3),字长8位(WDLEN1=0)。
- 结果:每传输4个字节(32位),需要CPU/DMA进行4次写DXR1或读DRR1操作。总线频繁被占用。
方法二:利用长字长打包(高效)
- 配置:单相位帧(PHASE=0),每帧1个字(FRLEN1=0),字长32位(WDLEN1=5)。
- 结果:硬件将连续的4个8位字“看作”一个32位字。CPU/DMA只需要2次操作(先写/读高16位DXR2/DRR2,再写/读低16位DXR1/DRR1)即可完成32位数据传输。总线占用减半。
- 关键:这要求发送端和接收端采用相同的“看待”数据的方式。通常需要在软件或DMA中,将四个8位数据打包成一个32位数据再写入DXR。
方法三:利用帧同步忽略(FIG)实现连续流
- 配置:在方法二的基础上,设置
(R/X)FIG = 1。 - 场景:如果外部设备持续地、以最高包频率(每个字一个帧同步)发送8位数据流。
- 结果:McBSP在收到第一个帧同步脉冲后开始接收,并将后续的帧同步脉冲全部忽略,从而将整个数据流当作一个超长的、不间断的帧来处理。这同样将总线交互次数降低到原来的一半。
- 优势:这种方法特别适合与那些固定产生帧同步的外部设备通信,你可以在不改变对方的情况下,在McBSP端优化数据吞吐。
6. 常见问题排查与调试心得
即使理解了所有原理,实际调试中还是会遇到各种问题。下面是我总结的一些典型症状和排查思路:
问题一:McBSP完全不工作,收不到也发不出数据。
- 检查复位状态:首先确认XRST、RRST、GRST是否都已置1(使能)。最常见的就是初始化流程没走完,模块还处在复位状态。
- 检查时钟:用示波器测量MCLKX/MCLKR/CLKG引脚是否有时钟信号?频率是否正确?如果没有时钟,一切免谈。检查CLKXM/CLKRM、CLKSM、CLKGDV的配置。
- 检查帧同步:用示波器测量FSX/FSR引脚。帧同步信号来了吗?极性(FSXP/FSRP)对吗?宽度和周期对吗?如果使用内部帧同步(FSXM/FSRM=1),检查FRST是否已置1。
- 检查引脚复用:确认芯片的引脚复用控制寄存器,是否已将相关引脚配置为McBSP功能,而不是普通的GPIO或其他外设功能。
问题二:能收到数据,但数据值全是错的或高低位反了。
- 检查字长和对齐:确认(R/X)WDLEN设置是否正确。检查RJUST位,确保接收数据的对齐方式与发送端匹配。对于大于16位的字,严格���查DXR2/DRR2和DXR1/DRR1的读写顺序。
- 检查时钟极性:检查CLKXP和CLKRP。发送和接收的采样边沿必须一致。通常,发送在时钟的上升沿输出数据,接收在下降沿采样数据(CLKXP=0, CLKRP=0),但具体要看对端设备的要求。
- 检查数据延迟:检查(R/X)DATDLY。大多数标准协议(如SPI, I2S)使用1位数据延迟,即数据在帧同步有效后的第二个时钟边沿开始。但有些设备可能使用0或2位延迟。
问题三:数据传输不稳定,偶尔丢失数据或产生同步错误。
- 检查中断或DMA服务速度:是否因为CPU负载过高或中断被屏蔽,导致RRDY置位后未能及时读取DRR(造成接收溢出RFULL),或XRDY置位后未能及时写入DXR(造成发送下溢XEMPTY)?优化ISR,或考虑使用DMA来搬运数据。
- 检查缓冲区:在使能模块前,是否预先向DXR写了数据?避免发送器一启动就处于“饥饿”状态。
- 检查仿真模式:如果正在调试,检查FREE和SOFT位的设置是否合适。不恰当的设置可能在断点处导致数据丢失或溢出。
- 检查多通道使能寄存器:如果使用了多通道模式,确保你需要收发的通道在RCER/XCER寄存器中已被正确使能。一个常见的疏忽是只配置了MCR,忘了配置具体的通道使能寄存器。
问题四:如何验证配置是否正确?
- 使用数字回环(DLB):这是最有效的自检方法。将SPCR1.DLB置1,然后自发自收。如果能正确收到自己发送的数据,证明McBSP内核、时钟、数据通路基本正常,问题可能出在外部电路或与对端设备的协议匹配上。
- 简化配置:从最简配置开始(如单相位、8位字长、内部时钟、查询方式),让模块先跑起来,再逐步增加复杂功能(如DMA、多通道、压缩扩展等)。
最后,记住一点:McBSP的配置寄存器,只有在相应模块(发送器、接收器、采样率发生器)处于复位状态时,修改才是安全的。动态修改运行中的配置是灾难的根源。每次修改重要参数(如波特率、帧格式)时,最稳妥的方法是先复位对应模块,配置,再重新使能。