打印
[STM32N6]

【STM32N6570-DK】+ LCD绘图和字体显示

[复制链接]
339|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

上期通过STM32CubeMX配置LTDC外设实现了lcd屏幕显示,本次继续深入实现lcd绘图和字体显示测试。

由于STM32N6有很大的RAM空间且连续的,这次直接使用LCD整屏RAM buffer显存显示。

LCD整屏显存需要800X480X2=750K。AXISRAM3\4区域各自只有448K,合起来共896K。

具体地址使用AXISRAM3\4区域RAM。由于AXISRAM3\4区域默认是无效的,需要使能时钟和电源。

image.png

首先配置一下RAMCFG:

image.png

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

image.png

  /* 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后显示会不正常。

image.png

image.png

生成代码之后,添加绘图函数。

/*
 * 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 */
}

下面编译烧录查看显示效果:

image.png

1749657207725.png

1749657230352.png

1749657223803.png

upload 附件:n6_lcd.zip

使用特权

评论回复
沙发
minzisc| | 2025-6-15 21:44 | 只看该作者
利用LTDC和DMA2D提升显示效率,双缓冲避免闪烁。

使用特权

评论回复
板凳
timfordlare| | 2025-6-16 09:36 | 只看该作者
RGB 接口数据线需等长布线,避免信号延迟差异

使用特权

评论回复
地板
elsaflower| | 2025-6-16 10:00 | 只看该作者
如果使用自定义字体库,需要将字体数据加载到显存中,并编写相应的显示函数。

使用特权

评论回复
5
wengh2016| | 2025-6-16 10:44 | 只看该作者
针对支持DMA的LCD接口,使用DMA加速数据传输。

使用特权

评论回复
6
51xlf| | 2025-6-16 11:23 | 只看该作者
STM32芯片本身没有直接支持汉字显示的功能,因此需要借助外部字库。

使用特权

评论回复
7
jtracy3| | 2025-6-16 14:44 | 只看该作者
绘图操作(如画圆、填充)需临时缓冲区,避免覆盖帧缓冲区,建议使用栈或堆

使用特权

评论回复
8
mmbs| | 2025-6-16 15:05 | 只看该作者
提前建立显示缓冲区,避免频繁操作LCD。

使用特权

评论回复
9
ingramward| | 2025-6-16 15:51 | 只看该作者
选择一个适合STM32的图形库,如u8g2、lvgl、TouchGFX等

使用特权

评论回复
10
maqianqu| | 2025-6-16 16:18 | 只看该作者
如果需要显示复杂的图形或动画,可以考虑使用硬件加速(如DMA2D或GPU)来提高性能。

使用特权

评论回复
11
modesty3jonah| | 2025-6-16 17:59 | 只看该作者
使用前缓冲(显示)和后缓冲(绘制),避免画面撕裂。切换缓冲时通过 LCD_WriteReg() 写入新的帧缓冲地址。

使用特权

评论回复
12
yeates333| | 2025-6-16 18:50 | 只看该作者
合理配置驱动参数,优化绘图与字体渲染逻辑,控制资源占用。

使用特权

评论回复
13
loutin| | 2025-6-16 19:15 | 只看该作者
使用GB2312编码索引,可建立结构体数组。

使用特权

评论回复
14
yorkbarney| | 2025-6-16 19:34 | 只看该作者
使用合适的LCD驱动程序,根据LCD控制器的特性和数据手册进行配置。

使用特权

评论回复
15
51xlf| | 2025-6-16 20:41 | 只看该作者
优化绘图和字体显示算法,减少不必要的计算和内存访问。

使用特权

评论回复
16
pixhw| | 2025-6-16 21:18 | 只看该作者
启用双缓冲或调整刷新率              

使用特权

评论回复
17
yeates333| | 2025-6-16 21:52 | 只看该作者
通过去耦电容、差分信号等措施抑制干扰

使用特权

评论回复
18
loutin| | 2025-6-16 22:18 | 只看该作者
开启缓存(CACHE)和内存保护单元(MPU),并确保显存区域设置为非缓存区,以避免显示异常。

使用特权

评论回复
19
uytyu| | 2025-6-17 10:25 | 只看该作者
LCD的刷新率足够高,以避免闪烁和拖影。

使用特权

评论回复
20
fengm| | 2025-6-17 10:57 | 只看该作者
可简化文本渲染和其他图形元素的创建。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

4772

帖子

28

粉丝