簡體   English   中英

在 STM32L476 和 CubeMX 上使用 DMA 的 SD 卡中沒有中斷

[英]No interrupt in SDcard with DMA on STM32L476 and CubeMX

我有一個未解決的 SD 卡問題。

該項目基於 STM32L476,IDE 是 Atollic,配置是由 STM32CucbeMX 完成的(就像我所有的設計一樣)。

如果沒有 DMA(FATFS 中沒有 DMA 模板,也沒有配置的 DMA 通道),SD 卡可以工作。 當我使用 DMA 時(見屏幕截圖),第一次讀取操作卡住了,在 30 秒超時后出現錯誤。

DMA配置

我已經在代碼內部進行了調查,並且有證據表明在 HAL_SD_ReadBlocks_DMA() 之后沒有任何中斷。 這就是超時的原因。 該函數本身沒有返回錯誤,因此它認為數據傳輸正在運行,但事實並非如此。

中斷是這樣配置的:

中斷請求配置

CubeMX 是 6.2.1 版。 並且更新了 STM32L4 包。

我的觀點是庫或 Cube 生成的代碼中存在一些錯誤。 我看過其他(罕見的)關於類似問題的帖子,懷疑是庫錯誤。

這對我來說很尷尬,因為我有一個重要的設計,就是等待 SD 卡全速工作。

沒有 DMA,正如我所說,SD 卡可以工作,但寫入速度太低,我必須以非常低的頻率運行接口以避免寫入錯誤。 我想通過 DMA 的讀/寫操作會給我所需的速度,但是這個中斷問題使所有事情都停滯不前。

對非工作中斷有什么想法嗎?

非常感謝

我有同樣的問題,這是我修復它的方法。

這個解決方案是我在 stm32 論壇上找到的一個解決方案的基礎,但我試圖移動一些東西以使其易於實現,這樣每次使用多維數據集 mx 重新生成時都不會丟失任何東西。 我將覆蓋函數放在 main 中,但我認為它們也可以放在 bsp 文件的用戶部分。

作為參考,我從這個例子開始,然后應用下面的修復https://community.st.com/s/article/how-to-create-a-file-system-on-a-sd-card-using-stm32bubeide ?t=1637759710161

修復步驟:

  1. 在cubeMX 中,在通道4 上使用單個DMA,而不是1 用於Rx,1 用於Tx。

  2. 在 main.c

    • 為 Tx 和 Rx dma 創建配置函數
/* USER CODE BEGIN PFP */
    //Create config functions for rx and tx dma
    static HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd);
    static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd);
    /* USER CODE END PFP */
  • 每次 tx 或 rx 時都會調用這些函數來為 rx 或 tx 重新配置 DMA
        /* USER CODE BEGIN 4 */
    
    /**
      * @brief Configure the DMA to receive data from the SD card
      * @retval
      *  HAL_ERROR or HAL_OK
      */
    static HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd)
    {
      static DMA_HandleTypeDef hdma_rx;
      HAL_StatusTypeDef status = HAL_ERROR;
    
      /* Configure DMA Rx parameters */
      hdma_rx.Init.Request             = DMA_REQUEST_7;
      hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
      hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
      hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;
      hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
      hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
      hdma_rx.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
    
      hdma_rx.Instance = DMA2_Channel4;
    
      /* Associate the DMA handle */
      __HAL_LINKDMA(hsd, hdmarx, hdma_rx);
    
      /* Stop any ongoing transfer and reset the state*/
      HAL_DMA_Abort(&hdma_rx);
    
      /* Deinitialize the Channel for new transfer */
      HAL_DMA_DeInit(&hdma_rx);
    
      /* Configure the DMA Channel */
      status = HAL_DMA_Init(&hdma_rx);
    
      /* NVIC configuration for DMA transfer complete interrupt */
      HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 6, 0);
      HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
    
      return (status);
    }
    
    /**
      * @brief Configure the DMA to transmit data to the SD card
      * @retval
      *  HAL_ERROR or HAL_OK
      */
    static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd)
    {
      static DMA_HandleTypeDef hdma_tx;
      HAL_StatusTypeDef status;
    
      /* Configure DMA Tx parameters */
      hdma_tx.Init.Request             = DMA_REQUEST_7;
      hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
      hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
      hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
      hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
      hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
      hdma_tx.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
    
      hdma_tx.Instance = DMA2_Channel4;
    
      /* Associate the DMA handle */
      __HAL_LINKDMA(hsd, hdmatx, hdma_tx);
    
      /* Stop any ongoing transfer and reset the state*/
      HAL_DMA_Abort(&hdma_tx);
    
      /* Deinitialize the Channel for new transfer */
      HAL_DMA_DeInit(&hdma_tx);
    
      /* Configure the DMA Channel */
      status = HAL_DMA_Init(&hdma_tx);
    
      /* NVIC configuration for DMA transfer complete interrupt */
      HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 6, 0);
      HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
    
      return (status);
    }

  • 同樣在主要的用戶部分 4 中,覆蓋 tx 和 rx 的 bsp 函數
//Override DMA write functions
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
  uint8_t sd_state = MSD_OK;

  // Invalidate the dma rx handle
  hsd1.hdmarx = NULL;

  // Prepare the dma channel for a read operation
  sd_state = SD_DMAConfigTx(&hsd1);

  if(sd_state == HAL_OK)
  {
    /* Write block(s) in DMA transfer mode */
    sd_state = HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks);
  }

  if( sd_state == HAL_OK)
  {
    return MSD_OK;
  }
  else
  {
    return MSD_ERROR;
  }

  return sd_state;
}

//Override DMA read functions
uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
  uint8_t sd_state = MSD_OK;
  /* Invalidate the dma tx handle*/
  hsd1.hdmatx = NULL;

  /* Prepare the dma channel for a read operation */
  sd_state = SD_DMAConfigRx(&hsd1);

  if(sd_state == HAL_OK)
  {
       /* Read block(s) in DMA transfer mode */
        sd_state = HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks);
  }

  if( sd_state == HAL_OK)
  {
    return MSD_OK;
  }
  else
  {
    return MSD_ERROR;
  }
}

  1. 最后,根據狀態改變stm32l4xx_it.c中的DMA IRQ使用rx參數或tx參數
/**
  * @brief This function handles DMA2 channel4 global interrupt.
  */
void DMA2_Channel4_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Channel4_IRQn 0 */

  /* USER CODE END DMA2_Channel4_IRQn 0 */
    //DMAFIX comment or delete HAL_DMA_IRQHandler(&hdma_sdmmc1);
  /* USER CODE BEGIN DMA2_Channel4_IRQn 1 */
  //DMAFIX separate irq handler by tx/rx, new code in irq handler
  if((hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_READ_SINGLE_BLOCK)) ||
     (hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_READ_MULTIPLE_BLOCK)))
      {
        //BSP_SD_DMA_Rx_IRQHandler();
       HAL_DMA_IRQHandler(hsd1.hdmarx);

      }
   else if((hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_WRITE_SINGLE_BLOCK)) ||
           (hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_WRITE_MULTIPLE_BLOCK)))
     {
        //BSP_SD_DMA_Tx_IRQHandler();
       HAL_DMA_IRQHandler(hsd1.hdmatx);
     }
  /* USER CODE END DMA2_Channel4_IRQn 1 */
}

注意:每次使用 Cube Mx 重新生成時,您都需要返回注釋或刪除對 HAL_DMA_IRQHandler(&hdma_sdmmc1); 的調用。

希望它會有所幫助,我還沒有完成那個項目,可能有更好的方法,但到目前為止,這就是我解除封鎖的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM