【问题标题】:The Cleanest Reset for an ARM ProcessorARM 处理器最干净的复位
【发布时间】:2011-02-19 11:22:19
【问题描述】:

最近,我一直在清理一些在 ARM7 控制器上运行的 C 代码。在某些情况下(升级、致命错误等),程序将执行重置。目前它只是跳转到 0 并假设启动代码将正确地重新初始化所有内容。这让我开始思考什么是 ARM 重置的最佳程序,例如“不留痕迹”。这是我的第一次破解:

void Reset(void)
{
   /* Disable interrupts */
   __disable_interrupts();

/* Reset peripherals, externals and processor */
AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY | AT91C_RSTC_PERRST | AT91C_RSTC_EXTRST| AT91C_RSTC_PROCRST;

while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP);

/* Jump to the reset vector */
(*(void(*)())0)();
}

此代码假定使用 IAR ARM 编译器和 At91Lib。有什么我没有考虑过的吗?

【问题讨论】:

    标签: c arm reset processor


    【解决方案1】:

    完成“硬重置”的最佳解决方案,而不是简单地跳过重置向量,是强制看门狗定时器重置 - 如果你有,那就是。

    由于您的标题是“最干净的重置”,这是我的建议。如果您只是简单地执行“跳转到复位向量”,则系统可能处于任意数量的状态(外设仍处于活动状态,ADC 转换正在进行等...)

    【讨论】:

    • 在上面的示例代码中,完成了外围设备(内部和外部)的重置。
    • AFAIK 看门狗重置是最常用的方法。但是,您通常可以向看门狗提供错误的代码,而不是设置短暂的超时和等待 - 在大多数实现中,它会导致立即重置。使用手动重置您可能会忘记重置某些内容,而使用看门狗则无需费心。
    【解决方案2】:

    我同意@Dan 的观点,如果您的系统有可用的看门狗定时器,那应该提供最干净的全板重置。但是...如果您的处理器是 ARMv7-M 架构(例如 Cortex-M3 等),即使您没有可用的看门狗定时器,您也可以执行以下操作,具体取决于您的特定实现:

    #define SYSRESETREQ    (1<<2)
    #define VECTKEY        (0x05fa0000UL)
    #define VECTKEY_MASK   (0x0000ffffUL)
    #define AIRCR          (*(uint32_t*)0xe000ed0cUL) // fixed arch-defined address
    #define REQUEST_EXTERNAL_RESET (AIRCR=(AIRCR&VECTKEY_MASK)|VECTKEY|SYSRESETREQ)
    
    printf("\nRequesting an external reset...\n");
    fflush(stdout);
    REQUEST_EXTERNAL_RESET;
    printf("\nIt doesn't seem to have worked.\n");
    fflush(stdout);
    

    请参阅 ARMv7-M 架构参考手册,搜索 AIRCR 和 SYSRESETREQ。

    这实际上可能与“Judge Maygarden”发布的解决方案相同,但他的帖子中使用的标识符似乎是 Atmel 特定的,而 AIRCR 寄存器和 SYSRESETREQ 位由底层 ARMv7-M 架构定义,而不是通过爱特梅尔。

    【讨论】:

      【解决方案3】:

      这应该可以解决问题。我在 Atmel SAM3U 上使用了类似的功能。我从来没有费心去查询状态寄存器,但这是个好主意,我现在就去添加它!

      但是,您永远不应该到达复位向量线,因为处理器已经复位。 IAR 有一个__noreturn 属性用于这些情况,以允许进一步的编译器优化。我还将重置功能加载到 ram 中(请参阅 __ramfunc),因为我在固件更新结束时使用微控制器无法从闪存运行。

      此外,除非您使用该行控制外部设备的重置,否则您不需要 AT91C_RSTC_EXTRST 标志。

      __noreturn void Reset(void)
      {
          __disable_interrupts();
      
          AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY |
                                      AT91C_RSTC_PERRST |
                                      AT91C_RSTC_EXTRST |
                                      AT91C_RSTC_PROCRST;
      
          while (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-20
        • 1970-01-01
        • 2013-01-16
        • 1970-01-01
        • 1970-01-01
        • 2012-06-01
        相关资源
        最近更新 更多