Integrating DHT11 Sensor Driver into Yocto Image for BeagleBone | Master Step-by-Step LDD Guide

On: September 1, 2025
Integrating DHT11 Sensor Driver into Yocto Image for BeagleBone

DHT11 Sensor Driver into Yocto : When I first got my BeagleBone board, I was super excited. I wanted to connect real-world sensors and see live data flowing into my board. One of the simplest yet powerful sensors I picked was the DHT11, a low-cost digital temperature and humidity sensor.

At first glance, I thought: “It should be as easy as connecting a wire and running a Python script, right?” But then came the challenge — I wanted to integrate it properly at the kernel driver level and make it part of my Yocto-built image, so that every time I flashed my SD card, my BeagleBone would already have the driver and I could directly fetch temperature readings.

If you’ve ever felt this curiosity, this guide is for you. Let’s go step by step.

Manual Way: Adding DHT11 Sensor Driver into Yocto for BeagleBone

Why DHT11 Sensor Driver into Yocto ?

  • Consistency: Every image build includes your driver — no need to manually insert modules each time.
  • Customization: You can control how the driver behaves and integrate it with other services.
  • Scalability: If tomorrow you move to another sensor or a production board, your Yocto setup scales with you.

Step 1: Set Up Yocto Project Environment

  1. Download Poky and layers git clone git://git.yoctoproject.org/poky.git cd poky git checkout <yocto-version> # e.g., dunfell, honister
  2. Add necessary layers for BeagleBone git clone git://git.yoctoproject.org/meta-ti.git git clone git://git.yoctoproject.org/meta-openembedded.git
  3. Create a build directory source oe-init-build-env build
  4. Set your machine in conf/local.conf MACHINE ?= "beaglebone"

Step 2: Understand Your DHT11 Sensor

  • DHT11 uses 1-wire digital communication.
  • Pins:
    • VCC: 3.3V or 5V
    • GND: Ground
    • DATA: Connected to a GPIO pin on BeagleBone
  • The driver needs to read the digital pulses and convert them to temperature and humidity.

Step 3: Create a Custom Layer

  1. Create a new layer for your driver: bitbake-layers create-layer meta-dht11
  2. Add this layer to your build: bitbake-layers add-layer ../meta-dht11

Step 4: Write the Kernel Driver

4.1: Create Driver Skeleton

  • Go to your layer: meta-dht11/recipes-kernel/dht11/
  • Create dht11.c:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DHT11_PIN 60  // Example: GPIO1_28 on BeagleBone

static int major;
static char temp_str[16];

static int dht11_open(struct inode *inode, struct file *file) {
    return 0;
}

static int dht11_release(struct inode *inode, struct file *file) {
    return 0;
}

static ssize_t dht11_read(struct file *file, char __user *buf, size_t len, loff_t *offset) {
    int temperature = 25; // Mock value (we’ll implement real reading later)
    snprintf(temp_str, sizeof(temp_str), "%d\n", temperature);
    if (copy_to_user(buf, temp_str, strlen(temp_str))) {
        return -EFAULT;
    }
    return strlen(temp_str);
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = dht11_open,
    .release = dht11_release,
    .read = dht11_read,
};

static int __init dht11_init(void) {
    major = register_chrdev(0, "dht11", &fops);
    printk(KERN_INFO "DHT11 driver loaded. Major=%d\n", major);
    return 0;
}

static void __exit dht11_exit(void) {
    unregister_chrdev(major, "dht11");
    printk(KERN_INFO "DHT11 driver unloaded\n");
}

