OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12435|回复: 5

STM32F407 SDIO驱动SD卡 发生DMA FIFO溢出错误

[复制链接]

1

主题

14

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1454
金钱
1454
注册时间
2015-8-18
在线时间
115 小时
发表于 2018-2-25 19:09:37 | 显示全部楼层 |阅读模式
10金钱
本帖最后由 juky2008 于 2018-2-25 19:56 编辑

大家好:
      我最近在使用原子哥的探索者STM32F407的开发板,芯片是STM32F407ZET6,原先我使用STM32CubeMX4.21和F4库 1.16.0 生成FreeRTOS+Fatfs+SD卡的工程来调试SD卡驱动程序,用STM32CubeMX配置收发DMA数据流传输,但是生成的sd_disk.c中SD_read,SD_write函数并没有调用BSP_SD_ReadBlocks_DMA,BSP_SD_WriteBlocks_DMA函数。生成代码可以读取SD卡的信息,fatfs也可以挂载,但是多次新建文件打开和关闭后,fatfs返回FR_DISK_ERR;是由于SD卡无响应后超时导致,BSP_SD_ReadBlocks(),BSP_SD_WriteBlocks()函数执行时关闭中断可以解决SD卡超时的问题,但是软件的实时性变差
    然后我下载STM32CubeMX4.24和1.19.0库文件,配置好后,生成的sd_disk.c中SD_read,SD_write函数使用了BSP_SD_ReadBlocks_DMA,BSP_SD_WriteBlocks_DMA函数和信号量(队列),进行了线程保护,但是生成的代码并不能使用。读写函数都卡在了 event = osMessageGet(SDQueueID, SD_TIMEOUT);分析后发现程序中并没有释放信号量,于是我在sd_disk.c文件最后添加了
[mw_shl_code=applescript,true]void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
  BSP_SD_ReadCpltCallback();
}

void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
  BSP_SD_WriteCpltCallback();
}[/mw_shl_code]
void DMA2_Stream6_IRQHandler(void)中断调用了HAL_SD_TxCpltCallback回调函数,但是HAL_SD_RxCpltCallback()回调函数并没有被调用。FatFs不能正常读写SD卡。
最后我在CubeMX中开启了SDIO global interrupt 中断后,HAL_SD_RxCpltCallback()才被调用。现在Fatfs可以正常读写SD卡(8GB)了。
间隔200ms给Fatfs测试任务发送通知,Fatfs测试任务完成创建文件(文件名不重复),写入数据(8192字节),关闭文件的功能,25000次(大概3小时)都没有问题,但是任务的完成时间由原来的200ms间隔(每次给任务发送通知),逐渐增加到1.2秒(每次任务完成后,会通过串口打印将信息发给电脑,串口助手有时间戳)。这个原因我现在不清楚。
通过仿真发现在发送数据流中断中一直进入FIFO Error错误。但是SD卡可以正常读写。我没有找到原因,会不会是DPSM引起?
[mw_shl_code=applescript,true]void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
  /* FIFO Error Interrupt management ******************************************/
  if ((tmpisr & (DMA_FLAG_FEIF0_4 << hdma->StreamIndex)) != RESET)
  {
    if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_FE) != RESET)
    {
      /* Clear the FIFO error flag */
     regs->IFCR = DMA_FLAG_FEIF0_4 << hdma->StreamIndex;

     /* Update error code */
     hdma->ErrorCode |= HAL_DMA_ERROR_FE;
    }
  }
}[/mw_shl_code]

仿真时发现 在stm32f4xx_hal_sd.c ,只要一执行SDIO_ConfigData(hsd->Instance, &config);后就出现错误。
[mw_shl_code=applescript,true]HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
{
  SDIO_DataInitTypeDef config;
  uint32_t errorstate = HAL_SD_ERROR_NONE;
  
  if(NULL == pData)
  {
    hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
    return HAL_ERROR;
  }
  
  if(hsd->State == HAL_SD_STATE_READY)
  {
    hsd->ErrorCode = HAL_DMA_ERROR_NONE;
   
    if((BlockAdd + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
    {
      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
      return HAL_ERROR;
    }
   
    hsd->State = HAL_SD_STATE_BUSY;
   
    /* Initialize data control register */
    hsd->Instance->DCTRL = 0U;
   
    /* Enable SD Error interrupts */  
#ifdef SDIO_STA_STBITER
    __HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR));   
#else /* SDIO_STA_STBITERR not defined */
    __HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_TXUNDERR));   
