痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用。
我们知道稍大规模的项目代码设计一般都是多人协作完成的,在项目开始阶段的总体设计时,项目组长通常会将代码按功能进行划分,每个功能块代码之间尽量做到耦合度低、互不依赖、互不影响,这样各功能可以独立进行单元测试,项目得以并行开发,后期通过事先定义好的接口/协议进行功能块集成即可。
但上述方法在嵌入式软件项目里有时候会遇到功能块集成后互相干扰的问题,因为嵌入式项目很多时候并不是纯软件设计,也会跟片内外设资源打交道,而片内外设属于硬件范畴,硬件模块的工作是有前后状态依赖的(这点在片内时钟的配置上体现得尤其明显),出了问题传统方法是具体分析具体解决,来一个就解决一个,但任何代码的改动或者后期新特性的增加都可能会带来新的潜在干扰问题。
那么对于上述困境,有没有一个一劳永逸的解决方法?其实是有的!那就是每个功能块在设计时都不要依赖芯片初始状态,按照进入时先清理系统环境,然后做功能设计,退出时做一下系统恢复。这种方法虽然保险,但是会引入集成后项目整体运行低效的问题。今天痞子衡要在具体项目实战中介绍一种利用i.MXRT芯片内System Reset后不复位的GPR寄存器来解决属性上互斥的功能代码块集成互相干扰问题的方法。
一、SBL项目中的痛点
恩智浦MCU SE团队近期一直在加班加点赶一个大项目,这个项目是为客户产品OTA需求而生的。我们知道在线升级是每个智能产品都不可绕开的话题,恩智浦SE团队为了方便客户在基于i.MXRT/LPC的产品上做在线升级,特别推出OTA参考设计,下面是功能架构简图:项目分为SBL + SFW两部分,SBL负责ISP本地更新(UART/USB)以及App切换管理;SFW是一个示例App,其除了客户项目业务功能外,也集成了远程更新功能(WiFi、以太、U盘、SD卡四种升级方式)。
在SBL代码设计里,主要有两大子功能模块:一个是ISP本地更新 (isp_boot_main),另一个是App切换管理(sbl_boot_main),其中ISP本地更新属于可选项,而App切换管理是必选。
SBL的主流程是上电启动运行后,先执行ISP本地更新功能块,在超时时间内,如果有收到来自Host的ISP命令,则进入ISP命令处理,此后除非执行ISP复位命令或者有板级复位,否则不会退出ISP;
如果在超时时间内没有收到ISP命令,则转到App切换管理功能块。在验证App时,如果发现Flash里有合法App,则跳转过去执行;如果没有发现合法的App,会重新返回ISP本地更新(此时是无限超时)。大概主逻辑代码如下:
#define COMPONENT_MCU_ISP
#define ISP_TIMEOUT (5) // in seconds
int main(void)
{
#if (defined(COMPONENT_MCU_ISP))
// 先尝试isp本地更新(有5s超时)
bool isInfiniteIsp = false;
isp_boot_main(isInfiniteIsp);
#endif
// 无本地升级则进入app跳转处理
sbl_boot_main();
}
#if (defined(COMPONENT_MCU_ISP))
void isp_boot_main(bool isInfiniteIsp)
{
if (isInfiniteIsp || ISP_TIMEOUT)
{
// isp相关功能外设初始化
isp_boot_init();
// 在5s超时时间内/无限超时去等待isp命令
isp_boot_run(isInfiniteIsp);
}
}
#endif
void sbl_boot_main(void)
{
// 判断Flash里是否存在合法的app
if (sbl_boot_go() != 0)
{
#if (defined(COMPONENT_MCU_ISP))
// 无合法app,重入isp本地更新(无限超时)
bool isInfiniteIsp = true;
isp_boot_main(isInfiniteIsp);
#endif
NVIC_SystemReset();
}
else
{
// 有合法app,跳转到app执行
sbl_do_boot();
}
while (1);
}
上述SBL设计里,你会发现ISP本地更新和App切换管理两个功能块在执行上是互斥的,是Flash里的App处理需求将它们联系在了一起。从软件集成角度来说,这两个功能本不该互相影响,但实际上它们之间产生了互相影响,因为各自在设计时没有遵循进入时清理系统、退出时恢复现场的准则,所以 isp_boot_main() 在超时结束后跳到 sbl_boot_main() 对其部分验签功能产生了影响,而 sbl_boot_main() 执行后没找到合法App跳回 isp_boot_main() 时又出现ISP功能不正常的情况,我们需要解决这个问题。
二、寻找i.MXRT中理想的GPR寄存器
第一小节里描述的问题,可以通过功能块退出时恢复现场来解决,但是每个模块代码量都比较大,使用代码去逐一恢复现场不太容易。痞子衡想到的一个好办法就是调用 NVIC_SystemReset() 函数来简单粗暴地将芯片系统复位,我们所需要做的就是寻找一个区域,能够临时存放标志位,并且这个区域内容不受系统软复位的影响,芯片复位回来之后在SBL里增加对标志位的判断处理,处理结束后再将标志位清掉。
在寻找这个不受系统软复位影响的区域前,我们先对i.MXRT里面的电源管理架构作个基本了解。下图是i.MXRT1060的电源架构,除了USB和ADC模块特殊供电需求外,芯片一共有四种电源输入。在板级供电设计时,通常VDD_SNVS_IN需要单独一路外部输入(设计上应由电池供电),其他三路电源VDD_HIGH_IN / DCDC_IN / VDD_SOC_IN可共用一路外部输入(芯片POR_B引脚往往连在这个外部输入控制上)。
VDD_HIGH_IN:给芯片内部LDO供电
DCDC_IN:给芯片内部DCDC模块供电
VDD_SOC_IN:给芯片主系统(Core,SoC,Memory)供电
VDD_SNVS_IN:给芯片内部SNVS域相关模块供电
从芯片系统复位等级上来分,一共有三类复位:第一类是借助Cortex-M7内核SCB模块的AIRCR寄存器中集成的SYSRESETREQ复位的支持、第二类是DCDC重新上电(POR_B复位)、第三类是整体重新上电。依据这三种不同程度的复位,痞子衡整理了i.MXRT上所有可存放标志位的区域受不同复位类型影响情况如下:
模块 \ 复位类型 | NVIC_SystemReset() | POR_B和DCDC重新上电 | 整体重新上电 |
---|---|---|---|
TCM OCRAM IOMUXC_GPR SRC_GPR |
保持 | 复位 | 复位 |
IOMUXC_SNVS_GPR SNVS_LPGPR |
保持 | 保持 | 复位 |
Flash, eFuse | 保持 | 保持 | 保持 |
根据上表,我们先排除掉NVM属性的Flash和eFuse,它们不符合临时存放、轻松读写的需求。TCM / OCRAM可用,但需要在SBL工程里做特殊处理,分配一块.noinit区,并且要确定BootROM没有使用这个区域,用起来还是有点麻烦。IOMUXC_GPR / SRC_GPR用起来简单,但它们已被SoC / BootROM占用了,不能随便使用,对芯片产生的影响未知。IOMUXC_SNVS_GPR / SNVS_LPGPR这两个都不错,但后者在使能加密时有时会被用来存放用户密钥。所以 IOMUXC_SNVS_GPR 寄存器才是最佳选择,这也是真正意义上开放给用户自由使用的GPR寄存器。
三、在SBL项目中使用GPR寄存器
现在我们找到了理想的 IOMUXC_SNVS_GPR 寄存器,那么可在SBL代码中增加两个函数 isp_cleanup_enter()、isp_cleanup_exit(),前者用于触发软复位前标记状态,后者用于软复位后读取标记的状态做相应处理。最终修改后的SBL主逻辑代码如下:
#define CLEANUP_ISP_TO_SBL (0x5A)
#define CLEANUP_SBL_TO_ISP (0xA5)
bool isp_cleanup_exit(bool *isInfiniteIsp)
{
uint32_t flag = IOMUXC_SNVS_GPR->GPR0;
switch (flag)
{
// SBL_TO_ISP软复位情况下,进入无限超时isp
case CLEANUP_SBL_TO_ISP:
*isInfiniteIsp = true;
flag = 0x0;
break;
// 第一次上电或ISP_TO_SBL软复位情况下,直接退出isp
case CLEANUP_ISP_TO_SBL:
default:
break;
}
IOMUXC_SNVS_GPR->GPR0 = 0x0;
return flag;
}
void isp_cleanup_enter(uint32_t flag)
{
IOMUXC_SNVS_GPR->GPR0 = flag;
NVIC_SystemReset();
}
#if (defined(COMPONENT_MCU_ISP))
void isp_boot_main(bool isInfiniteIsp)
{
// 加一级对于Reset不复位flag的判断处理
if (!isp_cleanup_exit(&isInfiniteIsp))
{
if (isInfiniteIsp || ISP_TIMEOUT)
{
isp_boot_init();
isp_boot_run(isInfiniteIsp);
// 标记flag为ISP_TO_SBL,并触发软复位
isp_cleanup_enter(CLEANUP_ISP_TO_SBL);
}
}
}
#endif
void sbl_boot_main(void)
{
if (sbl_boot_go() != 0)
{
#if (defined(COMPONENT_MCU_ISP))
// 标记flag为SBL_TO_ISP,并触发软复位
isp_cleanup_enter(CLEANUP_SBL_TO_ISP);
#endif
NVIC_SystemReset();
}
else
{
sbl_do_boot();
}
while (1);
}
至此,i.MXRT1xxx里SystemReset不复位的GPR寄存器的小妙用痞子衡便介绍完毕了,掌声在哪里~~~
欢迎订阅
文章会同时发布到我的 博客园主页、CSDN主页、知乎主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。
痞子衡嵌入式:在SBL项目实战中妙用i.MXRT1xxx里SystemReset不复位的GPR寄存器的更多相关文章
- 痞子衡嵌入式:关于i.MXRT中FlexSPI外设lookupTable里配置Normal read的一个小误区
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT中FlexSPI外设lookupTable里配置Normal read的一个小误区. 关于串行四线NOR Flash,当其作 ...
- 痞子衡嵌入式:聊聊系统看门狗WDOG1在i.MXRT1xxx系统启动中的应用及影响
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是系统看门狗WDOG1在i.MXRT1xxx系统启动中的应用及影响. 软件看门狗模块(WDOG)在 MCU 应用里可以说是非常基础的功能模 ...
- 痞子衡嵌入式:理解i.MXRT中FlexSPI外设lookupTable里配置访问行列混合寻址Memory的参数值
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT中FlexSPI外设lookupTable里配置访问行列混合寻址Memory的参数值. 关于 FlexSPI 外设的 loo ...
- 痞子衡嵌入式:从头开始认识i.MXRT启动头FDCB里的lookupTable
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT启动头FDCB里的lookupTable. 一个MCU内部通常有很多外设模块,这些外设模块是各MCU厂商做差异化产品的本质, ...
- 痞子衡嵌入式:系统时钟配置不当会导致i.MXRT1xxx系列下OTFAD加密启动失败
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是系统时钟配置不当会导致i.MXRT1xxx系列下OTFAD加密启动失败问题. 我们知道,i.MXRT1xxx家族早期型号(RT1050/ ...
- 痞子衡嵌入式:了解i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择. 关于 i.MXRT 系列 BootROM 中串行 NOR ...
- 痞子衡嵌入式:对比i.MXRT与LPC在RTC外设GPREG寄存器使用上的异同
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是对比i.MXRT与LPC在RTC外设GPREG寄存器使用上的异同. 本篇是 <在SBL项目实战中妙用i.MXRT1xxx里Syst ...
- 痞子衡嵌入式:i.MXRT1010, 1170型号上不一样的SNVS GPR寄存器读写控制设计
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1010, 1170型号上不一样的SNVS GPR寄存器读写控制设计. 痞子衡之前两篇文章 <在SBL项目实战中妙用i ...
- 痞子衡嵌入式:改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是改动i.MXRT1xxx里IOMUXC_GPR寄存器保留位可能会造成系统异常. 痞子衡的嵌入式技术交流群里有一位非常活跃的朋友(网名:文 ...
随机推荐
- Mybatis3源码笔记(二)SqlSession
1. 核心层次 2. SqlSession 先从顶层的SqlSession接口开始说起.SqlSession是MyBatis提供的面向用户的API,表示和数据库的会话对象,用于完成对数据库的一系列CR ...
- 1443. Minimum Time to Collect All Apples in a Tree
Given an undirected tree consisting of n vertices numbered from 0 to n-1, which has some apples in t ...
- 关于sysmon.exe高cpu占用
sysmon.exe是干嘛的? 这里面有介绍:https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon 是windows官方提供的监 ...
- 2-7 Java基础数据类型之字符型
代码中输入如下部分: /* char的取值范围0-65535 */ public class DataType06 { public static void main(String[]args){ c ...
- mac系统 PHP Nginx环境变量修改
场景:php默认的环境变量不是我们实际工作中想要的 执行命令:which php 查看默认的php指向的目录 : /usr/bin/php 修改· ~/.bash_profile 文件 添加php环 ...
- 【docker-compose】docker-compose环境安装
docker-compose: 是一个用于定义和运行多容器 Docker 的应用程序工具,可以帮助我们可以轻松.高效的管理容器 安装: 1.安装pip 工具-目的是为了下载docker-compose ...
- 从苏宁电器到卡巴斯基第31篇:难忘的三年硕士时光 IX
在校的最后一个月 毕业答辩的评审老师宣布我没能通过,让我瞬间不知道该怎么好了.已经到了中午,老师们也都是准备吃盒饭去了,我和其他已经通过了的同学随便收拾了一下教室,然后无助的我赶紧去找旁听的教学秘书, ...
- hdu4720 三角形的外接圆
题意: 给你四个点,问你第四个点是否在前三个点围成的三角形的外接圆上. 思路: 水题,就是练练用魔板罢了,当该三角形是锐角三角形的时候,圆心是任意两条边中垂线的交点,半径是圆心 ...
- POJ3114强连通+spfa
题意: 给你n个点,m条有向边,q询问,每次询问给两个数a,b输出a->b的最短路,但是题目有个限制,就是在一个环上的任意两点距离为0. 思路: 简单题目,直接强连通压缩 ...
- POJ2060最小路径覆盖
题意: 有n个任务,如果时间来得及干完某些任务后还可以接着干别的任务,给一个任务清单,问最少派出去多少人能完成所有任务. 思路: 比较简单的追小路径覆盖问题了,在DAG中找到 ...