ROSHEN_007 发表于 2023-3-6 13:20

[STM32H7] [STM32H7] STM32H750B-DK TouchGFX 测评——视频播放

本帖最后由 ROSHEN_007 于 2023-3-6 13:20 编辑

#申请原创#

一、搭建存储系统
视频播放一般需要SD卡进行视屏文件存储,但是开发板上没有SD卡,查看了板子的硬件资源,发现板子上有两块EMMC,所以想着用EMMC来作为存储设备,搭建USB+EMMC+FATFS存储读写系统;
1、USB驱动配置
直接使用CUBEMX进行配置,比较方便,需要注意的是,配置时钟的时候,千万别选自动生成USB时钟,自动生成会造成"系统紊乱",因为USB默认时钟是从PLL1上取得,要配置成48MHZ,会改PLL1的输出时钟,很多外设都用PLL1生成时钟,这里直接手动选择RC48即可;



2、EMMC驱动配置
查看STM32H750的手册,发现支持8bit DDR模式,但是实际调试的时候发现速率根本达不到200Mhz,这里简直是深坑,调试出错的时候我以为是EMMC不支持,后来查看EMMC的手册,是可以支持200M ddr模式的,应该还是ST的问题,IO翻转速度达不到200MHZ,时钟改成四分频到50MHZ就可以跑起来了;支持 1线、4线、8线MMC模式,根据需要选择即可,另外打开中断配置;





3、USBMSC驱动代码修改调试
改过SD开驱动的应该都比较熟悉,这里我们直接找到usbd_storage_if.c文件,改写下图中的这些函数,代码下面也贴出,改写的时候主要的是要把自己添加的代码写到“恰当的位置”,不然如果你修改CUBMUX的配置,你辛辛苦苦添加的代码就会消失不见了,我也是刚开始使用cubide,在这上面吃了点小亏;

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file         : usbd_storage_if.c
* @version      : v1.0_Cube
* @brief          : Memory management layer.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"
/* USER CODE BEGIN INCLUDE */
#include "FreeRTOS.h"
#include "semphr.h"
/* USER CODE END INCLUDE */

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

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* 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 */
//#define EMMC_USE_DMA
/* 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 */
volatileuint8_twrite_flag = 0, read_flag = 0;
extern MMC_HandleTypeDef hmmc1;
extern SemaphoreHandle_t xSemaphoreEmmc;
/* 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 */
void HAL_MMC_TxCpltCallback(MMC_HandleTypeDef *hmmc)
{
      write_flag = 1;
}
void HAL_MMC_RxCpltCallback(MMC_HandleTypeDef *hmmc)
{
      read_flag = 1;
}
/* 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 ---------------------------------------------------------*/
/**
* @briefInitializes the storage unit (medium) over USB FS IP
* @paramlun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Init_FS(uint8_t lun)
{
/* USER CODE BEGIN 2 */
UNUSED(lun);
// hmmc1.Instance = SDMMC1;
// hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
// hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
// hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
// hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
// hmmc1.Init.ClockDiv = 0;
// if (HAL_MMC_Init(&hmmc1) != HAL_OK)
// {
//   return USBD_FAIL;
// }
// HAL_MMC_CardStateTypeDef State;
// HAL_MMC_CardCIDTypeDef EMMC_CardCID;
// State = HAL_MMC_GetCardState(&hmmc1);
// if(State == HAL_MMC_CARD_TRANSFER)
// {
//      HAL_MMC_GetCardCID(&hmmc1,&EMMC_CardCID);
// }
// if(HAL_MMC_Erase(&hmmc1,0,hmmc1.MmcCard.BlockNbr) == HAL_OK)
// {
//         while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
// }
return (USBD_OK);
/* USER CODE END 2 */
}

/**
* @briefReturns the medium capacity.
* @paramlun: Logical unit number.
* @paramblock_num: Number of total block number.
* @paramblock_size: 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_MMC_CardStateTypeDef State;
HAL_MMC_CardCIDTypeDef EMMC_CardCID;
State = HAL_MMC_GetCardState(&hmmc1);
if(State == HAL_MMC_CARD_TRANSFER)
{
      HAL_MMC_GetCardCID(&hmmc1,&EMMC_CardCID);
      *block_num= hmmc1.MmcCard.BlockNbr;
      *block_size = hmmc1.MmcCard.BlockSize;
      return (USBD_OK);
}
else
      return USBD_FAIL ;
/* USER CODE END 3 */
}