#endif /* SDIO_STA_STBITERR */
   
    /* Set the DMA transfer complete callback */
    hsd->hdmatx->XferCpltCallback = SD_DMATransmitCplt;
   
    /* Set the DMA error callback */
    hsd->hdmatx->XferErrorCallback = SD_DMAError;
   
    /* Set the DMA Abort callback */
    hsd->hdmatx->XferAbortCallback = NULL;
   
    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
    {
      BlockAdd *= 512U;
    }
   
    /* Set Block Size for Card */
    errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
      hsd->ErrorCode |= errorstate;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
   
    /* Write Blocks in Polling mode */
    if(NumberOfBlocks > 1U)
    {
      hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
      
      /* Write Multi Block command */
      errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, BlockAdd);
    }
    else
    {
      hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_DMA);
      
      /* Write Single Block command */
      errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, BlockAdd);
    }
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
      hsd->ErrorCode |= errorstate;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
   
    /* Enable SDIO DMA transfer */
    __HAL_SD_DMA_ENABLE(hsd);
   
    /* Enable the DMA Channel */
    HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pData, (uint32_t)&hsd->Instance->FIFO, (uint32_t)(BLOCKSIZE * NumberOfBlocks)/4);   //DMA2 stream6 发送0x80个数据,执行这条语句后,寄存器S6NDTR从0x80变成0xFFFF,太奇怪了。此时寄存器TCIF6=0,FEIF6=0;
   
    /* Configure the SD DPSM (Data Path State Machine) */
    config.DataTimeOut   = SDMMC_DATATIMEOUT;
    config.DataLength    = BLOCKSIZE * NumberOfBlocks;
    config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
    config.TransferDir   = SDIO_TRANSFER_DIR_TO_CARD;
    config.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;
    config.DPSM          = SDIO_DPSM_ENABLE;
    SDIO_ConfigData(hsd->Instance, &config);//执行完这条语句后,S6NDTR=0xFF7F, 相当于发送的字节数0xFFFF-0xFF7F=0x80,难道是巧合?此时寄存器TCIF6=1,FEIF6=1;接着就进入DMA2_Stream6的FIFO ERROR中断了,每次都一样。但是数据已经发送出去了,TCIF也等于1了,Fatfs的f_write() 返回FR_OK。
   
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}[/mw_shl_code]
大家有没有碰到过这个问题啊?请大家多多指教。

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165475
金钱
165475
注册时间
2010-12-1
在线时间
2115 小时
发表于 2018-2-26 01:44:48 | 显示全部楼层
回复

使用道具 举报

3

主题

85

帖子

0

精华

高级会员

Rank: 4

积分
586
金钱
586
注册时间
2016-5-13
在线时间
106 小时
发表于 2018-3-2 11:18:16 | 显示全部楼层
hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_sdio_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
尝试一下这样修改,CUBEMX生成的默认都是WORD,会出现对齐错误,把下面的改成BYTE实验一下
回复

使用道具 举报

1

主题

14

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1454
金钱
1454
注册时间
2015-8-18
在线时间
115 小时
 楼主| 发表于 2018-3-4 11:48:19 | 显示全部楼层
abdfgh 发表于 2018-3-2 11:18
hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_tx.Init.MemDataAlignment ...

你好,我按照你的设置试了一下,也是进入发送DMA FIFO溢出中断。
[mw_shl_code=applescript,true]    在HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)函数中
HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pData, (uint32_t)&hsd->Instance->FIFO, (uint32_t)(BLOCKSIZE * NumberOfBlocks)/4);//DMA2 stream6 发送0x80个数据,执行这条语句后,//寄存器S6NDTR从0x80变成0xFFFF,此时寄存器TCIF6=0,FEIF6=0;
   
    /* Configure the SD DPSM (Data Path State Machine) */
    config.DataTimeOut   = SDMMC_DATATIMEOUT;
    config.DataLength    = BLOCKSIZE * NumberOfBlocks;
    config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
    config.TransferDir   = SDIO_TRANSFER_DIR_TO_CARD;
    config.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;
    config.DPSM          = SDIO_DPSM_ENABLE;
    SDIO_ConfigData(hsd->Instance, &config);//执行完这条语句后,S6NDTR=0xFF7F,寄存器TCIF6=1,FEIF6=1;接着就进入DMA2_Stream6的FIFO ERROR中断。[/mw_shl_code]
回复

使用道具 举报

37

主题

596

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1574
金钱
1574
注册时间
2017-7-17
在线时间
308 小时
发表于 2018-11-12 11:55:16 | 显示全部楼层
参考我的一个帖子,SDIO的DMA访问不了DPSM,是你把DMA的缓冲区设置到DPSM区域去了,你设置成AXI SDRAM就好了。
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
5
金钱
5
注册时间
2020-12-16
在线时间
1 小时
发表于 2020-12-16 11:31:17 | 显示全部楼层
问题解决了嘛?怎么解决的能说下嘛
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-14 19:03

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表