lvgl / lv_platformio

PlatformIO project example for LVGL
MIT License
246 stars 89 forks source link

Undefined reference to 'lv_example_x_x' on PlatformIO #56

Open SalmoF opened 1 year ago

SalmoF commented 1 year ago

Perform all steps below and tick them with [x]

Describe the bug

after compiling the code targeting an Arduino board or similar (in my case i tried with a XIAO ESP32C3 and a Blackpill F401CC), if I enabled a demo on the main.cpp code runs as expected. When i enable an example I get the following compilation error:

c:/users/x/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld.exe: .pio/build/blackpill_f401cc/src/main.cpp.o: in function `setup':
main.cpp:(.text.setup+0xe8): undefined reference to `lv_example_btn_1'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\blackpill_f401cc\firmware.elf] Error 1

I have tried different examples and the result is the same. I've made all of the adjustments needed on the lv_config.h and copied the examples and demos folder in lvgl/src/ folder. To use the latest release of lvgl (version 8.3.8) I added it in the lib folder of my PlatformIO project, because the PlatformIO library registry goes up only to version 8.3.7 (at the time of writing). TFT_eSPI and Adafruit TouchScreen were added with lib_deps.

My main.cpp is a modified version of the arduino lvgl example to use the Adafruit Touchscreen library.

To try if the problem was caused by my modifications , I copied the libraries in a folder that I set up as an Arduino Sketchbook and converted the main.cpp in to a .ino file and the code compiled. I was able to run both examples and demos.

I think is an issue of PlatformIO, but I have not found anything useful to my case.

To Reproduce

  1. create a project on Platformio, add the following libraries using lib_deps : .. TFT_eSPI .. Adafruit TouchScreen (only if using my version of the code)
  2. get the lvgl v8.3.8 release from github, and coping the lvgl folder in the lib folder of the project.
  3. use the arduino lvgl example or use my modified version of it as main.cpp
  4. follow the documentation of LVGL with Arduino
  5. compile

I can't reproduce it on the Code::Blocks simulator.

HARDWARE USED
My modified version of the Arduino Example
//#include <Arduino.h>
/*Using LVGL with Arduino requires some extra steps:
 *Be sure to read the docs here: https://docs.lvgl.io/master/get-started/platforms/arduino.html  */

#include <lvgl.h>
#include <TFT_eSPI.h>
#include <TouchScreen.h>

/*To use the built-in examples and demos of LVGL uncomment the includes below respectively.
 *You also need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`.
 Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
 as the examples and demos are now part of the main LVGL library. */

#include <examples/lv_examples.h>
#include <demos/lv_demos.h>

#define TOUCH_YP PA0
#define TOUCH_XM PA1
#define TOUCH_YM PA2
#define TOUCH_XP PA3

#define MIN_PRESSURE 10
#define MAX_PRESSURE 1000

TouchScreen touchScreen = TouchScreen(TOUCH_XP, TOUCH_YP, TOUCH_XM, TOUCH_YM, 300);

/*Change to your screen resolution*/
static const uint16_t screenWidth  = 320;
static const uint16_t screenHeight = 240;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * screenHeight / 10 ];

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */

#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char * buf)
{
    Serial.printf(buf);
    Serial.flush();
}
#endif

/* Display flushing */
void my_disp_flush( lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p )
{
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );

    tft.startWrite();
    tft.setAddrWindow( area->x1, area->y1, w, h );
    tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
    tft.endWrite();

    lv_disp_flush_ready( disp_drv );
}

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{
    TSPoint touchPoint = touchScreen.getPoint();

    if (touchPoint.z > MIN_PRESSURE && touchPoint.z < MAX_PRESSURE)
    {

        int lvglX = map(touchPoint.x, 0, 1023, -10, screenWidth*1.18);
        int lvglY = map(touchPoint.y, 0, 1023, -20, screenHeight*1.29);
        data->state = LV_INDEV_STATE_PR;
        data->point.x = lvglX;
        data->point.y = lvglY;
        Serial.print("X = "); Serial.print(touchPoint.x);
        Serial.print("\tY = "); Serial.print(touchPoint.y);
        Serial.print("\tPressure = "); Serial.println(touchPoint.z);
        Serial.print("mapped X = "); Serial.print(lvglX);
        Serial.print("\tmapped Y = "); Serial.println(lvglY);
    }
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }
}

