|
最近用STM32H743做一个音乐频谱,驱动一个1024x600的RGB屏,目前全屏刷新可以有30~50帧;
最近在加一些动画,想着在一个图层上用双缓存更新刷屏,但是开了行中断后,外面的代码就运行不了,
中断分组2,LTDC中断为(3,3)。
网上搜了一番,大多仅是介绍或者提及,目前还没看到实际在H7应用这种LTDC双缓存,是不好用吗?
以下是伪代码:
#include "main.h"
#include "stm32h7xx_hal.h"
/* 定义显示缓冲区大小 */
#define BUFFER_WIDTH 800
#define BUFFER_HEIGHT 480
#define PIXEL_FORMAT LTDC_PIXEL_FORMAT_RGB565
#define PIXEL_SIZE 2 /* RGB565每像素2字节 */
/* 定义两个显示缓冲区 */
uint8_t displayBuffer1[BUFFER_WIDTH * BUFFER_HEIGHT * PIXEL_SIZE] __attribute__((aligned(32)));
uint8_t displayBuffer2[BUFFER_WIDTH * BUFFER_HEIGHT * PIXEL_SIZE] __attribute__((aligned(32)));
/* 当前活动缓冲区指针 */
uint8_t* activeBuffer = displayBuffer1;
uint8_t* drawingBuffer = displayBuffer2;
/* 缓冲区切换标志 */
volatile bool bufferReady = false;
/* 外设句柄声明 */
LTDC_HandleTypeDef hltdc;
DMA2D_HandleTypeDef hdma2d;
SDRAM_HandleTypeDef hsdram1;
/* 函数声明 */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_LTDC_Init(void);
static void MX_DMA2D_Init(void);
static void MX_FMC_Init(void);
void HAL_LTDC_FrameEventCallback(LTDC_HandleTypeDef *hltdc);
void drawTestPattern(uint8_t* buffer);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_FMC_Init(); /* 初始化SDRAM */
MX_LTDC_Init(); /* 初始化LTDC */
MX_DMA2D_Init(); /* 初始化DMA2D用于加速图形操作 */
/* 初始化缓冲区内容 */
drawTestPattern(displayBuffer1);
drawTestPattern(displayBuffer2);
/* 设置初始活动缓冲区 */
hltdc.LayerCfg[0].FBStartAdress = (uint32_t)displayBuffer1;
HAL_LTDC_ConfigLayer(&hltdc, &hltdc.LayerCfg[0], 0);
/* 启用LTDC */
HAL_LTDC_Enable(&hltdc);
/* 设置LTDC帧更新中断优先级 */
HAL_NVIC_SetPriority(LTDC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(LTDC_IRQn);
/* 启用LTDC帧更新中断 */
__HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_FU);
while (1)
{
/* 绘制到后台缓冲区 */
drawTestPattern(drawingBuffer);
/* 标记缓冲区准备好切换 */
bufferReady = true;
/* 等待垂直同步事件处理完成 */
while(bufferReady);
/* 延时一段时间 */
HAL_Delay(1000);
}
}
void drawTestPattern(uint8_t* buffer)
{
/* 使用DMA2D加速填充渐变图案 */
hdma2d.Init.Mode = DMA2D_R2M;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
hdma2d.Init.OutputOffset = BUFFER_WIDTH - BUFFER_WIDTH;
hdma2d.XferSize = BUFFER_WIDTH * BUFFER_HEIGHT;
hdma2d.DestAddress = (uint32_t)buffer;
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
{
Error_Handler();
}
/* 设置前景色为蓝色 */
__HAL_DMA2D_SET_FOREGROUND_COLOR(&hdma2d, 0x001F);
if (HAL_DMA2D_Start(&hdma2d) != HAL_OK)
{
Error_Handler();
}
/* 等待DMA2D传输完成 */
HAL_DMA2D_PollForTransfer(&hdma2d, 100);
}
void HAL_LTDC_FrameEventCallback(LTDC_HandleTypeDef *hltdc)
{
/* 帧更新事件回调(替代垂直同步) */
if(bufferReady)
{
/* 交换前后台缓冲区 */
uint8_t* temp = activeBuffer;
activeBuffer = drawingBuffer;
drawingBuffer = temp;
/* 更新LTDC指向新的活动缓冲区 */
hltdc->LayerCfg[0].FBStartAdress = (uint32_t)activeBuffer;
HAL_LTDC_ConfigLayer(hltdc, &hltdc->LayerCfg[0], 0);
/* 清除缓冲区准备标志 */
bufferReady = false;
}
}
/* 系统时钟配置函数 */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** 初始化RCC振荡器
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 160;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** 初始化RCC时钟
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D1PCLK1|RCC_CLOCKTYPE_D3PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
/** 初始化外设时钟
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC|RCC_PERIPHCLK_FMC;
PeriphClkInitStruct.PLL2.PLL2M = 2;
PeriphClkInitStruct.PLL2.PLL2N = 25;
PeriphClkInitStruct.PLL2.PLL2P = 2;
PeriphClkInitStruct.PLL2.PLL2Q = 2;
PeriphClkInitStruct.PLL2.PLL2R = 2;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_D1HCLK;
PeriphClkInitStruct.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;
PeriphClkInitStruct.PLL3.PLL3M = 4;
PeriphClkInitStruct.PLL3.PLL3N = 24;
PeriphClkInitStruct.PLL3.PLL3P = 2;
PeriphClkInitStruct.PLL3.PLL3Q = 2;
PeriphClkInitStruct.PLL3.PLL3R = 2;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_3;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
}
/* LTDC初始化函数 */
static void MX_LTDC_Init(void)
{
LTDC_LayerCfgTypeDef pLayerCfg = {0};
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = 40;
hltdc.Init.VerticalSync = 9;
hltdc.Init.AccumulatedHBP = 88;
hltdc.Init.AccumulatedVBP = 32;
hltdc.Init.AccumulatedActiveW = 888;
hltdc.Init.AccumulatedActiveH = 512;
hltdc.Init.TotalWidth = 910;
hltdc.Init.TotalHeigh = 525;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = BUFFER_WIDTH;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = BUFFER_HEIGHT;
pLayerCfg.PixelFormat = PIXEL_FORMAT;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
pLayerCfg.FBStartAdress = (uint32_t)displayBuffer1;
pLayerCfg.ImageWidth = BUFFER_WIDTH;
pLayerCfg.ImageHeight = BUFFER_HEIGHT;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
}
/* DMA2D初始化函数 */
static void MX_DMA2D_Init(void)
{
hdma2d.Instance = DMA2D;
hdma2d.Init.Mode = DMA2D_M2M;
hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB565;
hdma2d.Init.OutputOffset = 0;
if (HAL_DMA2D_Init(&hdma2d) != HAL_OK)
{
Error_Handler();
}
}
/* FMC初始化函数 */
static void MX_FMC_Init(void)
{
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
hsdram1.Instance = FMC_SDRAM_DEVICE;
hsdram1.Init.SDBank = FMC_SDRAM_BANK2;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 4;
SdramTiming.RowCycleDelay = 7;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler();
}
/* 配置SDRAM时序参数 */
__IO uint32_t tmpmrd = 0;
/* 发送SDRAM初始化序列 */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
/* 发送SDRAM模式寄存器配置命令 */
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0x1000);
}
/* GPIO初始化函数 */
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOJ_CLK_ENABLE();
__HAL_RCC_GPIOK_CLK_ENABLE();
/* 配置所有LTDC和FMC相关的GPIO引脚 */
/* 此处省略具体GPIO配置,实际应用中需要根据硬件连接配置 */
}
|
|