Thursday, September 12, 2013

pcDuino - Interrupt Tutorial

This is the latest installment of my series of pcDuino tutorials.  This tutorial will show you how to setup and program the pcDuino to respond to an external interrupt.

This assumes that you have a basic working knowledge of the pcDuino and Linux.  It builds upon the pcDuino – Blink Totorial.

For this tutorial you will need the following items:

  1. A pcDuino running the 20130531 Ubuntu image.
  2. A breadboard.
  3. A button such as the Mini Push Button Switch sold by Sparkfun.
  4. Three jumper wires.
  5. A 10K ohm resistor.
  6. The source code below for building interrupt.c.

DSCF4974

Hardware Setup

The setup for this is simple.  You connect one end of the switch to the 3.3V pin on the pcDuino.  You connect the other end of the switch to GPIO2 pin on the pcDuino and to ground through the 10K resistor.  The 10K resistor as it is connected to ground is a pull-down resistor.  It keeps the signal at 0V when the switch is open.  If a pull-up or pull-down resistor was not used the signal would float which could cause intermittent interrupts when one was not signaled.

image

The pins used are shown by the red arrows in the board diagram above.

Interrupt Program

An interrupt is described in Wikipedia as a signal to the processor emitted by hardware or software indicating an event that needs immediate attention.  In this tutorial we are working with a hardware interrupt. 

The pcDuino is setup with two pins that can be used for interrupts: GPIO2 and GPIO3.  The program is written to use SWIRQ_PIN1 and GPIO2.  However, SWIRQ_PIN2 is also define which corresponds to GPIO3.

The way the program works is that when the switch is opened gpio pin 2 is is connected to ground at 0V.  When the switch is pushed it connects 3.3V to gpio pin 2 which is read by the system and results in an interrupt service routine (ISR) being called if one is defined.

There are 5 types of interrupts:

  1. Rising – called when the signal goes from low to high.
  2. Falling – called when the signal goes from high to low.
  3. High – called when the signal is high.
  4. Low – called when the signal is low.
  5. Change – called when the signal goes from low to high and then again when it goes from high to low.

interrupt.c

#include <stdio.h> 
#include <signal.h>   
#include <stdlib.h>    
#include <inttypes.h>    
#include <sys/ioctl.h>    
#include <fcntl.h>
// sw_interrupt must be loaded.  
// if it isn't load using:
// modprobe sw_interrupt

// Data structure for defining an interrupt on the pcDuino   
typedef struct swIRQ {    
    uint8_t channel;    
    int mode;    
    int pid;    
} swIRQt,*irqSWp;

// Pseudo device for controlling interrupts   
static const char *swirq_dev = "/dev/swirq";

#define SWIRQ_START   (0x201)   
#define SWIRQ_STOP    (0x202)    
#define SWIRQ_SETPID  (0x203)    
#define SWIRQ_ENABLE  (0x204)    
#define SWIRQ_DISABLE (0x205)

#define SWIRQ_RISING  (0x00)   
#define SWIRQ_FALLING (0x01)    
#define SWIRQ_HIGH    (0x02)    
#define SWIRQ_LOW     (0x03)    
#define SWIRQ_CHANGE  (0x04)

#define SWIRQ_PIN1    (0x0)   
#define SWIRQ_PIN2    (0x1)

int main(int _argc, char **_argv) {   
  int fd;    
  int ret;    
  uint8_t swIrqNum = 0;    
  swIRQt swIrqCfg;    
 
  // Define ISR    
  int irqPin1Cnt = 0;    
  int irqPin1Func (void) {    
    irqPin1Cnt++;    
  }

  // Attach the ISR to the USR1 signal which is triggered by the OS when the interupt is signaled.   
  signal(SIGUSR1, (void (*) (int))irqPin1Func);

  // Setup to use pin1 / gpio2 when the signal goes from low to high.   
  swIrqCfg.channel = SWIRQ_PIN1;    
  swIrqCfg.mode = SWIRQ_RISING;    
  swIrqCfg.pid = getpid();    
  swIrqNum = SWIRQ_PIN1;    
 
  // Connect a file descriptor to the pseudo device used to control interrupts    
  fd = open(swirq_dev, O_RDONLY);    
  if ( fd < 0 ) {    
    printf("open swirq device fail");    
    exit(0);    
  }    
 
  // Disable interrupts using pin1 / gpio2    
  ret = ioctl(fd, SWIRQ_STOP, &swIrqNum);    
  if (ret < 0) {    
    printf("can't set SWIRQ_STOP");    
    exit(0);    
  }    
 
  // Configure pin1 / gpio2 interrupts    
  ret = ioctl(fd, SWIRQ_SETPID, &swIrqCfg);    
  if (ret < 0) {    
    printf("can't set SWIRQ_SETPID");    
    exit(0);    
  }    
 
  // Enable interrupts on pin1 / gpio2    
  ret = ioctl(fd, SWIRQ_START, &swIrqNum);    
  if (ret < 0) {    
    printf("can't set SWIRQ_START");    
    exit(0);    
  }    
 
  // Disconnect from the pseudo device    
  if (fd) close(fd);    

  // Loop forever. Print out the counter when the ISR has been called.    
  int oldValue = 0;    
  while (2>1) {    
    if (oldValue != irqPin1Cnt) {    
      printf("irqPin1Funct: %d\n", irqPin1Cnt);    
      oldValue = irqPin1Cnt;    
    }    
  }    
}

