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:

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.

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.
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:
Hardware Platforms |
Board Name |
Build Target |
---|---|---|
RTL8773EWP HDK |
RTL8773EWP EVB |
|
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.
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.

8773EWP EVB with LCD

8773EWP EVB
The mapping relationship of the LCD, and EVB pins is shown in the following table.
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.

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.

GUI Package Tool
Place the bin files of the images and fonts into the root folder.
Execute the
gen_root_image.bat
.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.

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

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

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.

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.

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

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:
Open the project rtl87x3ep_dashboard.uvprojx.
Make sure that
F_APP_DASHBOARD_DEMO_SUPPORT
is set to1
in Keil project settings.Define Macro Definition
Choose the build target
dashboard_dual_bank0
.Choose Build Target
Build the target.
Start Building
After a successful buliding, the APP bin file
dashboard_bank0_MP-v0.0.0.0-xxx.bin
will be generated in the directorybin\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.
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 directorybin\rtl87x3ep\app_demo_bin\mdk\dashboard\16M\BANK0
. Users can directly use this default file without modifying any code.
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.User Data Bin
Userdata bin which prefix starts with
root
is in the directorybin\rtl87x3ep\flash_16M_dualbank\bank0
.Location of User Data Bin
Press the Reset button on EVB board.
J-Link Download and Debug
J-Link is an emulator/debugger developed by SEGGER. It is a tool specifically for ARM processors that can be used to develop, debug, and test firmware for embedded devices. J-Link has high-speed and reliable simulation performance, supports real-time debugging and fast firmware downloading, and can help developers speed up the process of debugging and verifying embedded systems and improve development efficiency and quality.
J-Link supports multiple connection interfaces, such as JTAG, SWD, etc. Because SWD uses fewer wires, RTL8773EWP uses this interface, SWD corresponding interface. In addition, J-Link is also compatible with multiple development environments and IDEs (such as Keil MDK, IAR Embedded Workbench, etc.). For Keil environment settings, please refer to Quick Start to build and download.
It is recommended to use J-Link Software v6.44 (or later). For more information, please refer to Quick Start to build and download.
SWD Wiring
RTL8773EWP |
SWD |
---|---|
GND |
GND |
P1_0 |
SWIO |
P1_1 |
SWCK |
VDEX |
Vterf/3.3V |

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
Build the application, and download images into DUT.
Testing Phase
After the program is burned, refer to Working Mode to put the EVB into working mode.
DUT press Reset button, if boot success, the LCD will show screen below.

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

Pair with Dashboard
After pairing successfully, the device dashboard will show in list MY DEVICES.

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

Message Display on Dashboard
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.

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

Simplified Navigation Display on Dashboard

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
andsdk\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 (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 |
|
1K |
0x02055000 |
|
163K |
0x02055400 |
|
104K |
0x0207E000 |
|
1136K |
0x02098000 |
|
128K |
0x021B4000 |
|
200K |
0x021D4000 |
|
20K |
0x02206000 |
|
8K |
0x0220B000 |
|
0K |
0x00000000 |
|
0K |
0x00000000 |
|
0K |
0x00000000 |
|
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
To adjust flash layout, flow the steps listed on the Generating Flash Map in Quick Start.
After flash layout adjustment, users must flow the steps listed on the Generating OTA Header and Generating MCU Configuration File with new
flash_map.ini
.
Software Architecture
The system software architecture is shown below:

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.

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.

Dashboard Application Task Composition
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

APP Task Architecture
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.The user application layer freely implements the control of Bluetooth LE behavior, including broadcast switch, establishing connection, updating connection parameters, etc.
New APP Task: The structure of
app_dashboard_launcher
displays two basic elements:thread_detry
andui_design
.The
ui_design
function creates the UI interface and required system resources.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.

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.

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
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); } }
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(); }
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); }
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
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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, ¤t_phone_status, sizeof(app_phone_data)); }
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)); }
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(¤t_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"); } }
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(¤t_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(¤t_phone_status); current_phone_status.phone_status = T_PHONE_STATUS_NONE; app_dashboard_data_set_phone_status(current_phone_status); } }
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; }
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, ¤t_navi_data, sizeof(app_navi_data)); }
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)); }
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(¤t_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); }
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, ¤t_message_status, sizeof(app_message_data)); }
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)); }
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(¤t_message_status); memset(current_message_status.wechat_msg, 0x0, sizeof(current_message_status.wechat_msg)); current_message_status.wechat_msg_len = length; memcpy(¤t_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"); } }
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()); } }
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; }
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; }
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; }
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(¤t_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); } }
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(¤t_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
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 eventsobj_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.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(¤t_phone_status); short_tel_number = gui_text_create(target_main_display, "short_tel_number", 322, 415, 158, 30); memcpy(&show_tel_number[0], ¤t_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(¤t_message_status); memcpy(&show_message_data[0], ¤t_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(¤t_phone_status); app_dashboard_update_main_display_message_infor(¤t_message_status); }
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(¤t_navi_data); memcpy(&show_c_navigation_msg[0], ¤t_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], ¤t_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], ¤t_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(¤t_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], ¤t_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(¤t_message_status); memcpy(&show_c_message_data[0], ¤t_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(¤t_phone_status); app_dashboard_update_connected_display_message_infor(¤t_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.
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).Download the Flash Area: Use the MPPG Tool to burn into the EVB XIP flash area.
Read Data in Flash: Use QSPI, 80MHz bandwidth, and double edge data (DTR) reading method.
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.
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).
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.
TFT display: After PPE processing, the pixel is moved to the PSRAM cache via DMA, and finally displayed on the screen via LCDC (OPI).
Data Path
PPE2.0 Performance Measurement
As shown below, seven tasks have been created for the user application:
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.
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
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
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
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.
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);
}
}
Wait for the previous section to be transferred: the middle layer API interface
drv_lcd_transfer_done()
, the bottom layer implementsrtk_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); }
Set the drawing area: the middle layer API interface
rtk_lcd_hal_set_window()
, corresponding to the underlying implementationrtk_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(); }
Start from the frame buffer transfer: the middle layer API interface
rtk_lcd_hal_start_transfer()
, corresponding to the bottom layer implementationrtk_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); }
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; }
Screen parameter configuration, completely refer to the situation where PSRAM is used as screen cache, configure basic screen information, and modify section height.