Dashboard

This document aims to guide users in quickly setting up a development environment, including compiling the SDK, flashing firmware, upgrading firmware, and capturing logs. Users can download the test files from the SDK to ensure that the EVB functions properly and is compatible with the development environment.

The Dashboard SDK provides commonly used basic features such as vehicle speed monitoring, GUI framework, and message distribution. Additionally, the SDK offers easily expandable API interfaces, facilitating secondary development for dashboard manufacturers.

Note

The dashboard example described in this document uses the RTL8773EWP chip, paired with the EQT500BYZ048G RGB (800 by 400) display screen. If developers choose to use the default hardware environment described in this document, they can directly run the example project.

According to the EVB workflow diagram, users can compile the project in the SDK using Keil. After that, they can use MPPG Tool to download the files into the EVB. Once the downloading is complete, they can use Debug Analyzer to capture the logs from the SoC side.

Practical Application Case

The following diagram illustrates the modules incorporated in the Dashboard application:

../../_images/fig_module_8773EWP.png

Dashboard Application Modules

The following diagram presents an overview of the modules included in the Dashboard application, it consists of a motherboard, a daughterboard, and an LCD screen.

../../_images/hal_env.png

Dashboard Application Case

Supported Features

Realtek dashboard application provides complete support for the dashboard features.

  • Supports Bluetooth/USB communication modes.

  • Supports the dashboard feature.

  • Supports OTA software upgrade.

  • Supports incoming call notification and message pop-up feature.

  • Supports A2DP.

  • Supports GATT over BR/EDR.

The RTL8773EWP supports the Bluetooth Core Specification v5.3 and has a wide power supply range of 1.8V to 3.3V, giving developers more flexibility in selecting compatible peripherals.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

Build Target

RTL8773EWP HDK

RTL8773EWP EVB

dashboard_dual_bank0

dashboard_dual_bank1

Note

To purchase EVB, please visit https://www.realmcu.com/en/Home/Shop.

To quickly set up the development environment, please refer to the detailed instructions provided in Quick Start.

LCD

The default supported LCD models in the application are listed in the following table.

LCD Modules

Board Name

LCD

RTL8773EWP EVB

EQT500BYZ048G

For convenience in testing the LCD, we have developed an adapter board. Simply plug the adapter board into the card slot of the EVB, and users can test and use the LCD.

RTL8773EWP EVB

The LCD model is connected to the EVB via an adapter board. Simply plug the adapter board into J35 of the EVB.

../../_images/dashboard_gui_evb_rtl8773ewp.png

8773EWP EVB with LCD

../../_images/dashboard_gui_evb_rtl8773ewp_B.png

8773EWP EVB

The mapping relationship of the LCD, and EVB pins is shown in the following table.

PINMUX Mapping

LCD

EVB

LCDC_DATA0

P2_6

LCDC_DATA1

P2_7

LCDC_DATA2

P4_0

LCDC_DATA3

P4_1

LCDC_DATA4

P4_2

LCDC_DATA5

P4_3

LCDC_DATA6

P4_4

LCDC_DATA7

P4_5

LCDC_DATA8

P4_6

LCDC_DATA9

P4_7

LCDC_DATA10

P8_0

LCDC_DATA11

P8_1

LCDC_DATA12

P8_2

LCDC_DATA13

P8_3

LCDC_DATA14

P8_4

LCDC_DATA15

P8_5

LCDC_DATA16

P8_6

LCDC_DATA17

P8_7

LCDC_DATA18

P9_1

LCDC_DATA19

P9_2

LCDC_DATA20

P9_3

LCDC_DATA21

P9_4

LCDC_DATA22

P9_5

LCDC_DATA23

P9_6

LCDC_RGB_WRCLK

P2_5

LCDC_HSYNC

P2_4

LCDC_CSN_DE

P2_3

LCDC_VSYNC

P2_2

LCDC_RESET

P9_0

Tools

SDK provides image conversion tools that facilitate the conversion of images, such as JPG, PNG, BMP, into burnable BIN files. The image conversion tool provided by the SDK is located in the sdk\tool path. The interface of the image conversion tool is as follows.

../../_images/dashboard_image_convert_tool.png

Image Convert Tool

If users want to learn more about the tool’s usage guidelines, more information can be found in the introduction documentation for the image conversion tool in the sdk\doc\EN directory.

Files

The previous chapter introduced the steps for converting image resources. For font resource conversion, it is necessary to consult with FAE to address the requirements. Once both the image and font resources have been generated as binary files, the packaging tool can be used to convert them into the final userdata binary file.

The GUI package tool provided by the SDK is located in the sdk\tool\Gadgets\gui_package_tool path. Select the folder according to the IC type.

../../_images/dashboard_gui_package_tool.png

GUI Package Tool

  1. Place the bin files of the images and fonts into the root folder.

  2. Execute the gen_root_image.bat.

  3. A userdata bin file will be generated in the current path. Please select the file with the suffix and random number.

While packing the userdata file, a resource.h file will also be generated. This file is used to generate the APP bin file, and the APP code can use the addresses of the images or fonts in this file to index the related resources.

Wiring

The EVB evaluation board provides a hardware environment for user development and application debugging. The EVB consists of a main board and a daughter board. It has download mode and working mode, and users need to use different wiring methods to set the EVB into the desired mode.

Power Supply

As shown in figure, the USB interface provides power to the EVB.

../../_images/dashboard_wiring_power_supply.png

Power Supply

Power Select

As shown in figure, all the jumpers marked with a red box need to be connected.

../../_images/dashboard_wiring_power_select.png

Power Selection

UART

As shown in figure, when using UART, users need to connect it to the FT232 USB.

../../_images/dashboard_wiring_ft232_usb.png

Dashboard with FT232

Download Mode

Two blue buttons are pressed status, short P2_0 and SW, then press the Reset button to enter download programming mode.

../../_images/dashboard_wiring_uart_download.png

Download Mode

Working Mode

To ensure the normal operation of the EVB, it is necessary to disconnect the shorting between P2_0 and SW. P2_0 is the default log output PINMUX. Users can connect the RXD of an external FT232 to receive the log.

../../_images/dashboard_wiring_uart_log_output.png

Working Mode

Reset

As shown in figure, there is a Reset button on both the front and back sides of the EVB board.

../../_images/dashboard_wiring_reset.png

Reset Button

Configurations

The functionalities included in the dashboard can be enabled or disabled through the following macro definitions.

#if F_APP_DASHBOARD_DEMO_SUPPORT

#undef F_APP_BT_AUDIO_TRANSMITTER_DEMO_SUPPORT
#define F_APP_BT_AUDIO_TRANSMITTER_DEMO_SUPPORT        0

#undef F_APP_DSP_SHM_80KB_TO_MCU_CHECK_SUPPORT
#define F_APP_DSP_SHM_80KB_TO_MCU_CHECK_SUPPORT         1

#undef F_APP_A2DP_SINK_SUPPORT
#define F_APP_A2DP_SINK_SUPPORT                 1
#undef F_APP_HFP_HF_SUPPORT
#define F_APP_HFP_HF_SUPPORT                    1

#undef F_APP_DISABLE_NOTIFICATION_SUPPORT
#define F_APP_DISABLE_NOTIFICATION_SUPPORT      1
#undef F_APP_BLE_HID_DEVICE_SUPPORT
#define F_APP_BLE_HID_DEVICE_SUPPORT            0
#undef F_APP_BT_PROFILE_PBAP_PCE_SUPPORT
#define F_APP_BT_PROFILE_PBAP_PCE_SUPPORT       1
#undef F_APP_PBAP_CMD_SUPPORT
#define F_APP_PBAP_CMD_SUPPORT                  1
#undef F_APP_BT_PROFILE_MAP_MCE_SUPPORT
#define F_APP_BT_PROFILE_MAP_MCE_SUPPORT        1
#undef F_APP_BT_ANCS_CLIENT_SUPPORT
#define F_APP_BT_ANCS_CLIENT_SUPPORT           1
#undef F_APP_BLE_AMS_CLIENT_SUPPORT
#define F_APP_BLE_AMS_CLIENT_SUPPORT            1


#ifdef CONFIG_SOC_SERIES_RTL8773E
#define F_APP_HONEY_GUI                     1
#define F_APP_GUI_USE_PSRAM                 1
#define F_APP_GUI_RAMLESS                   0
#define F_APP_PACKAGE_QFN68                 1
#define F_APP_SUPPORT_USB                   0
#define RTK_MODULE_RTK_PPEV2

#if F_APP_GUI_USE_PSRAM
#define PSRAM_FRAME_BUF1_ADDR               0x4000000
#define PSRAM_FRAME_BUF2_ADDR               (0x4000000 + 800 * 480 * 2)
#define PSRAM_GUI_HEAP_ADDR                 (0x4000000 + 800 * 480 * 2 * 2)
#define PSRAM_GUI_HEAP_SIZE                 0x200000
#else
#define ENABLE_RTK_GUI_OS_HEAP
#endif

#endif

#endif /* end of F_APP_DASHBOARD_DEMO_SUPPORT */

Building and Downloading

This application can be found under sdk\board\evb\dashboard\mdk in SDK folder structure.

Take the project rtl87x3ep_dashboard.uvprojx and target dashboard_dual_bank0 as an example, to build and run the sample with Keil development environment, follow the steps listed below:

  1. Open the project rtl87x3ep_dashboard.uvprojx.

  2. Make sure that F_APP_DASHBOARD_DEMO_SUPPORT is set to 1 in Keil project settings.

    ../../_images/dashboard_keil_options.png

    Define Macro Definition

  3. Choose the build target dashboard_dual_bank0.

    ../../_images/dashboard_chose_build_target.png

    Choose Build Target

  4. Build the target.

    ../../_images/dashboard_building.png

    Start Building

    After a successful buliding, the APP bin file dashboard_bank0_MP-v0.0.0.0-xxx.bin will be generated in the directory bin\rtl87x3ep\flash_16M_dualbank\bank0.

    Note

    If the version_gen_config.sh file cannot be executed during the compilation, please check if the following environments are correctly set up:

    • Ensure that the git software is installed.

    • If git bash is installed, make sure to configure the git bash environment variables correctly.

  5. Download the generated APP bin dashboard_bank0_MP-v0.0.0.0-xxx.bin into EVB.

    The files required for burning are as shown in the image below. The default paths for the burning files are:

    • bin\rtl87x3ep\8773EWP\16M\BANK0

    • bin\rtl87x3ep\8773EWP\16M\rcfg\For EVB

    Note

    • Be sure to place the SDK, tools, and other materials in non-Chinese paths, and ensure that all images in the aforementioned paths are loaded into the tool and burned together.

    • The SDK also provides a default bin for the dashboard APP bin dashboard_bank0_MP-va.b.c.d-yyyyyyyy in the directory bin\rtl87x3ep\app_demo_bin\mdk\dashboard\16M\BANK0. Users can directly use this default file without modifying any code.

    ../../_images/dashboard_all_download_image.png

    Download All Images

    If the IC type supports GUI functionality, it will also require download a resource bin named userdata.bin, which includes font and image resources.

    ../../_images/dashboard_download_userdata_bin.png

    User Data Bin

    Userdata bin which prefix starts with root is in the directory bin\rtl87x3ep\flash_16M_dualbank\bank0.

    ../../_images/dashboard_userdata_location.png

    Location of User Data Bin

  6. Press the Reset button on EVB board.

