64帧!STM32F407VET6 FSMC刷新9341屏幕(Arm2D)
之前搞过一次SPI刷新ILI9341的屏幕,但是感觉还是不太够看,SPI的带宽上限还是差点意思,于是整了一块FSMC接口的屏幕玩玩,发现效果还真就不错,于是开源分享一下。
设备STM32F407VET6 ILI9341屏幕
引脚连接
PE7 ------> FSMC_D4
PE8 ------> FSMC_D5
PE9 ------> FSMC_D6
PE10 ------> FSMC_D7
PE11 ------> FSMC_D8
PE12 ------> FSMC_D9
PE13 ------> FSMC_D10
PE14 ------> FSMC_D11
PE15 ------> FSMC_D12
PD8 ------> FSMC_D13
PD9 ------> FSMC_D14
PD10 ------> FSMC_D15
PD11 ------> FSMC_A16
PD14 ------> FSMC_D0
PD15 ------> FSMC_D1
PD0 ------> FSMC_D2
PD1 ------> FSMC_D3
PD4 ------> FSMC_NOE 输出使能
PD5 ------> FSMC_NWE 写使能
PD7 ------> FSMC_NE1 片选信号
PD6 ------> GPIO_OUTPUT
PD12 ------> GPIO_OUTPUT
CubeMX 图形配置
-
启用 FSMC
▸ Pinout → FSMC → “NE1” → Type = LCD;数据宽度 16 bit,
▸ GPIO配置OUTPUT,这里的背光用的PD12,复位用的PD6。 -
把 LCD 的“RS”脚接在 FSMC 地址线上(常用 A16)
这样 LCD 的 寄存器地址 =0x6000 0000,GRAM 地址 =0x6002 0000(A16=1)。 -
打开 DMA2,任意一条空闲 Stream
▸ 模式:Memory-to-Memory
▸ 数据宽度:Half-Word(16 bit)
▸ 源地址递增,目标地址 固定(FSMC 映射地址 0x6002 0000)
▸ Burst 可设 INCR8,FIFO 全开,优先级 High
▸ 开启 DMA 中断。 -
时钟配置168Mhz,堆栈拉到0X2000(少点其实也够)然后生成工程

Address Setup Time是地址建立时间,确保地址信号提前稳定;Data Setup Time是数据读取时的等待时间,保证数据被正确采样;Bus Turn-Around Time则是防止总线冲突,尤其在读写切换时。这里直接配置1,2,1足够了。


