2021-10-08

H734 USB_DEVICE with DMA as the SDCard reader

  • 使用開發版:原子阿波羅 + H743 核心板

  • 問題參考文章How to correctly setup your application to use USB DMA controller with STM32H7 devices
    -主要問題: 如果使用CubeMX搭建RTOS,牽涉到SD卡的部分,經會強制使用DMA,所以必須搭建一個使用DMA的SD程序。其中只有一個坑,見參考文章(在網路上撈了好久終於撈到這篇),其大意是,因為在H743中,CPU與SD溝通使用的是MDMA,而MDMA牽涉到CPU DCache。所以,必須將 CPU DCache Disable。
    在这里插入图片描述

  • SDMMC的設置:我們選擇SDMMC1,可以看到選項裡沒有DMA Setting ,這部分已經改到MDMA去了!使用原子的板子的話,就不用改GPIO了(可能要改上拉電阻,請自行檢查一下)在这里插入图片描述

  • 設定MDMA:除了add channel 選擇 SDMMC1 data end 外,其他都默認選項在这里插入图片描述

  • 設置USB OTG FS:這裡使用USB_OTG_FS,選擇Device Only,並且將DMA enable。在这里插入图片描述

  • 設置USB DEVICE:這裡選擇Mass Storage Class在这里插入图片描述

  • 時鐘設置:因為H743的高性能,這裡將時鐘頻率設置到最大容許值,usb使用 RC48,實測能跑!在这里插入图片描述

  • 中斷設置,SD>MDMA>USB(其實有次我忘了打開MDMA的中斷他也能跑?!但是我最後還是開了它)在这里插入图片描述

  • CODE:需要更改三個檔案
    1.CubeMX會引入 bsp_driver_sd.c 它會產生重複定義的錯誤,將錯誤的地方註解掉就行。
    2.會用到原子的sdmmc_sdcard.c與sdmmc_sdcard.h
    在sdmmc_sdcard.h 開啟 DMA#define SD_DMA_MODE 1這個設定將會在sdmmc_sdcard.c使用DMA的方式讀寫SD卡,例如

u8 SD_ReadDisk(u8* buf,u32 sector,u32 cnt)
{
    u8 sta=HAL_ERROR;
	SDCardReadStatus=0;
	
	if(HAL_SD_ReadBlocks_DMA(&hsd1,(uint8_t*)buf,(uint32_t)sector,(uint32_t)cnt)==HAL_OK)
	{
		while(SDCardReadStatus==0){};	//等待讀完成
		
		SDCardReadStatus=0;
		while(SD_GetCardState()){};		//等待SD卡空閒
		sta=HAL_OK;
	}
	
    return sta;
}  

因為 SD 已經被 CubeMX 產生的程式碼做部分的初始化,所以將sdmmc_sdcard.c內u8 SD_Init(void)重複的部分註釋掉:

u8 SD_Init(void)
{
    u8 SD_Error;
    
    //初始化時的時鐘不能大於400KHZ 
//    SDCARD_Handler.Instance=SDMMC1;
//    SDCARD_Handler.Init.ClockEdge=SDMMC_CLOCK_EDGE_RISING;              //上升沿     
//    SDCARD_Handler.Init.ClockPowerSave=SDMMC_CLOCK_POWER_SAVE_DISABLE;  //空閒時不關閉時鐘電源
//    SDCARD_Handler.Init.BusWide=SDMMC_BUS_WIDE_4B;                      //4位數據線
//    SDCARD_Handler.Init.HardwareFlowControl=SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;//關閉硬件流控
//    SDCARD_Handler.Init.ClockDiv=SDMMC_NSpeed_CLK_DIV;               	//SD傳輸時鐘頻率最大25MHZ
    
    SD_Error=HAL_SD_Init(&hsd1);
    if(SD_Error!=HAL_OK) return 1;
	
	//獲取SD卡信息
	HAL_SD_GetCardInfo(&hsd1,&SDCardInfo);
    return 0;
}