SWD Wiring

J-Link PINMUX Mapping

RTL8773EWP

SWD

GND

GND

P1_0

SWIO

P1_1

SWCK

VDEX

Vterf/3.3V

../../_images/dashboard_swd_wiring.png

J-Link PINMUX on EVB

Experimental Verification

After burning the sample program to the EVB, users can test it with a phone.

Testing with Phone

Prepare a development board named DUT and a Phone, and use Debug Analyzer to get the logs.

Preparation Phase

  1. Build the application, and download images into DUT.

Testing Phase

  1. After the program is burned, refer to Working Mode to put the EVB into working mode.

  2. DUT press Reset button, if boot success, the LCD will show screen below.

../../_images/dashboard_display.png

Display

  1. Enable Bluetooth in Settings, search the Bluetooth devices. Tap the device dashboard to pair.

../../_images/dashboard_phone_bluettoth_setting.jpg

Pair with Dashboard

  1. After pairing successfully, the device dashboard will show in list MY DEVICES.

../../_images/dashboard_phone_bluettoth_paired.jpg

Pairing Successfully

  1. Through the proprietary protocol or ANCS, notifications such as SMS and WeChat messages can be displayed in real-time on the dashboard interface.

../../_images/dashboard_message.png

Message Display on Dashboard

  1. Through the proprietary protocol or ANCS, notifications of calls can be displayed in real-time on the dashboard interface, enabling further call handling functionalities including answer/end call operations.

../../_images/dashboard_call.png

Call Display on Dashboard

  1. Through the proprietary protocol, navigation content (simplified or enhanced modes) can be displayed in real-time on the dashboard interface.

../../_images/dashboard_navigation_2.png

Simplified Navigation Display on Dashboard

../../_images/dashboard_navigation_1.png

Enhanced Navigation Display on Dashboard

Software Design Introduction

This chapter mainly introduces the software-related technical parameters and behavioral specifications of the RTL8773EWP dashboard solution. It provides a software overview of all dashboard functions, which are used to guide dashboard development and track problems encountered in software testing.

Source Code Directory

  • Project directory: sdk\board\evb\dashboard.

  • Source code directory: sdk\src\sample\dashboard and sdk\src\sample\bt_audio_trx.

Source files in dashboard application project are currently categorized into several groups as below.

└── Project: dashboard
    └── include                         includes project configuration header files
        ├── rom_uuid.h
        ├── board.h
        ├── config.h
        ├── mem_config.h
        ├── app_flags.h
        └── app_lea_customer.h
    └── lib                             includes all binary symbol files that user application is built on
    └── cmsis                           includes startup code
        ├── startup_rtl87x3ep.c
        └── system_rtl87x3.c
    └── app                             includes main and basic functions
        ├── app_main.c
        ├── app_cfg.c
        ├── app_console.c
        ├── app_io_msg.c
        └── ...
    ├── ble                             includes LE related code
    ├── uart_dfu                        includes UART DFU related code
    ├── cfu                             includes CFU related code
    └── dashboard_app                   includes dashboard related code
        ├── app_dashboard_connected_display.c
        ├── app_dashboard_data.c
        ├── app_dashboard_launcher.c
        ├── app_dashboard_main_display.c
        ├── app_panel_init.c
        ├── benchmark_common.c
        └── app_gui_bt_policy.c
    ├── realgui/port                    includes all GUI port
    ├── realgui/3rd                     includes Third-party library
    ├── realgui/app                     includes Realtek GUI APP
    ├── realgui/dc                      includes Realtek GUI APP
    ├── realgui/engine                  includes all GUI engine
    ├── realgui/demo                    includes all GUI demo
    ├── realgui/input                   includes all GUI input
    ├── realgui/misc                    includes all GUI misc
    ├── realgui/widget                  includes all GUI widget
    ├── ppe                             includes PPE related code
    ├── communication                   includes all communication drivers and module code used by the application
    ├── findmy
    └── ...

Flash Layout

Application default flash layout header file: sdk\bin\rtl87x3ep\flash_map_config\16M\flash_16M\flash_map.h.

Example Layout

Example Layout (Flash Size 16MB)

Size (byte)

Start Address

EQ_Fitting

4K

0x02000000

Reserve

7K

0x02000400

OEM Config

5K

0x02002000

Bank0 Boot Patch

12K

0x02004000

Bank1 Boot Patch

12K

0x02007000

Platform

20K

Lowerstack

28K

Upperstack

252K

OTA Bank0

1760K

0x02055000

  • OTA Header

1K

0x02055000

  • Stack Patch

163K

0x02055400

  • System Patch

104K

0x0207E000

  • APP

1136K

0x02098000

  • DSP System

128K

0x021B4000

  • DSP APP

200K

0x021D4000

  • DSP Config

20K

0x02206000

  • APP Config

8K

0x0220B000

  • APP Extend Image0

0K

0x00000000

  • APP Extend Image1

0K

0x00000000

  • APP Extend Image2

0K

0x00000000

  • APP Extend Image3

0K

0x00000000

OTA Bank1

1760K

0x0220D000

VP Data

200K

0x023C5000

FTL

84k

0x02FE9000

BKB DATA1

0

0x00000000

BKB DATA2

8k

0x02FFE000

APP Defined Section

60K

0x02400000

User Data1

9860K

0x0240f000

Important

Software Architecture

The system software architecture is shown below:

../../_images/template_sw_architecture.png

Software Architecture

  • Platform: Includes OTA, Flash, FTL and etc.

  • IO Drivers: Provide application layer access to the interface of peripherals.

  • OSIF: Abstraction layer for real-time operating systems.

  • GAP: Abstraction layer which user application communicates with LE stack.

../../_images/GUI_SW__architecture.png

Dashboard Application System Diagram

Tasks and Priorities

RTL8773EWP uses RTOS by default, and encapsulates a layer of OS if interface on this basis. RTL8773EWP has built-in Timer Task, Idle Task, Flash Task, Bluetooth Controller Stack Task, Bluetooth Host Stack Task, and the dashboard application has its own APP Task, GUI Task, Communication Send Task, and Communication Receive Task.

../../_images/dashboard_task.png

Dashboard Application Task Composition

Task and Priority Table

Task

Description

Priority

Timer Task

Implement software timers as required by FreeRTOS.

6

Bluetooth Controller Stack Task

Implement the Bluetooth protocol stack below the HCI layer.

6

Bluetooth Host Stack Task

Implement the Bluetooth protocol stack above the HCI layer.

3

Flash Task

Handle asynchronous flash requests.

1

Idle Task

Run background tasks, including DLPS.

0

Console Task

Process console UART messages.

3

APP Task

Process various messages and events through message queues and event processing functions to manage and control Bluetooth functions.

2

GUI Task

Process image generation and screen data transmission.

1

Communication Send Task

Manage and transmit Bluetooth data.

1

Communication Receiver Task

Receive and process Bluetooth data.

1

Receiving WiFi Data Task

Receive wifi data and process.

3

Note

  • Multiple application tasks can be created, and memory resources will be allocated accordingly.

  • Idle Task and Timer Task are provided by FreeRTOS.

  • Tasks have been configured to be preemptive based on their priority using the SysTick interrupt.

  • Interrupt Service Routines (ISR) have been implemented by the vendor.

APP Task initialization related code entry:

int main(void)
{
    ...

#if CONFIG_REALTEK_APP_DASHBOARD_DEMO_SUPPORT
    app_system_clock_init();
    drv_lcd_init();
#endif
    ...

#if CONFIG_REALTEK_APP_DASHBOARD_DEMO_SUPPORT
#if F_APP_CAN_SUPPORT
    extern void can_trx_dlps_demo(void);
    can_trx_dlps_demo();
#endif
#if F_APP_WIFI_SPI_MAP_SUPPORT
#if  SDIO_ENABLE
    app_sdio_console_init();
#else
    app_spi_console_init();
#endif
#endif
    app_task_init();
    communicate_task_init();
#endif

    APP_PRINT_INFO1("TIME FROM APP TO OS SCHED: %d ms", sys_timestamp_get() - time_entry_app);

    os_sched_start();

}

APP Task

../../_images/app_task.png

APP Task Architecture

  1. The Bluetooth LE related status is handled by gap_handle_msg() to process the messages sent by the upper layer, and the Bluetooth LE data sending and receiving callbacks are registered to the read/write interface registered when the app creates the service.

  2. The user application layer freely implements the control of Bluetooth LE behavior, including broadcast switch, establishing connection, updating connection parameters, etc.

  3. New APP Task: The structure of app_dashboard_launcher displays two basic elements: thread_detry and ui_design.

    1. The ui_design function creates the UI interface and required system resources.

    2. Developers can place programs that execute periodically in the thread_entry or message entry to receive messages from other tasks.

      gui_app_t app_dashboard_launcher =
      {
          .screen =
          {
              .name = "app_dashboard_launcher",
              .x    = 0,
              .y    = 0,
          },
          .thread_entry = app_dashboard_launcher_update_thread,
          .ui_design = app_dashboard_launcher_ui_design,
      };
    
      gui_app_t *get_app_dashboard_launcher(void)
      {
          return &app_dashboard_launcher;
    }
    

Receiving WiFi Data Task

WiFi 8720CF and RTL8773EWP Data Transmission via SPI/SDIO.

Interface:

  • 8720CF acts as the master with an SPI clock of 8MHz.

  • RTL8773EWP acts as the slave.

  • RTL8773EWP uses GDMA Multi-block transfer to read data from the master into the slave’s PSRAM buffer.

  • The GDMA block size is set to 32K, with 15 blocks.

  • Currently, GDMA block interrupts are enabled. This means GDMA generates an interrupt every time it transfers 32K of data. In the interrupt function, the p_spi_console_callback function is called to trigger the data processing flow.

