This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Implementing WS2812 Driver NCS (undefined reference to `__device_dts_ord_61')

I'm trying to implement the WS2812 driver in my own project. I'm referencing the sample code stored in zephyr/samples/drivers/led_ws2812. I have copied over all of the correct configuration files, however, I'm getting an error when I try to define the strip device struct. The line shown here is throwing the error: 

#define STRIP_NODE		DT_ALIAS(led_strip)
#define STRIP_NUM_PIXELS	DT_PROP(DT_ALIAS(led_strip), chain_length)

// I believe this is the problem somehow: 
static const struct device *strip = DEVICE_DT_GET(STRIP_NODE);

The error I'm getting on compile is: 

undefined reference to `__device_dts_ord_61'

I have triple-checked all of my includes, my proj.conf is exactly the same as the sample, and my nrf52dk_nrf52832.overlay has the correct configuration. What am I missing? The sample compiles just fine.

Alternately, how is the *strip definition different than a normal sensor definition? For example, I have initialized my accelerometer as such: 

const struct device *sensor = device_get_binding("LIS3DH");

Is there a way to follow that same convention for my LED strip that would prevent this error I am seeing? Calling device_get_binding("WS2812") results in a NULL device. See below for my overlay file:

&i2c1 {
	compatible = "nordic,nrf-twim";
	status = "okay";
	sda-pin = <30>;
	scl-pin = <31>;
    clock-frequency = <I2C_BITRATE_FAST>;
    
    lis2dh@18 {
        compatible = "st,lis2dh";        
        reg = <0x18>;
        label = "LIS3DH";
    };    
};

#include "../nrf52-bindings.h"

&arduino_spi { /* MOSI on D11 / P0.23 */
	compatible = "nordic,nrf-spim";
	led_strip: ws2812@0 {
		compatible = "worldsemi,ws2812-spi";
		label = "WS2812";

		/* SPI */
		reg = <0>; /* ignored, but necessary for SPI bindings */
		spi-max-frequency = <SPI_FREQ>;

		/* WS2812 */
		chain-length = <10>; /* arbitrary; change at will */
		spi-one-frame = <ONE_FRAME>;
		spi-zero-frame = <ZERO_FRAME>;
	};
};

/ {
	aliases {
		led-strip = &led_strip;
	};
};

  • Alternately, how is the *strip definition different than a normal sensor definition? For example, I have initialized my accelerometer as such: 

    Using device_get_binding() has been the main way of getting a device set in the device tree, which operates at run-time. However, there has been created some new macros recently that allows you to get the device during the preprocessor phase. 

    https://github.com/nrfconnect/sdk-zephyr/commit/c2d852a17106dc49e7c086a055522cb857ce5780 

    This will cause you to get errors when building the project instead while running it.

    It seems like more and more samples are going away from device_get_binding() and using DEVICE_DT_* macros instead:

    https://github.com/nrfconnect/sdk-zephyr/commit/2c793f72aeada2f5f29881e4036ec86bed636bd8

    https://github.com/nrfconnect/sdk-zephyr/commit/1dbf6f78273da80a5c1143a45e3df87f00370582

    https://github.com/nrfconnect/sdk-zephyr/commit/363a1d6c842a69706303bfd40a8d1ecc2615274d

    Is there a way to follow that same convention for my LED strip that would prevent this error I am seeing? Calling device_get_binding("WS2812") results in a NULL device. See below for my overlay file:

    I don't think the issue is related to the way you're getting the device, I think there is some issue with the generated dts definitions. If device_get_binding returns null, it means it couldn't find a node with the label "WS2812".  See https://github.com/nrfconnect/sdk-zephyr/blob/v2.6.0-rc1-ncs1-rc1/include/device.h#L542 

    Can you attach the file <sample>/build/zephyr/zephyr.dts? See if you can find the following inside it:

    		spi2: arduino_spi: spi@40023000 {
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x0 >;
    			reg = < 0x40023000 0x1000 >;
    			interrupts = < 0x23 0x1 >;
    			status = "okay";
    			label = "SPI_2";
    			compatible = "nordic,nrf-spim";
    			sck-pin = < 0x19 >;
    			mosi-pin = < 0x17 >;
    			miso-pin = < 0x18 >;
    			cs-gpios = < &arduino_header 0x10 0x1 >;
    			led_strip: ws2812@0 {
    				compatible = "worldsemi,ws2812-spi";
    				label = "WS2812";
    				reg = < 0x0 >;
    				spi-max-frequency = < 0x3d0900 >;
    				chain-length = < 0x10 >;
    				spi-one-frame = < 0x70 >;
    				spi-zero-frame = < 0x40 >;
    			};
    		};

    Best regards,

    Simon

  • Hi see below for my zephyr.dts contents. Can you help me understand what I should be looking for? I assume this was generated at build time, should there be a node for my LEDs here? 

    /dts-v1/;
    
    / {
    	#address-cells = < 0x1 >;
    	#size-cells = < 0x1 >;
    	model = "Nordic nRF52 DK NRF52832";
    	compatible = "nordic,nrf52-dk-nrf52832";
    	chosen {
    		zephyr,entropy = &rng;
    		zephyr,flash-controller = &flash_controller;
    		zephyr,console = &uart0;
    		zephyr,shell-uart = &uart0;
    		zephyr,uart-mcumgr = &uart0;
    		zephyr,bt-mon-uart = &uart0;
    		zephyr,bt-c2h-uart = &uart0;
    		zephyr,sram = &sram0;
    		zephyr,flash = &flash0;
    		zephyr,code-partition = &slot0_partition;
    	};
    	aliases {
    		led0 = &led0;
    		led1 = &led1;
    		led2 = &led2;
    		led3 = &led3;
    		pwm-led0 = &pwm_led0;
    		sw0 = &button0;
    		sw1 = &button1;
    		sw2 = &button2;
    		sw3 = &button3;
    		bootloader-led0 = &led0;
    		led-strip = &led_strip;
    	};
    	soc {
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x1 >;
    		compatible = "nordic,nRF52832-QFAA", "nordic,nRF52832", "nordic,nRF52", "simple-bus";
    		interrupt-parent = < &nvic >;
    		ranges;
    		nvic: interrupt-controller@e000e100 {
    			compatible = "arm,v7m-nvic";
    			reg = < 0xe000e100 0xc00 >;
    			interrupt-controller;
    			#interrupt-cells = < 0x2 >;
    			arm,num-irq-priority-bits = < 0x3 >;
    			phandle = < 0x1 >;
    		};
    		systick: timer@e000e010 {
    			compatible = "arm,armv7m-systick";
    			reg = < 0xe000e010 0x10 >;
    			status = "disabled";
    		};
    		flash_controller: flash-controller@4001e000 {
    			compatible = "nordic,nrf52-flash-controller";
    			reg = < 0x4001e000 0x1000 >;
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x1 >;
    			label = "NRF_FLASH_DRV_NAME";
    			flash0: flash@0 {
    				compatible = "soc-nv-flash";
    				label = "NRF_FLASH";
    				erase-block-size = < 0x1000 >;
    				write-block-size = < 0x4 >;
    				reg = < 0x0 0x80000 >;
    				partitions {
    					compatible = "fixed-partitions";
    					#address-cells = < 0x1 >;
    					#size-cells = < 0x1 >;
    					boot_partition: partition@0 {
    						label = "mcuboot";
    						reg = < 0x0 0xc000 >;
    					};
    					slot0_partition: partition@c000 {
    						label = "image-0";
    						reg = < 0xc000 0x32000 >;
    					};
    					slot1_partition: partition@3e000 {
    						label = "image-1";
    						reg = < 0x3e000 0x32000 >;
    					};
    					scratch_partition: partition@70000 {
    						label = "image-scratch";
    						reg = < 0x70000 0xa000 >;
    					};
    					storage_partition: partition@7a000 {
    						label = "storage";
    						reg = < 0x7a000 0x6000 >;
    					};
    				};
    			};
    		};
    		sram0: memory@20000000 {
    			compatible = "mmio-sram";
    			reg = < 0x20000000 0x10000 >;
    		};
    		adc: adc@40007000 {
    			compatible = "nordic,nrf-saadc";
    			reg = < 0x40007000 0x1000 >;
    			interrupts = < 0x7 0x1 >;
    			status = "okay";
    			label = "ADC_0";
    			#io-channel-cells = < 0x1 >;
    			phandle = < 0x6 >;
    		};
    		clock: clock@40000000 {
    			compatible = "nordic,nrf-clock";
    			reg = < 0x40000000 0x1000 >;
    			interrupts = < 0x0 0x1 >;
    			status = "okay";
    			label = "CLOCK";
    		};
    		ecb: ecb@4000e000 {
    			compatible = "nordic,nrf-ecb";
    			reg = < 0x4000e000 0x1000 >;
    			interrupts = < 0xe 0x1 >;
    			status = "okay";
    			label = "ECB";
    		};
    		uart0: arduino_serial: uart@40002000 {
    			reg = < 0x40002000 0x1000 >;
    			interrupts = < 0x2 0x1 >;
    			status = "okay";
    			label = "UART_0";
    			compatible = "nordic,nrf-uarte";
    			current-speed = < 0x1c200 >;
    			tx-pin = < 0x6 >;
    			rx-pin = < 0x8 >;
    			rts-pin = < 0x5 >;
    			cts-pin = < 0x7 >;
    		};
    		gpiote: gpiote@40006000 {
    			compatible = "nordic,nrf-gpiote";
    			reg = < 0x40006000 0x1000 >;
    			interrupts = < 0x6 0x5 >;
    			status = "okay";
    			label = "GPIOTE_0";
    		};
    		gpio0: gpio@50000000 {
    			compatible = "nordic,nrf-gpio";
    			gpio-controller;
    			reg = < 0x50000000 0x1000 >;
    			#gpio-cells = < 0x2 >;
    			label = "GPIO_0";
    			status = "okay";
    			port = < 0x0 >;
    			phandle = < 0x4 >;
    		};
    		i2c0: arduino_i2c: i2c@40003000 {
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x0 >;
    			reg = < 0x40003000 0x1000 >;
    			clock-frequency = < 0x186a0 >;
    			interrupts = < 0x3 0x1 >;
    			status = "okay";
    			label = "I2C_0";
    			compatible = "nordic,nrf-twi";
    			sda-pin = < 0x1a >;
    			scl-pin = < 0x1b >;
    		};
    		i2c1: i2c@40004000 {
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x0 >;
    			reg = < 0x40004000 0x1000 >;
    			clock-frequency = < 0x61a80 >;
    			interrupts = < 0x4 0x1 >;
    			status = "okay";
    			label = "I2C_1";
    			compatible = "nordic,nrf-twim";
    			sda-pin = < 0x1e >;
    			scl-pin = < 0x1f >;
    			lis2dh@18 {
    				compatible = "st,lis2dh";
    				reg = < 0x18 >;
    				label = "LIS3DH";
    			};
    		};
    		pwm0: pwm@4001c000 {
    			compatible = "nordic,nrf-pwm";
    			reg = < 0x4001c000 0x1000 >;
    			interrupts = < 0x1c 0x1 >;
    			status = "okay";
    			label = "PWM_0";
    			#pwm-cells = < 0x1 >;
    			ch0-pin = < 0x11 >;
    			ch0-inverted;
    			phandle = < 0x5 >;
    		};
    		pwm1: pwm@40021000 {
    			compatible = "nordic,nrf-pwm";
    			reg = < 0x40021000 0x1000 >;
    			interrupts = < 0x21 0x1 >;
    			status = "disabled";
    			label = "PWM_1";
    			#pwm-cells = < 0x1 >;
    		};
    		pwm2: pwm@40022000 {
    			compatible = "nordic,nrf-pwm";
    			reg = < 0x40022000 0x1000 >;
    			interrupts = < 0x22 0x1 >;
    			status = "disabled";
    			label = "PWM_2";
    			#pwm-cells = < 0x1 >;
    		};
    		qdec: qdec@40012000 {
    			compatible = "nordic,nrf-qdec";
    			reg = < 0x40012000 0x1000 >;
    			interrupts = < 0x12 0x1 >;
    			status = "disabled";
    			label = "QDEC";
    		};
    		rng: random@4000d000 {
    			compatible = "nordic,nrf-rng";
    			reg = < 0x4000d000 0x1000 >;
    			interrupts = < 0xd 0x1 >;
    			status = "okay";
    			label = "RNG";
    		};
    		spi0: spi@40003000 {
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x0 >;
    			reg = < 0x40003000 0x1000 >;
    			interrupts = < 0x3 0x1 >;
    			status = "disabled";
    			label = "SPI_0";
    			compatible = "nordic,nrf-spi";
    			sck-pin = < 0x1b >;
    			mosi-pin = < 0x1a >;
    			miso-pin = < 0x1c >;
    		};
    		spi1: spi@40004000 {
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x0 >;
    			reg = < 0x40004000 0x1000 >;
    			interrupts = < 0x4 0x1 >;
    			status = "okay";
    			label = "SPI_1";
    			compatible = "nordic,nrf-spi";
    			sck-pin = < 0x1f >;
    			mosi-pin = < 0x1e >;
    			miso-pin = < 0x1d >;
    		};
    		spi2: arduino_spi: spi@40023000 {
    			#address-cells = < 0x1 >;
    			#size-cells = < 0x0 >;
    			reg = < 0x40023000 0x1000 >;
    			interrupts = < 0x23 0x1 >;
    			status = "okay";
    			label = "SPI_2";
    			compatible = "nordic,nrf-spim";
    			sck-pin = < 0x19 >;
    			mosi-pin = < 0x17 >;
    			miso-pin = < 0x18 >;
    			cs-gpios = < &arduino_header 0x10 0x1 >;
    			led_strip: ws2812@0 {
    				status = "okay";
    				compatible = "worldsemi,ws2812-spi";
    				label = "WS2812";
    				reg = < 0x0 >;
    				spi-max-frequency = < 0x3d0900 >;
    				chain-length = < 0xa >;
    				spi-one-frame = < 0x70 >;
    				spi-zero-frame = < 0x40 >;
    			};
    		};
    		rtc0: rtc@4000b000 {
    			compatible = "nordic,nrf-rtc";
    			reg = < 0x4000b000 0x1000 >;
    			cc-num = < 0x3 >;
    			interrupts = < 0xb 0x1 >;
    			status = "okay";
    			clock-frequency = < 0x8000 >;
    			prescaler = < 0x1 >;
    			label = "RTC_0";
    		};
    		rtc1: rtc@40011000 {
    			compatible = "nordic,nrf-rtc";
    			reg = < 0x40011000 0x1000 >;
    			cc-num = < 0x4 >;
    			interrupts = < 0x11 0x1 >;
    			status = "okay";
    			clock-frequency = < 0x8000 >;
    			prescaler = < 0x1 >;
    			label = "RTC_1";
    		};
    		rtc2: rtc@40024000 {
    			compatible = "nordic,nrf-rtc";
    			reg = < 0x40024000 0x1000 >;
    			cc-num = < 0x4 >;
    			interrupts = < 0x24 0x1 >;
    			status = "okay";
    			clock-frequency = < 0x8000 >;
    			prescaler = < 0x1 >;
    			label = "RTC_2";
    		};
    		timer0: timer@40008000 {
    			compatible = "nordic,nrf-timer";
    			status = "okay";
    			reg = < 0x40008000 0x1000 >;
    			cc-num = < 0x4 >;
    			interrupts = < 0x8 0x1 >;
    			prescaler = < 0x0 >;
    			label = "TIMER_0";
    		};
    		timer1: timer@40009000 {
    			compatible = "nordic,nrf-timer";
    			status = "okay";
    			reg = < 0x40009000 0x1000 >;
    			cc-num = < 0x4 >;
    			interrupts = < 0x9 0x1 >;
    			prescaler = < 0x0 >;
    			label = "TIMER_1";
    		};
    		timer2: timer@4000a000 {
    			compatible = "nordic,nrf-timer";
    			status = "okay";
    			reg = < 0x4000a000 0x1000 >;
    			cc-num = < 0x4 >;
    			interrupts = < 0xa 0x1 >;
    			prescaler = < 0x0 >;
    			label = "TIMER_2";
    			phandle = < 0x3 >;
    		};
    		timer3: timer@4001a000 {
    			compatible = "nordic,nrf-timer";
    			status = "okay";
    			reg = < 0x4001a000 0x1000 >;
    			cc-num = < 0x6 >;
    			interrupts = < 0x1a 0x1 >;
    			prescaler = < 0x0 >;
    			label = "TIMER_3";
    		};
    		timer4: timer@4001b000 {
    			compatible = "nordic,nrf-timer";
    			status = "okay";
    			reg = < 0x4001b000 0x1000 >;
    			cc-num = < 0x6 >;
    			interrupts = < 0x1b 0x1 >;
    			prescaler = < 0x0 >;
    			label = "TIMER_4";
    		};
    		temp: temp@4000c000 {
    			compatible = "nordic,nrf-temp";
    			reg = < 0x4000c000 0x1000 >;
    			interrupts = < 0xc 0x1 >;
    			status = "okay";
    			label = "TEMP_0";
    		};
    		wdt: wdt0: watchdog@40010000 {
    			compatible = "nordic,nrf-watchdog";
    			reg = < 0x40010000 0x1000 >;
    			interrupts = < 0x10 0x1 >;
    			status = "okay";
    			label = "WDT";
    		};
    		ficr: ficr@10000000 {
    			compatible = "nordic,nrf-ficr";
    			reg = < 0x10000000 0x1000 >;
    			status = "okay";
    		};
    		uicr: uicr@10001000 {
    			compatible = "nordic,nrf-uicr";
    			reg = < 0x10001000 0x1000 >;
    			status = "okay";
    		};
    	};
    	cpus {
    		#address-cells = < 0x1 >;
    		#size-cells = < 0x0 >;
    		cpu@0 {
    			device_type = "cpu";
    			compatible = "arm,cortex-m4f";
    			reg = < 0x0 >;
    			swo-ref-frequency = < 0x1e84800 >;
    		};
    	};
    	sw_pwm: sw-pwm {
    		compatible = "nordic,nrf-sw-pwm";
    		status = "disabled";
    		label = "SW_PWM";
    		generator = < &timer2 >;
    		channel-count = < 0x3 >;
    		clock-prescaler = < 0x0 >;
    		ppi-base = < 0x0 >;
    		gpiote-base = < 0x0 >;
    		#pwm-cells = < 0x1 >;
    	};
    	leds {
    		compatible = "gpio-leds";
    		led0: led_0 {
    			gpios = < &gpio0 0x11 0x1 >;
    			label = "Green LED 0";
    		};
    		led1: led_1 {
    			gpios = < &gpio0 0x12 0x1 >;
    			label = "Green LED 1";
    		};
    		led2: led_2 {
    			gpios = < &gpio0 0x13 0x1 >;
    			label = "Green LED 2";
    		};
    		led3: led_3 {
    			gpios = < &gpio0 0x14 0x1 >;
    			label = "Green LED 3";
    		};
    	};
    	pwmleds {
    		compatible = "pwm-leds";
    		pwm_led0: pwm_led_0 {
    			pwms = < &pwm0 0x11 >;
    		};
    	};
    	buttons {
    		compatible = "gpio-keys";
    		button0: button_0 {
    			gpios = < &gpio0 0xd 0x11 >;
    			label = "Push button switch 0";
    		};
    		button1: button_1 {
    			gpios = < &gpio0 0xe 0x11 >;
    			label = "Push button switch 1";
    		};
    		button2: button_2 {
    			gpios = < &gpio0 0xf 0x11 >;
    			label = "Push button switch 2";
    		};
    		button3: button_3 {
    			gpios = < &gpio0 0x10 0x11 >;
    			label = "Push button switch 3";
    		};
    	};
    	arduino_header: connector {
    		compatible = "arduino-header-r3";
    		#gpio-cells = < 0x2 >;
    		gpio-map-mask = < 0xffffffff 0xffffffc0 >;
    		gpio-map-pass-thru = < 0x0 0x3f >;
    		gpio-map = < 0x0 0x0 &gpio0 0x3 0x0 >, < 0x1 0x0 &gpio0 0x4 0x0 >, < 0x2 0x0 &gpio0 0x1c 0x0 >, < 0x3 0x0 &gpio0 0x1d 0x0 >, < 0x4 0x0 &gpio0 0x1e 0x0 >, < 0x5 0x0 &gpio0 0x1f 0x0 >, < 0x6 0x0 &gpio0 0xb 0x0 >, < 0x7 0x0 &gpio0 0xc 0x0 >, < 0x8 0x0 &gpio0 0xd 0x0 >, < 0x9 0x0 &gpio0 0xe 0x0 >, < 0xa 0x0 &gpio0 0xf 0x0 >, < 0xb 0x0 &gpio0 0x10 0x0 >, < 0xc 0x0 &gpio0 0x11 0x0 >, < 0xd 0x0 &gpio0 0x12 0x0 >, < 0xe 0x0 &gpio0 0x13 0x0 >, < 0xf 0x0 &gpio0 0x14 0x0 >, < 0x10 0x0 &gpio0 0x16 0x0 >, < 0x11 0x0 &gpio0 0x17 0x0 >, < 0x12 0x0 &gpio0 0x18 0x0 >, < 0x13 0x0 &gpio0 0x19 0x0 >, < 0x14 0x0 &gpio0 0x1a 0x0 >, < 0x15 0x0 &gpio0 0x1b 0x0 >;
    		phandle = < 0x2 >;
    	};
    	arduino_adc: analog-connector {
    		compatible = "arduino,uno-adc";
    		#io-channel-cells = < 0x1 >;
    		io-channel-map = < 0x0 &adc 0x1 >, < 0x1 &adc 0x2 >, < 0x2 &adc 0x4 >, < 0x3 &adc 0x5 >, < 0x4 &adc 0x6 >, < 0x5 &adc 0x7 >;
    	};
    };
    

    Thanks,

    Eric

  • I see on line 248 of my zephyr.dts file contains the arduino_spi node bound to spi2. It contains the led_strip component. Doesn't this tell me that the device tree overlay is building correctly? Why else would I still be receiving this error? 

    main.c:141: undefined reference to `__device_dts_ord_60'

  • Yes, I agree with you, it seems like all the dts definitions are generated correctly, so I'm actually not sure what's going on here. 

    I was able to build the sample zephyr/samples/drivers/led_ws2812 using the board nrf52dk_nrf52832. So one approach to figure out what's causing the issue it to start with that sample, and gradually, step by step add stuff from your main sample (from prj.conf, main.c, overlay files and so on). Every time you add something new, build the sample, then you'll eventually figure out what's causing it to fail.

    Please share the solution if you find the cause. If you're not able to figure it out, would you be able to upload your sample in zipped format? Then I could take a look at it.

  • Hey Simon, thanks. I've been through this exercise a few times now. The compile error only occurs when I add code to interact with the strip device. 

    	if (device_is_ready(strip)) {
    		printk("Found LED strip device %s\n", strip->name);
    	} else {
    		printk("LED strip device %s is not ready\n", strip->name);
    		return;
    	}

    Defined as such: 

    #define STRIP_NODE		DT_ALIAS(led_strip)
    #define STRIP_NUM_PIXELS	DT_PROP(DT_ALIAS(led_strip), chain_length)
    
    struct led_rgb pixels[STRIP_NUM_PIXELS];
    
    static const struct device *strip = DEVICE_DT_GET(STRIP_NODE);

    Attached is the zip file directory. I just combined the peripheral_dis sample with the ws812 sample. As noted, the error occurs only after defining the strip node and calling device_is_ready. The WS812 sample compiles fine for me with no modification. But, pulling it into a new project throws the error. 

    dis_led_test.zip 

Related