Challenge

Project 1 - Develop the full featured char driver as a loaded module

Overview of the Project:

• Device Driver

o Write the device driver for MCP9808 Temperature Sensor.

 Probe function: Register the Platform device under driver/misc.

 Read function: It should send the i2c message to read the data from sensor and copy it to the user space.

 Alert pin connected to BBB as gpio interrupt. The temp sensor is programmed for Tlower and Tupper through dts file. Based on interrupt, Motor will be turned ON or OFF.

 Compatible string: it should be unique and same string should be entered in dts file.

 Dts file: The I2C instance and GPIO pins used should be configurable.

• Hardware Setup:

o MCP9808 Temperature sensor should be connected to the I2C and DC motor connected to the GPIO pin using the Driver IC LN293D.

• User Space Application

o Temperature must be monitored for every 15 mins and stored in the database (MySql).

o When the temperature exceeds the set value, the motor should turn On and Off when temperature comes down.

o Web page should be provide the following feature

 Set the Threshold Temperature

 Retrieve the data from database and plotted as a graph

Goals

• The student will have capability to build the customized image to the Embedded Target - Beagle bone black.

• The student will be able to connect the sensor and actuator to the embedded target.

Key Highlights of the Project:

• The project helps the student to understand the various steps involved in building the Embedded Linux target.

• It makes the students understand how to configure the pins exposed in the Beagle bone Header P8 and P9.

• It covers the various kernel subsystem like GPIO, I2C, Interrupt Handling, Platform device drivers.

• It also enables the write not only device driver but also the user space application to present the data to remote world.

Deliverables of this Project:

• Embedded Linux Image for the BBB - It contains U-Boot, Linux Kernel and Root File system.

• DTS source file - The file allows the user to configure the GPIO pins connected to Motor and Temperature sensor connected to I2C lines. The file can be compiled separately and updated to SD card if needed.

• Simple HTML web page capable of monitoring the temperature and controlling the motor.

• Database has to be capable of storing the temperature reading for 15 days.

Expected Outcomes:

• The students will learn the following things

o Able to build the custom kernel image for the embedded target.

o Able to configure the Gpio pins and Temperature sensor connected to target through DTS files.

o Able to learn the I2C and GPIO subsystem.

o Able to understand the remote monitoring of the device through internet.

Answer:

Step 1: Configure the kernel module.

1.1. Give the command for $ vim char_dev.c for Create a new file.

char_dec.c

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/slab.h>

#include <linux/cdev.h>

#include <asm/uaccess.h>

#include <linux/proc_fs.h>

MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME "chardev"

#define PROCFS_NAME "char_driver_size"

#define MAX_SIZE 1024

static int Major;

static int Device_Open = 0;

static char msg[MAX_SIZE];

static char *msg_Ptr;

static int size_of_msg = 0;

static struct proc_dir_entry *proc_file;

static struct cdev chardev;

static int chardev_open(struct inode *inode, struct file *filp)

{

if (Device_Open)

return -EBUSY;

Device_Open++;

msg_Ptr = msg;

try_module_get(THIS_MODULE);

return 0;

}

static int chardev_release(struct inode *inode, struct file *filp)

{

Device_Open--;

module_put(THIS_MODULE);

return 0;

}

static ssize_t chardev_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)

{

int bytes_read = 0;

if (*msg_Ptr == 0)

return 0;

while (count && *msg_Ptr)

{

put_user(*(msg_Ptr++), buf++);

count--;

bytes_read++;

}

return bytes_read;

}

static ssize_t chardev_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)

{

if (count > MAX_SIZE)

count = MAX_SIZE;

if (copy_from_user(msg, buf, count))

return -EFAULT;

size_of_msg = count;

return count;

}

static loff_t chardev_llseek(struct file *filp, loff_t off, int whence)

{

loff_t newpos;

switch (whence)

{

case 0:

newpos = off;

break;

case 1:

newpos = filp->f_pos + off;

break;

case 2:

newpos = size_of_msg + off;

break;

default:

return -EINVAL;

}

if (newpos < 0)

return -EINVAL;

filp->f_pos = newpos;

return newpos;

}

static const struct file_operations chardev_fops =

{

.owner = THIS_MODULE,

.read = chardev_read,

.write = chardev_write,

.open = chardev_open,

.release = chardev_release,

.llseek = chardev_llseek};

static int __init chardev_init(void)

{

int ret;

dev_t dev;

printk(KERN_INFO "chardev: Initializing the chardev modulen");

ret = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);

if (ret < 0)

{

printk(KERN_ALERT "chardev: Failed to allocate a major numbern");

return ret;

}

Major = MAJOR(dev);

printk(KERN_INFO "chardev: Major number assigned is %dn", Major);

cdev_init(&chardev, &chardev_fops);

chardev.owner = THIS_MODULE;

chardev.ops = &chardev_fops;

ret = cdev_add(&chardev, dev, 1);

if (ret < 0)

{

printk(KERN_ALERT "chardev: Failed to add the character device to the kerneln");

return ret;

}

proc_file = proc_create(PROCFS_NAME, 0, NULL, NULL);

if (proc_file == NULL)

{

printk(KERN_ALERT "chardev: Failed to create the proc filen");

return -ENOMEM;

}

printk(KERN_INFO "chardev: Module loaded successfullyn");

return 0;

}

static void __exit chardev_exit(void)

{

cdev_del(&chardev);

unregister_chrdev_region(Major, 1);

printk(KERN_INFO "chardev: Module unloaded successfullyn");

}

module_init(chardev_init);

module_exit(chardev_exit);

Step 2: Create Makefile.

2.1. Give command $ vim Makefile for create a makefile.

Makefile.

obj-m += char_dev.o

all:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Step 3: Build the kernel module.

3.1. Give command $ make.

3.2. Give command $ make -C /lib/modules/$(uname -r)/build M=$(pwd) modules.

Step 4: Load the kernel module.

4.1. Give the command $ sudo insmod char_dev.ko to load the module.

4.2. Give the command $ sudo dmesg | tail to check the kernel load or not.

Step 5: Create a device node Open another terminal, navigate to the directory with chardev.c, and create a device node using the major number obtained from the kernel log/

5.1. Give the command $ sudo mknod /dev/char_dev c 0 <major_number>

Step 6: Set permissions for the device node:

6.1. Give command $ sudo chmod 666 /dev/char_dev

Step 7: Test the device:

7.1. Give command $ echo "Hello, chardev!" > /dev/char_dev for Write a message to the device.

Step 8: Read from the device:

8.1. Give command $ cat /dev/char_dev for Read the message from the device.

Step 9: Unload the kernel module.

9.1. Give the command $ sudo rmmod char_dev to unload the module.

Step 10: Remove the proc file.

10.1. Give command $ sudo rm /proc/char_driver_size for remove the associated proc file.

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.