STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)

  • 使用FatFs文件系统

添加FatFs文件系统,使用DMA读写方式驱动。

1、打开配置文件,在FatFs勾选SD Card

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第1张图片

2、在configuration选项卡中打开“FATFS”选项,按下图配置,以支持中文和长目录。生成代码并打开工程。

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第2张图片

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第3张图片

 

打开菜单栏project -> settings,如图红框部分,调大堆栈,heap = 0x400, Stack = 0x1000.

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第4张图片

 

3、修改代码

添加FATFS测试代码。

打开main.c文件,在变量定义区( 79行附近 )加入变量:

FATFS fs;                 // Work area (file system object) for logical drive
	FIL fil;                  // file objects
	uint32_t byteswritten;                /* File write counts */
	uint32_t bytesread;                   /* File read counts */
	uint8_t wtext[] = "This is STM32 working with FatFs"; /* File write buffer */
	uint8_t rtext[100];                     /* File read buffers */
	char filename[] = "STM32cube.txt";

在void SD_Write_Read_Test(void)函数下面添加文件系统测试函数:

void Fatfs_RW_test(void)
{
	  printf("\r\n ****** FatFs Example ******\r\n\r\n");
 
    /*##-1- Register the file system object to the FatFs module ##############*/
    retSD = f_mount(&fs, "", 1);
    if(retSD)
    {
        printf(" mount error : %d \r\n",retSD);
        Error_Handler();
    }
    else
        printf(" mount sucess!!! \r\n");
     
    /*##-2- Create and Open new text file objects with write access ######*/
    retSD = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE);
    if(retSD)
        printf(" open file error : %d\r\n",retSD);
    else
        printf(" open file sucess!!! \r\n");
     
    /*##-3- Write data to the text files ###############################*/
    retSD = f_write(&fil, wtext, sizeof(wtext), (void *)&byteswritten);
    if(retSD)
        printf(" write file error : %d\r\n",retSD);
    else
    {
        printf(" write file sucess!!! \r\n");
        printf(" write Data : %s\r\n",wtext);
    }
     
    /*##-4- Close the open text files ################################*/
    retSD = f_close(&fil);
    if(retSD)
        printf(" close error : %d\r\n",retSD);
    else
        printf(" close sucess!!! \r\n");
     
    /*##-5- Open the text files object with read access ##############*/
    retSD = f_open(&fil, filename, FA_READ);
    if(retSD)
        printf(" open file error : %d\r\n",retSD);
    else
        printf(" open file sucess!!! \r\n");
     
    /*##-6- Read data from the text files ##########################*/
    retSD = f_read(&fil, rtext, sizeof(rtext), (UINT*)&bytesread);
    if(retSD)
        printf(" read error!!! %d\r\n",retSD);
    else
    {
        printf(" read sucess!!! \r\n");
        printf(" read Data : %s\r\n",rtext);
    }
     
    /*##-7- Close the open text files ############################*/
    retSD = f_close(&fil);
    if(retSD)  
        printf(" close error!!! %d\r\n",retSD);
    else
        printf(" close sucess!!! \r\n");
     
    /*##-8- Compare read data with the expected data ############*/
    if(bytesread == byteswritten)
    { 
        printf(" FatFs is working well!!!\r\n");
    }
}

添加完成后,到main函数中修改:

注释掉以下语句:

//  SD_EraseTest();

//  SD_Write_Read_Test();

 

接着添加:

Fatfs_RW_test();

4、完成后编译下载工程。

发现凉凉了。。。

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第5张图片

这就是ST挖的一个坑。。。

这个坑怎么填呢?

打开下载的库,找到下面的文件位置:

C:\Users\XXXXXX(你的电脑用户名)\STM32Cube\Repository\STM32Cube_FW_L4_V1.13.0\Projects\STM32L476G-EVAL\Applications\FatFs\FatFs_uSD_Standalone\MDK-ARM

打开ST的官方例程。

在“stm32l476g_eval_sd.c”文件下的第302行,发现了好东西。

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第6张图片

而打开我们的工程中的bsp_driver_sd.c,第214行,却发现少了点什么。

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第7张图片

 

ST官方的例子,在每次调用HAL_SD_WriteBlocks_DMA和HAL_SD_ReadBlocks_DMA之前都进行了DMA通道的初始化配置,这就是解决问题的关键。而CubeMX生成的源码缺少了这个配置,甚至连一个注释都没有。。。

 

