【IAP】FreeRTOS多线程环境下调用NVIC_SystemReset()系统复位函数出现问题

发布时间:2024年01月16日

衔接 上篇 调好写入Flash失败后,又出现新问题:
由BOOT跳APP再跳APP,在升级接受升级文件过程中,突然出现系统复位,而且出现位置和时间都是随机的。
定位问题

  1. 尝试改RTOS空间大小
    本以为是FreeRTOS空间给小了,尝试加大还是无果,最后怀疑应该不是RTOS问题,因为如果任务挂了应该会死机不会出现类似重新上电一样的复位。

  2. 怀疑BOOT和APP存储地址错误
    怀疑可能是写入地址出错,APP和BOOT地址交叉了,但最后比较地址发现APP区域和BOOT区域是隔开的,并没有影响,并且用JLINK读取芯片存储空间也是正常的,BOOT区域并没受影响,所以与地址空间配置无关

  3. 上网查阅资料系统复位需要配置什么,尤其是任务中系统复位
    因为之前由BOOT跳转APP在任务中和不在任务中有不同的配置,好像是要关闭中断,

void jumpToApp(uint32_t appBaseAddr)
{
    void (*firmwareFunc)(void);
    uint32_t fwStackVal = *((uint32_t *)(appBaseAddr));     /* the first word is for the stack pointer. */
    uint32_t fwEntryVal = *((uint32_t *)(appBaseAddr+4U));  /* the second works is for the boot function. */
    firmwareFunc = (void (*)(void))fwEntryVal;

    SCB->VTOR = appBaseAddr; /* The stack address is also the start address of vector. */
    __set_MSP(fwStackVal);
    __set_PSP(fwStackVal);
    firmwareFunc();
}
void jumpToAppInTask(uint32_t appBaseAddr)
{
    void (*firmwareFunc)(void);
		SysTick->CTRL = 0X00;//禁止SysTick
    SysTick->LOAD = 0;
    SysTick->VAL = 0;
    __disable_irq();
    uint32_t fwStackVal = *((uint32_t *)(appBaseAddr));     /* the first word is for the stack pointer. */
    uint32_t fwEntryVal = *((uint32_t *)(appBaseAddr+4U));  /* the second works is for the boot function. */
    firmwareFunc = (void (*)(void))fwEntryVal;

    SCB->VTOR = appBaseAddr; /* The stack address is also the start address of vector. */
    __set_MSP(fwStackVal);
    __set_PSP(fwStackVal);
    firmwareFunc();
}

所以怀疑APP跳BOOT可能也要有不同处理, 最后查到这篇
尝试了一下

__disable_irq();  
__set_FAULTMASK(1);	
NVIC_SystemReset();

还是没用, (不是很懂上面具体作用是什么,欢迎大佬赐教)
4. 发现代码漏洞
后面换了板子,升级成功2次后,第三次还是有类似问题,所以升级逻辑应该没问题,可能是跳转影响了,而BOOT程序就一个线程在跑,收发数据然后升级,不存在跳转,只有可能是APP程序影响到了BOOT。
但已经APP已经跳过来BOOT了,怎么还能影响,可能是FREERTOS的一些问题,后面证实确实是,但不知道具体原理是什么。参考了这篇文章

使用NVIC_SystemReset实现APP跳转到UBOOT时,连续多次跳转,容易出现MCU崩溃。

因为通信库的缘故,解析指令是多线程解析,加日志打印发现APP中复位确实存在多任务多次执行NVIC_SystemReset();的情况,所以可能是跳转去BOOT后,升级过程中随机调度起任务执行NVIC_SystemReset();导致,BOOT升级中复位。

最后屏蔽APP中的NVIC_SystemReset();函数,直接BOOT升级,一次成功,定位到问题。

解决问题

  1. 加锁
taskENTER_CRITICAL();
NVIC_SystemReset();
taskEXIT_CRITICAL();

多线程调度NVIC_SystemReset,加锁理论上应该可以解决,最后发现,还是BOOT升级中复位了,以为是复位NVIC_SystemReset();又释放了taskEXIT_CRITICAL();

static __INLINE void NVIC_SystemReset(void)
{
  __DSB();                                                     /* Ensure all outstanding memory accesses included
                                                                  buffered write are completed before reset */
  SCB->AIRCR  = ((0x5FA << SCB_AIRCR_VECTKEY_Pos)      |
                 (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
                 SCB_AIRCR_SYSRESETREQ_Msk);                   /* Keep priority group unchanged */
  __DSB();                                                     /* Ensure completion of memory access */
  while(1);                                                    /* wait until reset */
}

但NVIC_SystemReset里面有个while怎么还会释放呢?我猜想可能是升级中RAM空间不稳定,导致临界区空间被压榨了,锁没了,其他线程又复原了然后进来执行但NVIC_SystemReset。
2. 加标志

	taskENTER_CRITICAL();

	if(isSystemReset == DRIVER_FALSE)
	{
		isSystemReset = DRIVER_TRUE;
		NVIC_SystemReset();
	}

	taskEXIT_CRITICAL();

加标志,保证只进来一次?结果还是不行,应该也是APP区域已经被擦除的缘故,变量没有保存,最后还是寄了。
3. 挂起调度器

	taskENTER_CRITICAL();
	vTaskSuspendAll();
	if(isSystemReset == DRIVER_FALSE)
	{
		isSystemReset = DRIVER_TRUE;
		NVIC_SystemReset();
	}
	xTaskResumeAll();
	taskEXIT_CRITICAL();

如果挂起调度器,不让任务调度,是不是可以避免多线程干扰,最后多次测试,BOOT升级过程中,没有再发生复位情况,与第一条猜想符合,这还不行就只能创线程,指令改标志位,保证串行执行系统复位了。
总之FreeRTOS里面升级还是不安全,上面一些原理欢迎大佬赐教

文章来源:https://blog.csdn.net/weixin_43752106/article/details/135623624
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。