Data Parsing:

  • RTL8773EWP has a circular buffer pool with a size of CONSOLE_RX_BUFFER_SIZE (15 * 32 * 1024 bytes).

  • SPI triggers a GDMA block interrupt every time it receives 32KB of data, updating the buffer pool with the received data.

  • If data parsing is not busy, it triggers the mp_cmd_set_parser function to parse the data; otherwise, it waits until data parsing is not busy.

  • Each time, 32KB of data is passed to the parser. If there is still data left to parse after parsing 32KB, it continues to trigger the next 32KB data parsing. If the buffer pool is empty, parsing stops.

Data Processing:

  • After parsing, the data is verified using CRC. The relevant parameters are then extracted and passed to the app_handle_cmd_set function for data processing.

  • The current CMD_IDs used for WiFi transmission are:

    • CMD_FILE_TX_START_CMD (0x0050): Indicates entering or exiting WiFi data transmission mode.

    • CMD_FILE_CMD (0x0051): Indicates data transmission control, including File Index, data transmission start or end, File Type, total File Size, File Name length, CRC, and file name.

    • CMD_FILE_DATA (0x0052): Indicates data content. The transmission content is set as follows:

      • Each file is sliced into 500KB chunks by default.

      • buf_500k_index indicates the current 500KB chunk number.

      • buf_500k_size indicates the size of the chunk, default is 500KB.

      • packet_500k indicates the packet number within the 500KB chunk ,for data is sent in 1KB packets by default.

      • packet_flag indicates whether the current packet is the first, last, or a middle packet.

    • CMD_FILE_DUMMY_DATA (0x0053): Indicates dummy data. Since data transfer is done via DMA, a 32K data processing trigger is needed. After all valid data is sent, 32K of dummy data is sent to ensure all valid data is parsed.

Communication Task

Two communication tasks have been implemented, including Communication Receive Task and Communication Send Task, which are responsible for the management of GATT data transmission, packaging the data according to the current transmission data command format and sending it through the Bluetooth protocol stack. Customers generally use their own Bluetooth data interaction format. Tasks can be used as a reference for sending methods or they can be implemented by themselves. Developers must refer to Bluetooth to familiarize themselves with the GATT service structure and how to process messages. In this design document, we will use the specified GATT service of the dashboard application as a demonstration. Developers can choose which GATT services to use in the mobile application according to their product requirements.

../../_images/dashboard_ble_task.png

Dashboard Communication Block Diagram

After the mobile APP successfully connects to the dashboard device, the APP can transmit necessary information to the device using LE write requests. All messages will be written via characteristics.

/*** @brief write characteristic data from stack. *
* @param ServiceId ServiceId generated when register to BT Host stack.
* @param iAttribIndex Attribute index of getting characteristic data.
* @param wLength length of data to be written.
* @param pValue pointer of data to be written.
* @return TProfileResult profile procedure results.         */
T_APP_RESULT bwps_service_attr_write_cb(uint8_t conn_id, T_SERVER_ID service_id,
    uint16_t attrib_index, T_WRITE_TYPE write_type, uint16_t length, uint8_t *p_value,
                                        P_FUN_WRITE_IND_POST_PROC *p_write_ind_post_proc)
{
    T_APP_RESULT  wCause  = APP_RESULT_SUCCESS;
    uint8_t *buf = NULL;
    APP_PRINT_INFO2("bwps_service_attr_write_cb: attrib_index = %d, data %b", attrib_index,
    CE_BINARY(length, p_value));

    if (p_value == NULL)
    {
        APP_PRINT_ERROR0("bwps_service_attr_write_cb, p_value is NULL");
        wCause = APP_RESULT_INVALID_VALUE_SIZE;
        return wCause;
    }

    switch (attrib_index)
    {
    default:
        wCause = APP_RESULT_ATTR_NOT_FOUND;
        APP_PRINT_ERROR2("bwps_service_attr_write_cb Error: attrib_index 0x%x, length %d", attrib_index,  length);
        break;
    case GATT_SRV_BWPS_TX_INDEX:
        APP_PRINT_INFO0("bwps_service_attr_write_cb, GATT_SRV_BWPS_TX_INDEX");
        /* copy gatt write value in tx_buffer, the first byte is value length*/
#if 1
        buf = malloc((length + 1) * sizeof(uint8_t));
        buf[0] = length;
        memcpy(buf + 1, p_value, length);
        extern void *raw_data_receive_queue_handle;
        if (os_msg_send(raw_data_receive_queue_handle, &buf, 0) == false)
        {
            APP_PRINT_ERROR0("send_msg_to_l1send_task_fail");
            free(buf);
        }
#endif
        break;
    case GATT_SRV_BWPS_DEVNAME_INDEX:
        APP_PRINT_INFO0("BWPS: update device name\n");
        break;
    }

    return wCause;
}

All received messages will be published to the raw_data_receive_queue_handle queue, which will be processed in the resolve_remote_data.

void l1receive_task(void *pvParameters)
{
    uint8_t *buf = NULL;
    os_alloc_secure_ctx(1024);
    os_msg_queue_create(&raw_data_receive_queue_handle, "rec_raw_data", 0x10, sizeof(void *));

    while (true)
    {
        if (os_msg_recv(raw_data_receive_queue_handle, &buf, 0xFFFFFFFF) == true)
        {
            //rt_kprintf("buf2 = 0x%x \n", buf);
            resolve_remote_data(buf + 1, buf[0]);
            free(buf);
        }
    }
}

Once the received data passes the data integrity check, the L2_frame_resolve will process the request. In the dashboard application, developers only need to process three types of data:

  • NAVIGATION_INFORMATION_ID

  • NOTIFY_COMMAND_ID

  • CONTROL_COMMAND_ID

bool L2_frame_resolve(uint8_t *pData, uint16_t length)
{
    if ((pData == NULL) || (length == 0))
    {
        return false;
    }

    WRISTBAND_COMMUNICATE_COMMAND command_id = (WRISTBAND_COMMUNICATE_   COMMAND)pData[0];
    uint8_t first_key = pData[2];
    uint16_t first_value_length = (((pData[3] << 8) | pData[4]) & 0x1FF);
    APP_PRINT_INFO1("L2_frame_resolve length is %d", length);
    switch (command_id)
    {
    case NAVIGATION_INFORMATION_ID:
        {
            APP_PRINT_INFO1("NAVIGATION_INFORMATION_ID, KEY = 0x%x", first_key);
            APP_PRINT_INFO1("NAVIGATION_INFORMATION_ID,length is %d", length);
            APP_PRINT_INFO1("RECEIVE navi info is  %b", TRACE_BINARY(length,
                                                                    (uint8_t *)pData + L2_FIRST_VALUE_POS));
            resolve_Navigation_command(first_key, pData + L2_FIRST_VALUE_POS, first_value_length);
        }
        break;
    case NOTIFY_COMMAND_ID:
        {
            APP_PRINT_INFO2("NOTIFY_COMMAND_ID, KEY = 0x%x, info= 0x%x", first_key, pData[5]);
            resolve_Notify_command(first_key, pData + L2_FIRST_VALUE_POS, first_value_length, pData[5]);
        }
        break;

    case CONTROL_COMMAND_ID:
        {
            APP_PRINT_INFO1("CONTROL_COMMAND, KEY = 0x%x", first_key);
            resolve_Control_command(first_key, pData + L2_FIRST_VALUE_POS, first_value_length);
        }
        break;
    default:
        break;
    }
    return true;
}

Whenever LE receives a message from the mobile APP, it will update the data to the dashboard data container, and then the UI update thread will get the latest information and refresh the display.

GUI Task

GUI refresh is triggered by keystrokes, timers, and other application behaviors. Before the interface is refreshed, the user updates the information of each control in the interface according to the current behavior. The core part of the GUI is drawn in the frame buffer according to the type and position of each control. The frame buffer can be internal RAM or PSRAM. In order to save RAM resources, a whole frame of FrameBuffer is divided into multiple parts (10 lines are used as a block in the current SDK, and a total of 48 blocks are drawn), and the segments are drawn and sent to the screen synchronously through LCDC. When using PSRAM, each part is first updated to the whole frame PSRAM, and then the whole frame is sent directly to the screen through DPI.

../../_images/gui_task_architecture.png

GUI Task architecture

The screen resolution in the demo application is 800*480. We will create two Window widgets as basic containers to display information in the LE connected and unconnected states. The functions app_dashboard_create_main_display and app_dashboard_create_connected_display will create the remaining widgets and attach them to the two window widgets respectively.

Dashboard API Description

Dashboard API Interface

Description

app_dashboard_launcher_update_thread()

The developer can put the data refresh process within this API.

app_dashboard_launcher_ui_design()

Main entrance of UI interface.

app_dashboard_create_main_display()

Display dashboard home page information.

app_dashboard_data_get_show_main_display()

Get dashboard home page information.

app_dashboard_create_connected_display()

Display navigation page information.

app_dashboard_initialize_data()

Initialize control content.

app_update_gui_widget()

Update control content.

app_dashboard_get_data()

Get dashboard information.

app_dashboard_data_set_battery_level()

Set the latest battery data.

app_dashboard_data_get_battery_level()

Get current battery data.

app_dashboard_data_set_car_speed()

Set the current car speed.

app_dashboard_data_get_car_speed()

Get the current car speed.

app_dashboard_data_set_car_turn_info()

Set the current car turning information.

app_dashboard_data_get_car_turn_info()

Get the current car turning information.

app_dashboard_data_set_bluetooth_status()

Set the current Bluetooth status.

app_dashboard_data_get_bluetooth_status()

Get the current Bluetooth status.

app_dashboard_data_set_navi_status()

Set the current navigation status.

app_dashboard_data_get_navi_status()

Get the current navigation status.

app_dashboard_data_update_navi_status()

Update the current navigation status.

app_dashboard_data_set_phone_status()

Set the current phone status.

app_dashboard_data_get_phone_status()

Get the current phone status.

app_dashboard_data_update_phone_status()

Set the current phone information.

app_dashboard_data_set_message_data_update()

Set the current message information.

app_dashboard_data_get_message_data_update()

Get the current message information.

app_dashboard_data_update_message_status()

Update the current message information.

app_dashboard_data_set_current_timer()

Set the current time information.

app_dashboard_data_get_current_timer()

Get the current time information.

app_dashboard_data_set_tense_timer_info()

Set the current tense information.

app_dashboard_data_get_tense_timer_info()

Get the current tense information.

app_dashboard_data_set_reject_end_call()

Set the rejection and hang up the phone.

app_dashboard_data_set_accept_call()