5、找到问题的所在就开始解决问题。

添加以下源码到main.c的void Fatfs_RW_test(void)函数的后面:

/**
  * @brief Configure the DMA to receive data from the SD card
  * @retval
  *  HAL_ERROR or HAL_OK
  */
HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd)
{
  HAL_StatusTypeDef status = HAL_ERROR;
  
  /* Configure DMA Rx parameters */
  hdma_sdmmc1_rx.Instance = DMA2_Channel4;
	hdma_sdmmc1_rx.Init.Request = DMA_REQUEST_7;
	hdma_sdmmc1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
	hdma_sdmmc1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
	hdma_sdmmc1_rx.Init.MemInc = DMA_MINC_ENABLE;
	hdma_sdmmc1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
	hdma_sdmmc1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
	hdma_sdmmc1_rx.Init.Mode = DMA_NORMAL;
  hdma_sdmmc1_rx.Init.Priority = DMA_PRIORITY_LOW;

  /* Associate the DMA handle */
  __HAL_LINKDMA(hsd,hdmarx,hdma_sdmmc1_rx);

  /* Stop any ongoing transfer and reset the state*/
  HAL_DMA_Abort(&hdma_sdmmc1_rx);
  
  /* Deinitialize the Channel for new transfer */
  HAL_DMA_DeInit(&hdma_sdmmc1_tx);//注意这里!!!DeInit的是另一个通道!!!

  /* Configure the DMA Channel */
  status = HAL_DMA_Init(&hdma_sdmmc1_rx);
    
  return (status);
}

/**
  * @brief Configure the DMA to transmit data to the SD card
  * @retval
  *  HAL_ERROR or HAL_OK
  */
HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd)
{
  HAL_StatusTypeDef status;
  
  /* SDMMC1_TX Init */
	hdma_sdmmc1_tx.Instance = DMA2_Channel5;
	hdma_sdmmc1_tx.Init.Request = DMA_REQUEST_7;
	hdma_sdmmc1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
	hdma_sdmmc1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
	hdma_sdmmc1_tx.Init.MemInc = DMA_MINC_ENABLE;
	hdma_sdmmc1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
	hdma_sdmmc1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
	hdma_sdmmc1_tx.Init.Mode = DMA_NORMAL;//这里NORMAL或其他都可以,无所谓
	hdma_sdmmc1_tx.Init.Priority = DMA_PRIORITY_LOW;

  /* Associate the DMA handle */
  __HAL_LINKDMA(hsd, hdmatx, hdma_sdmmc1_tx);
  
  /* Stop any ongoing transfer and reset the state*/
  HAL_DMA_Abort(&hdma_sdmmc1_tx);
  
  /* Deinitialize the Channel for new transfer */
  HAL_DMA_DeInit(&hdma_sdmmc1_rx);  //注意这里!!!DeInit的是另一个通道!!!
  
  /* Configure the DMA Channel */
  status = HAL_DMA_Init(&hdma_sdmmc1_tx); 

  return (status);
}

 

  注意:经测试实验,SD_DMAConfigRx和SD_DMAConfigTx函数可做适当精简,可以只保留

HAL_DMA_DeInit和HAL_DMA_Init,如果是收发复用DMA,仅格外配置变化项(hdma_sdmmc1_tx.Init.Direction)和__HAL_LINKDMA即可。

 

然后,打开bsp_driver_sd.c文件,到BSP_SD_ReadBlocks_DMA函数中(186行附近),在

 if (HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK)

  {

    sd_state = MSD_ERROR;

  }

上方添加以下代码:

if(SD_DMAConfigRx(&hsd1) != HAL_OK)
{
		return MSD_ERROR;
}

在BSP_SD_WriteBlocks_DMA(214行附近),在

if (HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK)

  {

    sd_state = MSD_ERROR;

  }

上方添加以下代码:

if(SD_DMAConfigTx(&hsd1) != HAL_OK)
{
		return MSD_ERROR;
}

添加完成后效果:(头文件声明自己改改)

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第8张图片

 

编译工程,下载测试。将SD卡取出插到电脑上,可以看到生成的文件和文件内容。

STM32L4新版HAL库SDIO(DMA)、FatFs使用教程(三)_第9张图片

你可能感兴趣的:(STM32开发)