From bb310ad60d73e32cb2cdad3e2810eea5250de18d Mon Sep 17 00:00:00 2001 From: cepetr Date: Thu, 6 Jun 2024 13:19:02 +0200 Subject: [PATCH] fix(core): improve framebuffer switching [no changelog] --- core/embed/trezorhal/bg_copy.h | 20 +- .../trezorhal/stm32f4/displays/st7789v.c | 4 +- .../stm32f4/xdisplay/st-7789/display_driver.c | 26 +- .../stm32f4/xdisplay/st-7789/display_fb.c | 278 ++++++++++-------- .../stm32f4/xdisplay/st-7789/display_fb.h | 2 - .../xdisplay/st-7789/display_internal.h | 59 ++++ .../stm32f4/xdisplay/st-7789/display_io.c | 5 +- .../stm32f4/xdisplay/st-7789/display_nofb.c | 18 +- core/embed/trezorhal/stm32u5/bg_copy.c | 9 +- core/embed/trezorhal/xdisplay_legacy.c | 6 +- 10 files changed, 279 insertions(+), 148 deletions(-) create mode 100644 core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h diff --git a/core/embed/trezorhal/bg_copy.h b/core/embed/trezorhal/bg_copy.h index 2bbc8959d..be40c2542 100644 --- a/core/embed/trezorhal/bg_copy.h +++ b/core/embed/trezorhal/bg_copy.h @@ -7,9 +7,10 @@ #include /** - * Wait for the data transfer completion + * Callback function invoked from the IRQ context + * when the transfer is complete */ -void bg_copy_wait(void); +typedef void (*bg_copy_callback_t)(void); /** * Performs data copy from src to dst in the background. The destination is @@ -19,8 +20,21 @@ void bg_copy_wait(void); * @param src source data address * @param dst destination data address * @param size size of data to be transferred in bytes + * @param callback optional callback to be called when the transfer is complete + */ +void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size, + bg_copy_callback_t callback); + +/** + * Waits for the data transfer completion + */ +void bg_copy_wait(void); + +/** + * Immediately aborts the data transfer + * + * @note The callback will not be called */ -void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size); void bg_copy_abort(void); diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.c b/core/embed/trezorhal/stm32f4/displays/st7789v.c index 55659d54a..b0b03d9e1 100644 --- a/core/embed/trezorhal/stm32f4/displays/st7789v.c +++ b/core/embed/trezorhal/stm32f4/displays/st7789v.c @@ -567,12 +567,12 @@ void DISPLAY_TE_INTERRUPT_HANDLER(void) { if (act_frame_buffer == 1) { bg_copy_start_const_out_8((uint8_t *)PhysFrameBuffer1, (uint8_t *)DISPLAY_DATA_ADDRESS, - DISPLAY_RESX * DISPLAY_RESY * 2); + DISPLAY_RESX * DISPLAY_RESY * 2, NULL); } else { bg_copy_start_const_out_8((uint8_t *)PhysFrameBuffer0, (uint8_t *)DISPLAY_DATA_ADDRESS, - DISPLAY_RESX * DISPLAY_RESY * 2); + DISPLAY_RESX * DISPLAY_RESY * 2, NULL); } pending_fb_switch = false; diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c index 2a3cd3e6e..74a49e4f1 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_driver.c @@ -22,6 +22,7 @@ #include #include "display_fb.h" +#include "display_internal.h" #include "display_io.h" #include "display_panel.h" @@ -39,14 +40,8 @@ #error "Incompatible display resolution" #endif -// Display driver context. -typedef struct { - // Current display orientation (0, 90, 180, 270) - int orientation_angle; -} display_driver_t; - // Display driver instance -static display_driver_t g_display_driver; +display_driver_t g_display_driver; void display_init(void) { display_driver_t* drv = &g_display_driver; @@ -84,7 +79,8 @@ void display_reinit(void) { void display_finish_actions(void) { #ifdef XFRAMEBUFFER #ifndef BOARDLOADER - wait_for_fb_switch(); + display_ensure_refreshed(); + svc_disableIRQ(DISPLAY_TE_INTERRUPT_NUM); #endif #endif } @@ -135,18 +131,4 @@ int display_get_orientation(void) { return drv->orientation_angle; } -void display_wait_for_sync(void) { -#ifdef DISPLAY_TE_PIN - uint32_t id = display_panel_identify(); - if (id && (id != DISPLAY_ID_GC9307)) { - // synchronize with the panel synchronization signal - // in order to avoid visual tearing effects - while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) - ; - while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) - ; - } -#endif -} - void display_set_compatible_settings(void) { display_panel_set_big_endian(); } diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c index 8a53c4882..a0e89d1bd 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.c @@ -25,6 +25,7 @@ #include STM32_HAL_H #include "display_fb.h" +#include "display_internal.h" #include "display_io.h" #include "display_panel.h" #include "xdisplay.h" @@ -41,173 +42,220 @@ #error Framebuffer only supported on STM32U5 for now #endif +// The following code supports only 1 or 2 frame buffers +_Static_assert(FRAME_BUFFER_COUNT == 1 || FRAME_BUFFER_COUNT == 2); + // Size of the physical frame buffer in bytes #define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2) // Physical frame buffers in internal SRAM memory. // Both frame buffers layes in the fixed addresses that // are shared between bootloaders and the firmware. -__attribute__((section(".fb1"))) +static __attribute__((section(".fb1"))) ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]); -__attribute__((section(".fb2"))) -ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]); - -// The current frame buffer selector at fixed memory address -// It's shared between bootloaders and the firmware -__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer = - 0; -void display_physical_fb_clear(void) { - memset(physical_frame_buffer_0, 0, sizeof(physical_frame_buffer_0)); - memset(physical_frame_buffer_1, 0, sizeof(physical_frame_buffer_1)); -} - -#ifndef BOARDLOADER -static volatile uint16_t pending_fb_switch = 0; -static volatile uint32_t last_fb_update_time = 0; +#if (FRAME_BUFFER_COUNT > 1) +static __attribute__((section(".fb2"))) +ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]); #endif -#ifndef BOARDLOADER -void DISPLAY_TE_INTERRUPT_HANDLER(void) { - if (pending_fb_switch == 1) { - if (current_frame_buffer == 1) { - bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_1, - (uint8_t *)DISPLAY_DATA_ADDRESS, - DISPLAY_RESX * DISPLAY_RESY * 2); - - } else { - bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_0, - (uint8_t *)DISPLAY_DATA_ADDRESS, - DISPLAY_RESX * DISPLAY_RESY * 2); - } - last_fb_update_time = HAL_GetTick(); - pending_fb_switch = 2; - } else if (pending_fb_switch == 2) { - HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); - pending_fb_switch = 0; +// Returns the pointer to the physical frame buffer (0.. FRAME_BUFFER_COUNT-1) +// Returns NULL if the framebuffer index is out of range. +static uint8_t *get_fb_ptr(uint32_t index) { + if (index == 0) { + return physical_frame_buffer_0; +#if (FRAME_BUFFER_COUNT > 1) + } else if (index == 1) { + return physical_frame_buffer_1; +#endif } else { - HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); - pending_fb_switch = 0; + return NULL; } - __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); } -static void copy_fb_to_display(const uint16_t *fb) { - for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { - // 2 bytes per pixel because we're using RGB 5-6-5 format - ISSUE_PIXEL_DATA(fb[i]); +void display_physical_fb_clear(void) { + for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { + memset(get_fb_ptr(i), 0, PHYSICAL_FRAME_BUFFER_SIZE); } } -void wait_for_fb_switch(void) { - if (is_mode_handler()) { - if (pending_fb_switch != 0) { - if (current_frame_buffer == 0) { - copy_fb_to_display((uint16_t *)physical_frame_buffer_1); - } else { - copy_fb_to_display((uint16_t *)physical_frame_buffer_0); - } - pending_fb_switch = 0; - } - } else { - while (pending_fb_switch != 0) { - __WFI(); - } - bg_copy_wait(); +#ifndef BOARDLOADER + +// Callback called when the background copying is done +// It's called from the IRQ context +static void bg_copy_callback(void) { + display_driver_t *drv = &g_display_driver; + + if (drv->queue.rix >= FRAME_BUFFER_COUNT) { + // This is an invalid state and we should never get here + return; } + + drv->queue.entry[drv->queue.rix] = FB_STATE_EMPTY; + drv->queue.rix = (drv->queue.rix + 1) % FRAME_BUFFER_COUNT; } -#endif -static void switch_fb_manually(void) { - // sync with the panel refresh - while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { - } - while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { - } +// Interrupt routing handling TE signal +void DISPLAY_TE_INTERRUPT_HANDLER(void) { + display_driver_t *drv = &g_display_driver; - if (current_frame_buffer == 0) { - current_frame_buffer = 1; - copy_fb_to_display((uint16_t *)physical_frame_buffer_1); - memcpy(physical_frame_buffer_0, physical_frame_buffer_1, - sizeof(physical_frame_buffer_0)); + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); - } else { - current_frame_buffer = 0; - copy_fb_to_display((uint16_t *)physical_frame_buffer_0); - memcpy(physical_frame_buffer_1, physical_frame_buffer_0, - sizeof(physical_frame_buffer_1)); + if (drv->queue.rix >= FRAME_BUFFER_COUNT) { + // This is an invalid state and we should never get here + return; } -} - -#ifndef BOARDLOADER -static void switch_fb_in_background(void) { - if (current_frame_buffer == 0) { - current_frame_buffer = 1; - memcpy(physical_frame_buffer_0, physical_frame_buffer_1, - sizeof(physical_frame_buffer_0)); + switch (drv->queue.entry[drv->queue.rix]) { + case FB_STATE_EMPTY: + case FB_STATE_PREPARING: + // No new frame queued + break; + + case FB_STATE_COPYING: + // Currently we are copying a data to the display. + // We need to wait for the next TE interrupt. + break; + + case FB_STATE_READY: + // Now it's proper time to copy the data to the display + drv->queue.entry[drv->queue.rix] = FB_STATE_COPYING; + display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + bg_copy_start_const_out_8(get_fb_ptr(drv->queue.rix), + (uint8_t *)DISPLAY_DATA_ADDRESS, + PHYSICAL_FRAME_BUFFER_SIZE, bg_copy_callback); - pending_fb_switch = 1; - __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); - svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); - } else { - current_frame_buffer = 0; - memcpy(physical_frame_buffer_1, physical_frame_buffer_0, - sizeof(physical_frame_buffer_1)); + // NOTE: when copying is done, this queue slot is marked empty + // (see bg_copy_callback()) + break; - pending_fb_switch = 1; - __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); - svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + default: + // This is an invalid state and we should never get here + break; } } #endif display_fb_info_t display_get_frame_buffer(void) { - void *addr; + display_driver_t *drv = &g_display_driver; + + frame_buffer_state_t state; + + // We have to wait if the buffer was passed for copying + // to the interrupt handler + do { + state = drv->queue.entry[drv->queue.wix]; + } while (state == FB_STATE_READY || state == FB_STATE_COPYING); + + if (state == FB_STATE_EMPTY) { + // First use of this buffer, copy the previous buffer into it +#if (FRAME_BUFFER_COUNT > 1) + uint8_t *src = get_fb_ptr((FRAME_BUFFER_COUNT + drv->queue.wix - 1) % + FRAME_BUFFER_COUNT); + uint8_t *dst = get_fb_ptr(drv->queue.wix); + memcpy(dst, src, PHYSICAL_FRAME_BUFFER_SIZE); +#endif + }; - if (current_frame_buffer == 0) { - addr = (void *)physical_frame_buffer_1; - } else { - addr = (void *)physical_frame_buffer_0; - } + drv->queue.entry[drv->queue.wix] = FB_STATE_PREPARING; display_fb_info_t fb = { - .ptr = addr, + .ptr = get_fb_ptr(drv->queue.wix), .stride = DISPLAY_RESX * sizeof(uint16_t), }; return fb; } +// Copies the frame buffer with the given index to the display +static void copy_fb_to_display(uint8_t index) { + uint16_t *fb = (uint16_t *)get_fb_ptr(index); + + if (fb != NULL) { + display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { + // 2 bytes per pixel because we're using RGB 5-6-5 format + ISSUE_PIXEL_DATA(fb[i]); + } + } +} + +static void wait_for_te_signal(void) { + // sync with the panel refresh + while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { + } + while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { + } +} + void display_refresh(void) { -#ifndef BOARDLOADER + display_driver_t *drv = &g_display_driver; + + if (drv->queue.entry[drv->queue.wix] != FB_STATE_PREPARING) { + // No refresh needed as the frame buffer is not in + // the state to be copied to the display + return; + } +#ifndef BOARDLOADER if (is_mode_handler()) { - if (pending_fb_switch != 0) { - pending_fb_switch = 0; - bg_copy_abort(); + // Disable scheduling of any new background copying + HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); + // Wait for next TE signal. During this time the + // display might be updated in the background + wait_for_te_signal(); + // Stop any background copying even if it is not finished yet + bg_copy_abort(); + // Copy the frame buffer to the display manually + copy_fb_to_display(drv->queue.wix); + // Reset the buffer queue so we can eventually continue + // safely in thread mode + drv->queue.wix = 0; + drv->queue.rix = 0; + for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { + drv->queue.entry[i] = FB_STATE_EMPTY; } - display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); - switch_fb_manually(); + // Enable normal processing again + HAL_NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM); } else { - wait_for_fb_switch(); - display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); - switch_fb_in_background(); + // Mark the buffer ready to switch to + drv->queue.entry[drv->queue.wix] = FB_STATE_READY; + drv->queue.wix = (drv->queue.wix + 1) % FRAME_BUFFER_COUNT; } -#else - display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); - switch_fb_manually(); + +#else // BOARDLOADER + wait_for_te_signal(); + copy_fb_to_display(drv->queue.wix); + drv->queue.entry[drv->queue.wix] = FB_STATE_EMPTY; #endif } void display_ensure_refreshed(void) { #ifndef BOARDLOADER + display_driver_t *drv = &g_display_driver; + if (!is_mode_handler()) { - wait_for_fb_switch(); - // the update time is collected after starting the BG copy, then we need to - // wait: for the bg copy to finish and for at least one full refresh cycle - // before we can consider the display fully redrawn - while (HAL_GetTick() - last_fb_update_time < 40) { + bool copy_pending; + + // Wait until all frame buffers are written to the display + // so we can be sure there's not scheduled or pending + // background copying + do { + copy_pending = false; + for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { + frame_buffer_state_t state = drv->queue.entry[i]; + if (state == FB_STATE_READY || state == FB_STATE_COPYING) { + copy_pending = true; + break; + } + } + __WFI(); + } while (copy_pending); + + // Wait until the display is fully refreshed + // (TE signal is low when the display is updating) + while (GPIO_PIN_RESET == + HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { __WFI(); } } diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.h b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.h index 437b54646..0afa1de2d 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.h +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_fb.h @@ -29,8 +29,6 @@ void display_physical_fb_clear(void); void display_ensure_refreshed(void); -void wait_for_fb_switch(void); - #endif // XFRAMEBUFFER #endif // TREZORHAL_DISPLAY_FB_H diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h new file mode 100644 index 000000000..611e02e0c --- /dev/null +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_internal.h @@ -0,0 +1,59 @@ +#ifndef TREZORHAL_DISPLAY_INTERNAL_H +#define TREZORHAL_DISPLAY_INTERNAL_H + +#include + +#ifdef XFRAMEBUFFER + +// Number of frame buffers used (1 or 2) +// If 1 buffer is selected, some animations may not +// be so smooth but the memory usage is lower. +#define FRAME_BUFFER_COUNT 2 + +// Each frame buffer can be in one of the following states: +typedef enum { + // The frame buffer is empty and can be written to + FB_STATE_EMPTY = 0, + // The frame buffer pass passed to application + FB_STATE_PREPARING = 1, + // The frame buffer was written to and is ready + // to be copied to the display + FB_STATE_READY = 2, + // The frame buffer is currently being copied to + // the display + FB_STATE_COPYING = 3, + +} frame_buffer_state_t; + +typedef struct { + // Queue entries + volatile frame_buffer_state_t entry[FRAME_BUFFER_COUNT]; + // Read index + // (accessed & updated in the context of the interrupt handlers + uint8_t rix; + // Write index + // (accessed & updated in context of the main thread) + uint8_t wix; + +} frame_buffer_queue_t; + +#endif // XFRAMEBUFFER + +// Display driver state +typedef struct { +#ifdef XFRAMEBUFFER + // Framebuffer queue + // (accessed & updated in the context of the main thread + // and the interrupt context) + volatile frame_buffer_queue_t queue; +#endif + + // Current display orientation (0, 90, 180, 270) + int orientation_angle; + +} display_driver_t; + +// Display driver instance +extern display_driver_t g_display_driver; + +#endif // TREZORHAL_DISPLAY_INTERNAL_H diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c index fe02ca207..edb12ef49 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_io.c @@ -22,6 +22,7 @@ #include "display_io.h" #include "irq.h" +#include "supervise.h" __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS = (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE); @@ -35,7 +36,6 @@ void display_io_init_gpio(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); - __HAL_RCC_FMC_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStructure; @@ -87,6 +87,8 @@ void display_io_init_gpio(void) { } void display_io_init_fmc(void) { + __HAL_RCC_FMC_CLK_ENABLE(); + // Reference UM1725 "Description of STM32F4 HAL and LL drivers", // section 64.2.1 "How to use this driver" SRAM_HandleTypeDef external_display_data_sram = {0}; @@ -141,5 +143,6 @@ void display_io_init_te_interrupt(void) { // setup interrupt for tearing effect pin HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0); + svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); } #endif diff --git a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c index 011bc7a3b..412427a0b 100644 --- a/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c +++ b/core/embed/trezorhal/stm32f4/xdisplay/st-7789/display_nofb.c @@ -25,7 +25,23 @@ #include "display_panel.h" void display_refresh(void) { - // if the framebuffer is not used the implementation is empty + // If the framebuffer is not used the, we do not need + // to refresh the display explicitly as we write the data + // directly to the display internal RAM. +} + +void display_wait_for_sync(void) { +#ifdef DISPLAY_TE_PIN + uint32_t id = display_panel_identify(); + if (id && (id != DISPLAY_ID_GC9307)) { + // synchronize with the panel synchronization signal + // in order to avoid visual tearing effects + while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) + ; + while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) + ; + } +#endif } static inline void set_window(const gfx_bitblt_t* bb) { diff --git a/core/embed/trezorhal/stm32u5/bg_copy.c b/core/embed/trezorhal/stm32u5/bg_copy.c index 054328c96..97c2b6b66 100644 --- a/core/embed/trezorhal/stm32u5/bg_copy.c +++ b/core/embed/trezorhal/stm32u5/bg_copy.c @@ -9,6 +9,7 @@ static volatile uint32_t dma_transfer_remaining = 0; static volatile uint32_t dma_data_transferred = 0; static void *data_src = NULL; static void *data_dst = NULL; +static bg_copy_callback_t bg_copy_callback = NULL; static DMA_HandleTypeDef DMA_Handle = {0}; void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma) { @@ -46,6 +47,10 @@ void GPDMA1_Channel0_IRQHandler(void) { HAL_NVIC_DisableIRQ(GPDMA1_Channel0_IRQn); data_src = NULL; data_dst = NULL; + + if (bg_copy_callback != NULL) { + bg_copy_callback(); + } } } @@ -57,12 +62,14 @@ void bg_copy_wait(void) { } } -void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size) { +void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size, + bg_copy_callback_t callback) { uint32_t data_to_send = size > MAX_DATA_SIZE ? MAX_DATA_SIZE : size; dma_transfer_remaining = size; dma_data_transferred = 0; data_src = (void *)src; data_dst = (void *)dst; + bg_copy_callback = callback; // setup DMA for data copy to constant output address diff --git a/core/embed/trezorhal/xdisplay_legacy.c b/core/embed/trezorhal/xdisplay_legacy.c index 516f74640..8f63db4bc 100644 --- a/core/embed/trezorhal/xdisplay_legacy.c +++ b/core/embed/trezorhal/xdisplay_legacy.c @@ -40,4 +40,8 @@ int display_backlight(int level) { } } -void display_sync(void) {} +void display_sync(void) { +#ifndef XFRAMEBUFFER + display_wait_for_sync(); +#endif +}