How to access the child nodes in a device tree (DTS) in Zephyr using DT_FOREACH_CHILD

1.2k views Asked by At

I'm developing an application for an nRF52 SoC to access some external devices, kind of detectors in this case, so I have defined a custom format (and its corresponding yaml file) for my device access description node. It is kind of:

n: detectors {
    compatible = "foo-detectors";
        
    // Definition of first channel
    det0: det_0 {
        irq-pins = <13 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
        label = "Bar detector channel 1";
    };
    // Definition of second channel
    det1: det_1 {
        irq-pins = <17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
        label = "Bar detector channel 2";
    };
};

Suppose I have a structure definition for holding data about the pins to which those devices are physically connected, say:

struct foo_detector_desc { 
    int irqpin; 
    int irqpin_flags;
}

Using Zephyr macros, I can use from my code the individual values for those nodes. For instance, DT_PROP_BY_IDX(DT_NODELABEL(det0), irq_pins, 0) expands to 13, DT_PROP_BY_IDX(DT_NODELABEL(det0), irq_pins, 1) expands to the value of OR'ed flags GPIO_PULL_UP | GPIO_ACTIVE_LOW.

But I don't want to create a ten-page code full of conditionals in the form DT_NODE_EXISTS(DT_ALIAS(det#)), but something more compact, flexible and maintainable.

I came across Zephyr macro DT_FOREACH_CHILD that is intended for being used in that scenario with which I can create a list with the labels, as showcased in the example embedded in the documentation:

#define LABEL_AND_COMMA(node_id) DT_LABEL(node_id),
const char *child_labels[] = {
    DT_FOREACH_CHILD(DT_NODELABEL(n), LABEL_AND_COMMA)
};

Trying to use that for filling a static structures array, I tried following code but, yet it expands to two elements in the array, the structure fields are not initialised with desired values.

#define PIN_INFO_AND_COMMA(node_id) \
    { \
        .pin=DT_PROP_BY_IDX(node_id, irq_pins, 0),\
        .flags=DT_PROP_BY_IDX(node_id, irq_pins, 1),\
    },

const struct detector_data _det_data[] = {
    DT_FOREACH_CHILD(DT_NODELABEL(n), PIN_INFO_AND_COMMA)
};

I'm using Visual Studio Code with the nRF Connect plugin.

Is there a way to generate/see how those macros expand when compiled?

What is the correct way for initialising the structure fields (pins, flags)?

BR

1

There are 1 answers

1
V.Lorz On BEST ANSWER

It is possible to expand the macros one level at a time in VS Code. It is needed to click over the macro, then select it by double-clicking on it, and a bulb light will, eventually, show up. The option Insert Macro will replace the macro with its expansion.

Regarding using the DTS in code, the code I wrote in my previous post is OK, but I think I found a bug in the debugger. If I don't include any code using the value of _det_data, the debugger doesn't say the constant was optimised-out and displays wrong values when inspecting its content. That made me waste a lot of time.

For anyone interested on using DTS files for nRF devices in Zephyr, I posted all details in a thread in Nordic's developers forum (here).

BR