然后配置ARM2D,可以参考之前发过的这篇文章:STM32 ILI9341屏幕(HAL库)Arm-2D框架_stm32+ili9341-CSDN博客
#ifndef __LCD_H
#define __LCD_H
#include "stm32f4xx.h"
#include "stdlib.h"
#ifndef u8
#define u8 uint8_t
#endif
#ifndef u16
#define u16 uint16_t
#endif
#ifndef u32
#define u32 uint32_t
#endif
//LCD重要参数集
typedef struct
{
u16 width; //LCD 宽度
u16 height; //LCD 高度
u16 id; //LCD ID
u8 dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
u16 wramcmd; //开始写gram指令
u16 setxcmd; //设置x坐标指令
u16 setycmd; //设置y坐标指令
}_lcd_dev;
//LCD参数
extern _lcd_dev lcddev; //管理LCD重要参数
/////////////////////////////////////用户配置区///////////////////////////////////
#define USE_HORIZONTAL 1//定义液晶屏顺时针旋转方向 0-0度旋转,1-90度旋转,2-180度旋转,3-270度旋转
//////////////////////////////////////////////////////////////////////////////////
//定义LCD的尺寸
#define LCD_W 240
#define LCD_H 320
//TFTLCD部分外要调用的函数
extern u16 POINT_COLOR;//默认红色
extern u16 BACK_COLOR; //背景颜色.默认为白色
//-----------------LCD端口定义----------------
////QDtech全系列模块采用了三极管控制背光亮灭,用户也可以接PWM调节背光亮度
#define LCD_LED_SET HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET) //LCD背光
//GPIO置位(拉高)
#define LCD_CS_SET ((void)0) //FSMC模式无需手动片选
#define LCD_RS_SET ((void)0) //FSMC模式由地址线控制
#define LCD_RST_SET HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET) //复位
//GPIO复位(拉低)
#define LCD_CS_CLR ((void)0) //FSMC模式无需手动片选
#define LCD_RS_CLR ((void)0) //FSMC模式由地址线控制
#define LCD_RST_CLR HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET) //复位
// FSMC 映射:NE1, A16 作为寄存器/数据选择
#define TFTLCD_BASE ((uint32_t)(0x60000000U))
#define TFTLCD_REG (*((volatile uint16_t *)(TFTLCD_BASE)))
#define TFTLCD_RAM (*((volatile uint16_t *)(TFTLCD_BASE | 0x00020000U)))
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
//GUI颜色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
//以上三色为PANEL的颜色
#define LIGHTGREEN 0X841F //浅绿色
#define LIGHTGRAY 0XEF5B //浅灰色(PANNEL)
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
void LCD_Init(void);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);
void LCD_Clear(u16 Color);
void LCD_SetCursor(u16 Xpos, u16 Ypos);
void LCD_DrawPoint(u16 x,u16 y);//画点
u16 LCD_ReadPoint(u16 x,u16 y); //读点
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);
u16 LCD_RD_DATA(void);//读取LCD数据
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
void LCD_WR_DATA(u8 data);
u16 LCD_ReadReg(u8 LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);
u16 LCD_ReadRAM(void);
u16 LCD_BGR2RGB(u16 c);
void LCD_SetParam(void);
void Lcd_WriteData_16Bit(u16 Data);
void LCD_direction(u8 direction );
int32_t Disp0_DrawBitmap(int16_t x, int16_t y,
int16_t w, int16_t h,
const uint16_t *rgb565);
#endif
#include "lcd.h"
#include "stdlib.h"
#include "main.h"
#include "dma.h"
#define u8 uint8_t
#define u16 uint16_t
//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;
//画笔颜色,背景颜色
u16 POINT_COLOR = 0x0000,BACK_COLOR = 0xFFFF;
u16 DeviceCode;
/*****************************************************************************
* @name :void LCD_WR_REG(u8 data)
* @date :2018-08-09
* @function :Write an 8-bit command to the LCD screen
* @parameters :data:Command value to be written
* @retvalue :None
******************************************************************************/
void LCD_WR_REG(u8 data)
{
// FSMC模式下:写寄存器地址到 A16=0 区域
TFTLCD_REG = (uint16_t)data;
}
/*****************************************************************************
* @name :void LCD_WR_DATA(u8 data)
* @date :2018-08-09
* @function :Write an 8-bit data to the LCD screen
* @parameters :data:data value to be written
* @retvalue :None
******************************************************************************/
void LCD_WR_DATA(u8 data)
{
// FSMC模式下:写数据到 A16=1 区域
TFTLCD_RAM = (uint16_t)data;
}
/*****************************************************************************
* @name :void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
* @date :2018-08-09
* @function :Write data into registers
* @parameters :LCD_Reg:Register address
LCD_RegValue:Data to be written
* @retvalue :None
******************************************************************************/
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_WR_DATA(LCD_RegValue);
}
/*****************************************************************************
* @name :void LCD_WriteRAM_Prepare(void)
* @date :2018-08-09
* @function :Write GRAM
* @parameters :None
* @retvalue :None
******************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
LCD_WR_REG(lcddev.wramcmd);
}
/*****************************************************************************
* @name :void Lcd_WriteData_16Bit(u16 Data)
* @date :2018-08-09
* @function :Write an 16-bit command to the LCD screen
* @parameters :Data:Data to be written
* @retvalue :None
******************************************************************************/
void Lcd_WriteData_16Bit(u16 Data)
{
TFTLCD_RAM = Data;
}
/*****************************************************************************
* @name :void LCD_DrawPoint(u16 x,u16 y)
* @date :2018-08-09
* @function :Write a pixel data at a specified location
* @parameters :x:the x coordinate of the pixel
y:the y coordinate of the pixel
* @retvalue :None
******************************************************************************/
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetCursor(x,y);//设置光标位置
Lcd_WriteData_16Bit(POINT_COLOR);
}
/*****************************************************************************
* @name :void LCD_Clear(u16 Color)
* @date :2018-08-09
* @function :Full screen filled LCD screen
* @parameters :color:Filled color
* @retvalue :None
******************************************************************************/
void LCD_Clear(u16 Color)
{
unsigned int i,m;
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);
LCD_CS_CLR;
LCD_RS_SET;
for(i=0;i<lcddev.height;i++)
{
for(m=0;m<lcddev.width;m++)
{
Lcd_WriteData_16Bit(Color);
}
}
LCD_CS_SET;
}
void LCD_RESET(void)
{
LCD_RST_CLR;
HAL_Delay(100);
LCD_RST_SET;
HAL_Delay(50);
}
/*****************************************************************************
* @name :void LCD_RESET(void)
* @date :2018-08-09
* @function :Initialization LCD screen
* @parameters :None
* @retvalue :None
******************************************************************************/
void LCD_Init(void)
{
LCD_RESET(); //LCD 复位
//*************2.8inch ILI9341初始化**********//
LCD_WR_REG(0xCF);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0xC9); //C1
LCD_WR_DATA(0X30);
LCD_WR_REG(0xED);
LCD_WR_DATA(0x64);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0X12);
LCD_WR_DATA(0X81);
LCD_WR_REG(0xE8);
LCD_WR_DATA(0x85);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x7A);
LCD_WR_REG(0xCB);
LCD_WR_DATA(0x39);
LCD_WR_DATA(0x2C);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x34);
LCD_WR_DATA(0x02);
LCD_WR_REG(0xF7);
LCD_WR_DATA(0x20);
LCD_WR_REG(0xEA);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xC0); //Power control
LCD_WR_DATA(0x1B); //VRH[5:0]
LCD_WR_REG(0xC1); //Power control
LCD_WR_DATA(0x00); //SAP[2:0];BT[3:0] 01
LCD_WR_REG(0xC5); //VCM control
LCD_WR_DATA(0x30); //3F
LCD_WR_DATA(0x30); //3C
LCD_WR_REG(0xC7); //VCM control2
LCD_WR_DATA(0XB7);
LCD_WR_REG(0x36); // Memory Access Control
LCD_WR_DATA(0x08);
LCD_WR_REG(0x3A);
LCD_WR_DATA(0x55);
LCD_WR_REG(0xB1);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x1A);
LCD_WR_REG(0xB6); // Display Function Control
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0xA2);
LCD_WR_REG(0xF2); // 3Gamma Function Disable
LCD_WR_DATA(0x00);
LCD_WR_REG(0x26); //Gamma curve selected
LCD_WR_DATA(0x01);
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x2A);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x0E);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x54);
LCD_WR_DATA(0XA9);
LCD_WR_DATA(0x43);
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_REG(0XE1); //Set Gamma
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x15);
LCD_WR_DATA(0x17);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x2B);
LCD_WR_DATA(0x56);
LCD_WR_DATA(0x3C);
LCD_WR_DATA(0x05);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x3F);
LCD_WR_DATA(0x3F);
LCD_WR_DATA(0x0F);
LCD_WR_REG(0x2B);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x3f);
LCD_WR_REG(0x2A);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0xef);
LCD_WR_REG(0x11); //Exit Sleep
HAL_Delay(120);
LCD_WR_REG(0x29); //display on
LCD_direction(USE_HORIZONTAL);//设置LCD显示方向
LCD_LED_SET;//点亮背光
LCD_Clear(WHITE);//清全屏白色
}
/*****************************************************************************
* @name :void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
* @date :2018-08-09
* @function :Setting LCD display window
* @parameters :xStar:the bebinning x coordinate of the LCD display window
yStar:the bebinning y coordinate of the LCD display window
xEnd:the endning x coordinate of the LCD display window
yEnd:the endning y coordinate of the LCD display window
* @retvalue :None
******************************************************************************/
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(xStar>>8);
LCD_WR_DATA(0x00FF&xStar);
LCD_WR_DATA(xEnd>>8);
LCD_WR_DATA(0x00FF&xEnd);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(yStar>>8);
LCD_WR_DATA(0x00FF&yStar);
LCD_WR_DATA(yEnd>>8);
LCD_WR_DATA(0x00FF&yEnd);
LCD_WriteRAM_Prepare(); //开始写入GRAM
}
/*****************************************************************************
* @name :void LCD_SetCursor(u16 Xpos, u16 Ypos)
* @date :2018-08-09
* @function :Set coordinate value
* @parameters :Xpos:the x coordinate of the pixel
Ypos:the y coordinate of the pixel
* @retvalue :None
******************************************************************************/
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);
}
/*****************************************************************************
* @name :void LCD_direction(u8 direction)
* @date :2018-08-09
* @function :Setting the display direction of LCD screen
* @parameters :direction:0-0 degree
1-90 degree
2-180 degree
3-270 degree
* @retvalue :None
******************************************************************************/
void LCD_direction(u8 direction)
{
lcddev.setxcmd=0x2A;
lcddev.setycmd=0x2B;
lcddev.wramcmd=0x2C;
switch(direction){
case 0:
lcddev.width=LCD_W;
lcddev.height=LCD_H;
LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0
break;
case 1:
lcddev.width=LCD_H;
lcddev.height=LCD_W;
LCD_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
break;
case 2:
lcddev.width=LCD_W;
lcddev.height=LCD_H;
LCD_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0
break;
case 3:
lcddev.width=LCD_H;
lcddev.height=LCD_W;
LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
break;
default:break;
}
}
到这一步其实屏幕可以正常驱动了,还没有用到ARM2D,LCD驱动是根据最早那篇博客修改的,主要就是读写底层逻辑改了一下,比我想象的还要简单。
一、无DMA算法
main.c的主体部分在三个算法中一样。
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "perf_counter.h"
#include "arm_2d.h"
#include "arm_2d_disp_adapter_0.h"
#include "arm_2d_helper.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_FSMC_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
perfc_init(true);
arm_irq_safe {
arm_2d_init();
}
disp_adapter0_init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
disp_adapter0_task();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

