Custom board I2C, device_is_ready() failing with init_res == 5

Hello Devzone Community,

I am facing a run time, peripheral or sensor initialization error in a Zephyr based app, built using sdk-nrf v1.6.1, and its corresponding Zephyr RTOS release 2.6.0. More specifically, I am having trouble porting a firmware project which runs correctly on a Thingy91_nrf9160 dev kit, to a new custom board with a similar layout.

With the Thingy91, I began with the aws_iot client sample app. I then manually incorporated a Nordic I2C sample app with this, to get a feel for and see the I2C subsystem and Zephyr device driver API working. To this I was able to add an external sensor, disable the onboard one by commenting out pertinent lines of DTS code in [west_workspace]/nrf/boards/arm/thingy91_nrf9160/thingy91_nrf9160_common.dts, and enable the external sensor on &i2c2.

For curiosity I also confirmed that my modified aws_iot sample app could talk to both sensors on &i2c2.

The major change I am working through is adapting to a custom board. While I cannot share a schematic of the custom board -- it is work related and not a personal project -- I can say that the board is similar to the Thingy91 in its employment of an nrf9160 SiP, and one or more sensors on an I2C bus. The specific error I'm finding arises when firmware calls a Zephyr API routine:


    if (!device_is_ready(sensor))

In this case my sensor data structure / pointer is declared this way:


   const struct device *sensor = DEVICE_DT_GET_ANY(st_iis2dh);


In the primary device tree source file, I have configured the code this way to reflect the sensor's hard wiring, and to set I2C clock and data pins as needed:


   &i2c2 {
     compatible = "nordic,nrf-twim";
     status = "okay";
     sda-pin = <6>;
     scl-pin = <5>;
     clock-frequency = <I2C_BITRATE_FAST>;
   };

In an overlay file, I append my sensor of interest to the app processor I2C2 peripheral:


  &i2c2 {
     stmicro_sen18: iis2dh@18 {
     status = "okay";
     compatible = "st,iis2dh";
     reg = <0x18>;
     label = "IIS2DH";
  };


As I am no longer building firmware for the thing91_nrf9160 board, I have also redirected Zephyr + Nordic toolchain to look for the custom board file in a more local place. Per instructions at docs.zephyrproject.org/.../index.html I have added next stanza to my project CMakeLists.txt file:


   set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})


And this is followed immediately in CMakeLists.txt by the lines:


   find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

   project(aws-iot-stand-alone)


In all the DTS files of which I'm aware for this project I find no other references to the application processor's (ARM M33) GPIO pins P0.5 and P0.6. From what I can tell these are not being used by nor for any other peripherals. My firmware builds, it executes, but when firmware call's Zephyr's `device_is_ready()` API function, the I2C peripheral is reported as not ready.

Returning to this run time failure, the furthest I can trace things is:


* device_is_ready(device_struct_ptr) returns `device_usable_check(dev) == 0`

* device_usable_check(dev) returns `z_device_ready(dev) ? 0 : -ENODEV;`

* z_device_ready(dev) returns `dev->state->initialized && (dev->state->init_res == 0U);`


When I printk() those two elements of my sensor device's state, initialized shows as 'true' and init_res shows as '5'. Zephyr Project documentation says that Zephyr uses its given minimal C library errno.h as its defining list of named error types. From [west_workspace]/zephyr/lib/libc/minimal/include/errno.h I find this meaning for error 5:


38 #define errno (*z_errno())
39
40 #define EPERM 1 /**< Not owner */
41 #define ENOENT 2 /**< No such file or directory */
42 #define ESRCH 3 /**< No such context */
43 #define EINTR 4 /**< Interrupted system call */
44 #define EIO 5 /**< I/O error */
. . .


Electrically what I can see is that the sensor on the custom board is powered. I2C clock and data lines are pulled high to their 1p8V rail. At firmware boot time SCL and SDA both go to ground for a brief moment, but there's no data packet and they quickly rise again to 1.8V. The I2C bus is just quiet, no activity. Nor is there indication that Zephyr tries to talk on the bus after device_is_ready() returns a failed status.

The sensor module I have is working. It's on a break out board which I have jumper-wired to both Thingy91 and custom board, and back again. I do not see contention on the custom board's I2C lines. In the absence of an obvious hardware problem I am struggling to find the root cause of `init_res == 5`.

If init_res == 5 means there is an general I/O error, I’d expect missing power or bus contention to be a couple likely causes for this, on an I2C bus with one peripheral device connected. If I have correctly ruled these hardware faults out, what else could cause Zephyr to return `init_res` equal to 5?

Has anyone else confronted and solved a problem like this? Is there a DTS or Kconfig mis-configuration which can produce this error at Zephyr run time?

- Ted

  • Hello again Devzone,

    In an unusual turn I have found the root cause soon after posting here, of our Zephyr based firmware on custom board returning *sensor->state->initialized = true, and *sensor->state->init_res = 5.  While I created most of the required custom board DTS and Kconfig files, I missed [custom_board_name].yaml.  Poor mistake on my part.  I also did not see direct mention of this .yaml file or its purpose in the general Device Tree how-to readings, nor Kconfig tutorials and explanatory notes.

    The custom board .yaml file contains the following:

    identifier: custom-board-name
    name: Custom-Board-Name-Non-Secure
    type: mcu
    arch: arm
    toolchain:
    - gnuarmemb
    - zephyr
    ram: 128
    flash: 256
    supported:
    - i2c

    The first two stanzas are all that I modified.  These appear to be free-form strings.  The last line caught my eye, as it was the I2C device which it felt like Zephyr was reporting to have a general I/O error.  Somehow it looks like `supported:  - i2c` is necessary in this .yaml file in addition to the app's prj.conf file which includes the line `CONFIG_I2C=y`.

    One thing that is strange, the RAM and FLASH sizes here are smaller than what's specified in Nordic nRF9160 documentation.  Those docs say that the application processor, an ARM Cortex-M33 has 256kB static RAM and 1024kB program flash.  I wonder why these differ?

    It is okay for Nordic Semi engineers to close this ticket.  Our firmware is largely ported to a custom board with this fix.

    - Ted

Related