This setup enables the user to interact with the device via a serial terminal and view the commands sent to the LCD through the IoT toolbox using a smartphone.
This code has been implemented using MCUXpresso IDE v11.10 and FRDM-MCXW71 SDK v2.16.0. LVGL v8.3.2 has been used to generate the initial design.
Note: To use any wireless example in the MCXW71, the user must upload the NBU image. This image comes into the SDK version: SDK_2_16_FRDM-MCXW71 > middleware > wireless > ble_controller > bin > mcxw71_nbu_ble-..-.sb3.
The following boards are required:
This section describes the steps to drive LCD-PAR-S035 using LVGL on FRDM-MCXW71 board.
To import the project "w_uart" into MCUXpresso IDE, refer to the MCUXpresso IDE 11.10.0 User Guide (document MCUXPRESSO-UG).
Note:
To see the wireless UART on the IoT tool box, change the GAP rol in the app. Press SW4 and then SW2.
Once you have imported the wireless UART example in your workspace, the next step is to add the right configurations to enable the LCD.
To integrate the OTAP LVGL service in your application, you must import additional software that is not included in other SDK examples by default. This step enables you to locate the files that you must merge into your project to support the LVGL service in your application.
The folders and files that are in the LVGL folders but not in wireless UART must be imported in your wireless UART project. For instance, the following must be imported:
- board > lvgl_support.c
- board > lvgl_support.h
- board > RTE_Device.h
- cmsis_drivers > Driver_Common.h
- cmsis_drivers > Driver_SPI.h
- drivers > fsl_edma.c
- drivers > fsl_edma.h
- drivers > fsl_lpi2c_edma.c
- drivers > fsl_lpi2c_edma.h
- drivers > fsl_lpi2c.c
- drivers > fsl_lpi2c.h
- drivers > fsl_lpspi_cmsis.c
- drivers > fsl_lpspi_cmsis.h
- drivers > fsl_lpspi_edma.c
- drivers > fsl_lpspi_edma.h
- drivers > fsl_lpspi.c
- drivers > fsl_lpspi.h
- source > lv_conf.h
- source > lvgl_demo_utils.c
- source > lvgl_demo_utils.h
Navigate to Project > Properties in MCUXpresso IDE. Go to C/C++ Build > Settings > Tool Settings > MCU C Compiler > Includes. Click the icon next to the Include paths textbox:
"${workspace_loc:/${ProjName}/source}"
"${workspace_loc:/${ProjName}/cmsis_drivers}"
"${workspace_loc:/${ProjName}/lvgl/lvgl/src/widgets}"
"${workspace_loc:/${ProjName}/generated/guider_customer_fonts}"
"${workspace_loc:/${ProjName}/generated/guider_fonts}"
"${workspace_loc:/${ProjName}/lvgl/lvgl}"
"${workspace_loc:/${ProjName}/lvgl/lvgl/src}"
"${workspace_loc:/${ProjName}/lvgl/lvgl/demos}"
"${workspace_loc:/${ProjName}/custom}"
"${workspace_loc:/${ProjName}/generated}"
"${workspace_loc:/${ProjName}/lcd}"
"${workspace_loc:/${ProjName}/lvgl}"
"${workspace_loc:/${ProjName}/touchpanel}"
Also, make sure that the LCD_ST7796S_IPS macro is set to 1:
This section explains code and file details.
main.c file
In this file, add the declarations, variables, and includes to configure the LVGL profile.
- Includes:
#include "lvgl.h"
#include "lvgl_support.h"
#include "gui_guider.h"
#include "custom.h"
#include"events_init.h"
#include "pin_mux.h"
- Variables:
/* 1 ms per tick. */
#ifndef LVGL_TICK_MS
#define LVGL_TICK_MS 1U
#endif
/* lv_task_handler is called every 5-tick. */
#ifndef LVGL_TASK_PERIOD_TICK
#define LVGL_TASK_PERIOD_TICK 5U
#endif
static void DEMO_SetupTick(void);
#if LV_USE_LOG
static void print_cb(const char *buf);
#endif
static volatile uint32_t s_tick = 0U;
static volatile bool s_lvglTaskPending = false;
lv_ui guider_ui;
- Functions:
static void DEMO_SetupTick(void)
{
if (0 != SysTick_Config(SystemCoreClock / (LVGL_TICK_MS * 1000U)))
{
while (1)
;
}
}
void SysTick_Handler(void)
{
s_tick++;
lv_tick_inc(LVGL_TICK_MS);
if ((s_tick % LVGL_TASK_PERIOD_TICK) == 0U)
{
s_lvglTaskPending = true;
}
}
In the main function, it is necessary to call the correct functions:
int main(void)
{
.
.
.
CLOCK_EnableClock(kCLOCK_Dma0);
BOARD_InitPins_SPI0();
I2C0_InitPins();
DEMO_SetupTick();
lv_port_pre_init();
lv_init();
lv_port_disp_init();
lv_port_indev_init();
setup_ui(&guider_ui);
events_init(&guider_ui);
custom_init(&guider_ui);
.
.
.
while(TRUE)
{
.
.
.
OSA_EnableIRQGlobal();
while (!s_lvglTaskPending)
{
}
s_lvglTaskPending = false;
lv_task_handler();
}
wireless_uart.c file
It is the main source file at the application level. This file contains information for managing all the procedures that the device performs, before, during, and after creating a connection.
- Variables:
extern int set_btn;
extern int reset_btn;
extern int start_btn;
extern int stop_btn;
extern int set_date_btn;
extern int set_timer_btn;
extern int timer_init;
extern uint8_t current_timer_ble[10];
extern uint8_t current_date_ble[20];
uint8_t vec_welcome[30] = "\r\n*====Kitchen Counter====*\r\n";
uint8_t vec_set_btn[30] = "\r\nSet button was pressed\r\n";
uint8_t vec_reset_btn[30] = "\r\nReset button was pressed\r\n";
uint8_t vec_start_btn[30] = "\r\nStart button was pressed\r\n";
uint8_t vec_stop_btn[30] = "\r\nStop button was pressed\r\n";
uint8_t vec_setdate_btn[40] = "\r\nthe date was set to: ";
uint8_t vec_timer_btn[40] = "\r\nthe timer was set to: ";
uint8_t vec_timerInit_btn[80] = "\r\nthe timer was stopped, press the RESET if you want to re-start the counter\r\n";
- Functions:
void LVGL_CallBack()
{
(void)TM_InstallCallback((timer_handle_t)mLVGLId, LVGL_TimerCallback, NULL);
(void)TM_Start((timer_handle_t)mLVGLId,
(uint8_t)kTimerModeLowPowerTimer | (uint8_t)kTimerModeSingleShot, LVGLIntervalInMs_c);
}
void LVGL_TimerCallback()
{
(void)LVGL_btn();
LVGL_CallBack();
}
void LVGL_init_demo()
{
BleApp_SendUartStream(&vec_welcome[0], 70U);
}
void LVGL_btn(void)
{
//display
if(set_btn == 1)
{
BleApp_SendUartStream(&vec_set_btn[0], 30U);
set_btn = 0;
}
else if(reset_btn == 1)
{
BleApp_SendUartStream(&vec_reset_btn[0], 30U);
reset_btn = 0;
}
else if(start_btn == 1)
{
BleApp_SendUartStream(&vec_start_btn[0], 30U);
start_btn = 0;
}
else if(stop_btn == 1)
{
BleApp_SendUartStream(&vec_stop_btn[0], 30U);
stop_btn = 0;
}
else if(set_date_btn == 1)
{
vec_setdate_btn[23]= '[';
vec_setdate_btn[24]= current_date_ble[0];
vec_setdate_btn[25]= current_date_ble[1];
vec_setdate_btn[26]= current_date_ble[2];
vec_setdate_btn[27]= current_date_ble[3];
vec_setdate_btn[28]= '/';
vec_setdate_btn[29]= current_date_ble[5];
vec_setdate_btn[30]= current_date_ble[6];
vec_setdate_btn[31]= '/';
vec_setdate_btn[32]= current_date_ble[8];
vec_setdate_btn[33]= current_date_ble[9];
vec_setdate_btn[34]= ']';
BleApp_SendUartStream(&vec_setdate_btn[0], 40U);
set_date_btn = 0;
}
else if(set_timer_btn == 1)
{
vec_timer_btn[23]= '[';
vec_timer_btn[24]= current_timer_ble[0];
vec_timer_btn[25]= current_timer_ble[1];
vec_timer_btn[26]= ':';
vec_timer_btn[27]= current_timer_ble[2];
vec_timer_btn[28]= current_timer_ble[3];
vec_timer_btn[29]= ':';
vec_timer_btn[30]= current_timer_ble[4];
vec_timer_btn[31]= current_timer_ble[5];
vec_timer_btn[32]= ']';
BleApp_SendUartStream(&vec_timer_btn[0], 40U);
set_timer_btn = 0;
}
else if(timer_init == 1)
{
BleApp_SendUartStream(&vec_timerInit_btn[0], 80U);
timer_init = 0;
}
}
The propose to use the LCD feature into the Wireless UART examples is that the user can interact with the board in a different way. So, it is necessary to call the function in the Bluetooth Low Energy functionality.
The user must call the LCD callback function in the BLE state machine handler:
static void BleApp_StateMachineHandler
(
deviceId_t peerDeviceId,
appEvent_t event
)
{
uint16_t tempMtu = 0;
union
{
uint8_t *pUuidArray;
bleUuid_t *pUuidObj;
} temp; /* MISRA rule 11.3 */
temp.pUuidArray = uuid_service_wireless_uart;
.
.
.
case mAppServiceDisc_c:
{
if (event == mAppEvt_ServiceDiscoveryComplete_c)
{
/* Moving to Running State*/
maPeerInformation[peerDeviceId].appState = mAppRunning_c;
//Display
LVGL_init_demo();
LVGL_CallBack();
.
.
.
default:
{
; /* No action required */
}
break;
}
}
}
The test case example has been designed to demonstrate the LVGL integration in testing the wireless UART-LVGL software.
- Open the IoT Toolbox app and select the Wireless UART demo. Click the SCAN button to start scanning for a suitable advertiser.
- Create a connection with the NXP_WU device. Then, the wireless UART interface is displayed on your smartphone.
- All the interactions with the LCD display are shown in the Wireless UART console.
if you have questions regarding MCXW71 please leave a question in our Wireless MCU Community! here.
Questions regarding the content/correctness of this example can be entered as issues within this GitHub repository.
Note: For more general technical questions regarding NXP Microcontrollers and the difference in expected functionality, enter your questions on the NXP Community Forum.
Version | Description | Release date |
---|---|---|
1.0 | Initial release on Application Code Hub | 6 November 2024 |
Example code shown in this document has the following copyright and BSD-3-Clause license:
Copyright 2024 NXP Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials must be provided with the distribution.
- Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.