Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MPU FAULT: Stacking error with lvgl on lv_timer_handler() #50226

Closed
Linzdigr opened this issue Sep 14, 2022 · 15 comments
Closed

MPU FAULT: Stacking error with lvgl on lv_timer_handler() #50226

Linzdigr opened this issue Sep 14, 2022 · 15 comments
Assignees
Labels
area: LVGL Light and Versatile Graphics Library Support bug The issue is a bug, or the PR is fixing a bug

Comments

@Linzdigr
Copy link

Linzdigr commented Sep 14, 2022

When I'm trying to use lvgl along with Zephyr, I get the following:

os: ***** MPU FAULT *****
[00:00:00.433,258] os: Stacking error (context area might be not valid)
[00:00:00.433,258] os: Data Access Violation
[00:00:00.433,258] os: MMFAR Address: 0x2001bd0c
[00:00:00.433,288] os: r0/a1: 0xe3151dd6 r1/a2: 0xc4cde9b8 r2/a3: 0x4b3693f9
[00:00:00.433,288] os: r3/a4: 0x8c8fc445 r12/ip: 0xa6146c42 r14/lr: 0x1b1f6087
[00:00:00.433,319] os: xpsr: 0x37422400
[00:00:00.433,319] os: Faulting instruction address (r15/pc): 0xb51f27a3
[00:00:00.433,349] os: >>> ZEPHYR FATAL ERROR 2: Stack overflow on CPU 0
[00:00:00.433,380] os: Current thread: 0x200004d0 (unknown)
[00:00:01.606,811] os: Halting system

I already tried to "play" with different CONFIG_MAIN_STACK_SIZE and CONFIG_IDLE_STACK_SIZE values with no success.

Here is the code I use to init and test the display

void view_lvgl() { // Runs in a dedicated k_thread
  /* Init LVGL */
  lv_init();

  /* A static or global variable to store the buffers */
  static lv_disp_draw_buf_t disp_buf;

  /* Note: it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized */
  static lv_color_t buf_1[SSD1333_MAX_COL * 10];
  static lv_color_t buf_2[SSD1333_MAX_COL * 10];

  /* Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_2 */
  lv_disp_draw_buf_init(&disp_buf, buf_1, buf_2, SSD1333_MAX_COL*10);

  static lv_disp_drv_t disp_drv;          /* A variable to hold the drivers. Must be static or global. */
  lv_disp_drv_init(&disp_drv);            /* Basic initialization */
  disp_drv.draw_buf = &disp_buf;          /* Set an initialized buffer */
  disp_drv.flush_cb = lvgl_flush_cb;      /* Set a flush callback to draw to the display */
  disp_drv.hor_res = SSD1333_MAX_COL;     /* Set the horizontal resolution in pixels */
  disp_drv.ver_res = SSD1333_MAX_ROW;     /* Set the vertical resolution in pixels */

  lv_disp_t * disp;

  disp = lv_disp_drv_register(&disp_drv); /* Register the driver and save the created display objects*/

  lv_obj_t * ta = lv_textarea_create(lv_scr_act());
  lv_textarea_set_one_line(ta, true);
  lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 10);
  lv_obj_add_state(ta, LV_STATE_FOCUSED); /*To be sure the cursor is visible*/

  static const char * btnm_map[] = {"1", "2", "3", "\n",
                                    "4", "5", "6", "\n",
                                    "7", "8", "9", "\n",
                                    LV_SYMBOL_BACKSPACE, "0", LV_SYMBOL_NEW_LINE, ""
                                    };

  lv_obj_t * btnm = lv_btnmatrix_create(lv_scr_act());
  lv_obj_set_size(btnm, 150, 130);
  lv_obj_align(btnm, LV_ALIGN_BOTTOM_MID, 0, -10);
  lv_obj_clear_flag(btnm, LV_OBJ_FLAG_CLICK_FOCUSABLE); /*To keep the text area focused on button clicks */
  lv_btnmatrix_set_map(btnm, btnm_map);

  uint32_t x = 5;
  while(1) {

    // lv_tick_inc(x);
    lv_timer_handler(); // <--------- Crashes here !
    k_msleep(x);
  }

And the vars:

CONFIG_GPIO=y
CONFIG_DEBUG_OPTIMIZATIONS=y
CONFIG_NEWLIB_LIBC=y
CONFIG_DEBUG_THREAD_INFO=y
CONFIG_THREAD_STACK_INFO=y

CONFIG_HEAP_MEM_POOL_SIZE=50512
CONFIG_IDLE_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_MAIN_STACK_SIZE=4096

