一只有理想的程序猿

一只有理想的程序猿

一 跳转方法

1、检查栈顶地址是否合法

      if (((*(uint32_t*)(NRF52840_APP_BASE)) & 0xffff0000 ) == 0x20040000 )
      {
         nrf_bootloader_app_start();
      }

在编译生成的APP.bin文件中,前4个字节存放的是__initial_sp,紧接着第二个地址存放的是Reset_Handler;这两个正是所谓的栈顶地址 reset 入口。

// 具体实现细节可能不同
    NVIC->ICER[0]=0xFFFFFFFF; // 关中断
    NVIC->ICPR[0]=0xFFFFFFFF; // 清除中断标志位

3、设置栈顶地址
方法:

//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(uint32_t addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}
另外一种写法
/**
  \brief   Set Main Stack Pointer
  \details Assigns the given value to the Main Stack Pointer (MSP).
  \param [in]    topOfMainStack  Main Stack Pointer value to set
 */
__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack)
{
  __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : );
}

设置栈顶地址函数的参考链接

4、跳转到指定app

void jump_to_addr(uint32_t new_msp, uint32_t addr)
{
    __set_MSP(new_msp);
    ((void (*)(void))addr)();
}
void(*)(void)是函数指针,返回void,参数void.
把addr 强制转化为函数指针
最后()起到调用函数作用

引申

栈的分类

栈是内存中用于暂时存储数据,栈可以分为满增栈、满减栈、空增栈、空减栈。“满”的意思是当前PC指针指向地址空间已经有了数据。存储数据时需要先移动指针,再存储数据。如下图
一文搞懂Bootloader跳转到APP 的方法和原理-LMLPHP
“空”则表示当前PC指针指向的地址空间没有存储数据,存储数据时需要先存储数据,再移动指针。如下图:
一文搞懂Bootloader跳转到APP 的方法和原理-LMLPHP
“增”,“减”则表示栈的增长方向,存储数据是栈是增长就是增栈,减小就是减栈,与前面的满空结合,就出现了4种结果
1、满减 2、满增 3、空减 4、空增
一文搞懂Bootloader跳转到APP 的方法和原理-LMLPHP

一文搞懂Bootloader跳转到APP 的方法和原理-LMLPHP
一文搞懂Bootloader跳转到APP 的方法和原理-LMLPHP
一文搞懂Bootloader跳转到APP 的方法和原理-LMLPHP
ARM 属于满减栈

判断当前CPU是否在中断

IPSR(中断程序状态寄存器),IPSR包含了当前正在执行的中断服务程序编号,用于识别当前中断

const uint32_t current_isr_num = (__get_IPSR() & IPSR_ISR_Msk);
ASSERT(current_isr_num == 0); // If this is triggered, the CPU is currently in an interrupt.
05-12 04:13