Out-of-tree driver - Zephyr (freestanding app)

out-of-tree-driver-test.zip

Hi,

We have a custom board that includes an ST LIS2DE12 sensor.  I followed what looks like the normal procedure to create an out-of-tree driver for it by refactoring the Zephyr driver for a similar ST part.  I've included the driver in my source tree, and it compiles normally, but won't link with the typical "undefined reference to `__device_dts_ord_xxx'" link error.

Note that this is a freestanding application.

I've cloned the hello_world application, and added my driver (and an overlay that includes the part).  Obviously - it can't run, since the DK board doesn't have the part - but what I'm trying to do is to get it to build without the linker error.  I've attached the code to this ticket.

What magic do I need to include in my source tree to get my out-of-tree driver to build and link as part of the zephyr tree?

Thanks in advance,

Cammie

  • Hello,

    what version of NCS are you trying to build this with?

  • I have the exact same problem right now and am trying to find a solution. My approach is to go deep into the Zephyr theory, looked into a lot of docs from docs.zephyrproject.org and watched youtube talks about writing custom drivers.
    I think the problem might be to the difference between freestanding projects vs. in-tree or in-workspace projects in combination with the Kconfig and west yaml.

    I will come back if I find a solution.

  • I tried to get this example driver code running in a freestanding fresh hello-world sample in VS Code.
    https://github.com/nobodyguy/HX711_zephyr_driver

    Getting the error main.c:61: undefined reference to `__device_dts_ord_8'

    Even had to add one line in my main Kconfig to get it so far:

    source "Kconfig.zephyr" # this one
    rsource "drivers/Kconfig"
    apparently freestanding apps have major problems easily compared to in-tree apps?
    Or I am just too stupid to acknowledge the very basics of Zephyr.

    My CMakeLists.txt for the app looks like this:

    cmake_minimum_required(VERSION 3.20.0)
    
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(hello_world)
    
    # Point to this project's root directory.
    set(HX711_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE PATH "HX711 module root directory")
    
    # Subdirectories
    add_subdirectory(drivers)
    
    # Include headers
    zephyr_include_directories(drivers)
    
    target_sources(app PRIVATE src/main.c)

    I now also tried https://github.com/jeremyherbert/zephyr_testrepo with no luck after I read https://github.com/zephyrproject-rtos/zephyr/issues/41677 where Jeremy seemingly got it working. (Had to adapt a few things like adding "zephyr" to each #include statement before the header names). Also, this repo does not even define an overlay.


  • First little check I made, was to verify that it is indeed a problem with the application type (out-of-tree vs. in-tree), and I did this by duplication an existing driver in the zephyr ncs:

    1. Duplicate the folder .../ncs/v2.4.0/zephyr/drivers/sensor/bmi270 to .../bmi271. For simplicity, the new folder can be added to the workspace in VS Code and then use "find in directory" to replace all case-sensitive instances of bmi270 with bmi271, and all BMI270 with BMI271. In the .../ncs/v2.4.0/zephyr/drivers/sensor/CMakeLists.txt file, I also had to duplicate the line for BMI270:

    add_subdirectory_ifdef(CONFIG_BMI270		bmi270)
    add_subdirectory_ifdef(CONFIG_BMI271		bmi271)

    In the .../ncs/v2.4.0/zephyr/drivers/sensor/Kconfig file too:
    source "drivers/sensor/bmi270/Kconfig"
    source "drivers/sensor/bmi271/Kconfig"
    In ncs/v2.4.0/zephyr/dts/bindings/sensor, duplicate the 3 Bosch bindings and rename them (both filename and all strings within the files).
    bosch,bmi270-i2c.yaml
    bosch,bmi270-spi.yaml
    bosch,bmi270.yaml
    bosch,bmi271-i2c.yaml
    bosch,bmi271-spi.yaml
    bosch,bmi271.yaml
    
     
    In the main.c of the sample project, the app.overlay now needs to be adjusted. For this, I created a second spi node, which looks as follows:
    imu: &spi1 {
        compatible = "nordic,nrf-spim";
        status = "okay";
        cs-gpios = <&gpio0 18 0>;
        
        fake_sensor: bmi271@0 {
            compatible = "bosch,bmi271";
            reg = <0>;
            spi-max-frequency = <10000000>;
        };
    };

    What's relevant is the compatible string and then the location in main.c:

    const struct device *const accel_sensor = DEVICE_DT_GET_ONE(bosch_bmi271);
    if (!device_is_ready(accel_sensor)) {
    		printf("Device %s is not ready\n", accel_sensor->name);
    		return 0;
    }
    
    char msg_accel[100];  // size might need to be adjusted based on your needs
    snprintf(msg_accel, sizeof(msg_accel), "Device %p name is %s", accel_sensor, accel_sensor->name);
    Note that I already had a Bosch BMI270 in my app.overlay at spi0 and it worked with the above code already. But I wanted to add an Kionix which is not in the Zephyr device tree and it did not work so far.
    My next steps are for now to use this workaround in-tree to get my own PoC for the Kionix, after that I can look into this problem again because I need my Kionix Driver to work out-of-tree anyways.

    Until then, kind regards.
Related