module_init(dht11_init);
module_exit(dht11_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nish");
MODULE_DESCRIPTION("DHT11 temperature driver for BeagleBone");

4.2: Create the Recipe (.bb file)

  • File: meta-dht11/recipes-kernel/dht11/dht11.bb
DESCRIPTION = "DHT11 temperature driver"
LICENSE = "GPLv2"
SRC_URI = "file://dht11.c"

S = "${WORKDIR}"

do_compile() {
    ${CC} -Wall -O2 -c ${WORKDIR}/dht11.c -o ${WORKDIR}/dht11.o
    ${CC} -Wall -O2 -shared -o ${WORKDIR}/dht11.ko ${WORKDIR}/dht11.o
}

do_install() {
    install -d ${D}${sysconfdir}/modules
    install -m 0644 ${WORKDIR}/dht11.ko ${D}${sysconfdir}/modules/
}

Step 5: Build and Add Driver to Image

  1. Build the driver: bitbake dht11
  2. Include it in your image (local.conf): IMAGE_INSTALL_append = " dht11"
  3. Rebuild your image: bitbake core-image-minimal

Step 6: Boot BeagleBone and Test

  1. Flash .wic image to SD card.
  2. Boot BeagleBone.
  3. Load driver: insmod /etc/modules/dht11.ko
  4. Check temperature: cat /dev/dht11

Step 7: Implement Actual DHT11 Reading

  • Replace mock temperature with real GPIO reading.
  • Use bit-banging with gpio_get_value() and precise timing with udelay().

Tips

  • Make sure GPIO pin numbers match your BeagleBone header.
  • For production, consider interrupt-based reading for better accuracy.
  • Use dmesg to debug kernel messages.

Auto Temperature Reading Without Manual Module Loading

Step 1: Setup Yocto Kirkstone Environment

  1. Clone Poky (Kirkstone branch):
git clone -b kirkstone git://git.yoctoproject.org/poky.git
cd poky
  1. Clone meta layers:
git clone -b kirkstone git://git.yoctoproject.org/meta-openembedded.git
git clone -b kirkstone git://git.yoctoproject.org/meta-ti.git
  1. Initialize the build environment:
source oe-init-build-env
  1. Set your target machine in conf/local.conf:
MACHINE ?= "beaglebone"

Step 2: Create a Custom Layer for DHT11

  1. Create layer:
bitbake-layers create-layer meta-dht11
  1. Add it to your build:
bitbake-layers add-layer ../meta-dht11

Step 3: Write the DHT11 Driver

  1. Go to your layer folder:
    meta-dht11/recipes-kernel/dht11/
  2. Create dht11.c:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DHT11_PIN 60  // Adjust according to BeagleBone header

static int major;
static char buf[32];

static int dht11_open(struct inode *inode, struct file *file) { return 0; }
static int dht11_release(struct inode *inode, struct file *file) { return 0; }

static int read_dht11(int *temperature, int *humidity) {
    int bits[40] = {0}, i, j=0, data[5] = {0};

    // Send start signal
    gpio_direction_output(DHT11_PIN, 0);
    mdelay(20);
    gpio_direction_input(DHT11_PIN);
    udelay(30);

    // Wait for response
    while(gpio_get_value(DHT11_PIN) == 1);
    while(gpio_get_value(DHT11_PIN) == 0);
    while(gpio_get_value(DHT11_PIN) == 1);

    // Read 40 bits
    for(i=0;i<40;i++){
        while(gpio_get_value(DHT11_PIN) == 0);
        j=0;
        while(gpio_get_value(DHT11_PIN) == 1){ udelay(1); j++; }
        bits[i] = (j > 40) ? 1 : 0;
    }

    // Convert bits to bytes
    for(i=0;i<5;i++){
        data[i]=0;
        for(j=0;j<8;j++){
            data[i]<<=1;
            data[i] |= bits[i*8+j];
        }
    }

    if(data[4] != ((data[0]+data[1]+data[2]+data[3]) & 0xFF)) return -1;

    *humidity = data[0];
    *temperature = data[2];
    return 0;
}

static ssize_t dht11_read(struct file *file, char __user *user_buf, size_t len, loff_t *offset){
    int temp=0, hum=0;
    if(read_dht11(&temp,&hum)!=0) return -EIO;
    snprintf(buf,sizeof(buf),"Temp:%dC Hum:%d%%\n",temp,hum);
    if(copy_to_user(user_buf,buf,strlen(buf))) return -EFAULT;
    return strlen(buf);
}

static struct file_operations fops = {
    .owner=THIS_MODULE,
    .open=dht11_open,
    .release=dht11_release,
    .read=dht11_read,
};

static int __init dht11_init(void){
    major = register_chrdev(0,"dht11",&fops);
    printk(KERN_INFO "DHT11 driver loaded. Major=%d\n",major);
    return 0;
}

static void __exit dht11_exit(void){
    unregister_chrdev(major,"dht11");
    printk(KERN_INFO "DHT11 driver unloaded\n");
}

module_init(dht11_init);
module_exit(dht11_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nish");
MODULE_DESCRIPTION("DHT11 driver for BeagleBone with real readings");

Step 4: Create the BitBake Recipe

Create dht11.bb in the same folder:

DESCRIPTION = "DHT11 Temperature & Humidity Kernel Driver"
LICENSE = "GPLv2"
SRC_URI = "file://dht11.c"

S = "${WORKDIR}"

do_compile() {
    ${CC} -Wall -O2 -c ${WORKDIR}/dht11.c -o ${WORKDIR}/dht11.o
    ${CC} -Wall -O2 -shared -o ${WORKDIR}/dht11.ko ${WORKDIR}/dht11.o
}

do_install() {
    install -d ${D}${nonarch_libdir}/modules
    install -m 0644 ${WORKDIR}/dht11.ko ${D}${nonarch_libdir}/modules/
    # Auto-load at boot
    install -d ${D}/etc/modules-load.d
    echo "dht11" > ${D}/etc/modules-load.d/dht11.conf
}

Step 5: Include Driver in Yocto Image

Edit conf/local.conf and add:

IMAGE_INSTALL_append = " dht11"

Step 6: Build the Image

bitbake core-image-minimal

After completion, your image already includes the DHT11 driver and will auto-load at boot.

Step 7: Flash SD Card and Test

  1. Flash .wic image to SD card.
  2. Boot BeagleBone.
  3. Check temperature and humidity:
cat /dev/dht11
# Example output: Temp:27C Hum:55%

✅ You don’t need to insmod anymore. The driver is now part of the image.

Integrating DHT11 Sensor Driver into Yocto Image for BeagleBone Master Step-by-Step Guide (2025)

Leave a Comment

Exit mobile version