void setup()
{
    Serial.begin( 115200 ); /* prepare for possible serial debug */
    analogReadResolution(10); //needed for the resistive touch to work
    String LVGL_Arduino = "Hello Arduino! ";
    LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();

    Serial.println( LVGL_Arduino );
    Serial.println( "I am LVGL_Arduino" );

    lv_init();

#if LV_USE_LOG != 0
    lv_log_register_print_cb( my_print ); /* register print function for debugging */
#endif

    tft.begin();          /* TFT init */
    tft.setRotation( 3 ); /* Landscape orientation, flipped */

    /*Set the touchscreen calibration data,
     the actual data for your display can be acquired using
     the Generic -> Touch_calibrate example from the TFT_eSPI library*/
    // uint16_t calData[5] = { 275, 3620, 264, 3532, 1 };
    // tft.setTouch( calData );

    lv_disp_draw_buf_init( &draw_buf, buf, NULL, screenWidth * screenHeight / 10 );

    /*Initialize the display*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init( &disp_drv );
    /*Change the following line to your display resolution*/
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register( &disp_drv );

    /*Initialize the (dummy) input device driver*/
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init( &indev_drv );
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = my_touchpad_read;
    lv_indev_drv_register( &indev_drv );

    /* Create simple label */
    lv_obj_t *label = lv_label_create( lv_scr_act() );
    lv_label_set_text( label, "Hello Ardino and LVGL!");
    lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );

    /* Try an example. See all the examples 
     * online: https://docs.lvgl.io/master/examples.html
     * source codes: https://github.com/lvgl/lvgl/tree/e7f88efa5853128bf871dde335c0ca8da9eb7731/examples */
     lv_example_btn_1();

     /*Or try out a demo. Don't forget to enable the demos in lv_conf.h. E.g. LV_USE_DEMOS_WIDGETS*/
    // lv_demo_widgets();               
    // lv_demo_benchmark();          
    // lv_demo_keypad_encoder();     
    // lv_demo_music();              
    // lv_demo_printer();
    // lv_demo_stress();

    Serial.println( "Setup done" );
}

void loop()
{
    lv_timer_handler(); /* let the GUI do its work */
    delay( 5 );
}

Expected behavior

Succesful compilation, and the example runs on the LCD of the device

Screenshots or video

hieracy
The Warning is caused by TFT_eSPI because I've not defined a TOUCH_CS pin

output
kisvegabor commented 1 year ago

Please be sure that LV_BUILD_EXAMPLES is enabled in lv_conf.h or the ini file.

SalmoF commented 1 year ago

Yes, LV_BUILD_EXAMPLES is enabled in lv_conf.h and I have also tried to enable it in the main.cpp file in the PlatformIO project. As I said on the first comment, if I move the lvgl library folder in an arduino sketchbook, copy my main.cpp in to a .ino file and compile it in the Arduino IDE it compiles successfully. And the board runs both demos and exaples. So this problem is only present in PlatformIO.

EDIT: I now managed to reproduce this issue using the PlatformIO LVGL simulator. i get the following output:

Processing emulator_64bits (platform: native@^1.1.3)
---------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 2 compatible libraries
Scanning dependencies...
Dependency Graph
|-- lv_drivers @ 8.2.0
|-- lvgl @ 8.3.8
Building in release mode
Compiling .pio\build\emulator_64bits\src\main.o
Linking .pio\build\emulator_64bits\program.exe
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/12.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: .pio/build/emulator_64bits/src/main.o:main.c:(.text+0x18): undefined reference to `lv_example_btn_1'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\emulator_64bits\program.exe] Error 1

I added the LV_BUILD_EXAMPLES in the .ini file, and modified the lib_deps with the following line lvgl=https://github.com/lvgl/lvgl/archive/refs/tags/v8.3.8.zip so that the compiler loads version 8.3.8 of LVGL. If i add this line +<../.pio/libdeps/emulator_64bits/lvgl/examples> in the .ini file of the emulator under build_src_filter it compiles and runs. Then I tried taking the folder lvgl-8.3.8 from my project and put it under the lib folder of the PlatformIO simulator project. I changed the build_src_filter line that i've added before to +<../lib/lvgl-8.3.8/examples> and worked again.

Doing the same on the .ini in my project i get the following error:

In file included from .pio\libdeps\blackpill_f401cc\TFT_eSPI\TFT_eSPI.cpp:16:      
.pio\libdeps\blackpill_f401cc\TFT_eSPI\TFT_eSPI.h:32:10: fatal error: SPI.h: No such file or directory

*************************************************************
* Looking for SPI.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:SPI.h"
* Web  > https://registry.platformio.org/search?q=header:SPI.h
*
*************************************************************

   32 | #include <SPI.h>
      |          ^~~~~~~
compilation terminated.
Compiling .pio\build\blackpill_f401cc\FrameworkArduino\WSerial.cpp.o
Compiling .pio\build\blackpill_f401cc\FrameworkArduino\WString.cpp.o
*** [.pio\build\blackpill_f401cc\libf81\TFT_eSPI\TFT_eSPI.cpp.o] Error 1
=========================== [FAILED] Took 10.95 seconds ===========================
kisvegabor commented 1 year ago

I believe it's really specific to PIO somehow and can't help much with it. :slightly_frowning_face: I suggest asking it on PIO's forum: https://community.platformio.org/

gw8484 commented 10 months ago

I also ran into the same problem. The workaround I found is to rename the "examples" folder to something else then everything in it gets compiled. It seems something is filtering out "examples" in the PIO dependency checking process for the lvgl library. I also posted about this problem on PIO forum at https://community.platformio.org/t/undefined-reference-to-lv-example-x-x-on-platformio/34777/3.

zzh-sc commented 6 months ago

I ran into same problem. The version what I use is "release/8.3".

Here is my solution. Add the "lv_example_x_x.c" and "lv_example_widgets.h" to the compilation as well. For example, the function "lv_example_btn_1.c" is located in source_of_lvgl/examples/widgets/btn. The .h of lv_example_btn_1 function is located in source_of_lvgl/examples/widgets/.