zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.88k stars 6.63k forks source link

Raspberry Pi Pico - ssd1306 display attempts to initialize before i2c bus is ready for communication #53800

Closed doctorseus closed 1 year ago

doctorseus commented 1 year ago

Describe the bug

Hi, I am working on a Raspberry Pi Pico connected to a ssd1306 based o-led display: https://www.adafruit.com/product/938 I used zephyr/boards/shields/ssd1306/ssd1306_128x32.overlay as a basis:

&i2c0 {
    status = "okay";

    ssd1306_ssd1306_128x64: ssd1306@3c {
        compatible = "solomon,ssd1306fb";
        reg = <0x3d>;
        width = <128>;
        height = <64>;
        segment-offset = <0>;
        page-offset = <0>;
        display-offset = <0>;
        multiplex-ratio = <31>;
        segment-remap;
        com-invdir;
        com-sequential;
        prechargep = <0x22>;
    };
};

When I run any of the display sample applications (e.g. zephyr/samples/subsys/display/cfb), the application will just work (as the device is just soft-resets before running the code and not disconnected from power). However, I noticed that when I unplug the RPI Pico and re-plug it again, the display stays black.

To me it appears, that the i2c is not immediately ready after power-on to actually be usable for the communication to the display IC when Zypher tries to initialize it. If I add a delay of about 170ms in the ssd1306_init_device function the app works correctly and the display is initialized. (Please note that there is no other modification of the sample code. I just attempted to flash the sample using the SHIELD define on a stock Raspberry Pi Pico.)

Also the console prints that node ssd1306@3c is not ready, before even initializing i2c.

To Reproduce Steps to reproduce the behavior:

  1. build cfb sample
  2. flash on a rpi_pico with a ssd1306 display connected
  3. See black display

Expected behavior See application working as expected.

Impact Delaying the initialization works for me but this might have other effects too.

Logs and console output

Device ssd1306@3c not ready
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_initialize > start        # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_runtime_configure > 1        # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_runtime_configure > 2        # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_initialize > end        # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_initialize > start         # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_runtime_configure > 1         # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_runtime_configure > 2         # dbg output added by me
[00:00:00.000,000] <inf> i2c_dw: I2C: i2c_dw_initialize > end         # dbg output added by me
[00:00:00.000,000] <inf> ssd1306: ssd1306_init > start         # dbg output added by me
[00:00:00.001,000] <err> ssd1306: Failed to initialize device!
*** Booting Zephyr OS build zephyr-v3.2.0-3446-g2017ed50bf9a ***

Environment (please complete the following information):

Additional context

doctorseus commented 1 year ago

Maybe someone has a similar ssd1306 display to re-run this example on a rpi_pico, in case this is connected to the particular shield I am using for this testing. Potentially it might require more time to boot up. Unfortunately I don't have the equipment at hand to verify the bus communication / voltage level.

thedjnK commented 1 year ago

cfb is outputting the error using printf which is likely bypassing the logging system, hence why you see it first, but in actuality the i2c errors are probably being emitted first.

If I add a delay of about 170ms in the ssd1306_init_device function the app works correctly and the display is initialized

This sums it up, you are trying to configure your display before the display itself is ready, which will fail.

yonsch commented 1 year ago

Both the I2C and SSD1306 are initialized in the POST_KERNEL phase with CONFIG_I2C_INIT_PRIORITY and CONFIG_DISPLAY_INIT_PRIORITY respectively, so I would guess that the display's init priority defaults to a higher priority. I would suggest that you try changing those defaults in your prj.conf. If that solves your issue then this is not a problem with the Pico. Maybe the default value for the display is too high and should be fixed, but that's should go through the display maintainers.

yonsch commented 1 year ago

@doctorseus Has this been resolved?

doctorseus commented 1 year ago

@doctorseus Has this been resolved?

No, this is still broken, I didn't get to it yet (free time project). Before even posting it I put the display on APPLICATION priority (which is last I believe) and it still failed, I haven't mentioned this initially. So I assume changing priorities alone wouldn't help but haven't verified yet so I didn't comment.

On the same (display) front this https://github.com/zephyrproject-rtos/zephyr/issues/46446 is still broken too and I ran into it right after this here, unfortunately it got closed automatically. I kinda want to look into both if possible, it's on my agenda.

nordicjm commented 1 year ago

I guess a question for @galak or maybe @JordanYates is how can this be solved, assuming that a micro starts up in (making numbers up here) 15ms and a driver attached to it takes 50ms before it can be communicated with - how can we have a generic way of specifying this or delaying specific driver initialisation until a specified period has elapsed after the micro has booted? I have the same issue with a display module whereby because it is slow to start, I need to delay the driver initialising for a period of time, and I've put the delay in the driver itself (which in my mind is the wrong place to have it)

JordanYates commented 1 year ago

I guess a question for @galak or maybe @JordanYates is how can this be solved, assuming that a micro starts up in (making numbers up here) 15ms and a driver attached to it takes 50ms before it can be communicated with - how can we have a generic way of specifying this or delaying specific driver initialisation until a specified period has elapsed after the micro has booted? I have the same issue with a display module whereby because it is slow to start, I need to delay the driver initialising for a period of time, and I've put the delay in the driver itself (which in my mind is the wrong place to have it)

For power domains there is a startup delay parameter which can be used to specify at the domain level how long to wait after turning it on before you can talk to anything. This is more aimed at supply stability than the delays of attached devices, but it can be used (abused) for that. https://github.com/zephyrproject-rtos/zephyr/blob/7e20b819541a028b7b298261e053cb000f2a8571/drivers/power_domain/power_domain_gpio.c#L66-L69

For a more generic solution at the device level, I would look at reviving #49318 and #50519 to enable #22545. If you have an ordered tree of dependencies and a method of shuffling the init order (via the arrays), you could order the tree init such that devices with a time delay are only run after devices without a delay are initialized. If that is the case, the driver can do k_sleep(K_TIMEOUT_ABS_MS(delay)) in the init function without downsides, as any other device that could do useful work has already run.

github-actions[bot] commented 1 year ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.

doctorseus commented 1 year ago

I would like to have the stale label removed to avoid loosing this again to eternity.

github-actions[bot] commented 1 year ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.

doctorseus commented 1 year ago

Still not resolved and relevant, so please remove the Stale label once again (and in general I think 60/14 days is quite short).

github-actions[bot] commented 1 year ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.

jhedberg commented 1 year ago

Any update on this one?

fabiobaltieri commented 1 year ago

Could repro locally, propsing exactly what @JordanYates suggested in https://github.com/zephyrproject-rtos/zephyr/pull/62049

fabiobaltieri commented 1 year ago

@doctorseus this one should be sorted, if you could open a PR for the issue in #46446 that'd be cool.