上期通过STM32CubeMX配置LTDC外设实现了lcd屏幕显示,本次继续深入实现lcd绘图和字体显示测试。
由于STM32N6有很大的RAM空间且连续的,这次直接使用LCD整屏RAM buffer显存显示。
LCD整屏显存需要800X480X2=750K。AXISRAM3\4区域各自只有448K,合起来共896K。
具体地址使用AXISRAM3\4区域RAM。由于AXISRAM3\4区域默认是无效的,需要使能时钟和电源。

首先配置一下RAMCFG:

添加额外代码使能代码如下:

/* SRAM3 and SRAM4 memories clock enable */
LL_MEM_EnableClock(LL_MEM_AXISRAM3);
LL_MEM_EnableClock(LL_MEM_AXISRAM4);
LL_MEM_EnableClock(LL_MEM_AXISRAM4);
LL_MEM_EnableClock(LL_MEM_AXISRAM4);
/* Power On AXSRAM3 and AXISRAM4 */
hramcfg_SRAM3.Instance = RAMCFG_SRAM3_AXI;
HAL_RAMCFG_EnableAXISRAM(&hramcfg_SRAM3);
hramcfg_SRAM4.Instance = RAMCFG_SRAM4_AXI;
HAL_RAMCFG_EnableAXISRAM(&hramcfg_SRAM4);
hramcfg_SRAM5.Instance = RAMCFG_SRAM5_AXI;
HAL_RAMCFG_EnableAXISRAM(&hramcfg_SRAM5);
hramcfg_SRAM6.Instance = RAMCFG_SRAM6_AXI;
HAL_RAMCFG_EnableAXISRAM(&hramcfg_SRAM6);
设置LCD显存起始地址在
define LCD_LAYER_0_ADDRESS 0x34200000U / SRAM3 /
可以在LTDC初始化中添加显存地址,或者在LTDC初始化之后添加调用如下函数设置显存地址。
HAL_LTDC_SetAddress(&hltdc,(uint32_t )LCD_LAYER_0_ADDRESS,0);
然后打开CACHE和MPU设置,这里要设置显存区域为非CACHE区。否则打开CACHE后显示会不正常。


