Re: device_get_binding() returns NULL on all but one vl53l0x


Erwan Gouriou
 

Hi Matthias,

Indeed this dynamic behavior is not implemented.
As you can see in vl53lx driver, vl53l0x_init make use of DT_INST_FOO(0, bar) macros.
Which means only the information from instance 0 are used.

This being said, enabling dynamic support should not be that complicated.
A lot of zephyr drivers support instantiation and could be used as example.

Here are the steps:
- Add a config struct to the driver init to store all the instance init data from device tree
- rework the vl53l0x_init function to be instance agnostic by using this config struct
- Instantiate the driver DEVICE_AND_API_INIT thanks to DT_INST_FOREACH_STATUS_OKAY(FOO) macro

DT_INST_FOREACH_STATUS_OKAY(FOO) will loop through all dt enabled instances of your sensor
and call FOO(i) for each instance.
You'll find doc and examples of use of this macro throughout the tree. 

Best regards
Erwan






 

On Wed, 2 Dec 2020 at 14:56, Matthias Wenzel <mw@...> wrote:
Hi,

I am using six vl53l0x (a laser time-of-flight sensor) on two I2C busses (three each), and device_get_binding() returns NULL on all but one.

The vl53l0x is special in that regard that it cannot be pin-strapped to a device-address, instead it always comes up as address 0x29, and has a SW command to assign it a new address. So when using multiple vl53l0x on one I2C bus the mechanism is to keep all-but-one in reset, assign a new address, and release the next from reset. This mechanism seems to work fine with this loop getting called with 0..5:

void vl53l0x_init_addr(int n)
{
    const struct device *i2c1 = device_get_binding(DT_LABEL(DT_PATH(soc, i2c_40005400)));
    const struct device *i2c2 = device_get_binding(DT_LABEL(DT_PATH(soc, i2c_40005800)));

    switch (n)
    {
        case 0:
            xshut_release(PORTPIN_TOF_C_XSHUT);
            vl53l0x_hop_to_addr(i2c1, 0x31);
            vl53l0x[2].vl53l0x = device_get_binding(DT_LABEL(DT_NODELABEL(vl53l0x_c)));
            break;
        case 1:
            xshut_release(PORTPIN_TOF_B_XSHUT);
            vl53l0x_hop_to_addr(i2c1, 0x30);
            vl53l0x[1].vl53l0x = device_get_binding(DT_LABEL(DT_NODELABEL(vl53l0x_b)));
            break;
        case 2:
            xshut_release(PORTPIN_TOF_A_XSHUT);
            vl53l0x[0].vl53l0x = device_get_binding(DT_LABEL(DT_NODELABEL(vl53l0x_a)));
            break;
        case 3:
            xshut_release(PORTPIN_TOF_F_XSHUT);
            vl53l0x_hop_to_addr(i2c2, 0x31);
            vl53l0x[5].vl53l0x = device_get_binding(DT_LABEL(DT_NODELABEL(vl53l0x_f)));
            break;
        case 4:
            xshut_release(PORTPIN_TOF_E_XSHUT);
            vl53l0x_hop_to_addr(i2c2, 0x30);
            vl53l0x[4].vl53l0x = device_get_binding(DT_LABEL(DT_NODELABEL(vl53l0x_e)));
            break;
        case 5:
            xshut_release(PORTPIN_TOF_D_XSHUT);
            vl53l0x[3].vl53l0x = device_get_binding(DT_LABEL(DT_NODELABEL(vl53l0x_d)));
            break;
    }
}

However when testing lateron, only vl53l0x[0].vl53l0x has an address, the other five are 0. Note that vl53l0x[0].vl53l0x gets actually set in the third call to the above function.

    for (int i = 0; i < N_VL53L0X; i++)
    {
        printf("DEV[%d] = %p\r\n", i, vl53l0x[i].vl53l0x);
    }
Prints:
DEV[0] = 0x20020f04
DEV[1] = 0x0
DEV[2] = 0x0
DEV[3] = 0x0
DEV[4] = 0x0
DEV[5] = 0x0

I am using an DT-overlay which is

&i2c1 {
    status = "okay";
    clock-frequency = < 100000 >;
    pinctrl-0 = < &i2c1_scl_pb6 &i2c1_sda_pb9 >;
    vl53l0x_a: tofi2c1@29 {
        compatible = "st,vl53l0x";
        reg = < 0x29 >;
        label = "VL53L0X_A";
    };
    vl53l0x_b: tofi2c1@30 {
        compatible = "st,vl53l0x";
        reg = < 0x30 >;
        label = "VL53L0X_B";
    };
    vl53l0x_c: tofi2c1@31 {
        compatible = "st,vl53l0x";
        reg = < 0x31 >;
        label = "VL53L0X_C";
    };
};
&i2c2 {
    status = "okay";
    clock-frequency = < 100000 >;
    pinctrl-0 = < &i2c2_scl_pf1 &i2c2_sda_pf0 >;
    vl53l0x_d: tofi2c2@29 {
        compatible = "st,vl53l0x";
        reg = < 0x29 >;
        label = "VL53L0X_D";
    };
    vl53l0x_e: tofi2c2@30 {
        compatible = "st,vl53l0x";
        reg = < 0x30 >;
        label = "VL53L0X_E";
    };
    vl53l0x_f: tofi2c2@31 {
        compatible = "st,vl53l0x";
        reg = < 0x31 >;
        label = "VL53L0X_F";
    };
};

Is this "dynamic" behaviour unsupported in current DT and/or the zephyr vl53l0x driver implementation, or am I missing some detail on how to implement this properly?
I am on an nucleo-144 STM32F767ZI eval board.

Thanks & best regards,

matthias





Join users@lists.zephyrproject.org to automatically receive all group messages.