Set the answer phone.

app_dashboard_update_main_display_speed_info()

Update the main interface speed information.

app_dashboard_update_main_display_turn_info()

Update the main interface turn information.

app_dashboard_update_main_display_bluetooth_info()

Update the Bluetooth connection information on the main interface.

app_dashboard_update_main_display_phone_infor()

Update the phone information on the main interface.

app_dashboard_update_main_display_message_infor()

Update the message information on the main interface.

map_update_buffers_display()

Used to update BR/EDR map information framebuffer.

map_display_buffer_stop()

Stop update BR/EDR map information framebuffer.

map_display_normal_navi_stop()

Stop update BLE map information framebuffer.

Application Initialization Functions
  1. app_dashboard_launcher_update_thread

    • Description: The function enters the UI design of the APP’s dashboard launcher.

    • Input Parameter: None.

    • Output Parameter: None.

    // Input parameter: void *this: Process entry
    // Output parameter: None
    void app_dashboard_launcher_update_thread(void *this)
    {
        while (1)
        {
            app_dashboard_auto_refresh_data_demo();
            gui_thread_mdelay(25);
        }
    }
    
  2. app_dashboard_launcher_ui_design

    • Description: APP dashboard launcher ui design enter.

    • Input Parameter: None.

    • Output parameter: None.

    void app_dashboard_launcher_ui_design(gui_app_t *app)
    {
        win_connected_display = gui_win_create(&(app->screen),
                                    "win_connected_display", 0, 0, 800, 480);
        win_main_display = gui_win_create(&(app->screen), "win_main_display", 0, 0, 800, 480);
        gui_font_mem_init(HARMONYOS_SIZE28_BITS1_FONT_BIN);
        gui_font_mem_init(HARMONYOS_SIZE32_BITS1_FONT_BIN);
        gui_font_mem_init(HARMONYOS_SIZE56_BITS1_FONT_BIN);
    
        app_dashboard_create_main_display(win_main_display);
        app_dashboard_create_connected_display(win_connected_display);
        win_main_display->base.not_show = false;
        win_connected_display->base.not_show = true;
        app_dashboard_initialize_data();
    }
    
  3. app_dashboard_initialize_data

    • Description: Initialize the widget content.

    • Input Parameter: None.

    • Output Parameter: None.

    void app_dashboard_initialize_data(void)
    {
        app_current_dashboard_data.current_bluetooth_status = T_BLUETOOTH_INFO_OFF;
        app_current_dashboard_data.show_main_display = true;
        app_current_dashboard_data.refresh_timer_value = 36900;
        app_current_dashboard_data.tense_apm_display = T_TENSE_AM_DISPLAY;
    
        os_timer_create(&refresh_count_timer, "gui-tick", 0, 1000, true, refresh_count_timer_cb);
        os_timer_start(&refresh_count_timer);
    }
    
  4. app_update_gui_widget

    • Description: Update the widget content.

    • Input Parameter:

      • gui_img_t *target_image_obj: Target image object.

      • uint8_t target_value: Update image index.

      • void* target_resource_file[]: Target image list.

      • uint8_t max_index_of_resource: Size of the image list.

    • Output Parameter: None.

    void app_update_gui_widget(gui_img_t *target_image_obj,
                                uint8_t target_value,
                                void *target_resource_file[],
                                uint8_t max_index_of_resource)
    {
        void *target_digital_resource_loc = 0x0;
    
        if (target_value > max_index_of_resource - 1)
        {
            return;
        }
    
        if (target_resource_file[target_value] != 0x0)
        {
            gui_img_set_attribute(target_image_obj,
                                    target_image_obj->base.name,
                                    target_resource_file[target_value],
                                    target_image_obj->base.x,
                                    target_image_obj->base.y);
        }
    }
    
Dashboard Data Management Functions
  1. app_dashboard_auto_refresh_data_demo

    • Description: Use this API to auto-refresh the dashboard’s data for demo purposes.

    • Input Parameter: None.

    • Output Parameter: None.

    void app_dashboard_auto_refresh_data_demo(void)
    {
        uint8_t current_battery_level_temp = 0x0;
        uint8_t current_speed_temp = 0x0;
        T_TURN_INFO current_turn_info_temp;
        T_BLUETOOTH_INFO current_bluetooth_status_temp;
        T_NAVI_INFO current_navi_information;
    
        temp_count++;
        if (temp_count % 2 == 0)
        {
            return;
        }
        current_counter++;
    
        current_battery_level_temp = app_dashboard_data_get_battery_level();
        current_speed_temp = app_dashboard_data_get_car_speed();
    
        current_battery_level_temp++;
        current_speed_temp++;
        if (current_speed_temp >= 50)
        {
            current_speed_temp = 0;
        }
    
        if (current_battery_level_temp >= 100)
        {
            current_battery_level_temp = 0;
        }
    
        /* Demo turn on/off the light */
        if (current_counter % 10 == 0)
        {
            is_blink_the_right_light = !is_blink_the_right_light;
        }
        if (current_counter % 1 == 0)
        {
            is_the_light_on = !is_the_light_on;
        }
        current_turn_info_temp = T_TURN_INFO_NONE;
        if (is_blink_the_right_light)
        {
            if (is_the_light_on)
            {
                current_turn_info_temp = T_TURN_INFO_RIGHT;
            }
        }
        else
        {
            if (is_the_light_on)
            {
                current_turn_info_temp = T_TURN_INFO_LEFT;
            }
        }
    
        app_dashboard_data_set_battery_level(current_battery_level_temp);
        app_dashboard_data_set_car_speed(current_speed_temp);
        app_dashboard_data_set_car_turn_info(current_turn_info_temp);
    }
    
  2. app_dashboard_get_data

    • Description: Retrieve the dashboard information.

    • Input Parameter: None.

    • Output Parameter:

      • app_dashboard_data*: Returns the dashboard data structure.

    app_dashboard_data* app_dashboard_get_data(void)
    {
        return &app_current_dashboard_data;
    }
    
  3. app_dashboard_data_set_battery_level

    • Description: Set the latest battery level data.

    • Input Parameter:

      • uint8_t battery_level: Current battery level data.

    • Output Parameter: None.

    void app_dashboard_data_set_battery_level(uint8_t battery_level)
    {
        app_current_dashboard_data.battery_level = battery_level;
    }
    
  4. app_dashboard_data_get_battery_level

    • Description: Get the current battery level data.

    • Input Parameter: None.

    • Output Parameter:

      • uint8_t: Current battery level data.

    uint8_t app_dashboard_data_get_battery_level(void)
    {
        return app_current_dashboard_data.battery_level;
    }
    
  5. app_dashboard_data_set_car_speed

    • Description: Set the current car speed data.

    • Input Parameter:

      • uint8_t current_car_speed: Current car speed data.

    • Output Parameter: None.

    void app_dashboard_data_set_car_speed(uint8_t current_car_speed)
    {
        app_current_dashboard_data.current_speed = current_car_speed;
    }
    
  6. app_dashboard_data_get_car_speed

    • Description: Get the current car speed data.

    • Input Parameter: None.

    • Output Parameter:

      • uint8_t: Current car speed data.

    uint8_t app_dashboard_data_get_car_speed(void)
    {
        return app_current_dashboard_data.current_speed;
    }
    
  7. app_dashboard_data_set_car_turn_info

    • Description: Set the current car turn information.

    • Input Parameter:

      • T_TURN_INFO current_car_turn_info: Current turn information.

    • Output Parameter: None.

    void app_dashboard_data_set_car_turn_info(T_TURN_INFO current_car_turn_info)
    {
        app_current_dashboard_data.current_turn_information = current_car_turn_info;
    }
    
  8. app_dashboard_data_get_car_turn_info

    • Description: Get the current car turn information.

    • Input Parameter: None.

    • Output parameter:

      • T_TURN_INFO: Current turn information.

    T_TURN_INFO app_dashboard_data_get_car_turn_info(void)
    {
        return app_current_dashboard_data.current_turn_information;
    }
    
  9. app_dashboard_data_set_bluetooth_status

    • Description: Set the current Bluetooth status information.

    • Input Parameter:

      • T_BLUETOOTH_INFO current_bluetooth_status: Current Bluetooth information.

    • Output Parameter: None.

    void app_dashboard_data_set_bluetooth_status(T_BLUETOOTH_INFO current_bluetooth_status)
    {
        app_current_dashboard_data.current_bluetooth_status = current_bluetooth_status;
    }
    
  10. app_dashboard_data_get_bluetooth_status

  • Description: Get the current Bluetooth information.

  • Input Parameter: None.

  • Output parameter:

    • T_BLUETOOTH_INFO: Current Bluetooth information.

T_BLUETOOTH_INFO app_dashboard_data_get_bluetooth_status(void)
{
    return app_current_dashboard_data.current_bluetooth_status;
}
  1. app_dashboard_data_set_navi_status

  • Description: Set the current navigation information.

  • Input Parameter:

    • T_NAVI_INFO current_navi_status: Current navigation status.

  • Output Parameter: None.

void app_dashboard_data_set_navi_status(T_NAVI_INFO current_navi_status)
{
    app_current_dashboard_data.current_navi_info = current_navi_status;
}
  1. app_dashboard_data_get_navi_status

  • Description: Get the current navigation information.

  • Input Parameter: None.

  • Output parameter:

    • T_NAVI_INFO: Current navigation status.

T_NAVI_INFO app_dashboard_data_get_navi_status(void)
{
    return app_current_dashboard_data.current_navi_info;
}
  1. app_dashboard_data_set_phone_status

  • Description: Set the current phone information.

  • Input Parameter:

    • app_phone_data current_phone_status: Current phone status.

  • Output Parameter: None.

void app_dashboard_data_set_phone_status(app_phone_data current_phone_status)
{
    memcpy(&app_current_dashboard_data.current_phone_status,
           &current_phone_status,
           sizeof(app_phone_data));
}
  1. app_dashboard_data_get_phone_status

  • Description: Get the current phone information.

  • Input Parameter: None.

  • Output parameter:

    • app_phone_data: Current phone status.

void app_dashboard_data_get_phone_status(app_phone_data *rtn_phone_status)
{
    memcpy(rtn_phone_status,
           &app_current_dashboard_data.current_phone_status,
           sizeof(app_phone_data));
}
  1. app_dashboard_data_update_phone_status

  • Description: Set the current phone information.

  • Input Parameter:

    • uint8_t key: Current phone status.

    • const uint8_t *pValue: Current phone information.

    • uint16_t length: Length of data.

  • Output Parameter: None.