/**
* @brief   Checks whether the medium is ready.
* @paramlun:Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
/* USER CODE BEGIN 4 */
uint8_t state = 0;
state = HAL_MMC_GetState(&hmmc1);
if(HAL_MMC_STATE_READY != state)
{
          return USBD_FAIL ;
}
return (USBD_OK);
/* USER CODE END 4 */
}

/**
* @briefChecks whether the medium is write protected.
* @paramlun: Logical unit number.
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
/* USER CODE BEGIN 5 */
UNUSED(lun);

return (USBD_OK);
/* USER CODE END 5 */
}

/**
* @briefReads data from the medium.
* @paramlun: Logical unit number.
* @parambuf: data buffer.
* @paramblk_addr: Logical block address.
* @paramblk_len: Blocks number.
* @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 ret = USBD_FAIL;
BaseType_t semRet = pdFAIL;
if(xSemaphoreEmmc!=NULL){
          semRet = xSemaphoreTakeFromISR(xSemaphoreEmmc,0);
}
if(semRet==pdPASS){
      #ifdef EMMC_USE_DMA
          if(HAL_OK == HAL_MMC_ReadBlocks_DMA(&hmmc1,(uint8_t *)buf, blk_addr , blk_len))
          {
               while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
               ret = USBD_OK;
          }
      #else
          if(HAL_OK == HAL_MMC_ReadBlocks(&hmmc1,(uint8_t *)buf, blk_addr , blk_len,0XFF))
          {
               while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
               ret = USBD_OK;
          }
      #endif
          xSemaphoreGiveFromISR(xSemaphoreEmmc,pdFALSE);
}
return ret;
/* USER CODE END 6 */
}

/**
* @briefWrites data into the medium.
* @paramlun: Logical unit number.
* @parambuf: data buffer.
* @paramblk_addr: Logical block address.
* @paramblk_len: Blocks number.
* @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 ret = USBD_FAIL;
BaseType_t semRet = pdFAIL;
if(xSemaphoreEmmc!=NULL){
          semRet = xSemaphoreTakeFromISR(xSemaphoreEmmc,0);
}
if(semRet==pdPASS){
      #ifdef EMMC_USE_DMA
          if(HAL_OK == HAL_MMC_WriteBlocks_DMA(&hmmc1, (uint8_t *)buf, blk_addr , blk_len))
          {
               while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
               ret = USBD_OK;
          }
      #else
          if(HAL_OK == HAL_MMC_WriteBlocks(&hmmc1, (uint8_t *)buf, blk_addr , blk_len,0XFF))
          {
               while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
               ret = USBD_OK;
          }
      #endif
          xSemaphoreGiveFromISR(xSemaphoreEmmc,pdFALSE);
}
return ret;
/* USER CODE END 7 */
}

