Hi folks,
I’m working on a project using LVGL (9.2.2) on an ATSAME54 microcontroller. My setup includes a 320x240 pixel display with an ST7789V driver (I’m using the driver from lvgl), which communicates via SPI using DMA (baudrate set to 18MHz, even though that is much more than ST7789V accepts). The system runs FreeRTOS, and I’ve integrated LVGL as follows:
lv_tick_inc
is called invApplicationTickHook
.- There are two FreeRTOS tasks:
- LVGL_Task: Responsible for running
lv_timer_handler
(file lvgl.c) - ChartDisplay_Task: Handles rendering audio bars (current power + moving average), files display_ui.c and display_init.c.
display_init.c
lv_color_t lcdChartBuffer[LCD_H_RES * LCD_V_RES / 10];
lv_color_t lcdChartBuffer1[LCD_H_RES * LCD_V_RES / 10];
void ChartDisplay_Init(void)
{
xTaskCreate(ChartDisplay_Task, "chart", 700, NULL, tskIDLE_PRIORITY + 2, NULL);
}
static void ChartDisplay_Task(void *p)
{
(void)p;
int32_t result;
TickType_t xLastWakeTime;
/* Initialize LCD I/O */
result = LCD_Init();
if (result != ERR_NONE) {
vTaskDelete(NULL);
return;
}
LVGL_Lock();
/* Create the LVGL display object and the LCD display driver */
lcdChartDisplay = lv_st7789_create(LCD_V_RES, LCD_H_RES, LV_LCD_FLAG_NONE, LCD_SendCmd, LCD_SendColor);
LCD_ChangeOrientation(lcdChartDisplay);
lv_lcd_generic_mipi_set_invert(lcdChartDisplay, true);
lv_display_set_buffers(lcdChartDisplay, lcdChartBuffer, lcdChartBuffer1, sizeof(lcdChartBuffer), LV_DISPLAY_RENDER_MODE_PARTIAL);
ChartDisplay_InitUi(lcdChartDisplay);
LVGL_Unlock();
xLastWakeTime = xTaskGetTickCount();
while (true) {
ChartDisplay_Update();
xTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(20));
}
}
display_ui.c
void ChartDisplay_Update(void)
{
LVGL_Lock();
display_demo();
LVGL_Unlock();
}
static void display_demo(void)
{
// ...
// logic which updates `var` and `average` values...
// ...
for (int i = 0; i < 8; i++) {
ChartDisplay_SetCurrentValue(i, var);
ChartDisplay_SetAverageValue(i, average);
}
}
void ChartDisplay_SetCurrentValue(uint8_t audio_channel, int32_t value)
{
lv_obj_t *bar;
if (audio_channel >= AUDIO_CHANNELS_COUNT) {
return;
}
if (value > AUDIO_POWER_MAX_DB) {
value = AUDIO_POWER_MAX_DB;
} else if (value < AUDIO_POWER_MIN_DB) {
value = AUDIO_POWER_MIN_DB;
}
bar = audio_channel_bar[audio_channel];
lv_bar_set_value(bar, value, LV_ANIM_ON);
}
static void ChartDisplay_SetAverageValue(uint8_t audio_channel, int32_t value)
{
lv_obj_t *average_line;
lv_coord_t y_max;
lv_coord_t y_min;
lv_coord_t y_offset;
if (audio_channel >= AUDIO_CHANNELS_COUNT) {
return;
}
if (value > AUDIO_POWER_MAX_DB) {
value = AUDIO_POWER_MAX_DB;
} else if (value < AUDIO_POWER_MIN_DB) {
value = AUDIO_POWER_MIN_DB;
}
average_line = audio_average_line_array[audio_channel].obj;
y_max = audio_average_line_array[audio_channel].y_max;
y_min = audio_average_line_array[audio_channel].y_min;
/* Calculate the 'y' offset of audio movinin average for a given channel */
y_offset = ((y_max - y_min) * value / (AUDIO_POWER_MAX_DB - AUDIO_POWER_MIN_DB)) + (y_max - (((y_max - y_min) * AUDIO_POWER_MAX_DB) / (AUDIO_POWER_MAX_DB - AUDIO_POWER_MIN_DB)));
lv_obj_align(average_line, LV_ALIGN_BOTTOM_LEFT, 0, y_offset + 3);
}
lvgl.c
void LVGL_Init(void)
{
xTaskCreate(LVGL_Task, "lvgl", 2048, NULL, tskIDLE_PRIORITY + 2, NULL);
}
static void LVGL_Task(void *pvParameters)
{
(void)pvParameters;
LVGL_Lock();
lv_init();
lv_tick_set_cb(xTaskGetTickCount);
LVGL_Unlock();
while (true) {
/* The task running lv_timer_handler should have lower priority than that running `lv_tick_inc` */
LVGL_Lock();
lv_timer_handler();
LVGL_Unlock();
vTaskDelay(pdMS_TO_TICKS(20));
}
}
How it works now?
Could you recommend what I can do to achieve satisfying refreshing rate. Currently this is not acceptable, especially that’s one of key functionality. Thanks in advance!