CONFIG_PRINTK=y
CONFIG_CONSOLE=y

CONFIG_RESET_ON_FATAL_ERROR=n
CONFIG_THREAD_NAME=y

# I2C
CONFIG_I2C=y

# SPI
CONFIG_SPI=y

CONFIG_LV_Z_MEM_POOL_NUMBER_BLOCKS=8

CONFIG_DISPLAY=y
CONFIG_DISPLAY_LOG_LEVEL_ERR=y

CONFIG_LOG=y

CONFIG_LVGL=y
CONFIG_LV_MEM_CUSTOM=y
CONFIG_LV_USE_LOG=y
CONFIG_LV_USE_LABEL=y
CONFIG_LV_USE_BTN=y
CONFIG_LV_USE_IMG=y
CONFIG_LV_FONT_MONTSERRAT_14=y

Environment:

  • OS: MacOS Monterey
  • Platform: nRF52840 DK
  • Toolchain nrf-connect.toolchain:2.0.2
  • Zephyr hash be360e7

Additional context
Unfortunately, there is not much about documentation on LVGL/Zephyr (https://docs.lvgl.io/master/get-started/os/zephyr.html) but I've seen some use case/examples without direct init call of the lvgl library but would like to use it "as is" (init on my own).

Thanks for your time !

@Linzdigr Linzdigr added the bug The issue is a bug, or the PR is fixing a bug label Sep 14, 2022
@nordicjm
Copy link
Collaborator

@pdgendt

@nordicjm nordicjm added the area: LVGL Light and Versatile Graphics Library Support label Sep 14, 2022
@pdgendt
Copy link
Collaborator

pdgendt commented Sep 14, 2022

Some things worth checking:

  • Does the color depth match your hardware? Check if the driver's current pixel format is compatible with the LVGL config
  • zephyr already initializes LVGL in modules/lib/gui/lvgl/zephyr/lvgl.c, does this conflict with your setup?
  • Can you run the lv_timer_handler a single time without crashing?
  • Can you connect a debugger and add a breakpoint in the display_write of the driver to verify buffers?
  • Potential alignment issues? What is SSD1333_MAX_COL?
  • ...

@Linzdigr
Copy link
Author

  • Color is on 16bits format (default from what I saw)
  • for the lv_init, I indeed saw this is done by Zephyr and would like to know if we can init by ourself instead ?
  • no, lv_timer_handler crashes at first call
  • actually, it crashes at timer's callback call :
    lv_timer.c
static bool lv_timer_exec(lv_timer_t * timer) {
[...]
if(timer->timer_cb && original_repeat_count != 0) timer->timer_cb(timer);
[...]
  • SSD1333_MAX_COL is the vertical resolution of the display, i.e 160

Looking now, I'm afraid it may be related to the compil-time warning :

CMake Warning at /opt/nordic/ncs/v2.0.2/zephyr/CMakeLists.txt:814 (message):
No SOURCES given to Zephyr library: drivers__display

Excluding target from build.

Actually, I've registered my own draw area function disp_drv.flush_cb = lvgl_flush_cb; so I don't have to register specific display at Zephyr level.

Am I wrong on doing this way ? Do I must implement specific SSD1333 display driver API instead of having my own project C file doing so ? (As I'm a bit overwhelmed here by all this new stuff 😕 )

@pdgendt
Copy link
Collaborator

pdgendt commented Sep 14, 2022

  • for the lv_init, I indeed saw this is done by Zephyr and would like to know if we can init by ourself instead ?

Maybe, but having both will create 2 lv_disp_t instances and the first will be the default (probably the zephyr one). So lv_scr_act will be for the wrong display.
Didn't you already have to add hacks around the DT_CHOSEN(zephyr_display) used in lvgl.c?

CMake Warning at /opt/nordic/ncs/v2.0.2/zephyr/CMakeLists.txt:814 (message):
No SOURCES given to Zephyr library: drivers__display
Excluding target from build.

Actually, I've registered my own draw area function disp_drv.flush_cb = lvgl_flush_cb; so I don't have to register specific display at Zephyr level.

Am I wrong on doing this way ? Do I must implement specific SSD1333 display driver API instead of having my own project C file doing so ? (As I'm a bit overwhelmed here by all this new stuff 😕 )

I think in the long run its easier to add an out-of-tree driver (or in-tree if you can upstream) and amend your driver to the display subsystem library. It will be easier to follow/debug if you follow the current API contracts IMO.

@Linzdigr
Copy link
Author

Linzdigr commented Sep 14, 2022

Didn't you already have to add hacks around the DT_CHOSEN(zephyr_display) used in lvgl.c

Well, not yet but in the end , you're right, nothing good comes along going against the framework :)
I'll implement the driver that way and let you know if it solves the issue

@Linzdigr
Copy link
Author

Finally manage to port code to a dedicate zephyr driver :)

I changed the code to align with samples/subsys/display/lvgl/src/main.c and got the following error on this :

display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));

In file included from /opt/nordic/ncs/v2.0.2/zephyr/include/zephyr/toolchain/gcc.h:88,
from /opt/nordic/ncs/v2.0.2/zephyr/include/zephyr/toolchain.h:50,
from /opt/nordic/ncs/v2.0.2/zephyr/include/zephyr/kernel_includes.h:19,
from /opt/nordic/ncs/v2.0.2/zephyr/include/zephyr/kernel.h:17,
from /opt/nordic/ncs/v2.0.2/zephyr/include/zephyr/zephyr.h:18,
from /Users/ferez/developpement/Quantum/src/view/view.c:10:
../src/view/view.c: In function 'view_lvgl':
/opt/nordic/ncs/v2.0.2/zephyr/include/zephyr/device.h:96:39: error: '__device_dts_ord_DT_CHOSEN_zephyr_display_ORD' undeclared (first use in this function)
96 | #define DEVICE_NAME_GET(name) _CONCAT(_device, name)
| ^~~~~~~~~

The prj.conf didn't changed much :

CONFIG_GPIO=y
CONFIG_DEBUG_OPTIMIZATIONS=y
CONFIG_NEWLIB_LIBC=y
CONFIG_DEBUG_THREAD_INFO=y
CONFIG_THREAD_STACK_INFO=y

CONFIG_HEAP_MEM_POOL_SIZE=50512
CONFIG_IDLE_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_MAIN_STACK_SIZE=4096

CONFIG_PRINTK=y
CONFIG_CONSOLE=y

CONFIG_RESET_ON_FATAL_ERROR=n
CONFIG_THREAD_NAME=y

# I2C
CONFIG_I2C=n

# SPI
CONFIG_SPI=y

CONFIG_SSD1333=y

CONFIG_DISPLAY=y
CONFIG_DISPLAY_LOG_LEVEL_ERR=y

CONFIG_LOG=y

CONFIG_LVGL=y
CONFIG_LV_MEM_CUSTOM=y
CONFIG_LV_Z_MEM_POOL_NUMBER_BLOCKS=8
CONFIG_LV_USE_LOG=y
CONFIG_LV_USE_LABEL=y
CONFIG_LV_USE_BTN=y
CONFIG_LV_USE_IMG=y
CONFIG_LV_FONT_MONTSERRAT_14=y

And the overlay :

/*
* nRF52840_dk      SSD1333 (160x128)
* 
* P0.28 (RESET)   RES
* P0.5 (D5)       DC (DATA/CMD)
* P0.27 (SCK)     SCL
* P0.26 (MOSI)    SDA
*/

/ {
  chosen {
    zephyr,display = &ssd1333;
  };
};

&pinctrl {
 spi3_default: spi3_default {
   group1 {
     psels = <NRF_PSEL(SPIM_SCK, 0, 5)>,
       <NRF_PSEL(SPIM_MOSI, 0, 32)>,
       <NRF_PSEL(SPIM_MISO, 0, 31)>;
   };
 };

 spi3_sleep: spi3_sleep {
   group1 {
     psels = <NRF_PSEL(SPIM_SCK, 0, 5)>,
       <NRF_PSEL(SPIM_MOSI, 0, 32)>,
       <NRF_PSEL(SPIM_MISO, 0, 31)>;
     low-power-enable;
   };
 };
};

&spi3 {
  compatible = "nordic,nrf-spim";
  status = "okay";
  pinctrl-0 = <&spi3_default>;
  pinctrl-1 = <&spi3_sleep>;
  cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
  pinctrl-names = "default", "sleep";

  ssd1333: ssd1333@0 {
    compatible = "solomon,ssd1333";
    label = "SSD1333";
    spi-max-frequency = <20000000>;
    reg = <0>;
    cmd-data-pin = <&gpio0 30 GPIO_ACTIVE_LOW>;
    reset-pin = < &gpio0 28 GPIO_ACTIVE_LOW >;
    width = <160>;
    height = <128>;
    x-offset = <0>;
    y-offset = <0>;
    vcom = <0x19>;
    gctrl = <0x35>;
  };
};

I forgot something I guess ?

@pdgendt
Copy link
Collaborator

pdgendt commented Sep 16, 2022

Are you sure the overlay is applied? Check build/zephyr/zephyr.dts for the merged devicetree.

@Linzdigr
Copy link
Author

Linzdigr commented Sep 16, 2022

It's not indeed, what should I do ?
I've rode https://docs.zephyrproject.org/3.1.0/build/dts/howtos.html#set-devicetree-overlays but don't really know what to do anymore

EDIT: I happened cmake -DDTC_OVERLAY_FILE argument on my build to do so. I don't know if it's the right way but I'll keep going until then with this :)

@Linzdigr
Copy link
Author

Linzdigr commented Sep 16, 2022

Ok so now I packed everything up and.. I still have the same MPU Fault Staking error at the same point 😕

As a reminder, here is the new lvgl calls based on samples/subsys/display/lvgl/src/main.c :

void view_lvgl() {
  uint32_t count = 0U;
  char count_str[11] = {0};
  const struct device *display_dev;
  lv_obj_t *hello_world_label;
  lv_obj_t *count_label;

  display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
  if (!device_is_ready(display_dev)) {
    printk("Device not ready, aborting test");
    return;
  }

  if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN)) {
    lv_obj_t *hello_world_button;

    hello_world_button = lv_btn_create(lv_scr_act());
    lv_obj_align(hello_world_button, LV_ALIGN_CENTER, 0, 0);
    hello_world_label = lv_label_create(hello_world_button);
  } else {
    hello_world_label = lv_label_create(lv_scr_act());
  }

  lv_label_set_text(hello_world_label, "Hello world!");
  lv_obj_align(hello_world_label, LV_ALIGN_CENTER, 0, 0);

  count_label = lv_label_create(lv_scr_act());
  lv_obj_align(count_label, LV_ALIGN_BOTTOM_MID, 0, 0);

  lv_task_handler();  // <------------ Still crashing here at lv_timer.c:314: timer->timer_cb(timer);
  display_blanking_off(display_dev);

  while (1) {
    if ((count % 100) == 0U) {
      sprintf(count_str, "%d", count/100U);
      lv_label_set_text(count_label, count_str);
    }
    lv_task_handler();
    k_sleep(K_MSEC(10));
    ++count;
  }
}