/**
* @briefReturns the Max Supported LUNs.
* @paramNone
* @retval Lun(s) number.
*/
int8_t STORAGE_GetMaxLun_FS(void)
{
/* USER CODE BEGIN 8 */
return (STORAGE_LUN_NBR - 1);
/* USER CODE END 8 */
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/**
* @}
*/

/**
* @}
*/

到这里USB MSC的驱动就改完了,插上USB看看,能不能驱动;


在电脑端显示为G盘,首先进行格式化,格式化后看到大小为4GB,与板子上EMMC容量大小一致,然后测试读写是否正常,直接在G盘中新建txt,输入内容保存再打开,显示没问题,说明读写正常;
4、添加文件系统
能把视屏文件存入EMMC了,现在还差文件系统读取视屏文件内容,添加FATFS文件系统,模式选择User-defined,将Code_page改成DBCS;

4、修改文件系统驱动代码这里面需要注意的是任务同步,因为USB驱动里面用EMMC的读写,fatfa也要用EMMC的读写,所以要做任务同步,这里千万不能用互斥体,因为FREERTOS的互斥体
是会自动调节任务优先级的,设计初衷是为了防止低优先级的任务占用锁但是得不到执行,高优先级的任务等锁产生死锁,而且互斥体不能用在中断中;而USB MSC驱动其实是中断执行的,所以要用信号量来完成;代码改写主要就是下面这几个函数

修改的相关代码都贴出来/**
* @brief SDMMC1 Initialization Function
* @param None
* @retval None
*/
static void MX_SDMMC1_MMC_Init(void)
{

/* USER CODE BEGIN SDMMC1_Init 0 */

/* USER CODE END SDMMC1_Init 0 */

/* USER CODE BEGIN SDMMC1_Init 1 */

/* USER CODE END SDMMC1_Init 1 */
hmmc1.Instance = SDMMC1;
hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hmmc1.Init.BusWide = SDMMC_BUS_WIDE_1B;
hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hmmc1.Init.ClockDiv = 4;
if (HAL_MMC_Init(&hmmc1) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN SDMMC1_Init 2 */
xSemaphoreEmmc = xSemaphoreCreateBinary();
if(xSemaphoreEmmc==NULL){
      Error_Handler();
}else{
      xSemaphoreGive(xSemaphoreEmmc);
}

/* USER CODE END SDMMC1_Init 2 */

}

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file    user_diskio.c
* @brief   This file includes a diskio driver skeleton to be completed by the user.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */

#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
/*
* Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
* To be suppressed in the future.
* Kept to ensure backward compatibility with previous CubeMx versions when
* migrating projects.
* User code previously added there should be copied in the new user sections before
* the section contents can be deleted.
*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
#endif

/* USER CODE BEGIN DECL */

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "ff_gen_drv.h"
#include "stm32h7xx_hal.h"
#include "semphr.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define EMMC_TIMEOUT 1000
/* Private variables ---------------------------------------------------------*/
extern SemaphoreHandle_t xSemaphoreEmmc;
extern MMC_HandleTypeDef hmmc1;
extern uint8_twrite_flag, read_flag;
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;
/* USER CODE END DECL */

/* Private function prototypes -----------------------------------------------*/
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */

Diskio_drvTypeDefUSER_Driver =
{
USER_initialize,
USER_status,
USER_read,
#if_USE_WRITE
USER_write,
#endif/* _USE_WRITE == 1 */
#if_USE_IOCTL == 1
USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};

/* Private functions ---------------------------------------------------------*/

/**
* @briefInitializes a Drive
* @parampdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
DSTATUS USER_initialize (
      BYTE pdrv         /* Physical drive nmuber to identify the drive */
)
{
/* USER CODE BEGIN INIT */
    Stat = STA_NOINIT;
    if (HAL_MMC_Init(&hmmc1) == HAL_OK){
            Stat &= ~STA_NOINIT;
    }
    return Stat;
/* USER CODE END INIT */
}

/**
* @briefGets Disk Status
* @parampdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
DSTATUS USER_status (
      BYTE pdrv       /* Physical drive number to identify the drive */
)
{
/* USER CODE BEGIN STATUS */
    Stat = STA_NOINIT;
    if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER )
    {
      Stat &= ~STA_NOINIT;
    }
    return Stat;
/* USER CODE END STATUS */
}

/**
* @briefReads Sector(s)
* @parampdrv: Physical drive number (0..)
* @param*buff: Data buffer to store read data
* @paramsector: Sector address (LBA)
* @paramcount: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
DRESULT USER_read (
      BYTE pdrv,      /* Physical drive nmuber to identify the drive */
      BYTE *buff,   /* Data buffer to store read data */
      DWORD sector,   /* Sector address in LBA */
      UINT count      /* Number of sectors to read */
)
{
/* USER CODE BEGIN READ */
   DRESULT ret = RES_ERROR;
   BaseType_t semRet = pdFAIL;
   if(xSemaphoreEmmc!=NULL){
         semRet = xSemaphoreTake(xSemaphoreEmmc,portMAX_DELAY);
   }
   if(semRet==pdPASS){
   #ifdef EMMC_USE_DMA
         uint32_t timeout;
         uint32_t alignedAddr;
         alignedAddr = (uint32_t)buff & ~0x1F;
         SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*MMC_BLOCKSIZE + ((uint32_t)buff - alignedAddr));
         if(HAL_MMC_ReadBlocks_DMA(&hmmc1, (uint8_t*)buff,
                                                                (uint32_t) (sector),
                                                               count) == HAL_OK)
         {

                  /* Wait that the reading process is completed or a timeout occurs */
                  timeout = HAL_GetTick();
                  while((read_flag == 0) && ((HAL_GetTick() - timeout) < EMMC_TIMEOUT));
                  /* incase of a timeout return error */
                  if (read_flag == 0)
                  {
                        ret = RES_ERROR;
                  }
                  else
                  {
                        read_flag = 0;
                        timeout = HAL_GetTick();
                        while((HAL_GetTick() - timeout) < EMMC_TIMEOUT)
                        {
                        if (HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)
                        {
                              ret = RES_OK;
                              SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*MMC_BLOCKSIZE + ((uint32_t)buff - alignedAddr));
                              break;
                        }
                        }
                  }
                }
      #else
                if(HAL_MMC_ReadBlocks(&hmmc1, (uint8_t*)buff,
                                                               (uint32_t) (sector),
                                                                  count,EMMC_TIMEOUT) == HAL_OK)
                {
                        while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
                        ret = RES_OK;
                }
      #endif
                xSemaphoreGive(xSemaphoreEmmc);
   }
   return ret;
