大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常

  痞子衡的嵌入式技术交流群里有一位非常活跃的朋友(网名:文,痞子衡已经指定他为副群主)近日向痞子衡反映了一个在i.MXRT1062应用程序里动态调整FlexRAM导致WDOG模块工作异常的问题,经过一番排查,痞子衡发现了i.MXRT芯片系统设计里的一个小秘密,这个秘密警示我们在MCU里应尽量遵循谨慎的外设寄存器赋值法,这个寄存器谨慎赋值法是什么,痞子衡先卖个关子,文末会揭秘。痞子衡今天就将这个问题解决过程还原一下,希望对大家有所启发:

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

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

int main(void)
{
wdog_config_t config;
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole(); PRINTF("\r\n******** System Start ********\r\n"); // 使能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---\r\n"); while (1)
{
// 故意不喂狗,让WDOG超时复位系统
//WDOG_Refresh(DEMO_WDOG_BASE);
PRINTF(" \r\nWDOG has be refreshed!"); /* Delay. */
delay(SystemCoreClock);
}
}

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

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

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

  由于这个WDOG例程并不是完全功能异常,至少首次打印是有的,说明重配FlexRAM并没有对程序堆栈运存等造成实质影响,启动文件里那段重配FlexRAM代码本身没有逻辑问题。而打印输出在WDOG超时时间到了之后就没有了,看起来WDOG模块应该是正常产生了软复位。为了最小化代码去定位问题,痞子衡将这个网友WDOG例程主函数修改如下,去掉WDOG相关代码,直接用 NVIC_SystemReset() 代替。运行后发现,仍然仅有一次打印,这个实验的意义是那段重配FlexRAM代码会导致软复位后程序没法再次运行,而跟具体WDOG模块无关。

int main(void)
{
BOARD_ConfigMPU();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole(); PRINTF("\r\n******** System Start ********\r\n"); 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寄存器在软复位后也不会改变其值 (参见《SystemReset不复位的GPR寄存器小结》一文)。

  难道问题是由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

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

  现在痞子衡揭秘文章开头卖的关子,到底什么是谨慎的外设寄存器赋值法。其实可以从芯片头文件定义里去学,假设我们有一个模块叫PERIPH,模块内部有一个名为REG的寄存器,这个寄存器中有功能位FUNC(单bit或者多bit),芯片头文件中通常定义如下:

typedef struct {
__IO uint32_t REG;
} PERIPH_Type; #define PERIPH_REG_FUNC_MASK (0x4U) // 或者 (0xCU)
#define PERIPH_REG_FUNC_SHIFT (2U)
#define PERIPH_REG_FUNC(x) (((uint32_t)(((uint32_t)(x)) << PERIPH_REG_FUNC_SHIFT)) & PERIPH_REG_FUNC_MASK) #define PERIPH_BASE (0x400AC000u)
#define PERIPH ((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寄存器保留位可能会造成系统异常痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常的更多相关文章

  1. 痞子衡嵌入式:IAR在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致(J-Link / CMSIS-DAP)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致. 做Cortex-M内核MCU嵌入式软件开发,可用的集成开发环境( ...

  2. 痞子衡嵌入式:Keil在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致(J-Link/DAPLink)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Keil在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致. 本篇是 <IAR EWARM复位类型>.<M ...

  3. 痞子衡嵌入式:我入选了2021年度与非网(eefocus)星选创作者Top10

    本周二「与非网」一个美女运营小姐姐加痞子衡微信,告知痞子衡评上了一个奖,让痞子衡把收件地址告诉她,她把证书寄过来. 昨天痞子衡收到了快递,拆开一看,原来是被评上了 与非网 2021 年度创作者,这个证 ...

  4. 痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用. 我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目 ...

  5. 痞子衡嵌入式:IVT里的不同entry设置可能会造成i.MXRT1xxx系列启动App后发生异常跑飞

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IVT里的不同entry设置可能会造成i.MXRT1xxx系列启动App后发生异常跑飞问题的分析解决经验. 事情缘起恩智浦官方论坛上的一 ...

  6. 痞子衡嵌入式:原来i.MXRT1xxx系列里也暗藏了Product ID寄存器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx系列里暗藏的Product ID寄存器. MCU 厂商在定义一个产品系列时,通常是会预先规划产品发展路线的(即会有一 ...

  7. 痞子衡嵌入式:嵌入式里堆栈原理及其纯C实现

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式里堆栈原理及其纯C实现. 今天给大家分享的这篇还是2016年之前痞子衡写的技术文档,花了点时间重新编排了一下格式.栈这种结构在嵌入式 ...

  8. 痞子衡嵌入式:利用i.MXRT1xxx系列ROM提供的FlexSPI driver API可轻松IAP

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT系列ROM中的FlexSPI驱动API实现IAP. 痞子衡的技术交流群里经常有群友提问: i.MXRT中的FlexSPI驱动 ...

  9. 痞子衡嵌入式:了解i.MXRTxxx系列ROM API及其与i.MXRT1xxx系列的差异

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM API设计细节. 痞子衡之前写过两篇文章 <利用i.MXRT1xxx系列ROM提供的FlexSPI ...

随机推荐

  1. 整合Atomikos、Quartz、Postgresql的踩坑日记

    前言 由于业务需要,在单体Spring Boot项目中需要引入分布式事务,来保证单体应用连接的多个数据源的事务统一. 而说到分布式事务,小伙伴们肯定会想到阿里的Seata,阿里Seata强大的AT模式 ...

  2. k8s 使用nfs做provisioner

    官方的nfs provisoner,serviceAccount RABC相关 请在这里下载https://raw.githubusercontent.com/kubernetes-incubator ...

  3. 8.switch语句

    switch语句语法 switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数 ...

  4. Bootstrap工具包--用于响应式布局和移动设备优先的web项目

    Bootstrap是用于前端开发的工具包,是一个css/html框架 用于响应式布局和移动设备优先的web项目 响应式布局--一个网站能兼容多个终端 有很多版本:v3,v4,v5   三个没啥区别  ...

  5. php判断请求类型(ajax|get|post|cli)

    php判断请求类型,可以通过 $_SERVER 相关的参数来实现, 这个很在对某些请求代码复用里面很常用.具体代码如下: /** *@todo: 判断是否为post */ if(!function_e ...

  6. 关于csv文件最大行数和最大列数

    excel 2003 =2^16 = 65 536 excel 2007 = 2^20 = 1048576 Excel2003,最大行数2^16=65536,最大列数256 Excel2007,最大行 ...

  7. hdu3035 最小割转换成最短路

    题意:       给你一个平面图,要求从求出从左上角到右下角的最小割. 思路:       如果大意的可能直接上来一遍最大流,然后就会各种悲剧的MLE,TLE,其实这个题目可以用到有个论文里面的那个 ...

  8. iOS安全些许经验和学习笔记

    http://bbs.pediy.com/showthread.php?t=209014 标题: [原创]iOS安全些许经验和学习笔记作者: MonkeyKey时间: 2016-03-30,16:32 ...

  9. UVA11520填充正方形

    题意:      给你一个n*n的矩阵,让你往里面添加大写字母,矩阵有的字母已经给填好了,然后要求是每个格子都不能与他相邻的格子的大写字母相同,如果有多个答案,输出从上到下,从左到右所连接的成的那个n ...

  10. Windows核心编程 第九章 线程与内核对象的同步(上)

    第9章 线程与内核对象的同步 上一章介绍了如何使用允许线程保留在用户方式中的机制来实现线程同步的方法.用户方式同步的优点是它的同步速度非常快.如果强调线程的运行速度,那么首先应该确定用户方式的线程同步 ...