本帖最后由 小恩GG 于 2021-5-15 09:13 编辑
背景介绍在嵌入式开发中,我们会不时用到软件复位来让系统重新启动,软件复位有别于POR(上电复位)和Reset引脚等需依赖硬件电路的硬件复位,它完全是基于代码实现, 其中Cortex-M核 MCU实现软件复位的方式大致如下: - 调用NVIC_SystemReset()函数;
- 开门狗软件复位;
- 芯片原厂提供的软件复位方式;
本篇分享源于客户的真实案例,客户尝试了上述的所有软件复位方式,仍无法成功复位MCU。 注:客户的开发板为:Embedded Artist RT1062 OEM board,其中的板载QSPI: Adesto ATXP032
图1 Embedded Artist RT1062 OEM board 问题真相
经过前期的测试后,客户发现在执行软件复位后,RT1060应该被‘困’在了解i.MXRT1060系列ROM中串行NOR Flash启动初始化流程优化点所介绍的从FlexSPI NOR启动初始化流程中了(如图2所示)。
图2 最后,经过反复实验发现软件复位失败是由于在对RT1060进行软件复位时,未能同步对 ATXP032进行专门的复位操作引起的,那么该如何对其进行复位操作呢? 复位ATXP032JEDEC复位指主机MCU发送序列信号到Flash设备并导致Flash设备上复位。主机MCU通过两个SPI接口引脚发送该序列信号(如下图所示)。
图 3 注:JEDEC标准复位仅针对于Adesto ATXP系列为代表的Flash 跟MCU中Reset 引脚功能类似(如下图所示),拉低Reset 引脚也将复位ATXP032。
图4 Reset 引脚 ‘改造’NVIC_SystemReset()函数通过Reset 引脚拉低来复位,本质上也是属于硬件复位,需要依赖电路,在这里就不做过多的讨论,而此篇的着眼点在于如何通过软件实现JEDEC标准复位。 由于core_cm7.h中的NVIC_SystemReset()函数(如下所示)未能成功实现软件复位, - void NVIC_SystemReset(void)
- {
- __DSB(); /* Ensure all outstanding memory accesses included
- buffered write are completed before reset */
- SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
- (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
- SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */
- __DSB(); /* Ensure completion of memory access */
- for(;;) /* wait until reset */
- {
- __NOP();
- }
- }
复制代码故需要‘改造’ 此函数,结合Embedded Artist RT1062 OEM board的连接ATXP032设计(如下表所示),手动实现图3所示的时序信号来触使ATXP032复位,具体代码如下:
表1 - /*
- * JEDEC reset of external serial flash in three steps:
- * 1) Disable interrupts and the data cache
- * 2) Do the JEDEC reset sequence
- * 3) Issue the NVIC_SystemReset() to do the actual reset
- *
- * Note: This function must be executing in RAM.
- * Note: The NVIC_SystemReset() call may take up to 3s to complete
- * depending on compiler and Debug/Release build
- * Note: Function call only valid for targets running in/from
- * flash - not for targets running in debugger and/or in RAM
- */
- __attribute__((section("RamFunction")))
- void Updated_NVIC_SystemReset(void)
- {
- #define CS (1<<6)
- #define SCK (1<<7)
- #define SI (1<<8)
- #define RESETMASK (CS|SCK|SI)
- #define IGNOREPINS ((1<<9)|(1<<10)|(1<<11)|(1<<1)|(1<<2)|(1<<3))
- #define LOW(__mask) GPIO3->DR &= ~(__mask) /* Set pin output to low level.*/
- #define HIGH(__mask) GPIO3->DR |= (__mask) /* Set pin output to high level.*/
- __disable_irq();
- SCB_DisableDCache();
- /* Configure CS/SCK/SI as outputs and the other flexspi pins as inputs */
- CLOCK_EnableClock(kCLOCK_Gpio3);
- GPIO3->IMR &= ~(RESETMASK | IGNOREPINS);
- GPIO3->GDIR |= (RESETMASK);
- GPIO3->GDIR &= ~(IGNOREPINS);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_06_GPIO3_IO06,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_07_GPIO3_IO07,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_08_GPIO3_IO08,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_09_GPIO3_IO09,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_10_GPIO3_IO10,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_GPIO3_IO11,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_01_GPIO3_IO01,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_02_GPIO3_IO02,0);
- IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_GPIO3_IO03,0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_06_GPIO3_IO06, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_07_GPIO3_IO07, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_08_GPIO3_IO08, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_09_GPIO3_IO09, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_10_GPIO3_IO10, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_11_GPIO3_IO11, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_01_GPIO3_IO01, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_GPIO3_IO02, 0x10b0);
- IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_GPIO3_IO03, 0x10b0);
- /* Reset sequence */
- HIGH(CS);
- LOW(SCK|SI);
- LOW(CS);
- HIGH(CS);
- HIGH(SI);
- LOW(CS);
- HIGH(CS);
- LOW(SI);
- LOW(CS);
- HIGH(CS);
- HIGH(SI);
- LOW(CS);
- HIGH(CS);
- /* Delay at least 110us */
- for (int i = 33000; i >= 0; i--) {
- __NOP();
- }
- /* Actual reset. This code is copied from NVIC_SystemReset() in core_cm7.h
- and must be copied here as MCUXpresso IDE (only for the Debug target)
- will keep the function in serial flash even if it is 'static inline'
- and called from a function placed in RAM and since we have resetted
- the serial flash using it results in a crash and not a reset. Manually
- copying the code seems to do the trick. */
- __DSB(); /* Ensure all outstanding memory accesses included
- buffered write are completed before reset */
- SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
- (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
- SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */
- __DSB(); /* Ensure completion of memory access */
- for(;;) /* wait until reset */
- {
- __NOP();
- }
- }
复制代码
|