/* USER CODE END READ */
}

/**
* @briefWrites Sector(s)
* @parampdrv: Physical drive number (0..)
* @param*buff: Data to be written
* @paramsector: Sector address (LBA)
* @paramcount: Number of sectors to write (1..128)
* @retval DRESULT: Operation result
*/
#if _USE_WRITE == 1
DRESULT USER_write (
      BYTE pdrv,          /* Physical drive nmuber to identify the drive */
      const BYTE *buff,   /* Data to be written */
      DWORD sector,       /* Sector address in LBA */
      UINT count          /* Number of sectors to write */
)
{
/* USER CODE BEGIN WRITE */
/* USER CODE HERE */
      DRESULT ret = RES_ERROR;
    BaseType_t semRet = pdFAIL;
    if(xSemaphoreEmmc!=NULL){
            semRet = xSemaphoreTake(xSemaphoreEmmc,portMAX_DELAY);
    }
    if(semRet==pdPASS){
      #ifdef EMMC_USE_DMA
         uint32_t alignedAddr;
         uint32_t timeout;

         alignedAddr = (uint32_t)buff & ~0x1F;
                SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*MMC_BLOCKSIZE + ((uint32_t)buff - alignedAddr));
                if(HAL_MMC_WriteBlocks_DMA(&hmmc1, (uint8_t*)buff,
                                                               (uint32_t) (sector),
                                                               count) == HAL_OK)
                {
                        /* Wait that the reading process is completed or a timeout occurs */
                  timeout = HAL_GetTick();
                  while((write_flag == 0) && ((HAL_GetTick() - timeout) < EMMC_TIMEOUT));
                  /* incase of a timeout return error */
                  if (write_flag == 0)
                  {
                        ret = RES_ERROR;
                  }
                  else
                  {
                        write_flag = 0;
                        timeout = HAL_GetTick();
                        while((HAL_GetTick() - timeout) < EMMC_TIMEOUT)
                        {
                        if (HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)
                        {
                              ret = RES_OK;
                              SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*MMC_BLOCKSIZE + ((uint32_t)buff - alignedAddr));
                              break;
                        }
                        }
                  }
                }

      #else
                if(HAL_MMC_WriteBlocks(&hmmc1, (uint8_t*)buff,
                                                               (uint32_t) (sector),
                                                                  count,EMMC_TIMEOUT) == HAL_OK)
                {
                        while(HAL_MMC_GetCardState(&hmmc1)!=HAL_MMC_CARD_TRANSFER);
                        ret = RES_OK;
                }
      #endif
                xSemaphoreGive(xSemaphoreEmmc);
    }
      return ret;
/* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */

