Notes About Working with Various Arduino & Netduino Microcontroller Boards

Friday, June 5, 2015

C Program for the Arduino Galileo to Read RFID Cards with an Innovations ID20-LA & Sparkfun RFID USB Reader Board

The Sparkfun RFID USB reader board provides an easy way to hook up an Innovations RFID reader chip.  While its main feature is the USB connection, the RFID USB reader board also provides a break out of the serial and power connections.  In this example, I present a C program for the Arduino Galileo that runs at the Linux command line (not an Arduino sketch) that configures the Galileo's serial pins, creates a serial connection, and reads the ID numbers of a 125kHz RFID card brought near the reader.  To reduce complexity, this code simply prints the card's number to the terminal.

Once again, I found information on Sergey Kiselev's blog - this time "Configuring the Serial Port in Linux" - very helpful.  Working with the RFID reader is by itself fairly simple, but configuring the GPIO pins for the serial connection and setting up the serial connection is a bit more complicated. The code for configuring and opening the serial connection is derived (and updated) from the Linux Documentation Project's program examples.

The program below runs, reads cards, and prints card IDs until the user presses control-c to quit.  The signal() handler restores the serial port's original settings and unexports the GPIO pins from sysfs before the program ends.

Connections


Reader Board   Arduino Galileo
VCC            3.3V
TX             RX (Digital 0)
TXR            TX (Digital 1)
GND            GND

Code 


Here is the C code. Again, this is designed to be compiled and run at the Galileo's Linux command prompt and is not an Arduino sketch.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

/* Galileo's digital pins 0 & 1 connect to /dev/ttyS0 */
#define SERIAL_DEV "/dev/ttyS0"

/* baudrasettings are defined in <asm/termbits.h>, which is
   included by <termios.h>. Change as needed, keep B 
*/
#define BAUDRATE B9600

/* POSIX compliant source */
#define _POSIX_SOURCE 1

// Function declarations
void configPins();
int openSerial(const char *);
void handleSIGINT(int);

/* Declare variable for original serial port settings here
   so it can be accessed from handleSIGINT function 
*/
struct termios savedTio;

/* Make descripter for serial connection global so
   handleSIGINT() can access it to restore original serial
   settings when program ends. 
*/ 
int serialHandle;

// Set loop that reads serial port to run indefinitely
int run = 1; 

int main() {
   int fd, c, res;
   char buf[255];

   printf("\nScan a tag to see its ID number. Press ctrl-c to quit.\n\n");

   // Program runs until user presses ctrl-c
   signal(SIGINT, handleSIGINT);
   
   configPins();
   serialHandle = openSerial(SERIAL_DEV);

   /* Loop continuously to handle serial input */
   while (run) {     
      /*  read blocks program execution until a line terminating character is
          input, even if more than 255 chars are input. If the number
          of characters read is smaller than the number of chars available,
          subsequent reads will return the remaining chars. res will be set
          to the actual number of characters actually read. 
      */
      res = read(serialHandle, buf, 255);
      /* set end of string, so we can printf */
      buf[res] = 0;
      printf("%s", buf, res);
   }
}

/* Function to configure the Galileo's serial pins (gpio40, gpio41). gpio4 
   is multiplexer that controls how serial pins behave.
*/
void configPins() {
   char *gpio[] = {"4", "40", "41"};
   char path[30];

   // Export ports for sysfs access
   int fd = open("/sys/class/gpio/export", O_WRONLY);
   int c;

   for(c = 0; c < 3; c++) {
      write(fd, gpio[c], strlen(gpio[c]));
   }
   close(fd);

   // Set direction
   for(c = 0; c < 3; c++) {
      sprintf(path, "/sys/class/gpio/gpio%s/direction", gpio[c]);
      fd = open(path, O_WRONLY);
      write(fd, "out", 3);
      close(fd);
   }

   // Set drive to strong for gpio40 & gpio41
   for(c = 1; c < 3; c++) {
      sprintf(path, "/sys/class/gpio/gpio%s/drive", gpio[c]);
      fd = open(path, O_WRONLY);
      write(fd, "strong", 6);
      close(fd);
   }

   // Turn on level shifter controlled by gpio4. Needed for serial.
   fd = open("/sys/class/gpio/gpio4/value", O_WRONLY);
   write(fd, "1", 1);
   close(fd);

   // Set mux for serial by setting gpio40 & gpio41 to 0
   for(c = 1; c < 3; c++) {
      sprintf(path, "/sys/class/gpio/gpio%s/value", gpio[c]);
      fd = open(path, O_WRONLY);
      write(fd, "0", 1);
      close(fd);
   }
}

