RT-Thread论坛
直播中

陈丽

8年用户 1607经验值
私信 关注
[问答]

请问flashdb的flash操作接口是否可以异步?

实现flashdb的falsh底层操作代码时 由于大量的数据保存可能会导致系统阻塞 我是否可以在

  • static int write(long offset, const uint8_t *buf, size_t size)
  • {
  •     size_t   i;
  •     uint32_t addr = STM32_onchip_flash.addr + offset;

  •     __ALIGN_BEGIN uint32_t write_data __ALIGN_END;
  •     __ALIGN_BEGIN uint32_t read_data  __ALIGN_END;

  •     if(addr%4 != 0)
  •         ef_err_port_cnt++;


  •     if((int)buf%4 != 0) {
  •         ef_err_port_cnt++;
  •         printf("write err cnt %d", ef_err_port_cnt);
  •     }

  •     HAL_FLASH_Unlock();
  •     for (i = 0; i < size; i += 4, buf+=4, addr += 4) {
  •         memcpy(&write_data, buf, 4); //用以保证HAL_FLASH_Program的第三个参数是内存首地址对齐
  •         HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, write_data);
  •         read_data = *(uint32_t *)addr;
  •         /* You can add your code under here. */
  •         if (read_data != write_data) {
  •             HAL_FLASH_Lock();
  •             return -1;
  •         }
  •         else{
  •             //FLash操作可能非常耗时,如果有看门狗需要喂狗,以下代码由用户实现
  •            feed_dog();
  •         }
  •     }
  •     HAL_FLASH_Lock();

  •     on_ic_write_cnt++;
  •     return size;
  • }


这个函数内将数据使用消息队列的形式抛给flash实际操作任务 这个任务设置优先级最低 这样是否会造成flashdb内核的数据不一致情况产生导致崩溃呢?


回帖(2)

闫玮婧

2025-9-19 16:53:10
  正常是应用层自己做异步处理就可以了,一般不在底层做异步处理,主要是各种应用场合不好统一            
举报

李丽

2025-9-23 17:03:21

FlashDB的Flash操作接口(如write函数)在默认实现中是同步的,这意味着大量数据写入时会导致系统阻塞。但你可以通过以下方法实现异步操作,避免阻塞:




异步实现方案




  1. 构建异步框架


    typedef struct {
       long offset;
       uint8_t *buf;    // 需动态分配内存
       size_t size;
       // 可添加回调函数字段
    } flash_operation_t;

    // 创建任务队列(线程安全)
    static rt_mailbox_t op_mailbox;   // RT-Thread示例



  2. 修改write函数为异步


    static int write_async(long offset, const uint8_t *buf, size_t size) {
       // 动态复制数据(避免原buf被修改)
       uint8_t *buf_copy = rt_malloc(size);
       if (!buf_copy) return -RT_ENOMEM;
       memcpy(buf_copy, buf, size);

       // 创建操作请求
       flash_operation_t op = {
           .offset = offset,
           .buf = buf_copy,
           .size = size
       };

       // 发送到队列(非阻塞)
       if (rt_mb_send(op_mailbox, (rt_ubase_t)&op) != RT_EOK) {
           rt_free(buf_copy); // 失败则释放内存
           return -RT_ERROR;
       }
       return RT_EOK; // 立即返回
    }



  3. 后台任务处理实际写入


    static void flash_worker_thread(void *param) {
       while (1) {
           flash_operation_t *op;
           // 阻塞等待任务
           rt_mb_recv(op_mailbox, (rt_ubase_t*)&op, RT_WAITING_FOREVER);

           // 实际Flash操作(同步)
           for (size_t i = 0; i < op->size; i += 4) {
               uint32_t data = *((uint32_t*)(op->buf + i));
               HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
                                 stm32_onchip_flash.addr + op->offset + i,
                                 data);
           }

           rt_free(op->buf); // 释放内存
           // 可添加回调通知完成
       }
    }



  4. 初始化异步框架


    void async_flash_init(void) {
       // 创建邮箱
       op_mailbox = rt_mb_create("flash_mb", 10, RT_IPC_FLAG_FIFO);
       // 启动后台线程
       rt_thread_t thread = rt_thread_create("flash_worker", flash_worker_thread,
                                            RT_NULL, 2048, 15, 10);
       rt_thread_startup(thread);
    }





关键注意事项




  1. 数据一致性



    • 异步写入后,Flash中的数据不会立即可读(需等待后台操作完成)。

    • 若需即时读取,需额外设计缓存层(如RAM缓存)。




  2. 内存管理



    • 动态分配buf_copy,避免原数据被修改。

    • 确保后台任务释放内存(如rt_free(op->buf))。




  3. 错误处理



    • flash_worker_thread中检查Flash操作结果(如HAL状态)。

    • 通过回调函数通知上层错误(可选)。




  4. 线程安全



    • 使用RTOS的同步机制(如邮箱、信号量)。

    • 若在裸机环境,需通过状态机+中断实现异步。




  5. 性能权衡



    • 优点:避免主线程阻塞,提高系统响应性。

    • 缺点:增加内存开销(数据拷贝),复杂度提升。






替代优化方案


如果不想重构为异步,可优化同步写入:


static int write(long offset, const uint8_t *buf, size_t size) {
    for (size_t i = 0; i < size; i += 4) {
        // 每次写入4字节
        uint32_t data = *((uint32_t*)(buf + i));
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
                          stm32_onchip_flash.addr + offset + i,
                          data);

        // 每写N次主动让出CPU(需RTOS支持)
        if ((i % 128) == 0) rt_thread_yield();
    }
    return 0;
}



结论



  • 可以异步化:通过任务队列+后台线程实现非阻塞写入。

  • 推荐场景:频繁写入大数据量且系统需高实时性时。

  • 简单场景:优化同步写入(分块+主动让出CPU)更易实现。


根据系统复杂度需求选择合适的方案。异步改造需处理数据生命周期,但能显著提升系统响应能力。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分