/**
* @briefI/O control operation
* @parampdrv: Physical drive number (0..)
* @paramcmd: Control code
* @param*buff: Buffer to send/receive control data
* @retval DRESULT: Operation result
*/
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
      BYTE pdrv,      /* Physical drive nmuber (0..) */
      BYTE cmd,       /* Control code */
      void *buff      /* Buffer to send/receive control data */
)
{
/* USER CODE BEGIN IOCTL */
    DRESULT res = RES_ERROR;
    HAL_MMC_CardInfoTypeDef emmcinfo;

    switch(cmd)
      {
                case CTRL_SYNC:
                        res = RES_OK;
                        break;
                case GET_SECTOR_SIZE:
                        *(WORD*)buff = 512;
                        res = RES_OK;
                        break;
                case GET_BLOCK_SIZE:
                        *(WORD*)buff = 8;
                        res = RES_OK;
                        break;
                case GET_SECTOR_COUNT:
                        HAL_MMC_GetCardInfo(&hmmc1,&emmcinfo);
                        *(WORD*)buff = emmcinfo.BlockNbr;
                        res = RES_OK;
                        break;
                default:
                        break;
      }
    return res;
/* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */

到此存储加读取部分工作完成;二、视屏播放接口驱动
1、使用LIBJPEG解码库
使用LIBJPEG解码库解码视屏压缩文件;

2、添加DMA2D支持



3、驱动代码修改
整个 代码依据的还是TOUCHGFX框架,这个框架是用C++写的,要熟系C++命名空间的语法,不然看着会很头晕,沥青不算特别复杂,挑重要的相关步骤贴一下从初始化入口
void touchgfx_init()
{
    Bitmap::registerBitmapDatabase(BitmapDatabase::getInstance(), BitmapDatabase::getInstanceSize());
    TypedText::registerTexts(&texts);
    Texts::setLanguage(0);

    FontManager::setFontProvider(&fontProvider);

    FrontendHeap& heap = FrontendHeap::getInstance();
    /*
   * we need to obtain the reference above to initialize the frontend heap.
   */
    (void)heap;

    /*
   * Initialize TouchGFX
   */
    hal.initialize();
}TouchGFX初始化,初始化解码器
void TouchGFXHAL::initialize()
{
    // Calling parent implementation of initialize().
    //
    // To overwrite the generated implementation, omit call to parent function
    // and implemented needed functionality here.
    // Please note, HAL::initialize() must be called to initialize the framework.

    TouchGFXGeneratedHAL::initialize();
    setFrameBufferStartAddresses((void*)frameBuffer0, (void*)frameBuffer1, (void*)animationBuffer);
    instrumentation.init();
    setMCUInstrumentation(&instrumentation);
    enableMCULoadCalculation(true);
}void TouchGFXGeneratedHAL::initialize()
{
    HAL::initialize();
    registerEventListener(*(Application::getInstance()));
    setFrameBufferStartAddresses((void*)frameBuf, (void*)(frameBuf + sizeof(frameBuf) / (sizeof(uint32_t) * 2)), (void*)0);

    /*
   * Add DMA2D to hardware decoder
   */
    mjpegdecoder1.addDMA(dma);

    /*
   * Add hardware decoder to video controller
   */
    videoController.addDecoder(mjpegdecoder1, 0);
    videoController.setRGBBuffer((uint8_t*)videoRGBBuffer, sizeof(videoRGBBuffer));
}
控件相关在mainvewbase里面MainViewBase::MainViewBase() :
    buttonCallback(this, &MainViewBase::buttonCallbackHandler)
{
    __background.setPosition(0, 0, 480, 272);
    __background.setColor(touchgfx::Color::getColorFromRGB(0, 0, 0));
    add(__background);

    backgorund.setXY(0, 0);
    backgorund.setBitmap(touchgfx::Bitmap(BITMAP_BACKGROUND_ID));
    add(backgorund);

    video.setPosition(132, 4, 216, 216);
    video.setVideoData(video_SampleVideo2_216x216_bin_start, video_SampleVideo2_216x216_bin_length);
    video.setRepeat(true);
    video.play();
    add(video);

    play.setXY(170, 230);
    play.setBitmaps(touchgfx::Bitmap(BITMAP_BUTTON_PLAY_PINK_ID), touchgfx::Bitmap(BITMAP_BUTTON_PLAY_WHITE_ID));
    play.setAction(buttonCallback);
    add(play);

    pause.setXY(278, 230);
    pause.setBitmaps(touchgfx::Bitmap(BITMAP_BUTTON_PAUSE_PINK_ID), touchgfx::Bitmap(BITMAP_BUTTON_PAUSE_WHITE_ID));
    pause.setAction(buttonCallback);
    add(pause);
}到这里video.setVideoData(video_SampleVideo2_216x216_bin_start, video_SampleVideo2_216x216_bin_length);这个函数就是这只播放数据的,这个是内置flash的播放数据,小视屏可放在flash里直接播放,但是大文件的是不可能放在flash里面的,我们要进行改写,这里面用C++的重载特性,函数名不变,改变形参,调用的时候根据形参确定执行哪个函数;



   

506787841 发表于 2023-5-16 17:17

你好,usb驱动那部分,我使用不带DMA的才能在电脑上显示出来,困扰好几天了,可以看看你的工程吗,
帮帮孩子吧,不胜感激!QQ:506787841

daichaodai 发表于 2023-5-16 20:07

不错,牛人啊。

Pretext 发表于 2023-5-18 14:43

有视频播放的视频吗?想看看播放效果。

天天向善 发表于 2023-5-18 14:44

一看楼主这代码量,就知道楼主撸了很久的代码。
页: [1]
查看完整版本: [STM32H7] [STM32H7] STM32H750B-DK TouchGFX 测评——视频播放