高级会员
- 积分
- 791
- 金钱
- 791
- 注册时间
- 2018-12-19
- 在线时间
- 163 小时
|
本帖最后由 854278507 于 2024-4-26 22:49 编辑
正点原子提供的LCD_Fill函数是使用CPU运算的方式,整屏填充需要10.375ms,算下来就是48.131帧,虽然已经很快了,但是如果使用DMA,还可以更快
下面是我修改后的LCD_Fill函数
- // 在指定区域内填充单个颜色
- //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
- // color:要填充的颜色
- void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color)
- {
- uint16_t i, j;
- uint16_t xlen = 0;
- uint16_t temp;
- if ((lcddev.id == 0x6804) && (lcddev.dir == 1)) // 6804横屏的时候特殊处理
- {
- temp = sx;
- sx = sy;
- sy = lcddev.width - ex - 1;
- ex = ey;
- ey = lcddev.width - temp - 1;
- lcddev.dir = 0;
- lcddev.setxcmd = 0x2A;
- lcddev.setycmd = 0x2B;
- LCD_Fill(sx, sy, ex, ey, color);
- lcddev.dir = 1;
- lcddev.setxcmd = 0x2B;
- lcddev.setycmd = 0x2A;
- }
- else
- {
- #if 1
- uint16_t width;
- uint16_t height;
-
- width = ex - sx + 1;
- height = ey - sy + 1;
-
-
-
- LCD_Set_Window(sx, sy, width, height);
- LCD_WriteRAM_Prepare();
-
- uint32_t lcdsize = width * height;
- uint32_t dmatransfered = 0;
-
- uint16_t color_buf[2];
-
- color_buf[0] = color;
- color_buf[1] = color;
-
- DMA_InitTypeDef DMA_InitStruct;
-
- lcdsize /= 2; /* 使用32位宽数据传输,数据量减少一半 */
-
- DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&LCD->LCD_RAM; /* 外设地址为LCD_RAM */
- DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)color_buf; /* 内存地址为显示缓存 */
- DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; /* DMA方向为内存到外设 */
- DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* 外设地址固定 */
- DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Disable; /* 内存地址固定 */
- DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;/* 外设数据宽度32位 */
- DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; /* 内存数据宽度32位 */
- DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; /* 普通模式 */
- DMA_InitStruct.DMA_Priority = DMA_Priority_High; /* DMA优先级为高 */
- DMA_InitStruct.DMA_M2M = DMA_M2M_Enable; /* 内存到内存模式(不需要外部触发) */
-
- while (lcdsize)
- {
- if (lcdsize >= 65535)
- {
- DMA_InitStruct.DMA_BufferSize = 65535; /* 单次数据传输量不能超过65535 */
- lcdsize -= 65535;
- dmatransfered += 65535;
- }
- else
- {
- DMA_InitStruct.DMA_BufferSize = lcdsize;
- lcdsize = 0;
- }
-
- DMA_Init(DMA2_Channel5, &DMA_InitStruct);
-
- DMA_Cmd(DMA2_Channel5, ENABLE);
-
- while (DMA_GetFlagStatus(DMA2_FLAG_TC5) == RESET)
- {
-
- }
-
- DMA_ClearFlag(DMA2_FLAG_TC5);
- }
- DMA_Cmd(DMA2_Channel5, DISABLE);
-
- LCD_Set_Window(0, 0, lcddev.width, lcddev.height);
- // LCD_WriteRAM_Prepare();
-
- #else
-
- xlen = ex - sx + 1;
- for (i = sy; i <= ey; i++)
- {
- LCD_SetCursor(sx, i); // 设置光标位置
- LCD_WriteRAM_Prepare(); // 开始写入GRAM
- for (j = 0; j < xlen; j++) // 显示颜色
- {
- LCD->LCD_RAM = color;
- }
- }
-
- #endif /* 0 */
- }
- }
复制代码 可能会有人有疑问,LCD是16位的8080 16位的接口,怎么可以使用32位的数据传输,实际上是可以的,也可以改成16位传输,这样速度会慢一点,因为 240 * 320 的屏用16位传输需要写 240 * 320 = 76800次,而STM32F103的DMA一次最多只能传输65535个数据,需要分两次传输,如果用32位传输就只需要 240 * 320 / 2 = 38400次,DMA一次就可以传输完成。
由于是单色填充,需要先定义一个数组,填充好要用的颜色数值,然后把这地址设置为DMA的内存地址,初始化DMA的时候要设置内存地址不自增,这样就可以快速整屏填充了。
下面是没有使用DMA刷屏速度截图
从上面的图片可以看出没有使用DMA的时候刷一屏需要10.375ms,刷屏速度48.131帧。
下面是使用DMA刷屏速度截图
从上面的图片可以看出使用DMA后刷一屏只需要6.411ms,刷屏速度77.99帧。
下面放上测试刷屏速度的代码
- void lcd_test_play(void)
- {
- #if 1
- const uint16_t color_table[] =
- {
- //画笔颜色
- WHITE ,
- BLACK ,
- BLUE ,
- BRED ,
- GRED ,
- GBLUE ,
- RED ,
- MAGENTA ,
- GREEN ,
- CYAN ,
- YELLOW ,
- BROWN ,
- BRRED ,
- GRAY ,
- DARKBLUE ,
- LIGHTBLUE ,
- GRAYBLUE ,
- LIGHTGREEN ,
- LGRAY ,
- LGRAYBLUE ,
- LBBLUE ,
- };
-
- uint8_t i;
-
- spb_delete();
- printf("\r\n[%s][%s][%04d]LCD刷屏 %d",
- __FILE__, __func__, __LINE__, system_task_return);
- system_task_return = 0;
-
- while (1)
- {
- for (i = 0; i < sizeof(color_table) / 2; i++)
- {
- LCD_Fill(0, 0, lcddev.width - 1, lcddev.height - 1, color_table[i]);
- LED_1_Turn();
- }
-
- if (system_task_return == 1)
- {
- if (TPAD_Scan(1))
- {
- break;
- }
- else
- {
- system_task_return = 0;
- }
- }
- }
- LED_1_Off();
-
- #else
-
- uint16_t r;
- uint16_t g;
- uint16_t b;
-
- spb_delete();
- printf("\r\n[%s][%s][%04d]LCD刷屏 %d",
- __FILE__, __func__, __LINE__, system_task_return);
- system_task_return = 0;
-
- while (1)
- {
- #define LCD_DELAY 20
- for (r = 0; r < (1 << 5); r++)
- {
- for (g = 0; g < (1 << 6); g++)
- {
- for (b = 0; b < (1 << 5); b++)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- for (b = (1 << 5); b > 0; b--)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- }
- for (g = (1 << 6); g > 0; g--)
- {
- for (b = 0; b < (1 << 5); b++)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- for (b = (1 << 5); b > 0; b--)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- }
- }
-
- for (r = (1 << 5); r > 0; r--)
- {
- for (g = 0; g < (1 << 6); g++)
- {
- for (b = 0; b < (1 << 5); b++)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- for (b = (1 << 5); b > 0; b--)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- }
- for (g = (1 << 6); g > 0; g--)
- {
- for (b = 0; b < (1 << 5); b++)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- for (b = (1 << 5); b > 0; b--)
- {
- LCD_Fill(0,
- 0,
- lcddev.width - 1,
- lcddev.height - 1,
- (r << 11) | (g << 5) | b);
- LED_1_Turn();
- OSTimeDly(LCD_DELAY);
- }
- }
- }
-
- if (system_task_return == 1)
- {
- if (TPAD_Scan(1))
- {
- break;
- }
- else
- {
- system_task_return = 0;
- }
- }
- }
- LED_1_Off();
-
- #endif /* 1 */
-
-
- }
复制代码
|
|