Enabling uarte0 causes i2c0 ssd1306 driver initialization failure

I'm using zephyr with a custom board (nrf52840) which has a ssd1306 OLED. I have it configured to use i2c0 and is working fine with lvgl.

When I try to enable uart0 (using the async API), the ssd1306 device initialization fails. I can confirm that both display and uart work as expected individually. When enabled together is when this issue occurs. I have triple checked that they don't have any overlapping pin configurations.

Is there anything else I should be checking?

Parents
  • Hi,

     

    Which GPIOs are you using for I2C0?

    I have triple checked that they don't have any overlapping pin configurations.

    Have you checked that the RTS/CTS does not overlap? That is by-default P0.05 to P0.08 on the nRF52840-DK.

     

    Kind regards,

    Håkon

  • I have my own board definition. In this board, I define the following:

    &pinctrl {
    	uart0_default: uart0_default {
    		group1 {
    			psels = <NRF_PSEL(UART_TX, 1, 11)>;
    		};
    		group2 {
    			psels = <NRF_PSEL(UART_RX, 1, 12)>;
    			bias-pull-up;
    		};
    	};
    
    	uart0_sleep: uart0_sleep {
    		group1 {
    			psels = <NRF_PSEL(UART_TX, 1, 11)>,
    				<NRF_PSEL(UART_RX, 1, 12)>;
    			low-power-enable;
    		};
    	};
    
    	i2c0_default: i2c0_default {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 0, 4)>,
    				<NRF_PSEL(TWIM_SCL, 0, 5)>;
    		};
    	};
    
    	i2c0_sleep: i2c0_sleep {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA, 0, 4)>,
    				<NRF_PSEL(TWIM_SCL, 0, 5)>;
    			low-power-enable;
    		};
    	};
    };

    And the the ssd1306 entry:

    &i2c0 {
    	status = "okay";
    	ssd1306_128x64: ssd1306@3c {
    		compatible = "solomon,ssd1306fb";
    		reg = <0x3c>;
    		width = <128>;
    		height = <64>;
    		segment-offset = <0>;
    		page-offset = <0>;
    		display-offset = <0>;
    		multiplex-ratio = <63>;
    		segment-remap;
    		com-invdir;
    		prechargep = <0x22>;
    	};
    };

  • > Please share the full boot sequence, as asked for here:

    I have code that enabled the OLED and UART. On reset, I see the following logs (which I posted earlier) and then nothing after that. Those are all the things that happen at boot.
    [00:00:00.763,458] <dbg> i2c: i2c_dump_msgs_rw: I2C msg: i2c@40003000, addr=3c    
    [00:00:00.763,488] <dbg> i2c: i2c_dump_msgs_rw:    W      len=01: 00
    [00:00:00.763,549] <dbg> i2c: i2c_dump_msgs_rw:    W    P len=01: ae
    [00:00:00.763,549] <err> ssd1306: Failed to initialize device!
    *** Booting Zephyr OS build v4.2.0-2290-g617b71bc174b ***        
    [00:00:00.764,709] <err> lvgl: Display device 0 is not ready                                                                                            
    [00:00:00.764,892] <err> app: Device not ready, aborting test
    Physically on SCL/SDA lines, there is no other activity.

    > The amount of debug logs in the driver is minimal, so you need to debug this. Enter debug mode, use break points to check where it returns EIO:

    I did just that and posted where it returns -EIO: the very first I2C transaction; in driver, that is at the call to ssd1306_suspend() here.

    > Try to expand the value of that config. Again, I have no idea if the picture that you posted of the SDA/SCL is mid-transaction or if that is the very first one. Please confirm.

    The posted scope capture is soon after reset after that there is no activity on the bus.

    I suspect that you missed at-least one of my earlier replies?

  • Hi,

     

    sidcha said:

    The posted scope capture is soon after reset after that there is no activity on the bus.

    I suspect that you missed at-least one of my earlier replies?

    Thank you for confirming this.

    In your log, it shows 3 rw transactions:

    [00:00:00.763,458] <dbg> i2c: i2c_dump_msgs_rw: I2C msg: i2c@40003000, addr=3c
    [00:00:00.763,488] <dbg> i2c: i2c_dump_msgs_rw: W len=01: 00
    [00:00:00.763,549] <dbg> i2c: i2c_dump_msgs_rw: W P len=01: ae

     

    However, the transaction on the SDA/SCL pins only show two. Is there a third transaction shifted out on the pins?

    sidcha said:
    I did just that and posted where it returns -EIO: the very first I2C transaction; in driver, that is at the call to ssd1306_suspend() here.

    Good. This command corresponds with the "0xae" that is sent, ie define SSD1306_DISPLAY_OFF, which is sent with a write and a stop condition (indicated with W and P).

     

    You mention that you have a scenario where this works as intended. Can you please share plots (of the SDA/SCL via a logic analyzer), so I can compare the transactions in the beginning?

     

    Kind regards,

    Håkon

  • > However, the transaction on the SDA/SCL pins only show two. Is there a third transaction shifted out on the pins?

    No, what I posted was everything that happened during the failure case.

    After some more trial and errors, I noticed that the uart0 was configured to do DMA while the i2c0 was not. First I tried removing DMA from uart0 -- it did not help. I then added DMA to i2c0 and things start working.

    For now this setup (both DMA) works but I would still like to understand how this is a problem. Can you help explaining?

  • Hi,

     

    sidcha said:
    After some more trial and errors, I noticed that the uart0 was configured to do DMA while the i2c0 was not. First I tried removing DMA from uart0 -- it did not help. I then added DMA to i2c0 and things start working.

    This is the change that you did, correct?

    &i2c0 {
    	compatible = "nordic,nrf-twim"; /* was nordic,nrf-twi */
    	...rest of config
    };

     

    This will use the DMA capable NRF_TWIM peripheral, as compared to the NRF_TWI peripheral.

    I would recommend that you use the DMA-capable periperhal when speed is one of your primary requirements (which it usually is with displays).

     

    That being said, it shall still work with the non-DMA capable NRF_TWI module. It sounds like there has been a timing-wise issue with the non-DMA capable NRF_TWI module, but it is hard to say without being able to recreate this scenario locally.

     

    Kind regards,

    Håkon

  • This is the change that you did, correct?

    Yes.

    That being said, it shall still work with the non-DMA capable NRF_TWI module. It sounds like there has been a timing-wise issue with the non-DMA capable NRF_TWI module, but it is hard to say without being able to recreate this scenario locally.

    TBH, it was a typo that led to i2c0 to not have DMA and I am glad that this combination works. It's just not clear to me how not having the DMA module can cause this issue. It's for sure not a physical issue as I have them both working together now.

Reply
  • This is the change that you did, correct?

    Yes.

    That being said, it shall still work with the non-DMA capable NRF_TWI module. It sounds like there has been a timing-wise issue with the non-DMA capable NRF_TWI module, but it is hard to say without being able to recreate this scenario locally.

    TBH, it was a typo that led to i2c0 to not have DMA and I am glad that this combination works. It's just not clear to me how not having the DMA module can cause this issue. It's for sure not a physical issue as I have them both working together now.

Children
  • Hi,

     

    I am glad to hear that it works consistently now.

    sidcha said:
    t's just not clear to me how not having the DMA module can cause this issue.

    It does sound like an issue/compatibility with the underlying driver, or a timing-wise problem wrt. I2C stop condition or something like that, but this is guessing from my side. Let me know if you run into any other issues with the TWIM module.

     

    I hope you have a great weekend!

     

    Kind regards,

    Håkon

Related