void app_dashboard_data_update_phone_status(uint8_t key, const uint8_t *pValue, uint16_t length)
{
    if (length <= 11)
    {
        app_phone_data current_phone_status;
        app_dashboard_data_get_phone_status(&current_phone_status);

        memset(current_phone_status.phone_num_msg, 0x0,
             sizeof(current_phone_status.phone_num_msg));

        if (key == KEY_INCOMMING_CALL)
        {
            current_phone_status.phone_status = T_PHONE_STATUS_ONGOING;
        }
        else if (key == KEY_INCOMMING_CALL_ACCEPT)
        {
            current_phone_status.phone_status = T_PHONE_STATUS_ACCEPT;
        }
        else if (key == KEY_INCOMMING_CALL_REFUSE)
        {
            current_phone_status.phone_status = T_PHONE_STATUS_NONE;
        }
        current_phone_status.phone_num_len = length;
        memcpy(current_phone_status.phone_num_msg,
                 pValue, length);
        app_dashboard_data_set_phone_status(current_phone_status);
    }
    else
    {
        APP_PRINT_INFO0("app_dashboard_data_update_phone_status over size");
    }
}
  1. app_dashboard_data_set_show_main_display

  • Description: Refresh the display status information.

  • Input Parameter:

    • uint8_t Value: Current navigation status information.

    • T_LE_EVENT event: Current Bluetooth information.

  • Output Parameter: None.

void app_dashboard_data_set_show_main_display(uint8_t Value, T_LE_EVENT event)
{
    if (event == BP_UPDATE_VALUE_EVENT)
    {
        if (Value == NAVI_START)
        {
            app_current_dashboard_data.show_main_display = false;
        }
        else if (Value == NAVI_IDLE)
        {
            app_current_dashboard_data.show_main_display = true;
        }
    }
    else if (event == BP_LE_DISC_EVENT)
    {
        app_current_dashboard_data.show_main_display = true;
        // message off
        app_message_data current_message_status;
        app_dashboard_data_get_message_data_update(&current_message_status);
        current_message_status.wechat_notify_message = false;
        app_dashboard_data_set_message_data_update(current_message_status);
        // phone num off
        app_phone_data current_phone_status;
        app_dashboard_data_get_phone_status(&current_phone_status);
        current_phone_status.phone_status = T_PHONE_STATUS_NONE;
        app_dashboard_data_set_phone_status(current_phone_status);
    }
}
  1. app_dashboard_data_get_show_main_display

  • Description: Get the current display information.

  • Input Parameter: None.

  • Output parameter:

    • uint8_t: Current display information.

uint8_t app_dashboard_data_get_show_main_display(void)
{
    return app_current_dashboard_data.show_main_display;
}
  1. app_dashboard_data_set_navi_data_update

  • Description: Set the current navigation information.

  • Input Parameter:

    • app_navi_data current_navi_data: Current navigation status.

  • Output Parameter: None.

void app_dashboard_data_set_navi_data_update(app_navi_data current_navi_data)
{
    memcpy(&app_current_dashboard_data.current_navi_data,
           &current_navi_data,
           sizeof(app_navi_data));
}
  1. app_dashboard_data_get_navi_data_update

  • Description: Get the current navigation information.

  • Input Parameter: None.

  • Output parameter:

    • app_navi_data: Current navigation status.

void app_dashboard_data_get_navi_data_update(app_navi_data *rtn_navi_data)
{
    memcpy(rtn_navi_data,
           &app_current_dashboard_data.current_navi_data,
           sizeof(app_navi_data));
}
  1. app_dashboard_data_update_navi_status

  • Description: Set the current navigation information.

  • Input parameters:

    • const uint8_t *pValue: Current navigation information.

    • uint16_t length: Length of data.

  • Output Parameter: None.

void app_dashboard_data_update_navi_status(const uint8_t *pValue, uint16_t length)
{
    int32_t distance = 0;
    uint8_t navi_type = 0;
    navi_type = ((uint8_t *)pValue)[0];

    if (navi_type == TURN_LEFT || navi_type == LEFT_FRONT || navi_type == LEFT_BACK
        || navi_type == LEFT_TURN_AROUND)
    {
        // turn_left();
        app_current_dashboard_data.current_navi_info = T_NAVI_INFO_2;
    }
    else if (navi_type == TURN_RIGHT || navi_type == RIGHT_FRONT || navi_type ==
RIGHT_BACK)
    {
        // turn_right();
        app_current_dashboard_data.current_navi_info = T_NAVI_INFO_3;
    }
    else
    {
        // straight_ahead();
        app_current_dashboard_data.current_navi_info = T_NAVI_INFO_1;
    }
    app_navi_data current_navi_data;
    app_dashboard_data_get_navi_data_update(&current_navi_data);

    memset(current_navi_data.navigation_msg, 0x0, sizeof(current_navi_data.navigation_msg));
    memset(current_navi_data.road_names, 0x0, sizeof(current_navi_data.road_names));

    distance = ((uint8_t *)pValue)[1];
    distance = (distance << 8) + ((uint8_t *)pValue)[2];

    if (distance / 1000)
    {
        sprintf((char *)current_navi_data.navigation_msg, "%d%s%d", distance / 1000, ".",
                (distance % 1000 / 100));
        current_navi_data.navigation_num_len = strlen((char *)
                current_navi_data.navigation_msg);

        memcpy(current_navi_data.navigation_unit, str_def1, strlen(str_def1));
        current_navi_data.navigation_unit_len = strlen(str_def1);

        memcpy(current_navi_data.road_names, str_def2, strlen(str_def2));
        current_navi_data.road_num_len = strlen(str_def2);
        memcpy(current_navi_data.road_names + current_navi_data.road_num_len,
                 (uint8_t *)pValue + 3, length - 3);
        current_navi_data.road_num_len = length - 3 + strlen(str_def2);
    }
    else
    {
        sprintf((char *)current_navi_data.navigation_msg, "%d", distance);
        current_navi_data.navigation_num_len = strlen((char *)
                current_navi_data.navigation_msg);

        memcpy(current_navi_data.navigation_unit, str_def3, strlen(str_def3));
        current_navi_data.navigation_unit_len = strlen(str_def3);

        memcpy(current_navi_data.road_names, str_def4, strlen(str_def4));
        current_navi_data.road_num_len = strlen(str_def4);
        memcpy(current_navi_data.road_names + current_navi_data.road_num_len,
                 (uint8_t *)pValue + 3, length - 3);
        current_navi_data.road_num_len = length - 3 + strlen(str_def4);
    }

    app_dashboard_data_set_navi_data_update(current_navi_data);
}
  1. app_dashboard_data_set_message_data_update

  • Description: Set the current message information.

  • Input Parameter:

    • app_message_data current_message_status: Current message status.

  • Output Parameter: None.

void app_dashboard_data_set_message_data_update(app_message_data current_message_status)
{
    memcpy(&app_current_dashboard_data.current_message_status,
           &current_message_status,
           sizeof(app_message_data));
}
  1. app_dashboard_data_get_message_data_update

  • Description: Get the current message information.

  • Input Parameter: None.

  • Output parameter:

    • app_message_data: Current message status.

void app_dashboard_data_get_message_data_update(app_message_data *rtn_message_status)
{
    memcpy(rtn_message_status,
           &app_current_dashboard_data.current_message_status,
           sizeof(app_message_data));
}
  1. app_dashboard_data_update_message_status

  • Description: Set the current message information.

  • Input parameters:

    • const uint8_t *pValue: Current message information.

    • uint16_t length: Length of data.

    • uint8_t messaye_type: Current message resource.

  • Output Parameter: None.

void app_dashboard_data_update_message_status(const uint8_t *pValue, uint16_t length,
                                            uint8_t messaye_type)
{
    if ((messaye_type == MESSGAE_INFO_QQ) ||
        (messaye_type == MESSGAE_INFO_WECHAT) ||
        (messaye_type == MESSGAE_INFO_MESSAGE))
    {
        app_message_data current_message_status;
        app_dashboard_data_get_message_data_update(&current_message_status);

        memset(current_message_status.wechat_msg, 0x0,
sizeof(current_message_status.wechat_msg));

        current_message_status.wechat_msg_len = length;
        memcpy(&current_message_status.wechat_msg[0], &pValue[0], length);
        current_message_status.wechat_notify_message = true;
        app_dashboard_data_set_message_data_update(current_message_status);

        os_timer_create(&dashboard_message_timer, "gui-tick", 0, 3000, true,
dashboard_message_timer_cb);
        os_timer_start(&dashboard_message_timer);
    }
    else
    {
        APP_PRINT_INFO0("app_dashboard_data_update_message_status message type not supported");
    }
}
  1. app_dashboard_data_set_current_timer

  • Description: Set the current timer information.

  • Input Parameter: None.

  • Output Parameter: None.

void app_dashboard_data_set_current_timer(void)
{
    app_current_dashboard_data.refresh_timer_value++;
    if (app_current_dashboard_data.refresh_timer_value == 43200)
    {
        app_current_dashboard_data.refresh_timer_value = 0;
        app_dashboard_data_set_tense_timer_info(!app_dashboard_data_get_tense_timer_info());
    }
}
  1. app_dashboard_data_set_tense_timer_info

  • Description: Set the current tense information.

  • Input Parameter:

    • T_TENSE_APM_INFO current_tense_apm_info: Current tense information.

  • Output Parameter: None.

void app_dashboard_data_set_tense_timer_info(T_TENSE_APM_INFO current_tense_apm_info)
{
    app_current_dashboard_data.tense_apm_display = current_tense_apm_info;
}
  1. app_dashboard_data_get_tense_timer_info

  • Description: Get the current tense information.

  • Input Parameter: None.

  • Output parameter:

    • T_TENSE_APM_INFO: Current tense information.

T_TENSE_APM_INFO app_dashboard_data_get_tense_timer_info(void)
{
    return app_current_dashboard_data.tense_apm_display;
}
  1. app_dashboard_data_get_current_timer

  • Description: Get the current timer information.

  • Input Parameter: None.

  • Output parameter:

    • uint32_t: Current timer information.

uint32_t app_dashboard_data_get_current_timer(void)
{
    return app_current_dashboard_data.refresh_timer_value;
}
  1. app_dashboard_data_set_reject_end_call

  • Description: Set the reject and end phone call.

  • Input Parameter: None.

  • Output Parameter: None.