生成代码之后,添加绘图函数。
/*
* Copyright (c) 2024, 流水源 Water Source (WoodData).
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-06 WoodData the first version
*/
#include "lcd_buffer.h"
/**
* [@brief](home.php?mod=space&uid=247401) Initialize the st7789h2 LCD component.
* @retval Component status.
*/
uint32_t lcd_buffer_init(void *args)
{
return 0;
}
uint32_t lcd_buffer_display_on(uint8_t light)
{
if(light)
{
/* Enable backlight */
//HAL_GPIO_WritePin(LCD_BACKLIGHT_GPIO_PORT, LCD_BACKLIGHT_GPIO_PIN, GPIO_PIN_SET);
}else
{
/* Deactivate backlight */
//HAL_GPIO_WritePin(LCD_BACKLIGHT_GPIO_PORT, LCD_BACKLIGHT_GPIO_PIN, GPIO_PIN_RESET);
}
return 0;
}
uint32_t lcd_buffer_pixel (int16_t x, int16_t y, lcd_color_t color)
{
if((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) || (x<0) || (y<0)) return 1;
/* Write data value to RAM memory */
*(__IO uint16_t*) (LCD_LAYER_0_ADDRESS + (2U*((y*LCD_WIDTH) + x))) = (uint16_t)color;
return 0;
}
uint32_t lcd_buffer_draw_bitmap (uint8_t mode, int16_t x, int16_t y, uint16_t w, uint16_t h, const uint8_t *bmp)
{
uint16_t x0,y0;
uint16_t *ptr;
ptr = (uint16_t *) bmp;
for(y0=0;y0<h;y0++)
{
for(x0=0;x0<w;x0++)
{
lcd_buffer_pixel(x+x0,y+y0,*ptr++);
}
}
return 0;
}
uint32_t lcd_buffer_fill (int16_t x, int16_t y, uint16_t w, uint16_t h, lcd_color_t color)
{
uint16_t x0,y0;
for(y0=0;y0<h;y0++)
{
for(x0=0;x0<w;x0++)
{
lcd_buffer_pixel(x+x0,y+y0,color);
}
}
return 0;
}
uint32_t lcd_buffer_draw_char_dot(uint8_t mode, int16_t x,int16_t y,uint16_t w,uint16_t h,const uint8_t *buff,lcd_color_t f_color,lcd_color_t b_color)
{
uint32_t i, j;
uint8_t *ptr= (uint8_t *)buff;
if((x >= LCD_WIDTH) || (y >= LCD_HEIGHT) || ((x+w)<=0) || ((y+h)<=0)) return 1;
switch(mode)
{
case 0:
for(i=0;i<h;i++)
{
for(j=0;j<w;)
{
if(*ptr & (0x80>>(j&0x07)))
{
lcd_buffer_pixel(x+j,y+i,f_color);
}else
{
lcd_buffer_pixel(x+j,y+i,b_color);
}
j++;
if(!(j&0x07))
{
ptr++;
}
}
if(w & 0x07) ptr++;
}
break;
case 1:
for(i=0;i<h;i++)
{
for(j=0;j<w;)
{
if(*ptr & (0x01<<(j&0x07)))
{
lcd_buffer_pixel(x+j,y+i,f_color);
}else
{
lcd_buffer_pixel(x+j,y+i,b_color);
}
j++;
if(!(j&0x07))
{
ptr++;
}
}
if(w & 0x07) ptr++;
}
break;
case 2:
break;
case 3:
break;
}
return 0;
}
lcd_adapter_t lcd_buffer_drv =
{
.info.sx = 0,
.info.sy = 0,
.info.width = LCD_WIDTH,
.info.height = LCD_HEIGHT,
.info.color_bit = 16,
.info.color_type = LCD_RGB565_16BIT,
.func.init = lcd_buffer_init,
.func.flush = NULL,
.func.get_backlight = NULL,
.func.set_backlight = lcd_buffer_display_on,
.draw.get_point = NULL,
.draw.set_point = lcd_buffer_pixel,
.draw.clear = NULL,
.draw.h_line = NULL,
.draw.v_line = NULL,
.draw.line = NULL,
.draw.fill = lcd_buffer_fill,
.draw.draw_bmp = lcd_buffer_draw_bitmap,
.draw.draw_char_bmp = lcd_buffer_draw_char_dot, //
};
主函数测试代码如下:
int main(void)
{
uint32_t i;
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* Enable the CPU Cache */
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* MCU Configuration--------------------------------------------------------*/
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_RAMCFG_Init();
MX_I2C1_Init();
MX_I2C2_Init();
MX_LTDC_Init();
MX_USART1_UART_Init();
MX_XSPI1_Init();
SystemIsolation_Config();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_LTDC_SetAddress(&hltdc,(uint32_t )LCD_LAYER_0_ADDRESS,0);
lcd_display_init(&lcd_buffer_drv);
lcd_clear(LCD_WHITE);
HAL_Delay(300);
lcd_clear(LCD_BLACK);
HAL_Delay(300);
lcd_clear(LCD_RED);
HAL_Delay(300);
lcd_clear(LCD_GREEN);
HAL_Delay(300);
lcd_clear(LCD_BLUE);
HAL_Delay(300);
for(i=0;i<10;i++){ lcd_draw_line(10+i*50,0,10+i*50,480,LCD_RED);HAL_Delay(200);}
for(i=0;i<10;i++){lcd_draw_line(0,10+i*40,800,10+i*40,LCD_GREEN);HAL_Delay(200);}
for(i=0;i<10;i++){lcd_draw_circle(400,240,10+i*20,LCD_YELLOW);HAL_Delay(200);}
for(i=0;i<10;i++){lcd_draw_rect(400-i*20,240-i*20,i*40,i*40,LCD_MAGENTA);HAL_Delay(200);}
lcd_fill_rect(80,30,80,80,LCD_RED);
lcd_draw_image(30,80,80,80,(uint8_t *)c_bmp_muzhu_RGB565);
lcd_set_font_window(0,0,lcd_get_width(),lcd_get_height());
lcd_set_font(&Font_ASCII16X8_default);
lcd_disp_str_at(200,200,"STM32N6-DK");
lcd_disp_str_at(250,250,"WoodData");
lcd_set_font(&Font_ASCII24x40);
lcd_disp_str_at(20,20,"Font_ASCII24x40");
HAL_Delay(5000);
while (1)
{
lcd_clear(LCD_RED);
HAL_Delay(1000);
lcd_clear(LCD_GREEN);
HAL_Delay(1000);
lcd_clear(LCD_BLUE);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
下面编译烧录查看显示效果:




附件:n6_lcd.zip