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寄存器保留位可能会造成系统异常便介绍完了。

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

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

    关注

    453

    文章

    50366

    浏览量

    421656
  • mcu
    mcu
    +关注

    关注

    146

    文章

    16980

    浏览量

    350219
  • 寄存器
    +关注

    关注

    31

    文章

    5308

    浏览量

    119981
  • 应用程序
    +关注

    关注

    37

    文章

    3240

    浏览量

    57595

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

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

收藏 人收藏

    评论

    相关推荐

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

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

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

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

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

    数据寄存器,数据寄存器是什么意思 数据寄存器数据寄存器包括累加AX、基址寄存器BX、计数
    发表于 03-08 14:38 1.2w次阅读

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

    移位寄存器,移位寄存器是什么意思 移位寄存器_
    发表于 03-08 14:50 1.7w次阅读

    ARM寄存器详解

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

    FPGA 调试 – 外设寄存器视图

    作为设计者,在 FPGA 设计中您可以访问众多外设器件的内部 寄存器 。一旦将FPGA设计下载到目标器件中并且代码已经运行在相应处理上,与这些寄存器进行交互的典型方法是通过嵌入
    发表于 05-15 11:49 3292次阅读
    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次下载

    寄存器与移位寄存器

    寄存器与移位寄存器:介绍寄存器原理和移位寄存器的原理及实现。
    发表于 05-20 11:47 0次下载

    STM32 BSRR BRR ODR寄存器详情解析

    BSRR 和 BRR 都是 STM32 系列 MCU 中 GPIO 的寄存器。 BSRR 称为端口位设置/清楚寄存器,BRR称为端口位**寄存器
    发表于 11-13 09:54 1.2w次阅读

    STM32系列MCU,写寄存器Or利用固件库

    嵌入式的编程,往下说就是操作MCU寄存器。而固件库就是函数的集合,固件库函数的作用是向下负责与寄存器直接打交道,向上提供用户函数调用的接口(API)。相对于固件库的方式,直接写寄存器
    的头像 发表于 08-09 17:22 7205次阅读
    STM32系列<b class='flag-5'>MCU</b>,写<b class='flag-5'>寄存器</b>Or利用固件库

    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>

    ---GD32 MCU---SYSCFG相关寄存器无法写入

    问题描述:客户在使用中断时,进行中断的相关配置,操作SYSCFG的相关寄存器,始终无法写入往SYSCFG的相关寄存器中写入非0的数据。原因:GD与ST的操作有差异,GD必须保证先打开外设时钟才能
    发表于 11-18 16:36 2次下载
    ---GD32 <b class='flag-5'>MCU</b>---SYSCFG相关<b class='flag-5'>寄存器</b>无法写入

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

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

    寄存器分为基本寄存器和什么两种

    寄存器是计算机中用于存储数据的高速存储单元,它们是CPU内部的重要组成部分。寄存器可以分为基本寄存器和扩展寄存器两种类型。 一、基本寄存器
    的头像 发表于 07-12 10:31 1100次阅读