//SDMMC底層驅動,時鐘使能,引腳配置,DMA配置
//此函數會被HAL_SD_Init()調用
//hsd:SD卡句柄
//void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
//{
//    GPIO_InitTypeDef GPIO_Initure;

//    __HAL_RCC_SDMMC1_CLK_ENABLE();  //使能SDMMC1時鐘
//    __HAL_RCC_GPIOC_CLK_ENABLE();   //使能GPIOC時鐘
//    __HAL_RCC_GPIOD_CLK_ENABLE();   //使能GPIOD時鐘
//    
//    //PC8,9,10,11,12
//    GPIO_Initure.Pin=GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
//    GPIO_Initure.Mode=GPIO_MODE_AF_PP;      //推挽復用
//    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
//    GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;     //高速
//    GPIO_Initure.Alternate=GPIO_AF12_SDIO1; //復用為SDIO
//    HAL_GPIO_Init(GPIOC,&GPIO_Initure);     //初始化
//    
//    //PD2
//    GPIO_Initure.Pin=GPIO_PIN_2;            
//    HAL_GPIO_Init(GPIOD,&GPIO_Initure);     //初始化

//#if (SD_DMA_MODE==1)                        //使用DMA模式
//    HAL_NVIC_SetPriority(SDMMC1_IRQn,2,0);  //配置SDMMC1中斷,搶佔優先級2,子優先級0
//    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);        //使能SDMMC1中斷
//#endif
//}

還有要將所有的 SD_HandleTypeDef SDCARD_Handler;改成 CubeMX 的定義 extern SD_HandleTypeDef hsd1;
3.改寫 usbd_storage_if.c,使用原子提供的讀寫函數做讀寫。(其實整個結構很像STM32給的example,參考他們的寫法自己寫一個也行),懶得剪下貼上,這裡給出所有的code

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : usbd_storage_if.c
  * @version        : v1.0_Cube
  * @brief          : Memory management layer.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"

