
Bhargav Patel
Introduction: The Need for Device Trees in Embedded Systems
In embedded Linux, the kernel must know the exact hardware configuration of the system—memory layout, peripherals, GPIOs, and communication buses (I2C, SPI, UART). Traditionally, this was done by hardcoding hardware details into the kernel, leading to:
- Bloat (different kernel versions for each board)
- Maintenance nightmares (any hardware change required kernel modification)
- Poor scalability (difficulty supporting new devices)
Device Trees (DT) solve this by providing a hardware description language that the Linux kernel interprets at boot.
1. Understanding Device Tree Structure
A Device Tree consists of:
- Nodes (represent devices, buses, or subsystems)
- Properties (key-value pairs defining hardware parameters)
- Hierarchy (parent-child relationships mirroring hardware connections)
Example: Basic Device Tree Syntax
c
Copy
/dts-v1/; // Device Tree version / { // Root node compatible = "raspberrypi,4-model-b"; // Board compatibility model = "Raspberry Pi 4 Model B"; // Human-readable name // CPU node cpus { #address-cells = <1>; // Number of cells for addressing child nodes #size-cells = <0>; // Size representation (not used here) cpu0: cpu@0 { // CPU label and address compatible = "arm,cortex-a72"; device_type = "cpu"; reg = <0>; // Register index }; }; // Memory node memory@0 { device_type = "memory"; reg = <0x00000000 0x3b400000>; // Start address and size }; // I2C Controller i2c1: i2c@7e804000 { compatible = "brcm,bcm2835-i2c"; reg = <0x7e804000 0x1000>; // Physical address and length interrupts = <2 21>; // IRQ number and flags clocks = <&i2c_clk>; status = "disabled"; // Disabled by default }; };
Key Elements Explained
Component | Purpose |
---|---|
/dts-v1/; | Declares Device Tree syntax version (always required). |
/ { ... }; | Root node containing all hardware descriptions. |
compatible | Matches the board with kernel drivers (e.g., "raspberrypi,4-model-b"). |
#address-cells | Defines how many 32-bit values are needed for addressing child nodes. |
reg = <0>; | Specifies register addresses (e.g., CPU index 0). |
interrupts = <2 21>; | Defines interrupt lines (2 = controller, 21 = line). |
status = "disabled"; | Controls whether a device is active ("okay") or inactive ("disabled"). |
2. How Device Trees Work on Raspberry Pi
Boot Process with Device Trees
- Bootloader (start.elf) loads:
- Kernel (kernel8.img)
- Device Tree Blob (bcm2711-rpi-4-b.dtb)
- Kernel parses the DTB to detect hardware.
- Drivers bind to devices based on compatible properties.
Viewing the Active Device Tree
bash
Copy
# Extract the live Device Tree dtc -I fs /proc/device-tree > current.dts
Output Example:
c
Copy
/ { compatible = "raspberrypi,4-model-b"; model = "Raspberry Pi 4 Model B"; ... i2c1: i2c@7e804000 { compatible = "brcm,bcm2835-i2c"; reg = <0x7e804000 0x1000>; }; };
3. Practical Device Tree Customization
Case 1: Enabling I2C via Overlay
Problem: I2C1 is disabled by default on Raspberry Pi.
Solution: Use an overlay in /boot/config.txt:
ini
Copy
dtparam=i2c_arm=on dtoverlay=i2c-sensor,addr=0x48 # Enable I2C and add a sensor at 0x48
What Happens Behind the Scenes?
- The firmware applies i2c1 node changes:
diff
Copystatus = "okay"; // Changed from "disabled"
- The kernel loads the i2c-bcm2835 driver (matched via compatible).
Case 2: Custom GPIO Configuration
Problem: Need to configure GPIO 17 as an output for an LED.
Solution: Create a custom overlay (led-gpio.dts):
c
Copy
/dts-v1/; /plugin/; / { compatible = "brcm,bcm2835"; fragment@0 { target = <&gpio>; __overlay__ { led_pin: led_pin { brcm,pins = <17>; // GPIO17 brcm,function = <1>; // Output (0=input, 1=output) brcm,pull = <0>; // No pull-up/down }; }; }; };
Compile and Apply:
bash
Copy
dtc -@ -I dts -O dtb -o /boot/overlays/led-gpio.dtbo led-gpio.dts
Add to /boot/config.txt:
ini
Copy
dtoverlay=led-gpio
Result:
- GPIO17 is now configured as an output at boot.
- Control it via /sys/class/gpio/gpio17/value.
4. Debugging Device Trees
Common Issues & Fixes
Problem | Debugging Command | Solution | |
---|---|---|---|
Overlay not applied | `dmesg | grep -i "dtoverlay"` | Check syntax in /boot/config.txt. |
Missing driver binding | cat /proc/device-tree/compatible | Verify compatible property. | |
Incorrect register map | devmem2 0x7e804000 (I2C1 physical address) | Validate reg values in DTS. |
5. Business Benefits of Device Trees
1. Reduced Development Time
- Example: A company using Raspberry Pi for industrial controllers reduced BSP development from 6 weeks to 1 week by switching to Device Trees.
2. Lower Maintenance Costs
- Single kernel image supports multiple hardware revisions via different DTBs.
3. Easier Compliance Testing
- Isolated hardware changes (via overlays) minimize re-certification efforts.
Conclusion
Device Trees decouple hardware and software in embedded Linux, enabling:
✅ Portability (One kernel, multiple boards)
✅ Maintainability (No kernel patching for hardware changes)
✅ Scalability (Dynamic overlays for custom configurations)
Next Steps:
- Experiment with dtc to decompile your Pi’s .dtb file.
- Create a custom overlay for your hardware.
Need Help? Contact our embedded Linux team for Device Tree consulting!
Appendix: Key Commands Cheat Sheet
Command | Purpose | |
---|---|---|
dtc -I dtb -O dts -o output.dts input.dtb | Decompile DTB to DTS. | |
`sudo vcdbg log msg | grep dtb` | Check which DTB was loaded at boot. |
fdtdump /boot/bcm2711-rpi-4-b.dtb | Inspect DTB contents. |