// Configure & open serial port. Run configPins() first.
int openSerial(const char *serial) {
   struct termios tio;
   /* Open device for reading and writing and not as controlling tty
      because we don't want to get killed if linenoise sends CTRL-C. */
   int fd = open(serial, O_RDWR | O_NOCTTY );
   if (fd < 0) { 
      printf("\nError opening %s.\n", serial); 
      exit(1); 
   }
   /* save current serial port settings to global var so they can be 
      restored when the program ends (see handleSIGINT). . 
   */
   tcgetattr(fd, &savedTio);
   /* clear struct for new port settings */
   memset(&tio, 0, sizeof(tio));

   /* CRTSCTS : output hardware flow control
      CS8     : 8n1 (8bit,no parity,1 stopbit)
      CLOCAL  : local connection, no modem contol
      CREAD   : enable receiving characters 
   */
   tio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

   /* IGNPAR  : ignore bytes with parity errors
      otherwise make device raw (no other input processing) 
   */
   tio.c_iflag = IGNPAR;

   /*  Raw output  */
   tio.c_oflag = 0;

   /* ICANON  : enable canonical input disable all echo functionality, and 
      don't send signals to calling program 
   */
   tio.c_lflag = ICANON;
   /* now clean serial line & activate settings for the port */
   tcflush(fd, TCIFLUSH);
   tcsetattr(fd,TCSANOW, &tio);
   return fd;
}

// Function to clean up & end program when user presses ctrl-C
void handleSIGINT(int signum) {
   char *gpio[] = {"4", "40", "41"};
   char path[30];
   tcsetattr(serialHandle, TCSANOW, &savedTio);
   printf("\nProgram ending...\n");
   // Export ports for sysfs access
   int fd = open("/sys/class/gpio/unexport", O_WRONLY);
   int c;
   for(c = 0; c < 3; c++) {
      write(fd, gpio[c], strlen(gpio[c]));
   }
   close(fd);
   exit(0);
}



Thursday, June 4, 2015

C Program to Read an MPR121 Capacitive Touch Keypad Connected to an Arduino Galileo

This example presents C code that reads input from a Sparkfun MPR121 capacitive touch keypad. There are sample Arduino sketches around, but I wanted to use the keypad with a C program running at the Linux command prompt on the Galileo.

I have tried to keep this code as simple as possible.  This example does not use an interrupt but continuously polls the keypad to check for input and prints out the character pressed. The code doesn't make use of any bells and whistles to track the press and release of the keys. This program treats the keypad like a phone keypad.

For I2C access, this example uses the smbus library compiled as a shared library discussed in this post.

Sparkfun's MPR121 Hookup Guide has been very helpful. My understanding of the configuration parameters is limited, so I have taken the settings from the Sparkfun material. For understanding the Galileo's GPIO pins,  Sergey Kisilev's blog post is a critical piece of the puzzle.

Connections


MPR121  Arduino Galileo
GND     GND
SDA     SDA
SCL     SCL
VCC     3.3V 


Code       


Header File (mpr121.h)

/*
    MPR121.h
April 8, 2010
by: Jim Lindblom
*/