void app_dashboard_data_set_reject_end_call(void)
{
    app_phone_data current_phone_status;
    app_dashboard_data_get_phone_status(&current_phone_status);

    if ((current_phone_status.phone_status == T_PHONE_STATUS_ACCEPT) ||
        (current_phone_status.phone_status == T_PHONE_STATUS_ONGOING))
    {
        struct protocol_pack p = {0};
        p.l2_cmd_id = NOTIFY_COMMAND_ID;
        p.l2_key = NOTIFY_CALL_EVENT_REJECT_END;
        p.l2_length = 1;
        p.l2_payload[0] = 0;
        package_prepare_send(&p);
    }
}
  1. app_dashboard_data_set_accept_call

  • Description: Set the accept phone call.

  • Input Parameter: None.

  • Output Parameter: None.

void app_dashboard_data_set_accept_call(void)
{
    app_phone_data current_phone_status;
    app_dashboard_data_get_phone_status(&current_phone_status);

    if (current_phone_status.phone_status == T_PHONE_STATUS_ONGOING)
    {
        struct protocol_pack p = {0};
        p.l2_cmd_id = NOTIFY_COMMAND_ID;
        p.l2_key = NOTIFY_CALL_EVENT_ACCEPT;
        p.l2_length = 1;
        p.l2_payload[0] = 0;
        package_prepare_send(&p);
    }
}
GUI Control Description

GUI Control

Description

gui_win_create()

Create win window.

gui_set_font_mem_resourse()

Find and set font resources in memory.

gui_win_set_animate()

Set window animation effect.

gui_img_set_attribute()

Set the attributes of image object.

gui_img_create_from_mem()

Create image object.

gui_text_create()

Create text object.

gui_text_mode_set()

Set the text mode of text object.

For more details about GUI controls, please refer to the documentation: https://docs.realmcu.com/Honeygui/en/latest/widgets/index.html.

GUI Interface
  1. Create a LE non-connected widget.

    The app_dashboard_create_main_display function will rely on the layout file LE Non-connected State Layout to assign the widgets to the correct coordinates. We will register two events obj_animate to handle the state of the panel before and after refresh. At the end of this function, we will call the refresh function of each widget to display the latest information to the user.

    ../../_images/dashboard_bLE_no_connect_display.png

    LE Non-connected State Layout

void app_dashboard_create_main_display(gui_win_t *target_main_display)
{
    /* set update callback */
    gui_log("app_dashboard_create_main_display\n");
    gui_win_set_animate(target_main_display, 1000, -1, paint_main_display_cb, target_main_display);
    /* set Image data */
    dashboard_background = gui_img_create_from_mem(target_main_display, "dashboard_background",
                                                BACKGROUND_BIN, 0, 0,
                                                800, 480);
    gui_img_set_mode(dashboard_background, IMG_COVER_MODE);
    dashboard_pointer = gui_img_create_from_mem(target_main_display, "dashboard_pointer",
                                                DASHBOARD_0_BIN, 243, 84,
                                                0, 0);
    speed_high_digital = gui_img_create_from_mem(target_main_display, "speed_high_digital", SPED0_BIN,
                                                360, 202, 40, 60);
    speed_low_digital = gui_img_create_from_mem(target_main_display, "speed_low_digital", SPED0_BIN,
                                                406, 202, 40, 60);

    bluetooth_status = gui_img_create_from_mem(target_main_display, "bluetooth_status", BTOF_BIN, 48,
                                            10, 23, 30);
    left_turn_light_status = gui_img_create_from_mem(target_main_display, "left_turn_light_status",
                                                    TL_OF_BIN, 48, 208, 42, 40);
    right_turn_light_status = gui_img_create_from_mem(target_main_display, "right_turn_light_status",
                                                    TR_OF_BIN, 710, 208, 42, 40);
    hour_high_digital = gui_img_create_from_mem(target_main_display, "hour_high_digital", TIMER0_BIN,
                                                355, 12, 9, 16);
    hour_low_digital = gui_img_create_from_mem(target_main_display, "hour_low_digital", TIMER0_BIN, 366,
                                            12, 9, 16);
    min_high_digital = gui_img_create_from_mem(target_main_display, "min_high_digital", TIMER0_BIN, 387,
                                            12, 9, 18);
    min_low_digital = gui_img_create_from_mem(target_main_display, "min_low_digital", TIMER0_BIN, 399,
                                            12, 9, 18);
    tense_high_digital = gui_img_create_from_mem(target_main_display, "tense_high_digital", APM_A_BIN,
                                                417,
                                                12, 9, 18);
    tense_low_digital = gui_img_create_from_mem(target_main_display, "tense_low_digital", APM_M_BIN,
                                                432,
                                                12, 9, 18);
    bat_high_digital = gui_img_create_from_mem(target_main_display, "bat_high_digital", TIMER0_BIN, 394,
                                            360, 9, 18);
    bat_low_digital = gui_img_create_from_mem(target_main_display, "bat_low_digital", TIMER0_BIN, 406,
                                            360, 9, 18);

    tel_box = gui_img_create_from_mem(target_main_display, "tel_box", TELBOX_BIN, 253, 410, 295, 49);
    tel_accept = gui_img_create_from_mem(target_main_display, "tel_accept", TELBOX_BIN, 253, 410, 295,
                                        49);
    tel_reject_end = gui_img_create_from_mem(target_main_display, "tel_reject_end", TELBOX_BIN, 253,
                                            410, 295,
                                            49);
    refuse_button = gui_img_create_from_mem(target_main_display, "refuse_button", REFUS_BIN, 263, 416,
                                            36, 36);
    ans_button = gui_img_create_from_mem(target_main_display, "ans_button", ANS_BIN, 500, 416, 36, 36);
    tel_box_left_button = gui_img_create_from_mem(target_main_display, "tel_box_left_button", SYMB1_BIN,
                                                315, 416, 36, 36);
    tel_box_right_button = gui_img_create_from_mem(target_main_display, "tel_box_right_button",
                                                SYMB2_BIN, 479, 416, 36, 36);
    short_message = gui_img_create_from_mem(target_main_display, "short_message", MESSAGE_BIN, 221,
                                            0, 359, 80);

    map_display = gui_img_create_from_mem(target_main_display, "dashboard_map",
                                        BACKGROUND_BIN, 0, 0,
                                        800, 480);
    map_display->base.not_show = true;
    /* set font data */
    app_phone_data current_phone_status;
    app_dashboard_data_get_phone_status(&current_phone_status);
    short_tel_number = gui_text_create(target_main_display,  "short_tel_number",  322, 415, 158, 30);
    memcpy(&show_tel_number[0], &current_phone_status.current_phone_number[0],
        current_phone_status.current_phone_number_len);
    gui_text_set(short_tel_number, (char *)show_tel_number, GUI_FONT_SRC_BMP, gui_rgb(UINT8_MAX,
                UINT8_MAX, UINT8_MAX), current_phone_status.current_phone_number_len, 28);
    gui_text_mode_set(short_tel_number, CENTER);
    short_tel_accept = gui_text_create(target_main_display, "short_tel_accept", 360, 415, 800, 30);
    gui_text_set(short_tel_accept, "calling", GUI_FONT_SRC_BMP, gui_rgb(UINT8_MAX, UINT8_MAX,
                                                                        UINT8_MAX),
                7, 32);

    app_message_data current_message_status;
    app_dashboard_data_get_message_data_update(&current_message_status);
    memcpy(&show_message_data[0], &current_message_status.wechat_msg[0],
        current_message_status.wechat_msg_len);
    short_message_data = gui_text_create(target_main_display,  "short_message_data",  300, 10, 240, 60);
    gui_text_set(short_message_data, (char *)show_message_data, GUI_FONT_SRC_BMP, gui_rgb(UINT8_MAX,
                UINT8_MAX, UINT8_MAX), (current_message_status.wechat_msg_len), 32);
    gui_text_mode_set(short_message_data, MULTI_LEFT);
    /* Prepare the intial data */
    app_dashboard_update_main_display_speed_info(app_dashboard_data_get_car_speed());
    app_dashboard_update_main_display_time_info();
    app_dashboard_update_main_display_tense_apm_info(app_dashboard_data_get_tense_timer_info());
    app_dashboard_update_main_display_battery_info(app_dashboard_data_get_battery_level());
    app_dashboard_update_main_display_turn_info(app_dashboard_data_get_car_turn_info());
    app_dashboard_update_main_display_bluetooth_info(app_dashboard_data_get_bluetooth_status());
    app_dashboard_update_main_display_phone_infor(&current_phone_status);
    app_dashboard_update_main_display_message_infor(&current_message_status);
}
  1. LE connection status layout.

