configure overlay with two mcp2515 spi device but error in compiler.

hello to all,

I need to insert two CAN ports on the spi3 port of the nrf52840 with two different chip select and interrupt.

I have created an overlay file that defines two MCP2515 nodes.

overlay:

&spi3 {
    status = "okay";
    cs-gpios = <&gpio1 3 1>, <&gpio1 4 1>;
    canprimary: mcp2515@0 {
        compatible = "microchip,mcp2515";
        spi-max-frequency = <1000000>;
        int-gpios = <&gpio1 5 1>;
        status = "okay";
        label = "MCP2515_A";
        reg = <0x0>;
        osc-freq = <10000000>;
        bus-speed = <250000>;
        sjw = <1>;
        prop-seg = <2>;
        phase-seg1 = <7>;
        phase-seg2 = <6>;
        #address-cells = <1>;
        #size-cells = <0>;
		sample-point = < 875 >;
    };
	cansecondary: mcp2515@1 {
        compatible = "microchip,mcp2515";
        spi-max-frequency = <1000000>;
        int-gpios = <&gpio1 6 1>;
        status = "okay";
        label = "MCP2515_B";
        reg = <0x1>;
        osc-freq = <10000000>;
        bus-speed = <250000>;
        sjw = <1>;
        prop-seg = <2>;
        phase-seg1 = <7>;
        phase-seg2 = <6>;
        #address-cells = <1>;
        #size-cells = <0>;
		sample-point = < 875 >;
    };
};

if I compile with only one of the two chips, I have no problems with initialization:

definition:

#define CAN0_NODE DT_NODELABEL(canprimary)
#define CAN1_NODE DT_NODELABEL(cansecondary)

initialization:

