DHT22 temperature sensor RPI kernel module with disabled IRQs and ioctrl

Status

Need to tidy up the open and close file stuff and also sort the read and write of the char device to be the right size and have useful data in them

Useage

build the module against the correct Linux kernel. Insert it with

sudo insmod DHT22_module.ko

(you can check with the dmesg to see if it all went well). Compile the user level code with

gcc DHT22_user.c

run this with

sudo ./a.out

check in the dmesg to see the output. If it says DHT22: RESULTS … then it worked ok. Otherwise you will error messages

Module Code: DHT22_module.c

</pre>
#include 	<linux/module.h>
#include 	<linux/delay.h>
#include 	<linux/kernel.h>
#include 	<linux/init.h>
#include 	<linux/gpio.h>
#include 	<linux/fs.h>
#include 	<linux/time.h>
#include 	<linux/device.h>
#include <asm/uaccess.h>
#include 	<linux/ioctl.h>
#define DHT22_MAJOR_NUM 248
#define IOCTL_DO_READING _IOR(DHT22_MAJOR_NUM, 0, int)
#define DEVICE_NAME "DHT22Dev" /* this is the device name i.e /dev/DHT22Dev */
#define CLASS_NAME "DHT22" /* the name of the device class */
#define DHT22_GPIO 22
#define DHT22_THRESHOLD 25 /* in uS, so 0 is 26uS, 1 is 70uS, threshold is half way = 48uS */
#define DHT22_MAXTIMINGS 40

static char msg[3];
static struct class* dht22Class = NULL;
static struct device* dht22Device = NULL;