void app_dashboard_create_connected_display(gui_win_t *target_connected_display)
{
    /* set update callback */
    gui_win_set_animate(target_connected_display, 1000, -1, paint_connected_display_cb,
                        target_connected_display);

    /* set Image data */
    dashboard_c_background = gui_img_create_from_mem(target_connected_display, "dashboard_c_background",
                                                    BACKGROUND_C_BIN, 0, 0, 800, 480);
    gui_img_set_mode(dashboard_c_background, IMG_COVER_MODE);
    speed_high_c_digital = gui_img_create_from_mem(target_connected_display, "speed_high_c_digital",
                                                SPED_C0_BIN, 214, 232, 27, 40);
    speed_low_c_digital = gui_img_create_from_mem(target_connected_display, "speed_low_c_digital",
                                                SPED_C0_BIN, 251, 232, 27, 40);
    hour_high_c_digital = gui_img_create_from_mem(target_connected_display, "hour_high_digital",
                                                TIMER0_BIN, 355, 12, 9, 16);
    hour_low_c_digital = gui_img_create_from_mem(target_connected_display, "hour_low_digital",
                                                TIMER0_BIN, 366, 12, 9, 16);
    min_high_c_digital = gui_img_create_from_mem(target_connected_display, "min_high_digital",
                                                TIMER0_BIN, 387, 12, 9, 18);
    min_low_c_digital = gui_img_create_from_mem(target_connected_display, "min_low_digital", TIMER0_BIN,
                                                399, 12, 9, 18);
    tense_high_c_digital = gui_img_create_from_mem(target_connected_display, "tense_high_c_digital",
                                                APM_CA_BIN, 417, 12, 9, 18);
    tense_low_c_digital = gui_img_create_from_mem(target_connected_display, "tense_low_c_digital",
                                                APM_CM_BIN,
                                                432, 12, 9, 18);
    bat_high_c_digital = gui_img_create_from_mem(target_connected_display, "bat_high_c_digital",
                                                TIMER0_BIN, 238, 371, 9, 18);
    bat_low_c_digital = gui_img_create_from_mem(target_connected_display, "bat_low_c_digital",
                                                TIMER0_BIN, 250, 371, 9, 18);
    left_turn_light_c_status = gui_img_create_from_mem(target_connected_display,
                                                    "left_turn_light_c_status", TL_OF_C_BIN, 110, 10, 42, 40);
    right_turn_light_c_status = gui_img_create_from_mem(target_connected_display,
                                                        "right_turn_light_c_status", TR_OF_C_BIN, 665, 10, 42, 40);
    navi_c_status = gui_img_create_from_mem(target_connected_display, "navi_c_status", NAVI_C1_BIN, 505,
                                            170, 268, 218);
    map_navi_c_status = gui_img_create_from_mem(target_connected_display, "navi_c_status", NAVI_C1_BIN,
                                                505,
                                                170, 268, 218);
    map_navi_c_status->base.not_show = true;
    refuse_c_button = gui_img_create_from_mem(target_connected_display, "refuse_c_button", REFUS_BIN,
                                            502, 410, 36, 36);
    ans_c_button = gui_img_create_from_mem(target_connected_display, "ans_c_button", ANS_BIN, 740, 410,
                                        36, 36);
    tel_box_left_c_button = gui_img_create_from_mem(target_connected_display, "tel_box_left_c_button",
                                                    SYMB1_BIN, 554, 414, 36, 36);
    tel_box_right_c_button = gui_img_create_from_mem(target_connected_display, "tel_box_right_c_button",
                                                    SYMB2_BIN, 718, 414, 36, 36);
    dashboard_Cpointer = gui_img_create_from_mem(target_connected_display, "dashboard_Cpointer",
                                                DASHBOARD_C2_BIN, 110, 133, 9, 18);
    short_c_message = gui_img_create_from_mem(target_connected_display, "short_c_message",
                                            MESSAGE_BIN, 221, 0, 359, 80);

    /* set font data */
    app_navi_data current_navi_data;
    app_dashboard_data_get_navi_data_update(&current_navi_data);

    memcpy(&show_c_navigation_msg[0], &current_navi_data.navigation_msg[0],
        current_navi_data.navigation_num_len);
    short_c_navi_message_1 = gui_text_create(target_connected_display,  "short_c_navi_message_1", 490,
                                            88, 150,
                                            60);
    gui_text_set(short_c_navi_message_1, (char *)show_c_navigation_msg, GUI_FONT_SRC_BMP,
                gui_rgb(UINT8_MAX, UINT8_MAX, UINT8_MAX), current_navi_data.navigation_num_len, 56);
    gui_text_mode_set(short_c_navi_message_1, RIGHT);

    memcpy(&show_c_navigation_unit[0], &current_navi_data.navigation_unit[0],
        current_navi_data.navigation_unit_len);
    short_c_navi_message_3 = gui_text_create(target_connected_display,  "short_c_navi_message_3", 640,
                                            108, 150,
                                            40);
    gui_text_set(short_c_navi_message_3, (char *)show_c_navigation_unit, GUI_FONT_SRC_BMP,
                gui_rgb(0xcc,
                        0xcc, 0xcc), current_navi_data.navigation_unit_len, 32);
    gui_text_mode_set(short_c_navi_message_3, LEFT);

    memcpy(&show_c_road_names[0], &current_navi_data.road_names[0],
        current_navi_data.road_num_len);
    short_c_navi_message_2 = gui_text_create(target_connected_display,  "short_c_navi_message_2", 490,
                                            148, 300,
                                            40);
    gui_text_set(short_c_navi_message_2, (char *)show_c_road_names, GUI_FONT_SRC_BMP, gui_rgb(0xcc,
                0xcc,
                0xcc), current_navi_data.road_num_len, 32);
    gui_text_mode_set(short_c_navi_message_2, CENTER);

    app_phone_data current_phone_status;
    app_dashboard_data_get_phone_status(&current_phone_status);
    short_c_tel_number = gui_text_create(target_connected_display,  "short_c_tel_number",  560, 410,
                                        158, 30);
    memcpy(&show_c_tel_number[0], &current_phone_status.current_phone_number[0],
        current_phone_status.current_phone_number_len);
    gui_text_set(short_c_tel_number, (char *)show_c_tel_number, GUI_FONT_SRC_BMP, gui_rgb(UINT8_MAX,
                UINT8_MAX, UINT8_MAX), current_phone_status.current_phone_number_len, 28);
    gui_text_mode_set(short_c_tel_number, CENTER);
    short_c_tel_accept = gui_text_create(target_connected_display,  "short_c_tel_accept",  600, 410,
                                        800, 30);
    gui_text_set(short_c_tel_accept, "calling", GUI_FONT_SRC_BMP, gui_rgb(UINT8_MAX, UINT8_MAX,
                                                                        UINT8_MAX), 7, 28);
    app_message_data current_message_status;
    app_dashboard_data_get_message_data_update(&current_message_status);
    memcpy(&show_c_message_data[0], &current_message_status.wechat_msg[0],
        current_message_status.wechat_msg_len);
    short_c_message_data = gui_text_create(target_connected_display,  "short_c_message_data",  300, 10,
                                        240, 60);
    gui_text_set(short_c_message_data, (char *)show_c_message_data, GUI_FONT_SRC_BMP,
                gui_rgb(UINT8_MAX,
                        UINT8_MAX, UINT8_MAX), (current_message_status.wechat_msg_len - 1), 32);
    gui_text_mode_set(short_c_message_data, MULTI_LEFT);

    /* Prepare the intial data */
    app_dashboard_update_connected_display_time_info();
    app_dashboard_update_connected_display_tense_apm_info(app_dashboard_data_get_tense_timer_info());
    app_dashboard_update_connected_display_battery_info(app_dashboard_data_get_battery_level());
    app_dashboard_update_connected_display_speed_info(app_dashboard_data_get_car_speed());
    app_dashboard_update_connected_display_turn_info(app_dashboard_data_get_car_turn_info());
    app_dashboard_update_connected_display_phone_infor(&current_phone_status);
    app_dashboard_update_connected_display_message_infor(&current_message_status);
}

For more details about GUI controls, please refer to the documentation: https://docs.realmcu.com/HoneyGUI/en/latest/widgets/index.html.

Troubleshooting

Graphic Data Loading Process

Load the program and drawing data from external Flash to PSRAM, and display the drawing data to TFT. The specific flow chart is as follows.

  1. User Resource Display File Processing: Graphic resources are processed using the image convert tool, and the image binary file is output, including the image attribute header (image size, compression, color format (RGB565, RGB888, etc.)), and User Data: root.bin is made (refer to section 2.5.1 for the process).

  2. Download the Flash Area: Use the MPPG Tool to burn into the EVB XIP flash area.

  3. Read Data in Flash: Use QSPI, 80MHz bandwidth, and double edge data (DTR) reading method.

  4. Allocate Memory: Before loading image data, it is necessary to allocate enough memory to store image pixel data (SRAM) according to the image size and format.

  5. Compressed Graphics Pixel Processing: The GUI image control indexes the address of the file in the flash by the image name, determines whether it is compressed, and needs to be decompressed if compressed, and is moved from the flash to the SRAM via DMA. The pixel is processed by the PPE pixel processing engine and stored in the previously allocated memory (SRAM).

  6. Uncompressed Graphics Pixel Processing: The GUI image control indexes the address of the file in the flash by the image name, determines whether it is compressed, and the uncompressed image is directly moved from the flash to the SRAM via DMA, processed by the PPE, and stored in the SRAM.

    Note

    PPE processes uncompressed data, and compressed data needs to be decompressed before it can be processed by PPE.

  7. TFT display: After PPE processing, the pixel is moved to the PSRAM cache via DMA, and finally displayed on the screen via LCDC (OPI).

    ../../_images/dashboard_display_progress.png

    Data Path

PPE2.0 Performance Measurement

As shown below, seven tasks have been created for the user application:

  1. Single input layer 480*480 ARGB8888 matrix 2x2, unit matrix; output layer 480*480 ARGB8888.

    ARGB8888 PPE2.0 Performance Measurement

    Path Number

    Data Path

    Measured Time (ms)

    Path 1

    SRAM -> PPE -> SRAM

    9.20

    Path 2

    SRAM -> PPE -> SRAM

    27.65

    Path 3

    SRAM -> PPE -> SRAM

    9.20

    Path 4

    PSRAM -> PPE -> SRAM

    108.7

    Path 5

    FLASH -> PPE -> SRAM

    184.08

    Path 6

    SRAM -> PPE -> PSRAM

    27.65

    Path 7

    SRAM -> PPE -> PSRAM

    9.20

    Path 8

    SRAM -> PPE -> SRAM

    30.28

Note

  • Path: XXX->PPE->YYY, where XXX represents the input address of input layer2, and YYY represents the input (old frame)/output (new frame) address of input layer1 and result layer 0.

  • The SRAM in this table refers to DTCM.

  1. Input layer1: color format RGB565, matrix 1x1, unit matrix, area 480*480, share memory with result layer. Input layer2: color format ARGB8565, matrix 2x2, conversion matrix as described above, mirror matrix, area 480*480. Result layer0: color format RGB565, area 480*480.

    ARGB8565 PPE2.0 Performance Measurement

    Path Number

    Data Path

    Measured Time (ms)

    Path 1

    SRAM -> PPE -> SRAM

    12.65

    Path 2

    SRAM -> PPE -> SRAM

    51.74

    Path 3

    SRAM -> PPE -> SRAM

    17.92

    Path 4

    PSRAM -> PPE -> SRAM

    112.80

    Path 5

    FLASH -> PPE -> SRAM

    189.83

    Path 6

    SRAM -> PPE -> PSRAM

    54.58

    Path 7

    SRAM -> PPE -> PSRAM

    32.51

    Path 8

    SRAM -> PPE -> SRAM

    64.58

    Path 9

    PSRAM -> PPE -> PSRAM

    164.52

Note

  • Path: XXX->PPE->YYY, where XXX represents the input address of input layer2, and YYY represents the input (old frame)/output (new frame) address of input layer1 and result layer 0.

  • The SRAM in this table refers to DTCM.

Port Adaptation LCD

LCD screen adaptation needs to be adapted according to the screen cache situation. In this sample, the default condition is that PSRAM is used as the screen cache. To select GRAM as the screen cache, please refer to the GRAM section.

RAMLESS

  1. Screen resolution information configuration (refer to the screen specification), mainly configure LCD width, height, pixel depth information. Take the example as an example, modify the corresponding parameters in the lcd_st7265_800480_rgb.h header file.

    #define ST7265_800480_LCD_WIDTH                   800  //Screen width
    #define ST7265_800480_LCD_HEIGHT                  480  //Screen Height