此处需要在disp_adapter_0.h关闭异步刷新
int32_t Disp0_DrawBitmap(int16_t x,
int16_t y,
int16_t width,
int16_t height,
const uint8_t *bitmap)
{
uint32_t total_pixels;
const uint8_t *data_ptr;
uint32_t i;
// 设置LCD显示窗口
LCD_SetWindows(x, y, x + width - 1, y + height - 1);
// 准备写入GRAM
LCD_WriteRAM_Prepare();
// 逐像素通过FSMC写入 RGB565 数据
total_pixels = (uint32_t)width * (uint32_t)height;
data_ptr = bitmap;
for (i = 0; i < total_pixels; i++)
{
uint16_t color = ((uint16_t)data_ptr[0] << 8) | data_ptr[1];
TFTLCD_RAM = color;
data_ptr += 2;
}
return 0;
}

45帧
二、轮询DMA
此处需要关闭交换高低字节

#define LCD_RAM_ADDR (*(__IO uint16_t *)0x60020000) /* FSMC 口 */
extern DMA_HandleTypeDef hdma_memtomem_dma2_stream0; /* CubeMX 生成 */
int32_t Disp0_DrawBitmap(int16_t x, int16_t y,
int16_t w, int16_t h,
const uint16_t *rgb565)
{
/* 1. 边界越界简单判断,这里省略 */
/* 2. 开窗 */
LCD_SetWindows(x, y, x + w - 1, y + h - 1);
/* 3. 发写 GRAM 命令 */
LCD_WriteRAM_Prepare(); // 寄存器口发 0x22
__DSB(); // 保证命令先写完
/* 4. 启动 DMA 轮询 */
HAL_DMA_Start(&hdma_memtomem_dma2_stream0,
(uint32_t)rgb565, // 源
(uint32_t)&LCD_RAM_ADDR, // 目标(固定)
w * h); // 像素个数
/* 5. 阻塞等完成 */
HAL_DMA_PollForTransfer(&hdma_memtomem_dma2_stream0,
HAL_DMA_FULL_TRANSFER,
HAL_MAX_DELAY); // 或者给 10 ms 超时
return 0;
}

53帧
三、异步刷新DMA
此处需要开启异步刷新

#define LCD_RAM_ADDR (*(__IO uint16_t *)0x60020000) /* FSMC 口 */
extern DMA_HandleTypeDef hdma_memtomem_dma2_stream0; /* CubeMX 生成 */
int32_t Disp0_DrawBitmap(int16_t x, int16_t y,
int16_t w, int16_t h,
const uint16_t *rgb565)
{
/* 1. 边界裁剪(略) */
/* 2. 开窗 */
LCD_SetWindows(x, y, x+w-1, y+h-1);
/* 3. 准备写 GRAM */
LCD_WriteRAM_Prepare(); // 拉低 RS,发 0x22 命令
__DSB(); // 保证命令先发完
/* 4. 启动 DMA */
HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0,
(uint32_t)rgb565, // 源:内存图像
(uint32_t)&LCD_RAM_ADDR, // 目标:FSMC 映射口
w*h); // 长度:像素个数
/* 5. 可选:等待完成,或放后台 */
// osSemaphoreAcquire(&lcd_sem, osWaitForever); // RTOS 信号量
return 0;
}
当然异步函数还需要加点东西
/* USER CODE BEGIN 4 */
void __disp_adapter0_request_async_flushing(
void *pTarget,
bool bIsNewFrame,
int16_t iX,
int16_t iY,
int16_t iWidth,
int16_t iHeight,
const COLOUR_INT *pBuffer)
{
Disp0_DrawBitmap(iX, iY, iWidth, iHeight, (const uint8_t *)pBuffer);
}
void Disp0DmaCpltCallback(void)
{
/* 释放信号量,或者切换下一帧缓冲 */
disp_adapter0_insert_async_flushing_complete_event_handler();
}
/* USER CODE END 4 */
这个Disp0DmaCpltCallback函数需要在main.h声明并在stm32f4xx_it.c中加入到DMA的中断处理。
void DMA2_Stream0_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream0_IRQn 0 */
/* USER CODE END DMA2_Stream0_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_memtomem_dma2_stream0);
/* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
Disp0DmaCpltCallback();
/* USER CODE END DMA2_Stream0_IRQn 1 */
}

64帧,达成。
更多推荐
所有评论(0)