Integrating DHT11 Sensor Driver into Yocto Image for BeagleBone
, , , , ,

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

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
Integrating DHT11 Sensor Driver into Yocto Image for BeagleBone Master Step-by-Step Guide (2025)

Leave a Reply

Your email address will not be published. Required fields are marked *