void can_api_init(void)
{
    int ret;
    can_dev_0 = DEVICE_DT_GET(CAN0_NODE);
    printk("GET: %s\n", can_dev_0->name); // node 1

/*     can_dev_1 = DEVICE_DT_GET(CAN1_NODE);
    printk("GET: %s\n", can_dev_1->name); */ // node 2
    
    ... etc

if I activate the second node,

void can_api_init(void)
{
    int ret;
    can_dev_0 = DEVICE_DT_GET(CAN0_NODE);
    printk("GET: %s\n", can_dev_0->name);

    can_dev_1 = DEVICE_DT_GET(CAN1_NODE); // <= activate second node !!!
    printk("GET: %s\n", can_dev_1->name); 

the compiler gives me an error:

[198/198] Linking C executable zephyr/zephyr.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:       58916 B         1 MB      5.62%
            SRAM:       31880 B       256 KB     12.16%
        IDT_LIST:          0 GB         2 KB      0.00%
 *  Terminal will be reused by tasks, press any key to close it. 

 *  Executing task: nRF Connect: Build: dual_can_external/build_external (active) 

Building dual_can_external
west build --build-dir /opt/nordic/CAN_52840dk/dual_can_external/build_external /opt/nordic/CAN_52840dk/dual_can_external

[1/11] Building C object CMakeFiles/app.dir/src/can/can.c.obj
[2/11] Linking C static library app/libapp.a
[3/11] Linking C executable zephyr/zephyr_pre0.elf
FAILED: zephyr/zephyr_pre0.elf zephyr/zephyr_pre0.map 
: && ccache /opt/nordic/ncs/toolchains/v2.0.0/opt/zephyr-sdk/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc   zephyr/CMakeFiles/zephyr_pre0.dir/misc/empty_file.c.obj -o zephyr/zephyr_pre0.elf  -fuse-ld=bfd  -Wl,-T  zephyr/linker_zephyr_pre0.cmd  -Wl,-Map=/opt/nordic/CAN_52840dk/dual_can_external/build_external/zephyr/zephyr_pre0.map  -Wl,--whole-archive  app/libapp.a  zephyr/libzephyr.a  zephyr/arch/common/libarch__common.a  zephyr/arch/arch/arm/core/aarch32/libarch__arm__core__aarch32.a  zephyr/arch/arch/arm/core/aarch32/cortex_m/libarch__arm__core__aarch32__cortex_m.a  zephyr/arch/arch/arm/core/aarch32/mpu/libarch__arm__core__aarch32__mpu.a  zephyr/lib/libc/minimal/liblib__libc__minimal.a  zephyr/lib/posix/liblib__posix.a  zephyr/soc/arm/common/cortex_m/libsoc__arm__common__cortex_m.a  zephyr/soc/arm/nordic_nrf/nrf52/libsoc__arm__nordic_nrf__nrf52.a  zephyr/drivers/clock_control/libdrivers__clock_control.a  zephyr/drivers/console/libdrivers__console.a  zephyr/drivers/gpio/libdrivers__gpio.a  zephyr/drivers/spi/libdrivers__spi.a  zephyr/drivers/can/libdrivers__can.a  zephyr/drivers/serial/libdrivers__serial.a  zephyr/drivers/timer/libdrivers__timer.a  zephyr/drivers/pinctrl/libdrivers__pinctrl.a  modules/nrf/lib/fatal_error/lib..__nrf__lib__fatal_error.a  modules/nrf/drivers/hw_cc310/lib..__nrf__drivers__hw_cc310.a  modules/hal_nordic/nrfx/libmodules__hal_nordic__nrfx.a  modules/segger/libmodules__segger.a  -Wl,--no-whole-archive  zephyr/kernel/libkernel.a  zephyr/CMakeFiles/offsets.dir/./arch/arm/core/offsets/offsets.c.obj  -L"/opt/nordic/ncs/toolchains/v2.0.0/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/10.3.0/thumb/v7e-m/nofp"  -L/opt/nordic/CAN_52840dk/dual_can_external/build_external/zephyr  -lgcc  zephyr/arch/common/libisr_tables.a  -no-pie  -mcpu=cortex-m4  -mthumb  -mabi=aapcs  -mfp16-format=ieee  -Wl,--gc-sections  -Wl,--build-id=none  -Wl,--sort-common=descending  -Wl,--sort-section=alignment  -Wl,-u,_OffsetAbsSyms  -Wl,-u,_ConfigAbsSyms  -nostdlib  -static  -Wl,-X  -Wl,-N  -Wl,--orphan-handling=warn  /opt/nordic/ncs/v2.0.0/nrfxlib/crypto/nrf_cc310_platform/lib/cortex-m4/soft-float/no-interrupts/libnrf_cc310_platform_0.9.14.a && cd /opt/nordic/CAN_52840dk/dual_can_external/build_external/zephyr && /opt/nordic/ncs/toolchains/v2.0.0/Cellar/cmake/3.20.5/bin/cmake -E echo
/opt/nordic/ncs/toolchains/v2.0.0/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/10.3.0/../../../../arm-zephyr-eabi/bin/ld.bfd: app/libapp.a(can.c.obj): in function `can_api_init':
/opt/nordic/CAN_52840dk/dual_can_external/src/can/can.c:401: undefined reference to `__device_dts_ord_130'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: /opt/nordic/ncs/toolchains/v2.0.0/bin/cmake --build /opt/nordic/CAN_52840dk/dual_can_external/build_external

some idea ??
Thank you

  • The reason you're not able to get both mcp2515 instances using DEVICE_DT_GET is because the can_cmp2515 driver will only create a device for the first found instance of "microchip,mcp2515". In that your case that is the node mcp2515@0.

    To understand it better, take a look at the DEVICE_DT_INST_DEFINE macro in can_mcp2515:

    https://github.com/nrfconnect/sdk-zephyr/blob/v3.1.99-ncs1/drivers/can/can_mcp2515.c#L997-L999

    DEVICE_DT_INST_DEFINE(0, &mcp2515_init, NULL,
    		    &mcp2515_data_1, &mcp2515_config_1, POST_KERNEL,
    		    CONFIG_CAN_INIT_PRIORITY, &can_api_funcs);

    As you can see it will only create a device for instance 0 (mcp2515@0).

    The adxl362 driver, on the other hand will iterate through all the adxl362 instances, by using DT_INST_FOREACH_STATUS_OKAY: https://github.com/nrfconnect/sdk-zephyr/blob/v3.1.99-ncs1/drivers/sensor/adxl362/adxl362.c#L770.

    As a test, can you try to modify the can_mcp2515 driver like the adxl362 driver and see if that works?

    I'm not sure why the can_mcp2515 driver won't iterate through all the instances, if it is intentional or just a mistake. Would you be able to create a Zephyr GitHub issue about this? Please link to the GitHub issue in this ticket, so other customer can benefit

    Best regards,

    Simon

  • Hello Simon,

    below, the response from the contributor; would you help me understand how to try to modify and / or replace macros?
    Thank you and 

    Best Regards

    Drivers have been updated over time but this one has not, it should be possible to replace the macros and add support for multiple devices.

  • Try the following patch:

    diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c
    index 395492ea77..b8fe42e4ef 100644
    --- a/drivers/can/can_mcp2515.c
    +++ b/drivers/can/can_mcp2515.c
    @@ -967,35 +967,38 @@ static int mcp2515_init(const struct device *dev)
     	return ret;
     }
     
    -#if DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay)
    -
    -static K_KERNEL_STACK_DEFINE(mcp2515_int_thread_stack,
    -			     CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE);
    -
    -static struct mcp2515_data mcp2515_data_1 = {
    -	.int_thread_stack = mcp2515_int_thread_stack,
    -	.tx_busy_map = 0U,
    -	.filter_usage = 0U,
    -};
    -
    -static const struct mcp2515_config mcp2515_config_1 = {
    -	.bus = SPI_DT_SPEC_INST_GET(0, SPI_WORD_SET(8), 0),
    -	.int_gpio = GPIO_DT_SPEC_INST_GET(0, int_gpios),
    -	.int_thread_stack_size = CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE,
    -	.int_thread_priority = CONFIG_CAN_MCP2515_INT_THREAD_PRIO,
    -	.tq_sjw = DT_INST_PROP(0, sjw),
    -	.tq_prop = DT_INST_PROP_OR(0, prop_seg, 0),
    -	.tq_bs1 = DT_INST_PROP_OR(0, phase_seg1, 0),
    -	.tq_bs2 = DT_INST_PROP_OR(0, phase_seg2, 0),
    -	.bus_speed = DT_INST_PROP(0, bus_speed),
    -	.osc_freq = DT_INST_PROP(0, osc_freq),
    -	.sample_point = DT_INST_PROP_OR(0, sample_point, 0),
    -	.phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(0, phys)),
    -	.max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(0, 1000000),
    -};
    -
    -DEVICE_DT_INST_DEFINE(0, &mcp2515_init, NULL,
    -		    &mcp2515_data_1, &mcp2515_config_1, POST_KERNEL,
    -		    CONFIG_CAN_INIT_PRIORITY, &can_api_funcs);
    -
    -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) */
    +#define MCP2515_DEFINE(inst)  \
    +\
    +static K_KERNEL_STACK_DEFINE(mcp2515_int_thread_stack,\
    +			     CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE);\
    +\
    +static struct mcp2515_data mcp2515_data_##inst = {\
    +	.int_thread_stack = mcp2515_int_thread_stack,\
    +	.tx_busy_map = 0U,\
    +	.filter_usage = 0U,\
    +};\
    +\
    +                        \
    +                              \
    +	static const struct mcp2515_config mcp2515_config_##inst = {   \
    +		.bus = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \
    +		.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),\
    +		.int_thread_stack_size = CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE,\
    +		.int_thread_priority = CONFIG_CAN_MCP2515_INT_THREAD_PRIO,\
    +		.tq_sjw = DT_INST_PROP(inst, sjw),\
    +		.tq_prop = DT_INST_PROP_OR(inst, prop_seg, 0),\
    +		.tq_bs1 = DT_INST_PROP_OR(inst, phase_seg1, 0),\
    +		.tq_bs2 = DT_INST_PROP_OR(inst, phase_seg2, 0),\
    +		.bus_speed = DT_INST_PROP(inst, bus_speed),\
    +		.osc_freq = DT_INST_PROP(inst, osc_freq),\
    +		.sample_point = DT_INST_PROP_OR(inst, sample_point, 0),\
    +		.phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)),\
    +		.max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000),\
    +	};\
    +\
    +	DEVICE_DT_INST_DEFINE(inst, &mcp2515_init, NULL,\
    +				&mcp2515_data_##inst, &mcp2515_config_##inst, POST_KERNEL,\
    +				CONFIG_CAN_INIT_PRIORITY, &can_api_funcs);\
    +
    +
    +DT_INST_FOREACH_STATUS_OKAY(MCP2515_DEFINE)
    

    or just remove this code, and replace it with the following:

    #define MCP2515_DEFINE(inst)  \
    \
    static K_KERNEL_STACK_DEFINE(mcp2515_int_thread_stack,\
    			     CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE);\
    \
    static struct mcp2515_data mcp2515_data_##inst = {\
    	.int_thread_stack = mcp2515_int_thread_stack,\
    	.tx_busy_map = 0U,\
    	.filter_usage = 0U,\
    };\
    \
                            \
                                  \
    	static const struct mcp2515_config mcp2515_config_##inst = {   \
    		.bus = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \
    		.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),\
    		.int_thread_stack_size = CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE,\
    		.int_thread_priority = CONFIG_CAN_MCP2515_INT_THREAD_PRIO,\
    		.tq_sjw = DT_INST_PROP(inst, sjw),\
    		.tq_prop = DT_INST_PROP_OR(inst, prop_seg, 0),\
    		.tq_bs1 = DT_INST_PROP_OR(inst, phase_seg1, 0),\
    		.tq_bs2 = DT_INST_PROP_OR(inst, phase_seg2, 0),\
    		.bus_speed = DT_INST_PROP(inst, bus_speed),\
    		.osc_freq = DT_INST_PROP(inst, osc_freq),\
    		.sample_point = DT_INST_PROP_OR(inst, sample_point, 0),\
    		.phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)),\
    		.max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000),\
    	};\
    \
    	DEVICE_DT_INST_DEFINE(inst, &mcp2515_init, NULL,\
    				&mcp2515_data_##inst, &mcp2515_config_##inst, POST_KERNEL,\
    				CONFIG_CAN_INIT_PRIORITY, &can_api_funcs);\
    
    
    DT_INST_FOREACH_STATUS_OKAY(MCP2515_DEFINE)

    I have not tested it thoroughly, so let me know if you face any issues.

    Best regards,

    Simon

  • ok, Simon
    tomorrow morning I try to do it and I tell you.
    thank you

    Best Regards,

    Silvio

Related