Integração no projeto LVGL de uma biblioteca gráfica para microcontroladores

LVGL - Biblioteca gráfica leve e versátil, também conhecida como LittleVGL.





A biblioteca suporta um grande número de microcontroladores, como STM32, ESP32 e outros. Até agora, consegui executar um programa de demonstração completo no ESP32 e STM32f429 Discovery. A biblioteca é de código aberto, suporta um grande número de elementos gráficos com temas escuros e claros. Distribuído sob a licença do MIT. Pode ser usado livremente, mesmo em produtos comerciais. Você pode assistir a uma demonstração online interativa sem instalar no dispositivo



A biblioteca suporta a conexão de dois tipos de display



  1. Diretamente via interface RGB, onde o buffer estará no lado MCU na RAM interna ou SDRAM externa
  2. Por meio de um controlador de display externo. Nesse caso, o MCU pode se comunicar com o controlador de display por meio do barramento SPI ou I2C. Para melhorar o desempenho, buffers de renderização intermediários dentro do MCU também podem ser usados ​​neste caso.


Duas configurações de hardware típicas
MCU with TFT/LCD driver If your MCU has a TFT/LCD driver periphery then you can connect a display directly via RGB interface. In this case, the frame buffer can be in the internal RAM (if the MCU has enough RAM) or in the external RAM (if the MCU has a memory interface).



External display controller If the MCU doesn't have TFT/LCD driver interface then an external display controller (E.g. SSD1963, SSD1306, ILI9341) has to be used. In this case, the MCU can communicate with the display controller via Parallel port, SPI or sometimes I2C. The frame buffer is usually located in the display controller which saves a lot of RAM for the MCU.





Tudo é muito flexível a este respeito. Se você tem um driver, mas a biblioteca ainda não tem uma porta para este driver, você pode facilmente integrar a biblioteca ao seu projeto.



A maneira mais fácil, mas também a mais lenta, é reescrever o retorno de chamada do desenho - my_flush_cb



void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
    int32_t x, y;
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
            put_px(x, y, *color_p)
            color_p++;
        }
    }

    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp);
}


put_px - Esta é a renderização de pixels do seu driver. Devido ao fato de que a renderização é pixel por pixel, isso é lento. A documentação da biblioteca detalha outros métodos de integração mais eficientes, integrando



LVGL ao projeto. O primeiro é inicializar o sistema de biblioteca, exibição e entrada.




   lv_init();
   tft_init();
   touchpad_init();

   lv_demo_widgets();  //     


Uma vez que a biblioteca possui um gerenciador de tarefas dentro de si. Sim, este é um sistema multi-threaded, corrija-me se não for assim, então precisamos aumentar o contador interno do despachante chamando lv_tick_inc



void * tick_thread (void *args)
{
      while(1) {
        usleep(5*1000);   /*Sleep for 5 millisecond*/
        lv_tick_inc(5);      /*Tell LVGL that 5 milliseconds were elapsed*/
    }
}


Além disso, é necessário transferir para a função os milissegundos que se passaram desde o momento de sua última chamada, ou seja, o tempo desde o momento da iteração anterior.



Para não desperdiçar recursos em um thread extra, você pode chamar essa função em uma interrupção do cronômetro. STM32 tem um temporizador SysTick para tais fins:




void systickInit (uint16_t frequency)
{
   RCC_ClocksTypeDef RCC_Clocks;
   RCC_GetClocksFreq (&RCC_Clocks);
   (void) SysTick_Config (RCC_Clocks.HCLK_Frequency / frequency);
}

extern "C" void SysTick_Handler (void)
 {
      lv_tick_inc(1);    // 1 ms
 }


SysTick timer
This timer is dedicated to real-time operating systems, but could also be used as a standard

downcounter. It features:



  • A 24-bit downcounter
  • Autoreload capability
  • Maskable system interrupt generation when the counter reaches 0
  • Programmable clock source.




Também é necessário chamar lv_task_handler no loop. Recomenda-se acioná-lo a cada 5 ms para garantir uma boa resposta. Tentei aumentar a velocidade de até 20 ms e o sistema ainda era bastante responsivo e suave. Pode ser deixado como um loop eterno ou usar Thread



while(1) {
  lv_task_handler();
  my_delay_ms(5);
}


Os ciclos devem estar em lugares diferentes. Eu cometi um erro e coloquei lv_tick_inc e lv_task_handler em um único loop. Aqui está o que resultou - Freios



Quando os dois métodos foram divididos em diferentes fluxos nos intervalos corretos, tudo funcionou de forma correta e rápida:





A biblioteca pode personalizar o número de buffers internos:



  1. Um buffer quando LVGL desenha o conteúdo da tela para um buffer e o envia para o display
  2. Dois buffers de tela parcial, enquanto renderizam em um buffer, o conteúdo do outro buffer é enviado para ser exibido em segundo plano
  3. Dois buffers de tela inteira


O site possui um conversor de fontes e imagens . Você pode adicionar com segurança sua fonte ao projeto ou seu ícone no menu. Além disso, você pode opcionalmente carregar imagens de armazenamento externo, como CD-CARD, ou de uma matriz de bytes localizada na memória Flash interna.



Como usar o arquivo gerado em LittlevGL?
For C arrays

Copy the result C file into your LittlevGL project

In a C file of your application declare the image as: LV_IMG_DECLARE(my_image_name);

Set the image for an lv_img object: lv_img_set_src(img1, &my_image_name);

For external binary files (e.g. SD card)

Set up a new driver. To learn more read the Tutorial.

Set the image for an lv_img object: lv_img_set_src(img1, «S:/path/to/image»);



Outro recurso importante e interessante desta biblioteca é que você pode usar o IDE Eclipse no Linux e no Windows para depurá-lo.







É bom que seja bem documentado para a biblioteca OpenSource. Existem muitos exemplos e portas. A biblioteca cresceu e se tornou uma comunidade bastante grande .



Lancei uma versão para ESP32. Mesmo ao usar mapeamento para pinos SPI, ou seja, não os padrões, nos quais a melhor taxa de transmissão é obtida, tudo funcionou sem lentidão:



ESP32 ST7789 LVGL

ESP32 ILI9341 LVGL



Materiais relacionados
docs.lvgl.io/latest/en/html/porting/sys.html

Basic systick configuration on the STM32




All Articles