#define ST7265_DRV_PIXEL_BITS                     16  //Pixel Depth
  1. The section height needs to be configured. The height selection depends on the actual situation. In the example project, configure LCD_SECTION_HEIGHT = 10. The corresponding parameters can be modified in gui_port_dc.c.

#define LCD_SECTION_HEIGHT                   14
  1. PSRAM needs to be configured with address information as screen cache. In gui_port_dc.c, the example of configuring PSRAM cache for framebuffer is as follows:

#define PSRAM_FRAME_BUF1_ADDR               0x4000000
#define PSRAM_FRAME_BUF2_ADDR               (0x4000000 + 800 * 480 * 2)
#define PSRAM_GUI_HEAP_ADDR                 (0x4000000 + 800 * 480 * 2 * 2)
Screen Display DMA Transfer API

API

Description

gdma_start_transfer()

DMA starts to transfer data.

gdma_wait_transfer_done()

Wait for DMA transfer to complete.

  1. Other interface APIs of LCD driver layer, corresponding to gui_port_dc.c.

    LCD Screen Display Driver Interface

    API

    Description

    drv_lcd_get_screen_width()

    Get screen width.

    drv_lcd_get_screen_height()

    Get screen height.

    drv_lcd_get_pixel_bits()

    Get screen pixel depth.

    port_gui_lcd_power_on()

    Screen startup.

    port_gui_lcd_power_off()

    Screen shutdown.

    gui_port_dc_init()

    Initialize LCD.

    port_gui_lcd_update()

    Update each segment of LCD.

    drv_lcd_update()

    Transfer the specified buffer to the screen.

Update the contents of the frame buffer on the LCD screen using the port_gui_lcd_update() interface. By default, the screen uses PSRAM as the frame buffer.

void port_gui_lcd_update(struct gui_dispdev *dc)
{

    uint32_t i = dc->section_count;
    uint32_t total_section_cnt = (drv_lcd_get_screen_height() / LCD_SECTION_HEIGHT + ((
                                      drv_lcd_get_screen_height() % LCD_SECTION_HEIGHT) ? 1 : 0));

    void *dst = (void *)(current_buffer + i * dc->fb_width * dc->fb_height * 2);
//    DBG_DIRECT("section:%d",i);
    if (i == 0)
    {
        gdma_start_transfer(dst, dc->frame_buf,
                            dc->fb_width * dc->fb_height);
    }
    else if (i == total_section_cnt - 1)
    {
        uint32_t last_height = dc->screen_height - dc->section_count * dc->fb_height;
        gdma_wait_transfer_done();
        gdma_start_transfer(dst, dc->frame_buf, dc->fb_width * last_height);
        gdma_wait_transfer_done();
        rtk_lcd_hal_update_framebuffer((uint8_t *)current_buffer, 0);

        if (current_buffer == PSRAM_FRAME_BUF1_ADDR)
        {
            current_buffer = PSRAM_FRAME_BUF2_ADDR;
        }
        else if (current_buffer == PSRAM_FRAME_BUF2_ADDR)
        {
            current_buffer = PSRAM_FRAME_BUF1_ADDR;
        }
        else
        {
            current_buffer = PSRAM_FRAME_BUF1_ADDR;
        }
    }
    else
    {
        gdma_wait_transfer_done();
        gdma_start_transfer(dst, dc->frame_buf,
                            dc->fb_width * dc->fb_height);
    }
}

GRAM

Compared with PSRAM, GRAM has a slower read and write speed. Therefore, for scenes that require frequent updates of displayed content (such as animation or video playback), GRAM may not be suitable. The following uses the st7789 driver screen as an example to explain several key functions required for screen update:

void port_gui_lcd_update(struct gui_dispdev *dc)
{

    uint32_t total_section_cnt = (rtk_lcd_hal_get_height() / LCD_SECTION_HEIGHT + ((
            rtk_lcd_hal_get_height() % LCD_SECTION_HEIGHT) ? 1 : 0));
    if (dc->section_count == 0)
    {
        rtk_lcd_hal_set_window(0, dc->fb_height * dc->section_count, dc->fb_width, dc->fb_height);
        rtk_lcd_hal_start_transfer(dc->frame_buf, dc->fb_width * dc->fb_height);
    }
    else if (dc->section_count == total_section_cnt - 1)
    {
        uint32_t last_height = dc->screen_height - dc->section_count * dc->fb_height;
        rtk_lcd_hal_transfer_done();
        rtk_lcd_hal_set_window(0, dc->fb_height * dc->section_count, dc->fb_width, last_height);
//        rtk_lcd_hal_set_TE_type(LCDC_TE_TYPE_NO_TE);
        rtk_lcd_hal_start_transfer(dc->frame_buf, dc->fb_width * last_height);
        rtk_lcd_hal_transfer_done();
    }
    else
    {
        rtk_lcd_hal_transfer_done();
        rtk_lcd_hal_set_window(0, dc->fb_height * dc->section_count, dc->fb_width, dc->fb_height);
//        rtk_lcd_hal_set_TE_type(LCDC_TE_TYPE_NO_TE);
        rtk_lcd_hal_start_transfer(dc->frame_buf, dc->fb_width * dc->fb_height);
    }

}
  1. Wait for the previous section to be transferred: the middle layer API interface drv_lcd_transfer_done(), the bottom layer implements rtk_lcd_hal_transfer_done().

void rtk_lcd_hal_transfer_done(void)
{
    LCDC_HANDLER_DMA_FIFO_CTRL_t handler_reg_0x18;
    do
    {
        handler_reg_0x18.d32 = LCDC_HANDLER->DMA_FIFO_CTRL;
    }
    while (handler_reg_0x18.b.dma_enable != RESET);
    LCDC_HANDLER_OPERATE_CTR_t handler_reg_0x14;
    do
    {
        handler_reg_0x14.d32 = LCDC_HANDLER->OPERATE_CTR;
    }
    while (handler_reg_0x14.b.auto_write_start != RESET);


    LCDC_ClearDmaFifo();
    LCDC_ClearTxPixelCnt();

    LCDC_Cmd(DISABLE);
}
  1. Set the drawing area: the middle layer API interface rtk_lcd_hal_set_window(), corresponding to the underlying implementation rtk_lcd_hal_set_window().

void rtk_lcd_hal_set_window(uint16_t xStart, uint16_t yStart, uint16_t w, uint16_t h)
{
    LCDC_Cmd(DISABLE);
    LCDC_SwitchMode(LCDC_MANUAL_MODE);
    LCDC_SwitchDirect(LCDC_TX_MODE);
    LCDC_Cmd(ENABLE);
    xStart = xStart + 53;
    yStart = yStart + 40;
    uint16_t xEnd = xStart + w - 1;
    uint16_t yEnd = yStart + h - 1;

    st7789_write_cmd(0x2a);
    st7789_write_data(xStart >> 8);
    st7789_write_data(xStart & 0xff);
    st7789_write_data(xEnd >> 8);
    st7789_write_data(xEnd & 0xff);

    st7789_write_cmd(0x2b);
    st7789_write_data(yStart >> 8);
    st7789_write_data(yStart & 0xff);
    st7789_write_data(yEnd >> 8);
    st7789_write_data(yEnd & 0xff);

    DBIB_SetCS();
}
  1. Start from the frame buffer transfer: the middle layer API interface rtk_lcd_hal_start_transfer(), corresponding to the bottom layer implementation rtk_lcd_hal_start_transfer().

void rtk_lcd_hal_start_transfer(uint8_t *buf, uint32_t len)
{
    if (((uint32_t)buf % 4) != 0)
    {
        while (1);
    }

    LCDC_DMA_InitTypeDef LCDC_DMA_InitStruct = {0};
    LCDC_DMA_StructInit(&LCDC_DMA_InitStruct);
    LCDC_DMA_InitStruct.LCDC_DMA_ChannelNum          = LCDC_DMA_CHANNEL_NUM;
    LCDC_DMA_InitStruct.LCDC_DMA_DIR                 = LCDC_DMA_DIR_PeripheralToMemory;
    LCDC_DMA_InitStruct.LCDC_DMA_SourceInc           = LCDC_DMA_SourceInc_Inc;
    LCDC_DMA_InitStruct.LCDC_DMA_DestinationInc      = LCDC_DMA_DestinationInc_Fix;
    LCDC_DMA_InitStruct.LCDC_DMA_SourceDataSize      = LCDC_DMA_DataSize_Word;
    LCDC_DMA_InitStruct.LCDC_DMA_DestinationDataSize = LCDC_DMA_DataSize_Word;
    LCDC_DMA_InitStruct.LCDC_DMA_SourceMsize         = LCDC_DMA_Msize_8;
    LCDC_DMA_InitStruct.LCDC_DMA_DestinationMsize    = LCDC_DMA_Msize_8;
    LCDC_DMA_InitStruct.LCDC_DMA_SourceAddr          = (uint32_t)buf;
    LCDC_DMA_InitStruct.LCDC_DMA_Multi_Block_En      = 0;
    LCDC_DMA_Init(LCDC_DMA_CHANNEL_INDEX, &LCDC_DMA_InitStruct);


    LCDC_ClearDmaFifo();
    LCDC_ClearTxPixelCnt();

    LCDC_SwitchMode(LCDC_AUTO_MODE);
    LCDC_SwitchDirect(LCDC_TX_MODE);
    DBIB_BypassCmdByteCmd(DISABLE);

    uint8_t cmd[1] = {0x2C};
    LCDC_DBIB_SetCmdSequence(cmd, 1);

    LCDC_SetTxPixelLen(len);

    LCDC_Cmd(ENABLE);


    LCDC_DMA_SetSourceAddress(LCDC_DMA_CHANNEL_INDEX, (uint32_t)buf);

    LCDC_DMAChannelCmd(LCDC_DMA_CHANNEL_NUM, ENABLE);
    LCDC_DmaCmd(ENABLE);
    LCDC_AutoWriteCmd(ENABLE);


}
  1. Te signal configuration to prevent screen tearing.

bool te_ready = false;

static void te_callback(void *args)
{
    te_ready = true;
}

static void port_lcd_te_wait(void)
{
    te_ready = false;
    drv_pin_irq_enable(LCD_SPI_TE, PIN_IRQ_ENABLE);

    while (te_ready == false)
    {
        platform_delay_us(1);
    }
    platform_delay_ms(3);

    drv_pin_irq_enable(LCD_SPI_TE, PIN_IRQ_DISABLE);
    te_ready = false;
}
  1. Screen parameter configuration, completely refer to the situation where PSRAM is used as screen cache, configure basic screen information, and modify section height.