// MPR121 Register Defines
#define MHD_R 0x2B
#define NHD_R 0x2C
#define NCL_R 0x2D
#define FDL_R 0x2E
#define MHD_F 0x2F
#define NHD_F 0x30
#define NCL_F 0x31
#define FDL_F 0x32
#define ELE0_T 0x41
#define ELE0_R 0x42
#define ELE1_T 0x43
#define ELE1_R 0x44
#define ELE2_T 0x45
#define ELE2_R 0x46
#define ELE3_T 0x47
#define ELE3_R 0x48
#define ELE4_T 0x49
#define ELE4_R 0x4A
#define ELE5_T 0x4B
#define ELE5_R 0x4C
#define ELE6_T 0x4D
#define ELE6_R 0x4E
#define ELE7_T 0x4F
#define ELE7_R 0x50
#define ELE8_T 0x51
#define ELE8_R 0x52
#define ELE9_T 0x53
#define ELE9_R 0x54
#define ELE10_T 0x55
#define ELE10_R 0x56
#define ELE11_T 0x57
#define ELE11_R 0x58
#define FIL_CFG 0x5D
#define ELE_CFG 0x5E
#define GPIO_CTRL0 0x73
#define GPIO_CTRL1 0x74
#define GPIO_DATA 0x75
#define GPIO_DIR 0x76
#define GPIO_EN 0x77
#define GPIO_SET 0x78
#define GPIO_CLEAR 0x79
#define GPIO_TOGGLE 0x7A
#define ATO_CFG0 0x7B
#define ATO_CFGU 0x7D
#define ATO_CFGL 0x7E
#define ATO_CFGT 0x7F


// Global Constants
#define TOU_THRESH 0x06
#define REL_THRESH 0x0A

C Source Code (mpr121.c)

#include "mpr121.h"
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <smbus.h>  // smbus.h copied to /usr/include
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>

