本帖最后由 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、USB MSC驱动代码修改调试
改过SD开驱动的应该都比较熟悉,这里我们直接找到usbd_storage_if.c文件,改写下图中的这些函数,代码下面也贴出,改写的时候主要的是要把自己添加的代码写到“恰当的位置”,不然如果你修改CUBMUX的配置,你辛辛苦苦添加的代码就会消失不见了,我也是刚开始使用cubide,在这上面吃了点小亏;
/* USER CODE BEGIN Header */
/**
******************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url] : usbd_storage_if.c
* [url=home.php?mod=space&uid=895143]@version[/url] : v1.0_Cube
* [url=home.php?mod=space&uid=247401]@brief[/url] : 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
* [url=home.php?mod=space&uid=247401]@brief[/url] Usb device.
* @{
*/
/** @defgroup USBD_STORAGE
* [url=home.php?mod=space&uid=247401]@brief[/url] Usb mass storage device module
* @{
*/
/** @defgroup USBD_STORAGE_Private_TypesDefinitions
* [url=home.php?mod=space&uid=247401]@brief[/url] Private types.
* @{
*/
/* USER CODE BEGIN PRIVATE_TYPES */
/* USER CODE END PRIVATE_TYPES */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Private_Defines
* [url=home.php?mod=space&uid=247401]@brief[/url] 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
* [url=home.php?mod=space&uid=247401]@brief[/url] Private macros.
* @{
*/
/* USER CODE BEGIN PRIVATE_MACRO */
/* USER CODE END PRIVATE_MACRO */
/**
* @}
*/
/** @defgroup USBD_STORAGE_Private_Variables
* [url=home.php?mod=space&uid=247401]@brief[/url] 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 */
volatile uint8_t write_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 ---------------------------------------------------------*/
/**
* @brief Initializes the storage unit (medium) over USB FS IP
* @param lun: 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 */
}
/**
* @brief Returns the medium capacity.
* @param lun: Logical unit number.
* @param block_num: Number of total block number.
* @param block_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.
* @param lun: 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 */
}
/**
* @brief Checks whether the medium is write protected.
* @param lun: 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 */
}
/**
* @brief Reads data from the medium.
* @param lun: Logical unit number.
* @param buf: data buffer.
* @param blk_addr: Logical block address.
* @param blk_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 */
}
/**
* @brief Writes data into the medium.
* @param lun: Logical unit number.
* @param buf: data buffer.
* @param blk_addr: Logical block address.
* @param blk_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 */
}
/**
* @brief Returns the Max Supported LUNs.
* @param None
* @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 */
/**
******************************************************************************
* [url=home.php?mod=space&uid=288409]@file[/url] 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_t write_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_drvTypeDef USER_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 ---------------------------------------------------------*/
/**
* @brief Initializes a Drive
* @param pdrv: 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 */
}
/**
* @brief Gets Disk Status
* @param pdrv: 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 */
}
/**
* @brief Reads Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data buffer to store read data
* @param sector: Sector address (LBA)
* @param count: 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 */
}
/**
* @brief Writes Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data to be written
* @param sector: Sector address (LBA)
* @param count: 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 */
/**
* @brief I/O control operation
* @param pdrv: Physical drive number (0..)
* @param cmd: 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++的重载特性,函数名不变,改变形参,调用的时候根据形参确定执行哪个函数;
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
|