In this small guide I will demonstrate how to integrate Riotboard with Ultrasonic sensor HC-SR04 .

 

HCSR04.jpg

 

Step1:

 

export ARCH & CROSS_COMPILE to environment path.

 

in my case its like below, yours might be different.

$ export ARCH=arm

$ export CROSS_COMPILE=<PATH_TO_TOOLCHAIN>/fsl-linaro-toolchain/bin/arm-fsl-linux-gnueabi-

 

Step2:

create a directory

$ mkdir driver

 

create a file named "Makefile"  and replace with your KDIR value, below is mine.

 

obj-m := sr04.o

KDIR := /home/tushar/riot_github/kernel_out/lib/modules/3.0.35-02887-g731b440/build

PWD := $(shell pwd)

 

all:

  $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:

  $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

 

next we will create the driver for sr04 module, create file "sr04.c" with below contents in it.

 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h> 


MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("HC-SR04 ultrasonic sensor");


#define HCSR04_ECHO 113 
#define HCSR04_TRIGGER 112

static int gpio_irq=-1;
static int valid_value = 0;


static ktime_t echo_start;
static ktime_t echo_end;

// write to "/sys/class/hcsr04/value"
static ssize_t hcsr04_value_write(struct class *class, struct class_attribute *attr, const char *buf, size_t len) 
{
  printk(KERN_INFO "Buffer len %d bytes\n", len);
  return len;
}


// read from "/sys/class/hcsr04/value"
static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf) 
{
  int counter;
  gpio_set_value(HCSR04_TRIGGER,1);
  udelay(10);
  gpio_set_value(HCSR04_TRIGGER,0);
  valid_value=0;
  counter=0;
  while (valid_value==0) {
  if (++counter>23200) {
  return sprintf(buf, "%d\n", -1);;
  }
  udelay(1);
  }
  return sprintf(buf, "%lld\n", ktime_to_us(ktime_sub(echo_end,echo_start)));;
}


// Sysfs definitions for hcsr04 class
static struct class_attribute hcsr04_class_attrs[] = {
  __ATTR(value, S_IRUGO | S_IWUSR, hcsr04_value_read, hcsr04_value_write),
  __ATTR_NULL,
};


// Name of directory created in /sys/class
static struct class hcsr04_class = {
  .name = "hcsr04",
  .owner = THIS_MODULE,
  .class_attrs = hcsr04_class_attrs,
};


// Interrupt handler on ECHO signal
static irqreturn_t gpio_isr(int irq, void *data)
{
  ktime_t ktime_dummy;
  if (valid_value==0) {
  ktime_dummy=ktime_get();
  if (gpio_get_value(HCSR04_ECHO)==1) {
  echo_start=ktime_dummy;
  } else {
  echo_end=ktime_dummy;
  valid_value=1;
  }
  }
  return IRQ_HANDLED;
}


static int hcsr04_init(void)
{
  int rtc;

  printk(KERN_INFO "HC-SR04 driver init...\n");


  if (class_register(&hcsr04_class)<0) goto fail;


  rtc=gpio_request(HCSR04_TRIGGER,"TRIGGER");
  if (rtc!=0) {
  printk(KERN_INFO "Error %d\n",__LINE__);
  goto fail;
  }


  rtc=gpio_request(HCSR04_ECHO,"ECHO");
  if (rtc!=0) {
  printk(KERN_INFO "Error %d\n",__LINE__);
  goto fail;
  }


  rtc=gpio_direction_output(HCSR04_TRIGGER,0);
  if (rtc!=0) {
  printk(KERN_INFO "Error %d\n",__LINE__);
  goto fail;
  }


  rtc=gpio_direction_input(HCSR04_ECHO);
  if (rtc!=0) {
  printk(KERN_INFO "Error %d\n",__LINE__);
  goto fail;
  }


  rtc=gpio_to_irq(HCSR04_ECHO);
  if (rtc<0) {
  printk(KERN_INFO "Error %d\n",__LINE__);
  goto fail;
  } else {
  gpio_irq=rtc;
  }


  rtc = request_irq(gpio_irq, gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED , "hc-sr04.trigger", NULL);


  if(rtc) {
  printk(KERN_ERR "Unable to request IRQ: %d\n", rtc);
  goto fail;
  }




  return 0;


fail:
  return -1;


}

static void hcsr04_exit(void)
{
  if (gpio_irq!=-1) {
  free_irq(gpio_irq, NULL);
  }
  gpio_free(HCSR04_TRIGGER);
  gpio_free(HCSR04_ECHO);
  class_unregister(&hcsr04_class);
  printk(KERN_INFO "HC-SR04 disabled.\n");
}

module_init(hcsr04_init);
module_exit(hcsr04_exit);

 

 

Now hit "make" command to compile the above driver.

 

Step3:

 

connect the Vcc    pin in hc-sr04 to Pin2 in J13.

connect the Trig   pin in hc-sr04 to Pin5 in J13.

connect the Echo  pin in hc-sr04 to Pin6 in J13.

connect the Gnd   pin in hc-sr04 to Pin4 in J13.

 

Now copy the compiled sr04.ko to  /opt/ in riotboard.

 

Next insert the compiled module using insmod:

insmod sr04.ko

 

Now configure the Trigger & Echo for gpio in Riotboard terminal:

devmem 0x20E009C w 0x5

devmem 0x20E00A0 w 0x5

 

Prepare sr04 for capturing values:

 

Export the gpio pins

echo 112 > /sys/class/gpio/export

echo 113 > /sys/class/gpio/export

 

Set the Direction

echo out > /sys/class/gpio/gpio112/direction

echo 1 > /sys/class/gpio/gpio112/value

 

 

To view the sonar values , hit below command

cat /sys/class/hcsr04/value

 

Step4:

To continuously view values & object distance in cm i wrote a small python script.

create a file "sr04_distance.py"  in riotboard terminal with below contents:

 

#!/usr/bin/python
f = open("/sys/class/hcsr04/value",'r')
d=f.read()
f.close()
if (long(d)==-1):
  print "N.A."
else:
  print "%.1f cm" % (float(d)/58)

 

 

With all connections ready, run the sr04_distance.py script:

$ python sr04_distance.py

 

The sonar will display values as objects encountered in its way .

 

 

Note: during module testing if found  this hc-sr04 module range is max 3 metres.

 

 

That's all.

 

Thanks

Tushar