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()){};
sta=HAL_OK;
}
return sta;
}
因為 SD 已經被 CubeMX 產生的程式碼做部分的初始化,所以將sdmmc_sdcard.c內u8 SD_Init(void) 重複的部分註釋掉:
u8 SD_Init(void)
{
u8 SD_Error;
SD_Error=HAL_SD_Init(&hsd1);
if(SD_Error!=HAL_OK) return 1;
HAL_SD_GetCardInfo(&hsd1,&SDCardInfo);
return 0;
}
還有要將所有的 SD_HandleTypeDef SDCARD_Handler; 改成 CubeMX 的定義 extern SD_HandleTypeDef hsd1; 3.改寫 usbd_storage_if.c,使用原子提供的讀寫函數做讀寫。(其實整個結構很像STM32給的example,參考他們的寫法自己寫一個也行),懶得剪下貼上,這裡給出所有的code
#include "usbd_storage_if.h"
#include "sys.h"
#include "sdmmc_sdcard.h"
#include "sdmmc.h"
vu8 USB_STATUS_REG=0;
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200
const int8_t STORAGE_Inquirydata_FS[] = {
0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ',
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '.', '0' ,'1'
};
extern USBD_HandleTypeDef hUsbDeviceFS;
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);
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
};
int8_t STORAGE_Init_FS(uint8_t lun)
{
u8 res=0;
MX_SDMMC1_SD_Init();
res=SD_Init();
return res;
}
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
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);
}
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
USB_STATUS_REG|=0X10;
return (USBD_OK);
}
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
return (USBD_OK);
}
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
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);
}
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
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);
}
int8_t STORAGE_GetMaxLun_FS(void)
{
HAL_SD_CardInfoTypeDef info;
HAL_SD_GetCardInfo(&hsd1,&info);
if(info.LogBlockNbr)return STORAGE_LUN_NBR-1;
else return STORAGE_LUN_NBR-2;
}
最後,我的測試方法為從PC複製一個TXT文件檔到H743上的SD卡,關閉PC上的檔案總管,在PC再次打開H743上的SD卡,讀取檔案,修改檔案,處存檔案,關閉檔案總管,再次在PC上打開H743上的SD卡,讀取被修改過的文件,正確無誤。 以上應該很詳細描述過程,相關的code已經很詳細。所以不再上傳資源了。有需要再跟我說! 因為我在台灣,很少上來,很少積分,更沒金錢,如果此文對您有幫助,所以期待大家能互助,也幫助我解決問題。謝謝大家!
|