【问题标题】:osdelay stucked after I called HAL_FLASHEx_Erase and HAL_FLASH_Prog in task我在任务中调用 HAL_FLASHEx_Erase 和 HAL_FLASH_Program 后,osdelay 卡住了
【发布时间】:2021-12-30 12:36:39
【问题描述】:

我正在将 LittleFS 移植到 STM32 G431Rb 内部闪存上。当我在 main 函数上读写文件时,一切都很好。但是当我在Task中写一些东西时,系统会卡在osdlelay上。

/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  int i = 0;
  for(;;)
  {
    ULOG_TRACE("Trace count = %d",i);
    i++;
    osDelay(5);
  }
  /* USER CODE END 5 */
}

在 ULOG_TRACE 函数中,我调用了 lfs_fs_write 函数。 lfs_fs_write 函数调用 HAL_FLASHEx_Erase 和 HAL_FLASH_Prog。


static FLASH_EraseInitTypeDef EraseInitStruct;
int stm32_interl_flash_block_erase(const struct lfs_config *c, lfs_block_t block)
{
    uint32_t PageError;
    __disable_irq();
    HAL_FLASH_Unlock();
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
                          FLASH_FLAG_OPERR | 
                          FLASH_FLAG_PROGERR |
                          FLASH_FLAG_WRPERR |
                          FLASH_FLAG_PGAERR |
                          FLASH_FLAG_SIZERR |
                          FLASH_FLAG_PGSERR |
                          FLASH_FLAG_MISERR );

    EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.Banks = FLASH_BANK_1;
    EraseInitStruct.Page = FS_BASE_PAGE_START + block;
    EraseInitStruct.NbPages = 1;
    
    if (HAL_FLASHEx_Erase(&EraseInitStruct,&PageError)!= HAL_OK){
        __enable_irq();
        return HAL_FLASH_GetError();
    }

    HAL_FLASH_Lock();
    __enable_irq();
    return 0;
}


int stm32_interl_flash_block_prog(const struct lfs_config *c, lfs_block_t block,
            lfs_off_t off, const void *buffer, lfs_size_t size)
{
    __disable_irq();
    HAL_FLASH_Unlock();
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
                        FLASH_FLAG_OPERR | 
                        FLASH_FLAG_PROGERR |
                        FLASH_FLAG_WRPERR |
                        FLASH_FLAG_PGAERR |
                        FLASH_FLAG_SIZERR |
                        FLASH_FLAG_PGSERR |
                        FLASH_FLAG_MISERR );
    uint32_t  dest_addr = FS_BASE_ADDR + c->block_size*block +off;
    uint64_t *pSrc = (uint64_t*)buffer;
    uint32_t  write_size = 0;
    while(write_size < size){
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,dest_addr,*(pSrc)) != HAL_OK){
            HAL_FLASH_Lock();
            __enable_irq();
            return HAL_FLASH_GetError();
        }
        pSrc++;
        dest_addr += 8;
        write_size += 8;
    }
    HAL_FLASH_Lock();
    __enable_irq();
    return 0;
}

我google了这些问题,有人说问题是我擦除或编程内部闪存时发生任务计划中断。但是我添加了disable_irq,它也有问题。

【问题讨论】:

  • Simple 不要将 HAL 用于类似任务。延迟依赖于中断。改用寄存器

标签: stm32 freertos


【解决方案1】:

不要禁用所有中断。至少 HAL 滴答应该运行得更远。 HAL_FLASH_* 方法依赖于它们。

使用osKernelSuspend()osKernelResume() 停止和继续线程调度。

进一步检查所有返回码,同样来自 HAL_FLASH_Unlock。

闪存外设在 STM32 控制器系列上有点讨厌。 如果出现问题,您访问的地址未对齐、越界或简单,外设设置其错误位并且 HAL 功能不再运行。您已经清除了错误标志。 我体验过在 HAL_FLASH_Program 之后检查和清除错误标志总是一个好主意。

PS:如果您的代码确实卡在 osDelay 中,那么您的 cmsis os 调度程序中断没有运行或调度程序被禁用/停止。

【讨论】:

  • osKernelSuspend 和 osKernelResume 在 STM32 Cube IDE 中不受支持。我尝试了 vTaskSuspendAll 和 xTaskResumeAll。但问题仍然在这里。我在 osDelay 中调试,系统卡在 configASSERT(uxSchedulerSuspended == 0);
  • 如果 uxSchedulerSuspended 为零,则您的 RTOS 不会运行,您的返回路径之一不会再次启用调度程序。这也是禁用中断的问题; SysTick 没有触发,因此 osDelay 卡住了。
【解决方案2】:

您没有具体说明代码卡住了多长时间,也没有说明您认为它卡在 osDelay 中的原因,但这里有一个猜测:

如果您在执行代码时在同一个闪存库中写入或擦除,您的代码将停止,直到操作完成。这将阻止所有任务和所有中断,无论它们是打开还是关闭。这是因为在闪存写入或擦除时无法从闪存中获取任何指令。如果已经预取了一些指令,它们可能仍会执行。

如果您能够使用双bank模式,您可以在从另一个bank执行的同时写入一个bank,但我认为128kB的部分可能只支持单bank flash,而其他的可能默认禁用dual-bank。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 2015-03-29
    • 1970-01-01
    • 2020-06-01
    • 2018-04-22
    • 1970-01-01
    相关资源
    最近更新 更多