int main() {
   configPins();
   int deviceHandle = openI2C(0x5A);
   mpr121QuickConfig(deviceHandle);
   while(1) {
      unsigned char lsb = i2c_smbus_read_byte_data(deviceHandle, 0);
      unsigned char msb = i2c_smbus_read_byte_data(deviceHandle, 1);
      short touchStatus = (msb << 8) | lsb;
      int c;
      for(c = 0; c < 12; c++) {
         if(touchStatus & (1 << c)) {
            printf("%c\n", KEY[c]);
            break; // only 1 key even if more pressed at a time
         }
      }
      // Pause for 0.15 second before reading again
      usleep(150000);
   }
   return 0;


// Configure multiplexing of Galileo's GPIO pins for I2C
void configPins() {
   // Set multiplexing for i2c pins via gpio29. Start by exporting gpio29 
   // so it can be accessed via sysfs.
   int fd = open("/sys/class/gpio/export", O_WRONLY);
   write(fd, "29", 2);
   // Export I2C pins, too, so they can be set to pullup
   write(fd, "48", 2);
   write(fd, "49", 2);
   close(fd);
   // Set gpio29's direction to out
   fd = open("/sys/class/gpio/gpio29/direction", O_WRONLY);
   write(fd, "out", 3);
   close(fd);

   // Set gpio29's value to 0 to enable i2c via Quark chip
   fd = open("/sys/class/gpio/gpio29/value", O_WRONLY);
   // Note that 0 is passed as a string/char.
   write(fd, "0", 1);
   close(fd);

   // Enable pullups on I2C pins. The default drive mode is pullup, 
   // so these lines may not be necessary. 
   fd = open("/sys/class/gpio/gpio48/drive", O_WRONLY);
   write(fd, "pullup", 6);
   close(fd);
   fd = open("/sys/class/gpio/gpio49/drive", O_WRONLY);
   write(fd, "pullup", 6);
   close(fd);
}

// Open connection to I2C device & return handle
int openI2C(unsigned char addr) {
   // On Galileo (Clanton), the I2C bus is /dev/i2c-0
   int deviceHandle = open("/dev/i2c-0", O_RDWR);
   // Connect to device at address
   if(ioctl(deviceHandle, I2C_SLAVE, addr) < 0) {
      fprintf(stderr, "Failed to open I2C device as slave.\n");
      exit(1);
   }
   return deviceHandle;
}

void mpr121QuickConfig(int dh) {
  i2c_smbus_write_byte_data(dh, ELE_CFG, 0x00); 

  // This group controls filtering when data is > baseline.
  i2c_smbus_write_byte_data(dh, MHD_R, 0x01);
  i2c_smbus_write_byte_data(dh, NHD_R, 0x01);
  i2c_smbus_write_byte_data(dh, NCL_R, 0x00);
  i2c_smbus_write_byte_data(dh, FDL_R, 0x00);

  // This group controls filtering when data is < baseline.
  i2c_smbus_write_byte_data(dh, MHD_F, 0x01);
  i2c_smbus_write_byte_data(dh, NHD_F, 0x01);
  i2c_smbus_write_byte_data(dh, NCL_F, 0xFF);
  i2c_smbus_write_byte_data(dh, FDL_F, 0x02);
  
  // This group sets touch and release thresholds for each electrode
  i2c_smbus_write_byte_data(dh, ELE0_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE0_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE1_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE1_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE2_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE2_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE3_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE3_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE4_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE4_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE5_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE5_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE6_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE6_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE7_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE7_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE8_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE8_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE9_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE9_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE10_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE10_R, REL_THRESH);
  i2c_smbus_write_byte_data(dh, ELE11_T, TOU_THRESH);
  i2c_smbus_write_byte_data(dh, ELE11_R, REL_THRESH);

  // Set the Filter Configuration
  i2c_smbus_write_byte_data(dh, FIL_CFG, 0x04);
  // Enable all 12 Electrodes
  i2c_smbus_write_byte_data(dh, ELE_CFG, 0x0C); 
  // Enable Auto Config and auto Reconfig
  i2c_smbus_write_byte_data(dh, ELE_CFG, 0x06);
}

To compile the program, run the gcc compiler like this -


gcc -lsmbus -o mpr121 mpr121.c

Wednesday, June 3, 2015

C Program to Read a 4x4 Keypad Connected to an Arduino Galileo

The Arduino keypad library (written in C++) works with Arduino sketches running on the Galileo, but I wanted to access a 4x4 keypad from a standard C program.  The following code shows how to configure the GPIO pins and read the keypad. The program just reads keypresses and prints the characters to the console (at the command line, not the Arduino serial monitor).

The biggest challenge was getting digital pins 2 through 9 configured correctly. The configPins() function in the code below handles the necessary GPIO configuration.

For this sketch, which runs from the Linux command line, to function correctly, make sure that you don't have an Arduino sketch running that accesses digital pins 2 through 9.  Uploading the BareMinimum via the Arduino IDE or deleting the files in the /sketch directory at the command line should take care of any conflicts.

To compile the code on the Galileo, you will need a Yocto image that includes gcc or have a look at this post about installing gcc on Clanton using opkg.

Connections


With the 4x4 keypad face up and the wires pointing down, connect the wires to the Arduino Galileo's digital pins 2 through 9.  It could be connected with wires running from right to left, but then the GPIO numbers and 2-dimensional layout array would need to be revised.

Code


#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#define KEY_PRESS_DELAY 100000 // Pause microseconds to debounce
                               // Adjust to control repeat rate
#define KEYPAD_COLUMNS 4
#define KEYPAD_ROWS    4

// Base of path to GPIO devices 
const char *gpioBase = "/sys/class/gpio"; 

// sysfs gpio# for       col3   col2  col1  col0
const char *gpioCols[] = {"32", "18", "28", "17"};
// sysfs gpio# for       row3   row2  row1  row0
const char *gpioRows[] = {"24", "27", "26", "19"};
// sysfs gpio# for mux for col3 and col2
const char *gpioMux[]  = {"31", "30"};

/* This layout assumes that keypad is connected to Galileo with leftmost 
   pin (when looking at front of keypad with wires pointed downward) to 
   Galileo digital 2. The other wires are connected in order on digital 
   pins 3 through 9. 
*/
const char layout[KEYPAD_ROWS][KEYPAD_COLUMNS] = {
   {'1','2','3','A'},
   {'4','5','6','B'},
   {'7','8','9','C'},
   {'*','0','#','D'}
};

// Function declarations
void configPins();  // Configure Galileo's GPIO pins 
char getKey();      // Read keypres

int main() {
   configPins();
   while(1) {
      printf("%c\n", getKey());
   }
   return 0;
}

void configPins() {
   /* Configuration involves the following:
1. Export gpio ports for sysfs access
        2. Set direction (out) for mux ports
        3. Set  value (1) for mux ports 
           that control pins 2 & 3
        4. Set port direction (out) 
        5. Set value (1) for columns
        6. Set drive mode for columns to pullup
        7. Set direction (in) for rows
        8. Set drive mode for rows to pullup

        Note that all configuration values are passed as strings.
  
        I have left out error handling if open() fails.
   */
   // path string for gpio devices & settings
   char path[30];
   int fd; // file handle
   int c;  // loop variable
   // Export gpio ports to sysfs
   sprintf(path, "%s/export", gpioBase);
   fd = open(path, O_WRONLY);
   // Loop to export pins for columns & rows
   for(c = 0; c < KEYPAD_COLUMNS; c++) {
      // export column pin
      write(fd, gpioCols[c], 2);
   }
   for(c = 0; c < KEYPAD_ROWS; c++) {
      // export row pin
      write(fd, gpioRows[c], 2);
   }
   // export multiplex pins
   for(c = 0; c < 2; c++) {
      write(fd, gpioMux[c], 2);
   }
   close(fd);
   // Set direction for the 2 mux ports
   for(c = 0; c < 2; c++) {
      sprintf(path, "%s/gpio%s/direction", gpioBase, gpioMux[c]);
      fd = open(path, O_WRONLY);
      write(fd, "out", 3);
      close(fd);
   }
   // Set value (1) for the 2 mux ports
   for(c = 0; c < 2; c++) {
      sprintf(path, "%s/gpio%s/value", gpioBase, gpioMux[c]);
      // Route pins 2 & 3 through Cypress CY8C9540A rather than Quark by
      // setting value to 1. This makes pins 2 & 3 avail. as sysfs 
      // gpio# 32 & 18.
      fd = open(path, O_WRONLY);
      write(fd, "1", 1);
      close(fd);
   }
   // Set direction (out) for ports for columns
   for(c = 0; c < KEYPAD_COLUMNS; c++) {
      sprintf(path, "%s/gpio%s/direction", gpioBase, gpioCols[c]);
      fd = open(path, O_WRONLY);
      write(fd, "out", 3);
      close(fd);
   }
   // Set colum pins to HIGH (1)
   for(c = 0; c < KEYPAD_COLUMNS; c++) {
      sprintf(path,"%s/gpio%s/value", gpioBase, gpioCols[c]);
      fd = open(path, O_WRONLY);
      write(fd, "1", 1);
      close(fd);
   }
   // Set drive mode for column pins to pullup
   for(c = 0; c < KEYPAD_COLUMNS; c++) {
      sprintf(path, "%s/gpio%s/drive", gpioBase, gpioCols[c]);
      fd = open(path, O_WRONLY);
      write(fd, "pullup", 6);
      close(fd);
   }
   // Set direction of row pins to input (in)
   for(c = 0; c < KEYPAD_ROWS; c++) {
      sprintf(path, "%s/gpio%s/direction", gpioBase, gpioRows[c]);
      fd = open(path, O_WRONLY);
      write(fd, "in", 2);
      close(fd);
   }
   // Set drive mode for row pins to pullup
   for(c = 0; c < KEYPAD_ROWS; c++) {
      sprintf(path, "%s/gpio%s/drive", gpioBase, gpioRows[c]);
      fd = open(path, O_WRONLY);
      write(fd, "pullup", 6);
      close(fd);
   }
}

char getKey() {
   // Need 2 file handles for nested loops to read columns & rows
   int fd, fd2;
   // String to hold path to gpio device & setting  
   char path[30];
   // Initialize key to space so loop runs until key pressed
   char key = ' ';
   int c, d; // loop variables
   // Wait for a key
   while(key == ' ') {
      // Loop through columns
      for(c = 0; c < 4; c++) {
         sprintf(path, "%s/gpio%s/value", gpioBase, gpioCols[c]);
         fd = open(path, O_WRONLY);
         // Set column LOW (0)
         write(fd, "0", 1);
         // Loop through rows & check for 0 to identify key
         int d;
         for(d = 0; d < 4; d++) {
            char rowPath[35];
            char value[1];
            sprintf(rowPath, "%s/gpio%s/value", gpioBase, 
                     gpioRows[d]);
            fd2 = open(rowPath, O_RDONLY);
            read(fd2, value, 1);
            close(fd2);
            if(value[0] == '0') {
               // wait & read again to confirm key press
               usleep(KEY_PRESS_DELAY);
               read(fd2, value, 1);
               if(value[0] == '0') {            
                  key = layout[c][d];
               }
            }
         }
         // Set column pin back to HIGH (1)
         write(fd, "1", 1);
         close(fd);
      }
   }
   return key;
}

Note: This code uses usleep(), which is deprecated by POSIX, so compiling with the -std=c99 switch won't work.  I tried to use nanosleep(), but I ran into problems: nanosleep() kept coming up as undeclared and the definition for struct timespec wasn't found. 

Friday, May 29, 2015

C Code for the Arduino Galileo to Read Barometric Pressure Using a BMP085

Below is a sample program written in C for the Galileo that reads the barometric pressure from an Adafruit BMP085.  This code just prints out the barometric pressure in inches of mercury (adjusted to sea level) until the user ends the program using ctrl-C.

You will need to install the gcc compiler. See my previous post, "Installing the gcc Compiler on an Arduino Galileo Running Clanton" for further information.

This example also uses the smbus I2C library compiled as a shared library. See "Building a Shared C Library Using gcc on the Arduino Galileo (Gen. 1)" for my notes on this.

For information on the Galileo's GPIO pins and how they are configured under Linux, see Sergey Kisilev's very useful post.

Connections


Galileo   BMP085
VIN       3.3V
GND       GND
SCL       SCL (or A5)
SDA       SDA (or A4)

Source Code


Header File bmp085.h

 #include <inttypes.h>

// Macro to flip bytes in short integer
#define flipBytes(val) ((val<<8) & 0xFF00) | ((val>>8) & 0xFF)

int deviceHandle; // Handle for accessing i2c. Global so sigaction can access it
int run = 1;      // Controls loop - set to run when 1, 0 to quit

// Variables to hold calibration values
int16_t ac1;
int16_t ac2;
int16_t ac3;
uint16_t ac4;
uint16_t ac5;
uint16_t ac6;
int16_t b1;
int16_t b2;
int16_t mb;
int16_t mc;
int16_t md;
int32_t b5;
int16_t t;
int32_t p;

const uint8_t OSS = 0;  // Oversampling Setting

// Function declarations
void configPins();
void openI2C();
void calibrate();
short getTemperature(uint16_t);
int32_t getPressure(uint32_t);                        
uint16_t getUncompensatedTemperature(uint16_t);
uint32_t getUncompensatedPressure(uint16_t);
void handleTermination(int);

C Source Code (bmp085.c)


/* This code uses smbus to access the i2c bus. You can find the source code for smbus at 
   https://www.john.geek.nz/2012/12/update-reading-data-from-a-bosch-bmp085-with-a-raspberry-pi/.  
   This version of the smbus code compiles on and works with the Galileo running Clanton 
   without modification */

#include "bmp085.h"
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <math.h>   // needed for trunc()
#include <signal.h> // needed for signal()
#include <smbus.h>  // smbus.h copied to /usr/include
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>

/* This program prints out the current barometric pressure in inches
   of mercury every 10 seconds. This code adjusts the pressure to
   sea-level based on the elevation here in Minneapolis. See comment
   below about how to change this adjustment for other elevations.

   The program runs until the user presses ctrl-C. This code uses 
   signal() to close the device handle for the I2C bus before
   exiting. */

int main() {
int32_t p; // 32-bit integer to hold pressure returned by sensor

// Set up handler for ctrl-C. End program by pressing ctrl-C
signal(SIGINT, handleTermination);
configPins();
openI2C();
calibrate(deviceHandle);
// loop runs while run is not 0
while(run) {
// Need to call function to read temperature to compensate pressure 
getTemperature(getUncompensatedTemperature(deviceHandle));
p = getPressure(getUncompensatedPressure(deviceHandle));
  double pInHg = p * 0.000295333727; // convert to inches of mercury
  // Now adjust to sea level: Add 1200 Pa / 100 meters in elev.
  // Minneapolis is 264m above sea level. This is 0.935" mercury
  pInHg += 0.935;
  pInHg = trunc(pInHg * 100)/100;
time_t t = time(NULL);
struct tm tm = *localtime(&t);
printf("%02d/%02d/%d %02d:%02d:%02d ", tm.tm_mon + 1, tm.tm_mday, 
               tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
  printf("Pressure: %.02f\n", pInHg);
// sleep for about 10 seconds
sleep(10);
}
return 0;
}

// Configure multiplexing of Galileo's GPIO pins for I2C
void configPins() {
   // Set multiplexing for i2c pins via gpio29. Start by exporting gpio 29 so
   // it can be accessed via sysfs.
   int fd = open("/sys/class/gpio/export", O_WRONLY);
   if(fd == -1) {
      fprintf(stderr, "Failed to open gpio export path.\n");
      exit(1);
   }
   write(fd, "29", 2);
   close(fd);
   // Set gpio29's direction to out
   fd = open("/sys/class/gpio/gpio29/direction", O_WRONLY);
   if(fd == -1) {
      fprintf(stderr, "Failed to open gpio direction path.\n");
      exit(2);
   }
   write(fd, "out", 3);
   close(fd);

   // Set gpio29's value to 0 to enable i2c via Quark chip
   fd = open("/sys/class/gpio/gpio29/value", O_WRONLY);
   if(fd == -1) {
      fprintf(stderr, "Failed to open gpio value path.\n");
      exit(3);
   }
   // Note that 0 is passed as a string/char.
   write(fd, "0", 1);
close(fd);
}

void openI2C() {
  // On Galileo (Clanton), the I2C bus is /dev/i2c-0
   deviceHandle = open("/dev/i2c-0", O_RDWR);
   if(deviceHandle < 0) {
      fprintf(stderr, "Failed to open /dev/i2c-0.\n");
      exit(4);
   }
// The BMP085 uses the device address 0x77
   if(ioctl(deviceHandle, I2C_SLAVE, 0x77) < 0) {
      fprintf(stderr, "Failed to open I2C device as slave.\n");
      exit(5);
   }
}

// Read registers with factory-set calibration values.  
void calibrate() {
   ac1 = i2c_smbus_read_word_data(deviceHandle, 0xAA);
// flipBytes is a macro defined in bmp085.h
   ac1 = flipBytes(ac1);
   ac2 = i2c_smbus_read_word_data(deviceHandle, 0xAC);
   ac2 = flipBytes(ac2);
   ac3 = i2c_smbus_read_word_data(deviceHandle, 0xAE);
   ac3 = flipBytes(ac3);
   ac4 = i2c_smbus_read_word_data(deviceHandle, 0xB0);
   ac4 = flipBytes(ac4);
   ac5 = i2c_smbus_read_word_data(deviceHandle, 0xB2);
   ac5 = flipBytes(ac5);
   ac6 = i2c_smbus_read_word_data(deviceHandle, 0xB4);
   ac6 = flipBytes(ac6);
   b1 = i2c_smbus_read_word_data(deviceHandle, 0xB6);
   b1 = flipBytes(b1);
   b2 = i2c_smbus_read_word_data(deviceHandle, 0xB8);
   b2 = flipBytes(b2);
   mb = i2c_smbus_read_word_data(deviceHandle, 0xBA);
   mb = flipBytes(mb);
   mc = i2c_smbus_read_word_data(deviceHandle, 0xBC);
   mc = flipBytes(mc);
   md = i2c_smbus_read_word_data(deviceHandle, 0xBE);
   md = flipBytes(md);
}

// Read the uncompensated temperature value
uint16_t getUncompensatedTemperature(uint16_t deviceHandle) {
   uint16_t ut;  
  // Write 0x2E into Register 0xF4
  // This requests a temperature reading
i2c_smbus_write_byte_data(deviceHandle, 0xF4, 0x2E);
// Wait at least 4.5ms (4500 microseconds for usleep() call)
usleep(4500);
  // Read two bytes from registers 0xF6 and 0xF7
  ut = i2c_smbus_read_word_data(deviceHandle, 0xF6);
  return flipBytes(ut);
}

// Read the uncompensated pressure value
uint32_t getUncompensatedPressure(uint16_t deviceHandle) {
  unsigned char msb, lsb, xlsb;
unsigned long up = 0;
  
// Write 0x34 + (OSS << 6) into register 0xF4
// Request a pressure reading w/ oversampling setting
i2c_smbus_write_byte_data(deviceHandle, 0xF4, 0x34 + (OSS << 6));
  // Wait for conversion. 5 milliseconds = 5000 microseconds
  usleep(5000);
  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
msb = i2c_smbus_read_byte_data(deviceHandle, 0xF6);
lsb = i2c_smbus_read_byte_data(deviceHandle, 0xF7);
xlsb = i2c_smbus_read_byte_data(deviceHandle, 0xF8);
up = (((uint32_t) msb << 16) | ((uint32_t) lsb << 8) | (uint32_t) xlsb) >> (8 - OSS);
  return up;
}

// Calculate temperature given unadjusted temp ut.
// Value returned will be in units of 0.1 deg C
int16_t getTemperature(uint16_t ut) {
  int32_t x1, x2;
  x1 = (((int32_t)ut - (int32_t)ac6) * (int32_t)ac5) >> 15;
  x2 = ((int32_t)mc << 11) / (x1 + md);
  b5 = x1 + x2;
  return ((b5 + 8)>>4);  
}

// Calculate pressure given unadjusted pressure up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(...) must be called first.
// Value returned will be pressure in units of Pa.
int32_t getPressure(uint32_t up) {
  int32_t x1, x2, x3, b3, b6, p;
uint32_t b4, b7;
  
b6 = b5 - 4000;
// Calculate B3
x1 = (b2 * (b6 * b6)>>12) >> 11;
x2 = (ac2 * b6) >> 11;
x3 = x1 + x2;
b3 = (((((int32_t)ac1) * 4 + x3) << OSS) + 2) >> 2;
  
// Calculate B4
x1 = (ac3 * b6) >> 13;
x2 = (b1 * ((b6 * b6) >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (uint32_t)(x3 + 32768)) >> 15;
  
b7 = ((uint32_t)(up - b3) * (50000 >> OSS));
if (b7 < 0x80000000) {
p = (b7 << 1) / b4;
}
  else {
    p = (b7 / b4) << 1;
}
    
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
p += (x1 + x2 + 3791) >> 4;
  
return p;
}

// Function that handles SIGINT (ctrl-C) and closes i2c
void handleTermination(int signum) {
  fprintf(stderr, "\nProgram exiting...\n");
   // Not possible to pass arguments to this function
   // so deviceHandle needs to be a global variable
   // (in this case, set in bmp085.h header file.
  close(deviceHandle);
// Setting run to 0 ends main program loop
  run = 0;
}

Compiling the Code


Assuming that the files bmp085.c and bmp085.h are in the current directory and that you've installed smbus as a shared library, the following command will compile the program:

gcc -Wall -lm -lsmbus -o bmp085 bmp085.c

-Wall turns on all warnings. -lm links in the math library and -lsmbus links in the smbus library.  As usual, the -o option identifies the executable file to be produced and the last file is the C source code file.