ST意法半导体
直播中

山中老虎

9年用户 1014经验值
擅长:制造/封装
私信 关注
[问答]

STM32F429 USB和FATFS同时操作eMMC冲突怎么解决?

有个32G的eMMC,分成了4个盘。
连上usb只会显示其中的一个盘,用户可以去操作这个盘。
希望在未显示u盘或者显示了u盘但是未进行读写的情况下判断另外几个盘是否存在文件并上传到服务器。
目前已经实现了连上u盘只显示一个盘的功能,读写也正常。退出u盘后,上传文件也正常。
目前的问题是u盘显示出来的情况下,同时进行文件上传就会出现disk error。
我知道是SDIO操作冲突了,想问下这个有好的方案么?
裸机开发,未使用操作系统。
我想到的是弄2个标志位(u盘读写和fatfs上传),u盘读写优先级要高于fatfs上传。
想问下大佬,这个标志位的判断裸机应该怎么写,或者有没有其他更好的方案?
/** * @brief  Reads Sector(s) * @param  pdrv: Physical drive number (0..) * @param  *buff: Data buffer to store read data * @param  sector: Sector address (LBA) * @param  count: Number of sectors to read (1..128) * @retval DRESULT: Operation result */DRESULT USER_read(    BYTE pdrv,    /* Physical drive nmuber to identify the drive */    BYTE *buff,   /* Data buffer to store read data */    DWORD sector, /* Sector address in LBA */    UINT count    /* Number of sectors to read */){  /* USER CODE BEGIN READ */  if (usbd_inuse)  {    return RES_NOTRDY;  }  fatfs_inuse = 1;  DRESULT res = FATFS_read(pdrv, buff, sector, count);  fatfs_inuse = 0;  return res;  /* USER CODE END READ */}/** * @brief  Writes Sector(s) * @param  pdrv: Physical drive number (0..) * @param  *buff: Data to be written * @param  sector: Sector address (LBA) * @param  count: Number of sectors to write (1..128) * @retval DRESULT: Operation result */#if _USE_WRITE == 1DRESULT USER_write(    BYTE pdrv,        /* Physical drive nmuber to identify the drive */    const BYTE *buff, /* Data to be written */    DWORD sector,     /* Sector address in LBA */    UINT count        /* Number of sectors to write */){  /* USER CODE BEGIN WRITE */  /* USER CODE HERE */  if (usbd_inuse)  {    return RES_NOTRDY;  }  fatfs_inuse = 1;  DRESULT res = FATFS_write(pdrv, buff, sector, count);  fatfs_inuse = 0;  return res;  /* USER CODE END WRITE */}#endif /* _USE_WRITE == 1 *//** * @brief  Reads data from the medium. * @param  lun: Logical unit number. * @param  buf: data buffer. * @param  blk_addr: Logical block address. * @param  blk_len: Blocks number. * @retval USBD_OK if all operations are OK else USBD_FAIL */int8_t STORAGE_Read_HS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len){  /* USER CODE BEGIN 13 */  UNUSED(lun);  usbd_inuse = 1;  if (fatfs_inuse)  {    return USBD_BUSY;  }  DRESULT res = FATFS_read(lun, buf, blk_addr, blk_len);  usbd_inuse = 0;  return res == RES_OK ? USBD_OK : USBD_FAIL;  /* USER CODE END 13 */}/** * @brief  Writes data into the medium. * @param  lun: Logical unit number. * @param  buf: data buffer. * @param  blk_addr: Logical block address. * @param  blk_len: Blocks number. * @retval USBD_OK if all operations are OK else USBD_FAIL */int8_t STORAGE_Write_HS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len){  /* USER CODE BEGIN 14 */  UNUSED(lun);  usbd_inuse = 1;  if (fatfs_inuse)  {    return USBD_BUSY;  }  DRESULT res = FATFS_write(lun, buf, blk_addr, blk_len);  usbd_inuse = 0;  return res == RES_OK ? USBD_OK : USBD_FAIL;  /* USER CODE END 14 */}

回帖(1)

甘满盛

2025-3-3 11:56:52

针对STM32F429中USB MSC(大容量存储)与FATFS文件上传操作冲突的问题,以下是分步解决方案:




核心思路


通过状态标志位 + 原子操作 + 任务调度实现优先级控制,确保同一时刻仅有一个任务访问SDIO接口的eMMC硬件资源。




具体实现步骤


1. 定义全局原子标志


volatile uint8_t usb_activity = 0;     // USB读写活动标志(原子操作)
volatile uint8_t upload_request = 0;   // 文件上传请求标志

2. USB MSC读写操作封装


在USB读写回调函数中更新状态:


// USB读开始回调
void USB_Read_Start_Callback(void) {
    __disable_irq();        // 关中断保证原子性
    usb_activity = 1;
    __enable_irq();
}

// USB读完成回调
void USB_Read_Complete_Callback(void) {
    __disable_irq();
    usb_activity = 0;
    __enable_irq();
}

// 同理实现USB_Write_Start/Complete_Callback

3. 文件上传任务调度


void FileUpload_Task(void) {
    if (upload_request && !usb_activity) {
        // 原子检查并抢占资源
        __disable_irq();
        if (!usb_activity) {
            usb_activity = 2; // 标记为文件上传占用
            __enable_irq();

            // 执行文件上传操作
            if (FATFS_UploadFiles() == FR_OK) {
                upload_request = 0; // 上传成功清除请求
            }

            __disable_irq();
            usb_activity = 0; // 释放资源
        }
        __enable_irq();
    }
}

4. 触发上传请求


// 在需要上传时设置标志(如定时器/按钮事件)
void Trigger_Upload(void) {
    if (!upload_request) {
        upload_request = 1;
    }
}

5. 主循环调度


while(1) {
    // 优先处理USB事件
    USB_Process(); // 内置USB状态机轮询

    // 非阻塞式处理上传
    FileUpload_Task();

    // 其他低优先级任务
    Idle_Task();
}



关键优化点




  1. 原子操作保证



    • 使用__disable_irq()/__enable_irq()确保标志位操作的原子性。

    • 或利用C11原子变量(需编译器支持):
      #include 
      atomic_uint_fast8_t usb_activity = ATOMIC_VAR_INIT(0);




  2. 优先级策略



    • USB实时响应:USB处理始终优先,确保枚举/数据传输不超时。

    • 上传延迟补偿:若USB持续占用,可加入退避算法(如指数退避)重试上传。




  3. 错误恢复机制


    if (FATFS_UploadFiles() != FR_OK) {
       // 记录错误次数,超阈值后复位SDIO
       if (++error_count > 3) {
           SDIO_Reinit();
           error_count = 0;
       }
    }



  4. SDIO驱动增强



    • 在切换操作前增加SDIO_CLEAR_FLAG()清除残留状态。

    • 配置DMA通道后增加延时,避免总线竞争。






扩展方案(可选)



  • 双缓冲队列:若上传任务频繁,可设计环形队列缓存待上传文件路径,由后台任务异步处理。

  • 硬件看门狗:监控长时间阻塞操作,防止死锁。




通过上述方法,可在无OS环境下安全协调USB与FATFS对eMMC的访问,确保系统稳定性和实时性。实际调试时需结合逻辑分析仪抓取SDIO波形,确认时序无冲突。

举报

更多回帖

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