0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MCU外设寄存器谨慎赋值法

Dp1040 来源:痞子衡嵌入式 2023-12-12 09:14 次阅读

今天给大家介绍的是改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常

在群里有一位非常活跃的朋友,前段时间反映了一个在i.MXRT1062应用程序里动态调整FlexRAM导致WDOG模块工作异常的问题。经过一番排查,发现了i.MXRT芯片系统设计里的一个小秘密,这个秘密警示我们在MCU里应尽量遵循谨慎的外设寄存器赋值法。

这个寄存器谨慎赋值法是什么?这里先卖个关子,文末会揭秘。今天就将这个问题解决过程还原一下,希望对大家有所启发:

一、重配FlexRAM影响WDOG的表象问题

先交待一下问题背景,这个网友是在i.MXRT1062板子上做的测试,使用的是 SDK_EVK-MIMXRT1060oardsevkmimxrt1060driver_exampleswdogiar 例程(XiP),他对工程启动文件和主函数改动如下:

9f3ed286-9886-11ee-8b88-92fbcf53809c.png

intmain(void)
{
wdog_config_tconfig;
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();

PRINTF("
********System Start********
");

//使能WDOG模块,设置Timeout时间,不启用中断
WDOG_GetDefaultConfig(&config);
//Timeout value is(0xF+1)/2=8 sec.
config.timeoutValue=0xFU;
WDOG_Init(DEMO_WDOG_BASE,&config);
PRINTF("---wdog Init done---
");

while(1)
{
//故意不喂狗,让WDOG超时复位系统
//WDOG_Refresh(DEMO_WDOG_BASE);
PRINTF("
WDOG has be refreshed!");

/*Delay.*/
delay(SystemCoreClock);
}
}

他在启动文件 startup_MIMXRT1062.s 里将默认128KB ITCM、128KB DTCM、256KB OCRAM的FlexRAM分配调整成了256KB DTCM、256KB OCRAM(关于FlexRAM基本知识,这种FlexRAM动态调整方式仅适用XiP工程。最终运行结果里看,应用程序似乎仅运行了一次,没有像预想得那样重复启动执行。

9f4d98f2-9886-11ee-8b88-92fbcf53809c.png

如果在 startup_MIMXRT1062.s 里将重配FlexRAM代码去掉,这个WDOG例程是可以正常工作的,串口助手里可以看到循环打印,所以这很容易让人推断出FlexRAM重配功能导致WDOG模块工作异常了。

9f5151b8-9886-11ee-8b88-92fbcf53809c.png

二、找到程序异常的根本原因

由于这个WDOG例程并不是完全功能异常,至少首次打印是有的,说明重配FlexRAM并没有对程序堆栈运存等造成实质影响,启动文件里那段重配FlexRAM代码本身没有逻辑问题。而打印输出在WDOG超时时间到了之后就没有了,看起来WDOG模块应该是正常产生了软复位。

为了最小化代码去定位问题,我们将这个网友WDOG例程主函数修改如下,去掉WDOG相关代码,直接用 NVIC_SystemReset() 代替。运行后发现,仍然仅有一次打印,这个实验的意义是那段重配FlexRAM代码会导致软复位后程序没法再次运行,而跟具体WDOG模块无关。

intmain(void)
{
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();

PRINTF("
********System Start********
");

while(1)
{
NVIC_SystemReset();
}
}

我们现在将焦点放回到重配FlexRAM那段汇编代码本身,代码很简单,就是将i.MXRT芯片内部的IOMUXC_GPR->GPR17(基址0x400ac044)和IOMUXC_GPR->GPR16(基址0x400ac040)分别整体赋值为0x5555aaaa和0x00000007,单纯从寄存器有效功能位定义上来看,这样操作是没问题的。

  LDR R0,=0x400AC044
  LDR R1,=0x5555aaaa
  STR R1,[R0]
  LDR R0,=0x400AC040
  LDR R1,=0x00000007
  STR R1,[R0]

翻看手册里关于IOMUXC_GPR->GPR17和IOMUXC_GPR->GPR16寄存器的位定义,发现IOMUXC_GPR->GPR16寄存器中有很多bit是保留位,并且其中bit21保留位默认值是1,与其他保留位默认值0不一样。显然 IOMUXC_GPR->GPR16 = 0x00000007 这样的赋值语句会将其bit21误清零,并且IOMUXC_GPR寄存器在软复位后也不会改变其值 。

9f5c3056-9886-11ee-8b88-92fbcf53809c.png

难道问题是由IOMUXC_GPR->GPR16[21]保留位被误清零导致的?死马当活马医吧,我们修改一下重配FlexRAM代码如下(两种方式都行),将IOMUXC_GPR->GPR16[21]保持为默认1。

运行后发现,异常问题解决了,串口助手里可以看到循环打印。现在我们知道了IOMUXC_GPR寄存器即使是保留位也不要轻易当用户标志位使用,更不要轻易改变其默认值,因为SoC占用了这些位,具体用途未详述。由此可以推测IOMUXC_GPR->GPR16[21]位跟系统启动有关,并且其值的设置是在软复位后才生效的。

#ifdef FLEXRAM_CFG_STANDARD
  LDR R0,=0x400AC044
  MOV32 R1,0x5555aaaa
  STR R1,[R0]
  LDR R0,=0x400AC040
  LDR R1,[R0]
  ORR R1,R1,#4
  STR R1,[R0]
#else
  LDR R0,=0x400AC044
  LDR R1,=0x5555aaaa
  STR R1,[R0]
  LDR R0,=0x400AC040
  LDR R1,=0x00200007
  STR R1,[R0]
#endif

三、MCU外设寄存器谨慎赋值法

现在为大家揭秘文章开头卖的关子,到底什么是谨慎的外设寄存器赋值法?

其实可以从芯片头文件定义里去学,假设我们有一个模块叫PERIPH,模块内部有一个名为REG的寄存器,这个寄存器中有功能位FUNC(单bit或者多bit),芯片头文件中通常定义如下:

typedefstruct{
__IOuint32_tREG;
}PERIPH_Type;

#definePERIPH_REG_FUNC_MASK(0x4U)//或者(0xCU)
#definePERIPH_REG_FUNC_SHIFT(2U)
#definePERIPH_REG_FUNC(x)(((uint32_t)(((uint32_t)(x))<< PERIPH_REG_FUNC_SHIFT)) & PERIPH_REG_FUNC_MASK)

#definePERIPH_BASE(0x400AC000u)
#definePERIPH((PERIPH_Type*)PERIPH_BASE)

谨慎寄存器赋值法的核心要义就是每次操作都只涉及一种功能位,并且不要影响其他功能位的值,就像下面代码所示。切忌出现 PERIPH->REG = value1 | value2 | ... 这样的一次性多个不同功能位一起赋值的操作。

谨慎寄存器赋值法既可以避免模块设计里不同功能位赋值有先后顺序的限制问题,也可以防止误改某些保留位默认值的异常情况发生。当然,这也是有小小代价的,那就是会增加了一些代码长度。

//如果PERIPH->REG[FUNC]是单bit
PERIPH->REG|=PERIPH_REG_FUNC_MASK;
PERIPH->REG&=~PERIPH_REG_FUNC_MASK;
//如果PERIPH->REG[FUNC]是多bit
PERIPH->REG=(PERIPH->REG&(~PERIPH_REG_FUNC_MASK))|PERIPH_REG_FUNC(value);

至此,改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常便介绍完了。

本文转载自痞子衡嵌入式公众号

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 芯片
    +关注

    关注

    447

    文章

    47804

    浏览量

    409179
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16019

    浏览量

    343669
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117746
  • 应用程序
    +关注

    关注

    37

    文章

    3136

    浏览量

    56405

原文标题:什么是MCU里应尽量遵循的寄存器谨慎赋值法?

文章出处:【微信号:玩点嵌入式,微信公众号:玩点嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    寄存器赋值问题

    ,会经常看到给单片机寄存器赋值的语句。下面就以最简单的控制51单片机引脚高低电平来说明一下。(不要总是存在51单片机已经淘汰的想法,51单片机至今任然是出货量最大的单片机,并且各大公司每年都有新款的51
    发表于 11-23 16:08

    如何给CC2650的寄存器赋值

    Hello, all!      由于在CCSv6.1中未能找到类似CC2650.h的头文件,所以无法在main函数中直接给CC2650的寄存器进行赋值。      问:如何给CC2650的寄存器
    发表于 06-21 09:35

    为什么把main函数的地址赋值给pc寄存器

    pc寄存器存放的是将要执行指令的地址norflash有一个main函数,SDRAM也有一个main函数,为什么把main函数的地址赋值给pc寄存器,就一定是把SDRAM上的main函数地址赋值
    发表于 03-06 07:45

    为什么SSI通信接口的数据寄存器不能直接赋值

    在学SSI的通信接口,试着通过寄存器直接控制,可是调试时发现,对SSI的数据寄存器直接赋值根本就不能赋值,换句话说赋值是无效的。这是什么情况
    发表于 09-04 06:11

    单片机如何给寄存器赋值

    2020-11-15单片机中在给寄存器赋值时,常常写data|=0x03不直接写data=0x03,是因为前者可以保护寄存器上其它位的值,只改变想要改变的位。
    发表于 01-24 07:52

    如何操作外设寄存器

    如何操作外设寄存器
    发表于 02-11 06:02

    寄存器,寄存器是什么意思

    寄存器,寄存器是什么意思 寄存器定义  寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用
    发表于 03-08 14:26 2.1w次阅读

    ARM寄存器详解

    ARM有37个寄存器,其中31个通用寄存器,6个状态寄存器。   这里尤其要注意区别的是ARM自身寄存器和它的一些外设
    发表于 07-10 10:04 2648次阅读

    FPGA 调试 – 外设寄存器视图

    作为设计者,在 FPGA 设计中您可以访问众多外设器件的内部 寄存器 。一旦将FPGA设计下载到目标器件中并且代码已经运行在相应处理器上,与这些寄存器进行交互的典型方法是通过嵌入
    发表于 05-15 11:49 3017次阅读
    FPGA 调试 – <b class='flag-5'>外设</b><b class='flag-5'>寄存器</b>视图

    STM32寄存器外设驱动x_实验四

    主要介绍STM32寄存器——外设驱动,图文详情,非常合适看
    发表于 02-22 15:46 0次下载

    DSP2407片内外设寄存器定义

    DSP2407片内外设寄存器定义,有需要的下来看看
    发表于 05-06 15:29 25次下载

    C语言访问MCU寄存器

    C语言访问MCU寄存器问题由来://下面这行代码的意思是直接操作0X020C4068这个寄存器//具体寄存器的作用是通过手册得到的#define CCM_CCGR0 *((volati
    发表于 10-25 13:21 3次下载
    C语言访问<b class='flag-5'>MCU</b><b class='flag-5'>寄存器</b>

    C语言访问MCU寄存器的三种方式

    C语言访问MCU寄存器的三种方式 MCU中的特殊功能寄存器SFR,实际上就是SRAM地址已经确定的SRAM单元,在C语言环境下对其访问归纳起来有3种方法。
    发表于 10-28 17:21 11次下载
    C语言访问<b class='flag-5'>MCU</b><b class='flag-5'>寄存器</b>的三种方式

    安卓如何逆向_Dalvik 寄存器,字节码,指令格式 2

    4位 move-wide vA,vB  为4为的寄存器赋值,源寄存器与目的寄存器都为4位 Move/from16 vAA,vBBBB  将vBBBB
    的头像 发表于 01-30 16:25 351次阅读

    干货满满:ARM的内核寄存器讲解

    内核寄存器外设寄存器: 内核寄存器外设寄存器是完全不同的概念。内核
    发表于 04-17 11:47 158次阅读
    干货满满:ARM的内核<b class='flag-5'>寄存器</b>讲解