Also, actual stack/heap size are defined like so :

CONFIG_HEAP_MEM_POOL_SIZE=50512
CONFIG_IDLE_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_MAIN_STACK_SIZE=16384

@brgl
Copy link
Collaborator

brgl commented Sep 16, 2022

@Linzdigr Have I understood correctly that you implemented a new display driver for SSD1333? Have you posted it somewhere? Have you been able to run the lvgl hello world on it?

@Linzdigr
Copy link
Author

Linzdigr commented Sep 16, 2022

@brgl Yes, but it was working on his "standalone" c file form on my color OLED display. I didn't publicly posted the Zephyr driver for now since I wanted to make sure it works first :)

Now I'm trying to do the job with Zephyr+LVGL as I didn't tried other way yet.

@Linzdigr
Copy link
Author

Ok so, the Zephyr driver is working fine without LVGL with last modifications.

As I switch back to the LVGL sample code, still the Stacking error comes 😕

Any idea ?

@Linzdigr
Copy link
Author

Last tries:

  • Setting CONFIG_LV_Z_POINTER_KSCAN=n
  • Setting CONFIG_LV_CONF_MINIMAL=y
  • Setting CONFIG_LV_MEM_CUSTOM=n
  • Defining a lower display resolution x/y from overlay
  • Calling no explicit lv_* functions until lv_task_handler()

No changes.

@pdgendt
Copy link
Collaborator

pdgendt commented Sep 20, 2022

Ok so, the Zephyr driver is working fine without LVGL with last modifications.

How did you test the driver itself?

Is it possible to share code for the driver?
What's the instruction that caused the fault (with addr2line)?
Can you attach a debugger and get to the display_write function?

@Linzdigr
Copy link
Author

@pdgendt I tested my driver from the nordic/ncs/v2.0.2/zephyr/samples/drivers/display/src/main.c and was able to print the expected screen

I'll fork the zephyr repo so I can show you, meanwhile, init of the display is done before the OS as expected (init/write/...), then no further call to any of the driver's function are done.

It seems lvgl crashes before soliciting the driver layer.


I just realized the stack size limit wasn't enough and independent from CONFIG_MAIN_STACK_SIZE as it runs in a k_thread...
Defining the value to 4096 did the job.
Can't believe I didn't look at this before...

Thanks anyway ! Will do a PR for the driver when it's clear and clean :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: LVGL Light and Versatile Graphics Library Support bug The issue is a bug, or the PR is fixing a bug
Projects
None yet
Development

No branches or pull requests

4 participants