void dht22_read( void )
{
int counter = 0;
int i;
unsigned long flags = 0;
int timeout;
int data[5];
int temperature, humidity;

int reads[50];
int r1,r2,r3,r4[40];
data[0] = data[1] = data[2] = data[3] = data[4] = data[5] = 0;
gpio_direction_input(DHT22_GPIO);

/* disable the interupts now */
local_irq_save(flags);

/* pull the pin high and wait 250 micro seconds to start things off */
gpio_direction_output(DHT22_GPIO,1);
gpio_set_value(DHT22_GPIO, 1);
udelay(250);

/* send a start of reading pulse 500us */
gpio_set_value(DHT22_GPIO, 0);
udelay(1000);

/* now let the bus pull up high and wait 20 to 40us for response */
gpio_direction_input(DHT22_GPIO);

/* so wait till it goes low in response - should be about 80uS */
timeout=0;
while (gpio_get_value(DHT22_GPIO)) {
udelay(1);
if (timeout++==200) {
printk(KERN_ERR "DHT22: Timed out looking for low pulse\n");
goto dht22_failed;
};
};
r1=timeout;

/* and wait for it to be high - again 80 uS */
timeout=0;
while (!gpio_get_value(DHT22_GPIO)) {
udelay(1);
if (timeout++==200) {
printk(KERN_ERR "DHT22: Timed out looking for high reponse pulse\n");
goto dht22_failed;
};
};
r2=timeout;

/* and wait for it to go low again - again 80 uS */
timeout=0;
while (gpio_get_value(DHT22_GPIO)) {
udelay(1);
if (timeout++==200) {
printk(KERN_ERR "DHT22: Timed out looking for low reponse pulse\n");
goto dht22_failed;
};
};
r3=timeout;

/* read in 40 bits of data */
for (i=0; i< DHT22_MAXTIMINGS; i++)
{
/* wait for the low pulse */
timeout=0;
while (!gpio_get_value(DHT22_GPIO)) {
udelay(1);
if (timeout++==200) {
printk(KERN_ERR "DHT22: Timed out looking for second low pulse\n");
goto dht22_failed;
}
};
r4[i]=timeout;

/* reset the bit period counter */
counter=0;

/* now time the high pulse */
while (gpio_get_value(DHT22_GPIO))
{
counter++;
udelay(1); /* wait for 1us to get sensible counter */
if (counter==200) {
printk(KERN_ERR "DHT22: Timed out reading the bit period %i\n", i);
goto dht22_failed;
};
}
reads[i]=counter;
}

/* all done so we can re-enable interrupts */
local_irq_restore(flags);

for(i=0;i<40;i++) {
data[i/8] <<= 1;
/* if it is 26 to 28uS then a 0, 70uS a 1 */
if (reads[i] > DHT22_THRESHOLD) data[i/8] |= 1;
}

/* Now check the checksum */
if ((data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
printk(KERN_ERR "DHT22: Failed checksum\n");
goto dht22_failed;
}
/*if msb of temp data[2]is set then it is negative. just remove the bit and */
/* print out the value (note it is x10) */
if (data[2]>>7) temperature=(((data[2] & 0x7f)<<8)+data[3]);
else temperature=((data[2])<<8)+data[3];
humidity = ((data[0]<<8)+data[1]);
printk(KERN_ERR "DHT22: RESULTS: Temperature is: %i.%i, Humidity is: %i.%i\n",
temperature/10, temperature%10, humidity/10, humidity%10);

// printk(KERN_ERR "DHT22: data = %i, %i, %i, %i, cs=%i\n",data[0],data[1],data[2],data[3],data[4]);
// printk(KERN_ERR "DHT22: r1=%i, r2=%i, r3=%i\n",r1,r2,r3);
// for (i=0;i<40;i++) printk(KERN_ERR "reading %i = %i, %i \n",i,r4[i],reads[i]);

return;

dht22_failed :

printk (KERN_ERR "DHT22 read failed\n");
}

static ssize_t device_read(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
{
return simple_read_from_buffer(buffer, length, offset, msg, 3);
}
static ssize_t device_write(struct file *filp, const char __user *buff, size_t len, loff_t *off)
{
if (len > 2)
return -EINVAL;
copy_from_user(msg, buff, len);
msg[len] = '\0';
return len;
}

static long device_ioctl(struct file *file,
unsigned int ioctl_num,
unsigned long ioctl_param)
{
switch (ioctl_num) {
case IOCTL_DO_READING:
dht22_read();
break;
};
return 0;
}

static struct file_operations fops = {
.read = device_read,
.write = device_write,
.unlocked_ioctl = device_ioctl,
// .open = device_open,
// .release = device_release
};

static int __init mymodule_init(void)
{
int ret;

printk (KERN_ERR "DHT22 module loading\n");

ret = register_chrdev(DHT22_MAJOR_NUM, "DHT22", &fops);
if (ret < 0)
{
printk (KERN_ERR "DHT22: Registering the character device failed with %d\n", ret);
return ret;
}
printk(KERN_ERR "DHT22: assigned major: %d\n", DHT22_MAJOR_NUM);

/* Register the device class */
dht22Class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(dht22Class))
{ // Check for error and clean up if there is
unregister_chrdev(DHT22_MAJOR_NUM, DEVICE_NAME);
printk(KERN_ERR "DHT22: Failed to register device class\n");
return PTR_ERR(dht22Class);
}
printk(KERN_INFO "DHT22: device class registered correctly\n");

/* Register the device driver */
dht22Device = device_create(dht22Class, NULL, MKDEV(DHT22_MAJOR_NUM, 0), NULL, DEVICE_NAME);
if (IS_ERR(dht22Device))
{
class_destroy(dht22Class);
unregister_chrdev(DHT22_MAJOR_NUM, DEVICE_NAME);
printk(KERN_ERR "DHT22: Failed to create the device\n");
return PTR_ERR(dht22Device);
}
printk(KERN_ERR "DHT22: device created correctly\n"); /* initialized */

/* first we get use of the gpio pin */
if (gpio_request(DHT22_GPIO,"dht22 input"))
{
printk(KERN_ERR "DHT22: can't request DHT22 GPIO\n");
return 0;
}
printk(KERN_ERR "DHT22: requested DHT22 GPIO\n");

return 0;

}

static void __exit mymodule_exit(void) {

device_destroy(dht22Class,MKDEV(DHT22_MAJOR_NUM, 0));
class_destroy(dht22Class);
unregister_chrdev(DHT22_MAJOR_NUM, "DHT22");
gpio_free(DHT22_GPIO);

printk (KERN_ERR "DHT22 module unloaded");
return;
}

module_init(mymodule_init);
module_exit(mymodule_exit);

MODULE_LICENSE("GPL");

Module Makefile

</pre>
# obj-m is a list of what kernel modules to build. The .o and other
# objects will be automatically built from the corresponding .c file -
# no need to list the source files explicitly.

obj-m := DHT22_module.o

# KDIR is the location of the kernel source. The current standard is
# to link to the associated source tree from the directory containing
# the compiled modules.
KDIR := ~/pi/linux/

# PWD is the current working directory and the location of our module
# source files.
PWD := $(shell pwd)

# default is the default make target. The rule here says to run make
# with a working directory of the directory containing the kernel
# source and compile only the modules in the PWD (local) directory.
default:
$(MAKE) -C $(KDIR) M=$(PWD) -j6 -lm ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules

User level Calling program: DHT22_user.c

</pre>
#include <fcntl.h> /* open */
#include <unistd.h> /* exit */
#include <sys/ioctl.h> /* ioctl */

#define DHT22_MAJOR_NUM 248
#define IOCTL_DO_READING _IOR(DHT22_MAJOR_NUM, 0, int)
#define DEVICE_NAME "/dev/DHT22Dev" /* this is the device name i.e /dev/DHT22Dev */

main()
{
int file_desc, ret_val;

file_desc = open(DEVICE_NAME, 0);
if (file_desc < 0) {
printf ("Can't open device file: %s\n",
DEVICE_NAME);
exit(-1);
}

ret_val = ioctl(file_desc, IOCTL_DO_READING, 1);

if (ret_val < 0) {
printf ("ioctl_set_msg failed:%d\n", ret_val);
}

close(file_desc);
}

 




%d bloggers like this: