Working around missing shield labels (on the nRF9160 DK)

Shields are a neat way of quickly getting some peripherals up and running on your projects. However, if you have tried using an Arduino shield on your nRF9160 DK, you have likely encountered an error along the lines of:

 Error: nrf9160dk_nrf9160ns.dts.pre.tmp:647.1-13 Label or path arduino_spi not found
Error: nrf9160dk_nrf9160ns.dts.pre.tmp:664.1-8 syntax error
FATAL ERROR: Unable to parse input tree
CMake Error at C:/ncs/v1.5.1/zephyr/cmake/dts.cmake:205 (message):
command failed with return code: 1

This is because the nRF9160 DK does not support Arduino shields out of the box, but it is on its way. Since I have spent some time fiddling around with working around this missing functionality, I will briefly explain how I have worked around this.

Objectives

  • Provide a way to work around missing shield label(s)
  • Gain a deeper understanding of how devicetree overlays work

What are device tree overlays, and how do they relate to shields?

Simply put, devicetree overlays are ways for you to overwrite properties of nodes in your board's device tree. For example, the device tree file of the nRF9160 DK can be found at ncs/zephyr/boards/arm/nrf9160dk_nrf9160/nrf9160dk_nrf9160_common.dts. If you want to change any of these properties for just one project, then you can do this in a devicetree overlay. This is well explained in the Zephyr project's docs and I recommend you check it out!

Why are Arduino nodes not recognized in the nRF9160 DK?

It is because support for Arduino nodes was never implemented. However, support for shields using arduino_i2c and arduino_serial are on their way. If you have received the error message in the introduction, you might have tried creating an alias to arduino_spi in a board overlay file. This does not work, however, as the current order in which overlay files are applied on top of the board device tree is: 

  1. board overlay
  2. shield overlay

This is intentional and is unlikely to change. As of right now, there is no way to provide an additional overlay that goes between the shield overlay and the board device tree, so we need to find a way to work around the missing node labels for arduino_spi, arduino_serial and arduino_serial like this.

The workaround: Using the shield as a board overlay

  1. Locate the shield's overlay file (typically found in zephyr/boards/shields).
  2. Copy-paste the contents of the shield's overlay file into your project's board overlay file.
  3. Now, for the tricky part: Replace all areas in the overlay file referring to Arduino as explained here.
    1. Replace the node names, named &arduino_serial, &arduino_spi or &arduino_i2c with:
      1. for the nRF9160 DK, you can replace &arduino_serial with &uart1, &arduino_spi with &spi3, and &arduino_i2c with &i2c2
    2. You might see that the overlay file refers to arduino_header. You will get an error if you do not change the arduino_header references according to the instructions below:
      1. To figure out which Arduino digital pin corresponds to which GPIO pin, you can: 
        1. Look at your physical board. You will likely find some pins named (ARDUINO D0), (D1) etc. If you cannot find them, try flipping the board around and check on the other side.
        2. You can also find the schematics and layout for the nRF9160 DK which describes what pins are connected to the Arduino headers here
      2. Once you have located the Arduino digital pins on your physical board, note the port and pin number. For the nRF9160 DK, Arduino D0 corresponds to P0.00. D1 corresponds to P0.01 and so on.
      3. In your overlay file, change the references to arduino_header.
        1. For example for the nRF9160 DK, the entry 
          cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>;    /* D10 */
          can be replaced with
          cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;    /* D10 */
          where gpio0 refers to P0.XX, and the number following gpio0 refers to the number after the dot on the board, that is, PX.10 in this case.
        2. For the nRF52840 DK, the entry 
          cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>;    /* D10 */
          is replaced with 
          cs-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;    /* D10 */ 
          as Arduino D10 is located on P1.12 on the nRF52840 DK.
  4. Insert the project configurations (found in the shield's Kconfig.defconfig) into your own project configuration file (typically prj.conf)

To illustrate, I have provided a zip of a project before and after this workaround. Check it out if you wanna see this workaround in practice! If you have any feedback or if anything is unclear, please leave a comment!

Further reading

An example of this workaround can be seen in my LVGL blog post.

Some forum threads have also discussed this issue:

https://devzone.nordicsemi.com/f/nordic-q-a/44205/nrf9160-dk-arduino-uno-compatibility

https://devzone.nordicsemi.com/f/nordic-q-a/43774/simple-gpio-example---nrf9160-dk/173307#173307

Attached files

workaround_in_practice.zip