/* USER CODE BEGIN INCLUDE */
#include "sys.h"
#include "sdmmc_sdcard.h"
#include "sdmmc.h"
/* USER CODE END INCLUDE */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
vu8 USB_STATUS_REG=0;
/* USER CODE END PV */

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
  * @brief Usb device.
  * @{
  */

/** @defgroup USBD_STORAGE
  * @brief Usb mass storage device module
  * @{
  */

/** @defgroup USBD_STORAGE_Private_TypesDefinitions
  * @brief Private types.
  * @{
  */

/* USER CODE BEGIN PRIVATE_TYPES */

/* USER CODE END PRIVATE_TYPES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_Defines
  * @brief Private defines.
  * @{
  */

#define STORAGE_LUN_NBR                  1
#define STORAGE_BLK_NBR                  0x10000
#define STORAGE_BLK_SIZ                  0x200

/* USER CODE BEGIN PRIVATE_DEFINES */

/* USER CODE END PRIVATE_DEFINES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_Macros
  * @brief Private macros.
  * @{
  */

/* USER CODE BEGIN PRIVATE_MACRO */

/* USER CODE END PRIVATE_MACRO */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_Variables
  * @brief Private variables.
  * @{
  */

/* USER CODE BEGIN INQUIRY_DATA_FS */
/** USB Mass storage Standard Inquiry Data. */
const int8_t STORAGE_Inquirydata_FS[] = {/* 36 */

  /* LUN 0 */
  0x00,
  0x80,
  0x02,
  0x02,
  (STANDARD_INQUIRY_DATA_LEN - 5),
  0x00,
  0x00,
  0x00,
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
  'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product      : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0' ,'1'                      /* Version      : 4 Bytes */
};
/* USER CODE END INQUIRY_DATA_FS */

/* USER CODE BEGIN PRIVATE_VARIABLES */

/* USER CODE END PRIVATE_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Exported_Variables
  * @brief Public variables.
  * @{
  */

extern USBD_HandleTypeDef hUsbDeviceFS;

/* USER CODE BEGIN EXPORTED_VARIABLES */

/* USER CODE END EXPORTED_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_FunctionPrototypes
  * @brief Private functions declaration.
  * @{
  */

static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

/**
  * @}
  */

USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
{
  STORAGE_Init_FS,
  STORAGE_GetCapacity_FS,
  STORAGE_IsReady_FS,
  STORAGE_IsWriteProtected_FS,
  STORAGE_Read_FS,
  STORAGE_Write_FS,
  STORAGE_GetMaxLun_FS,
  (int8_t *)STORAGE_Inquirydata_FS
};

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Initializes over USB FS IP
  * @param  lun:
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Init_FS(uint8_t lun)
{
  /* USER CODE BEGIN 2 */
	u8 res=0;
	MX_SDMMC1_SD_Init();
	res=SD_Init();
	return res; 
  //return (USBD_OK);
  /* USER CODE END 2 */
}

/**
  * @brief  .
  * @param  lun: .
  * @param  block_num: .
  * @param  block_size: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */
	HAL_SD_CardInfoTypeDef info;   
	HAL_SD_GetCardInfo(&hsd1,&info);
  *block_num = info.LogBlockNbr - 1;
  *block_size = info.LogBlockSize;
  printf("blocj_num = %d, block size=%d \r\n",*block_num ,*block_size  );
  return (USBD_OK);
  /* USER CODE END 3 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
  /* USER CODE BEGIN 4 */
	USB_STATUS_REG|=0X10;//標还輪詿
  return (USBD_OK);
  /* USER CODE END 4 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
  /* USER CODE BEGIN 5 */
	
  return (USBD_OK);
  /* USER CODE END 5 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
	int8_t res=0;
	printf("reading SD ..... ");
	USB_STATUS_REG|=0X02;//標还正?ܨ访?ո??? 

	res=SD_ReadDisk(buf,blk_addr,blk_len);
	if (res==HAL_OK) printf("read SD complete!\r\n");
	else printf("read SD err, err code = %d \r\n", res);
  return (res);
  /* USER CODE END 6 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */
	int8_t res=0;
	printf("writting SD ..... ");
	USB_STATUS_REG|=0X01;//標还正?ܨ寫數??? 
	res=SD_WriteDisk(buf,blk_addr,blk_len);
	if (res==HAL_OK) printf("read SD complete!\r\n");
	else printf("write SD err, err code = %d \r\n", res);
	if(res)
	{
		USB_STATUS_REG|=0X04;//寫錯調!	 
	} 
  return (USBD_OK);
  /* USER CODE END 7 */
}

/**
  * @brief  .
  * @param  None
  * @retval .
  */
int8_t STORAGE_GetMaxLun_FS(void)
{
  /* USER CODE BEGIN 8 */
	HAL_SD_CardInfoTypeDef info;
  HAL_SD_GetCardInfo(&hsd1,&info);
   
	if(info.LogBlockNbr)return STORAGE_LUN_NBR-1;
	else return STORAGE_LUN_NBR-2;
  //return (STORAGE_LUN_NBR - 1);
  /* USER CODE END 8 */
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

最後,我的測試方法為從PC複製一個TXT文件檔到H743上的SD卡,關閉PC上的檔案總管,在PC再次打開H743上的SD卡,讀取檔案,修改檔案,處存檔案,關閉檔案總管,再次在PC上打開H743上的SD卡,讀取被修改過的文件,正確無誤。
以上應該很詳細描述過程,相關的code已經很詳細。所以不再上傳資源了。有需要再跟我說!
因為我在台灣,很少上來,很少積分,更沒金錢,如果此文對您有幫助,所以期待大家能互助,也幫助我解決問題。謝謝大家!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值