Program Setup

Using the editor of your choice or the command “cat > interrupt.c” you will need to get the program on to your pcDuino.  See the Blink Tutorial for screen shots on how to do this.

Next you will need to load the appropriate driver if it isn’t already loaded when you boot your system.  You can check using the lsmod command and then load the driver using “sudo modprobe sw_interrupt” again there are screenshots of this in the Blink Tutorial.

Next compile your program using “gcc interrupt.c –o interrupt” and then run it using “./interrupt”.  When you press the button you should get a number printed on your screen.  You will need to use ctrl-c to exit the program.

Acknowledgements

Thanks to the folks at Sparkfun and their great Getting Started with pcDuino for getting me started with putting this tutorial together.  Also thanks to the folks on the pcDuino website for their support.  Check out the website and forums for more information.

Monday, September 2, 2013

pcDuino - Analog Read Tutorial

This tutorial will show you how to program the pcDuino to read an analog input.

It assumes you have a basic working knowledge of the pcDuino on Linux.  It builds upon the pcDuino – Blink Tutorial.

For this tutorial you will need the following items:

  1. A pcDuino running the 20130531 Ubuntu image with ssh.
  2. A breadboard.
  3. A potentiometer.
  4. Three wire jumpers.
  5. The source code below for analog.c

DSCF4970

Hardware Setup

A potentiometer also known as a pot has three terminals.  These terminals connect to the the input voltage, the input channel and ground.  The input channel terminal is connected inside the pot to a wiper that moves across resistive material in the pot.  The closer it is to the terminal with ground connected the lower the voltage and the closer it is to the terminal with the input voltage higher the voltage is.

I used a 10K Ohm breadboard compatible potentiometer similar to the one in the picture below.

From left to right on the breadboard in the picture above are connected: ground, ADC2, and 3.3V.

image

At this point you are ready to power up your pcDuino.

Analog Read Program

To read an analog pin you just need to open a special file and then read the file.

The file is /proc/adc# where the # is replaced with 0 – 5 depending on the pin you are using.  ADC0 and ADC1 work with voltages from 0V to 2V and have 6 bits.  This means that you are going to be reading values from 0 to 63.  ADC1 – ADC5 work with voltages from 0V to 3.3V and have 12 bits which means you will read values from 0 – 4095.

When /proc/adc# is read it returns the following string: adc#:<value> where # is the adc pin 0 to 5 and value is 0 to 63 for ADC0 and ADC1 and 0 to 4095 for ADC2 to ADC5.

analog.c

#include <stdio.h>   
#include <fcntl.h>

#define ADEV "/proc/adc2" int main(void) { int aPin = open(ADEV, O_RDONLY); while (2 > 1) { char tBuf[16]; // set to start of file lseek(aPin, 0, SEEK_SET); // read adc data int ret = read(aPin, tBuf, sizeof(tBuf)); // convert adc data to a value. int aVal = atoi(tBuf+5); printf("%d\n", aVal); } }

Program Setup

Using the editor of your choice or the command “cat > analog.c” you will need to get the program on to your pcDuino.  See the Blink Tutorial for screen shots on how to do this.

Next you will need to load the appropriate driver if it isn’t already loaded when you boot your system.  You can check using the lsmod command and then load the driver using “sudo modprobe adc” again there are screenshots of this in the Blink Tutorial.

Next compile your program using “gcc analog.c –o analog” and then run it using “./analog”.  You should get a series of numbers printed on your screen.  These numbers should change when you rotate the pot attached to the pcDuino.

Acknowledgements

Thanks to the folks at Sparkfun and their great Getting Started with pcDuino for getting me started with putting this tutorial together.  Also thanks to the folks on the pcDuino website for their support.  Check out the website and forums for more information.