Wednesday, December 11, 2013

Java Program to Read 1-Wire Temperature Data on a Beaglebone Black

This Java example shows how to read the current temperature from one or more DS18B20 temperature sensors.  If you need to install Java 7 on a Beaglebone Black, see this post.  

To configure the BB Black's pins for 1-wire support, see this post at Hipstercircuits.  This configuration is necessary before continuing.


Connections


Looking at the flat side of the DS18B20's plastic head, connect the left pin to ground on the Beaglebone Black (P9-1), the right pin to 3V3 (P9-3), and the center pin to P9-22.  A 4.7k Ohm pull-up resistor is required on the connection of the first sensor's center pin to P9-22.  If using multiple sensors, each needs to be connected to the voltage and ground; parasitic power mode does not seem to be supported.  The center (data) pins need to be connected together (with the pull-up on the connection to the BB Black)

Java Code


The following Java code finds the connected DS18B20s and prints each sensor's temperature data to the console.

import java.io.*;
import java.util.*;

public class w1 {
  // This directory created by 1-wire kernel modules
  static String w1DirPath = "/sys/bus/w1/devices";

  public static void main(String[] argv) throws Exception {
    File dir = new File(w1DirPath);
    File[] files = dir.listFiles(new DirectoryFileFilter());
    if (files != null) {
      for(File file: files) {
        System.out.print(file.getName() + ": ");
// Device data in w1_slave file
String filePath = w1DirPath + "/" + file.getName() + "/w1_slave";
File f = new File(filePath);
try(BufferedReader br = new BufferedReader(new FileReader(f))) {
          String output;
  while((output = br.readLine()) != null) {
    int idx = output.indexOf("t=");
    if(idx > -1) {
      // Temp data (x1000) in 5 chars after t=
      float tempC = Float.parseFloat(
          output.substring(output.indexOf("t=") + 2));
      // Divide by 1000 to get degrees Celsius
      tempC /= 1000;
      System.out.println(tempC);
    }
          }
}
catch(Exception ex) {
  System.out.println(ex.getMessage());
                   }
      }
    }
  } 
}

// This FileFilter selects subdirs with name beginning with 28-
// Kernel module gives each 1-wire temp sensor name starting 
// with 28-
class DirectoryFileFilter implements FileFilter
{
  public boolean accept(File file) {
    String dirName = file.getName();
    String startOfName = dirName.substring(0, 3);
    return (file.isDirectory() && startOfName.equals("28-"));
  }
}


Saturday, November 23, 2013

C Code to Read GPS Data via Serial on the Beaglebone Black

I've posted before abut using the Copernicus II GPS module from Sparkfun with a Python script.  The following example is a C program that reads serial data from this module.  The focus here is really on accessing the serial port on the Beaglebone Black, sending a configuration command to the GPS module, and continuously reading the output.  Data is just printed to the Linux command line on the Beaglebone Black. This example does not attempt to format or use this data.


Connections


GPS Module  Beaglebone Black
VCC         P9 3
GND         P9 1
TX-B        P9 26
RX-B        P9 24

In order to use the serial port, you need to configure the pins that connect to it.  See my post, "uart1.dts: Configuration File to Enable UART1 on Beaglebone Black," for the configuration file.  The C code below will load this pin configuration file.


C Code


This code is based on sample serial port code by Gary Frerking that I found at the Linux Documentation Project.

For more information about the commands to configure the Copernicus II, see Appendix C of the Copernicus II manual.  As was the case with the Python example, each command must include a 2-digit checksum after the asterisk.  See this page for an online tool to calculate the checksum.  

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

#include <stdlib.h>

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

/* change this definition for the correct port */
#define MODEMDEVICE "/dev/ttyO1" //Beaglebone Black serial port

#define _POSIX_SOURCE 1 /* POSIX compliant source */

#define FALSE 0
#define TRUE 1

main()
{
    int fd, c, res;
    struct termios oldtio, newtio;
    char buf[255];
    // Load the pin configuration
    int ret = system("echo uart1 > /sys/devices/bone_capemgr.9/slots");
    /* Open modem device for reading and writing and not as controlling tty
       because we don't want to get killed if linenoise sends CTRL-C. */
    fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
    if (fd < 0) { perror(MODEMDEVICE); exit(-1); }

    bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */

    /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
       CRTSCTS : output hardware flow control (only used if the cable has
                 all necessary lines. See sect. 7 of Serial-HOWTO)
       CS8     : 8n1 (8bit,no parity,1 stopbit)
       CLOCAL  : local connection, no modem contol
       CREAD   : enable receiving characters */
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

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

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

    /* ICANON  : enable canonical input
       disable all echo functionality, and don't send signals to calling program */
    newtio.c_lflag = ICANON;
    /* now clean the modem line and activate the settings for the port */
    tcflush(fd, TCIFLUSH);
    tcsetattr(fd,TCSANOW,&newtio);
    // NMEA command to ouput all sentences
    // Note that this code & format values in manual are hexadecimal
    write(fd, "$PTNLSNM,273F,01*27\r\n", 21);
    /* terminal settings done, now handle input*/
    while (TRUE) {     /* loop continuously */
        /*  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(fd, buf, 255);
        buf[res] = 0;             /* set end of string, so we can printf */
        printf("%s", buf, res);
    }
    tcsetattr(fd, TCSANOW, &oldtio);
}

Compiling & Running the Code


Compiling the code at the command line on the Beaglebone Black is very easy.  Change the commands to match the file name in which you've saved the source code -

gcc serial_gps.c -o serial_gps

And the following will run the new program until the user presses control-c -

./serial_gps



Sunday, October 6, 2013

Using Java & JNA to Access an I2C Device on a Beaglebone Black

Having gotten Java 7 installed on my Beaglebone Black, I wanted to find a way to access an I2C device from a Java program.  To keep things simple, I used a TMP102 temperature sensor from Sparkfun.  I started looking into JNI, but I decided to try JNA to access a simple C library to read the TMP102.

I downloaded the 2 JAR files for JNA (jna.jar & jna-platform.jar) from Git Hub and put them in the /usr/share/java directory.

Note (07/02/2014): I am having trouble with this under Java 8.  The code compiles, but it throws the exception NoClassDefFoundError: com/sun/jna/Library, even though the JAR files are included in my classpath.


C Library


The header file for the C library (tmp102.h) consists of a single line declaring the only method in this example:

extern int getTempC();

Here is the code for the library that will compiled into a .so file.

Note that the method returns an integer.  I wanted to used a float or a double, but I found that JNA did not return the correct values.  The values returned were completely nonsensical.  This is apparently related to differences between software and hardware float support. When I tried to return the data from the sensor to the Java program as a char */string, the result was a segment fault.  So, I decided to multiply the reading by 1000 and return the result as an integer (that the Java program can divide to get the temperature). 

#include <stdio.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include "tmp102.h"

int getTempC() {
        int devHandle;
        int readBytes;
        char b[2];
        // initialize buffer
        b[0] = 0x00;
        int devI2CAddr = 0x48;
        // open device on /dev/i2c-1
        if ((devHandle = open("/dev/i2c-1", O_RDWR)) < 0) {
                printf("Error: Couldn't open device! %d\n", devHandle);
                return 1;
        }
        // connect as i2c slave
        if (ioctl(devHandle, I2C_SLAVE, devI2CAddr) < 0) {
                printf("Error: Couldn't find device on address!\n");
                return 1;
        }
        // begin transmission and request acknowledgement
        readBytes = write(devHandle, b, 1);
        if (readBytes != 1)
        {
                printf("Error: No ACK-Bit, couldn't establish connection!");
        }
        else
        {
                // read response
                readBytes = read(devHandle, b, 2);
                if (readBytes != 2)
                {
                        printf("Error: Received no data!");
                }
                else
                {
                        float t = (((b[0] << 8) | b[1]) >> 4) * 0.0625;
                        return (int)(t*1000);
                }
        }
        // close connection and return
        close(devHandle);
        return 1;
}


The following command compiles the code to a shared library (tmp102.so).

gcc tmp102.c -o tmp102.so -shared

Copy the resulting tmp102.so file to the directory with the JNA JAR files (/usr/share/java).


Java Code


The first part of the Java code is the interface file (Tmp102Library.java):

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface Tmp102Library extends Library {
   Tmp102Library INSTANCE = (Tmp102Library) Native.loadLibrary("tmp102.so",
        Tmp102Library.class);
   int getTempC();
}

Here is the Java code for the program that uses the interface to access the library via JNA:

import com.sun.jna.Library;

public class tmp102 {
        public static void main(String[] args) {
                System.setProperty("jna.library.path","/usr/share/java");
                try {
                        float temp = Tmp102Library.INSTANCE.getTempC()/1000F;
                        System.out.println("Temp: " + Float.toString(temp));
                } catch(Exception e) {
                        e.printStackTrace();
                }
        }

}


The following commands compile the Java files:

javac -cp /usr/share/java/jna-4.0.0.jar:/usr/share/java/jna-platform-4.0.0.jar Tmp102Library.java

javac -cp /usr/share/java/jna-4.0.0.jar:/usr/share/java/jna-platform-4.0.0.jar:. tmp102.java

The following command runs the program:

java -cp /usr/share/java/jna-4.0.0.jar:/usr/share/java/jna-platform-4.0.0.jar:. tmp102

Wednesday, October 2, 2013

Oracle Java (JDK) 7 on the Beaglebone Black

Last May I posted about installing OpenJDK 6 on the Beagleone Black.  I now see that there are instructions on the BeagleBoard.org Web site for installing Oracle Java (JDK) 7 on the Beaglebone Black.  The process is very simple and I had no problems with the installation.  No additional components are needed to get the Linux ARM v6/v7 VFP Soft Float ABI version running on the Beaglebone Black.

To reduce the amount of space taken up by the installation, you can delete the src.zip file included in the tar.gz file.


Tuesday, October 1, 2013

GPS for the Beaglebone Black: Sparkfun Copernicus II DIP Module

Note (06/20/2014) - For an updated and improved version tested on the Beaglebone Black Rev. C running Ubuntu, see this post.

Earlier in the summer, I posted about using the D2523T 50 Channel Helical GPS Receiver with the Beaglebone Black.  I have also found the Copernicus II DIP Module from Sparkfun to be a very good GPS option. At $74.95, the price is similar to the D2532T.  To help with reception indoors at my desk while doing development, I am using this antenna.

The Python code below is very similar to my earlier post, but I have added a line showing how easy it is to write configuration commands to the module using the PySerial library.

For more information on the NMEA configuration commands, see Appendix C of the Copernicus II manual. The command must include a 2-digit checksum after the asterisk.  See this page for an online tool to calculate the checksum.

Connections


GPS Module  Beaglebone Black
VCC         P9 3
GND         P9 1
TX-B        P9 26
RX-B        P9 24

See this post for the configuration needed to use the Beaglebone Black's pins for serial (UART) communication.


Python Code



import serial
import time
import datetime
import re
import os

os.system("echo uart1 > /sys/devices/bone_capemgr.9/slots")

# Adjust the connection speed as needed. 
# You can use Triimble Studio on your PC to detect/set speed
# if you can't figure it out. 
serial = serial.Serial("/dev/ttyO1", baudrate=115200)

# Send NMEA config cmd to output only $GPRMC message every second
nmeaCmd = "$PTNLSNM,0100,01*56\r\n"
serial.write(nmeaCmd)

resp = ""

while True:
        while (serial.inWaiting() > 0):
                resp += serial.read()
                if "\r\n" in resp:
                        if "$GPRMC" in resp:
                                data = resp.split(',')
                                info = "UTC: %s  Date: %s  N Lat: %s  W Long: %s" % (
                                        data[1], data[9], data[3], data[5])
                                print info
                        resp = ""

Thursday, June 6, 2013

GPS for the Beaglebone Black: D2523T 50 Channel Helical GPS Receiver

The 50 Channel D2523T Helical GPS Receiver is a pricier GPS choice at $79, but I find that it works better than the cheaper 50 Channel GP-635T GPS Receiver ($39). I live in a multistory building in downtown Minneapolis. I can only get the GP-635T to work (sometimes) out on my balcony.  D2523T Helical GPS Receiver works inside near a window or glass door. Once it has acquired a signal, I can move it 12 to 15 back from the door or window without losing the signal.

[Note: As of October, 2013, Sparkfun no longer carries thie D2523T, but a Google search will locate other sources.]

I'm using this interface cable to connect the D2523T GPS module to this GPS breakout on a breadboard.

Connections 


GPS Breakout  Beaglebone Black
Pin 3 (3V3)   P9 3
Pin 4 (GND)   P9 1
Pin 5 (TX)    P9 26
Pin 6 (RX)    P9 24

See this post for the configuration needed to use the Beaglebone Black's pins for serial (UART) communication.


Python Code


The following code pulls the latitude and longitude from the $GPRMC sentence.

import serial
import time
import datetime
import re
import os

os.system("echo uart1 > /sys/devices/bone_capemgr.9/slots")

serial = serial.Serial("/dev/ttyO1", baudrate=9600)

resp = ""

while True:
        while (serial.inWaiting() > 0):
                resp += serial.read()
                if "\r\n" in resp:
                        if "$GPRMC" in resp:
                                data = resp.split(',')
                                info = data[3] + " " + data[4] + " " + data[5] + " " + data[6]
                                print info
                        resp = ""

Sunday, June 2, 2013

Reading Barometric Pressure with a Beaglebone Black & an Adafruit BMP085 Breakout Board

The Adafruit version of the BMP085 - BMP085 Barometric Pressure/Temperature/Altitude Sensor - is a barometer that connects to the Beaglebone Black via I2C.  The information on the Adafruit page says it is 5 volt ready, but it also works nicely with the 3.3 volt Beaglebone Black.

The example below shows how to read the barometric pressure (compensated for temperature and elevation above sea level). I've adapted this from the Adafruit library for the BMP085.


Connections


TMP085  Beaglebone Black
GND     P9 Pin 1
VIN     P9 Pin 3
SCL     P9 Pin 19
SDA     P9 Pin 20 


Python Code


import time
import smbus

bus = smbus.SMBus(1)
mode = 3
i2c_addr = 0x77

def read_word_signed(addr, reg):
msb = bus.read_byte_data(addr, reg)
if msb > 127: msb -= 256
lsb = bus.read_byte_data(addr, reg+1)
return (msb << 8) + lsb

def read_word_unsigned(addr, reg):
msb = bus.read_byte_data(addr, reg)
lsb = bus.read_byte_data(addr, reg+1)
return (msb << 8) + lsb

# Read factory programmed parameters
# These are used for calculations 
AC1 = read_word_signed(i2c_addr, 0xAA)
AC2 = read_word_signed(i2c_addr, 0xAC)
AC3 = read_word_signed(i2c_addr, 0xAE)
AC4 = read_word_unsigned(i2c_addr, 0xB0)
AC5 = read_word_unsigned(i2c_addr, 0xB2)
AC6 = read_word_unsigned(i2c_addr, 0xB4)
B1 = read_word_signed(i2c_addr, 0xB6)
B2 = read_word_signed(i2c_addr, 0xB8)
MB = read_word_signed(i2c_addr, 0xBA)
MC = read_word_signed(i2c_addr, 0xBC)
MD = read_word_signed(i2c_addr, 0xBE)

while True:
# read temperature cmd
bus.write_byte_data(i2c_addr, 0xF4, 0x2E) 
time.sleep(0.005)  # Wait 5ms
msb = bus.read_byte_data(i2c_addr, 0xF6)
lsb = bus.read_byte_data(i2c_addr, 0xF6+1)
raw_temp = (msb << 8) + lsb

X1 = ((raw_temp - AC6) * AC5) >> 15
X2 = (MC << 11) / (X1 + MD)
B5 = X1 + X2
# Read pressure cmd
bus.write_byte_data(i2c_addr, 0xF4, 0x34 + (1 << 6)) 
time.sleep(0.026)
msb = bus.read_byte_data(i2c_addr, 0xF6)
lsb = bus.read_byte_data(i2c_addr, 0xF6+1)
xlsb = bus.read_byte_data(i2c_addr, 0xF6+2)
raw_ps = ((msb << 16) + (lsb << 8) + xlsb) >> (8-mode)

B6 = B5 - 4000
X1 = (B2 * (B6 * B6) >> 12) >> 11
X2 = (AC2 * B6) >> 11
X3 = X1 + X2
B3 = (((AC1 * 4 + X3) << 3) + 2) / 4
X1 = (AC3 * B6) >> 13
X2 = (B1 * ((B6 * B6) >> 12)) >> 16
X3 = ((X1 + X2) + 2) >> 2
B4 = (AC4 * (X3 + 32768)) >> 15
B7 = (raw_ps - B3) * (50000 >> mode)

if (B7 < 0x80000000):
p = (B7 * 2) / B4
else:
p = (B7 / B4) * 2

X1 = (p >> 8) * (p >> 8)
X1 = (X1 * 3038) >> 16
X2 = (-7357 * p) >> 16
# Pressure in Pascals
p = p + ((X1 + X2 + 3791) >> 4)
p = p * 0.000295333727 # Convert to inches Hg
# Adjust for elevation: Add 1200 Pa / 100 meters in elev.
# MPLS is 264m above sea level
# Converted to inches Hg this is 0.935
print p + 0.935 
time.sleep(10)


Saturday, May 25, 2013

RFID via USB for the Beaglebone Black or pcDuino Using the Innovations ID-20LA & Sparkfun RFID USB Board

The Innovations ID-20LA is a 125 kHz RFID tag reader that works with input voltages from 2.8 to 5 volts. The Sparkfun RFID USB Reader (Board) provides a socket for the ID-20LA (with its 2mm pin spacing) a mini-USB (B) connector, and broken out pins for a serial connection.

Using the mini-USB connection, it is very easy to connect it to the Beaglebone Black.  The Ångström Linux distribution that comes installed on the Beaglebone Black includes the FTDI-SIO driver/kernel module, so no additional drivers are needed. When connected to the Beaglebone, the RFID reader is mapped to the serial device /dev/ttyUSB0.

For a Python script to read from a serial device, you do need to install the PySerial package (opkg install python-pyserial).


Python Code


import serial
serial = serial.Serial("/dev/ttyUSB0", baudrate=9600)

code = ''

while True:
        data = serial.read()
        if data == '\r':
                print(code)
                code = ''
        else:
                code = code + data

pcDuino 


When working with the pcDuino, everything is the same as for the Beaglebone, except for the command to install the PySerial package. On the pcDuino use the command apt-get install python-serial.

Friday, May 24, 2013

Adafruit TTL Serial JPEG Camera & the Beaglebone Black

The Adafruit TTL Serial JPEG Camera is a 5 volt device, but the serial (TTL) voltage is only 3.3 volt, so it is safe to use with the 3 volt pins on the Beaglebone Black.

See this post for information on how to configure the UART1 (/dev/ttyO1) pins.  This needs to be done every time the Beaglebone Black is rebooted.

Connections


Camera  Beaglebone Black
+5V     P9 7  (SYS_5V)
GND     P9 1  (GND)
RX      P9 24 (uart1_txd)
TX      P9 26 (uart1_rxd)


Code


The following Python code sets the picture size to 640 x 480 pixels, takes a picture and saves it to the /tmp directory with a file name made up of the date and time (including seconds, so duplicate names shouldn't be a problem).

import serial
import time
import datetime

# Initialize camera
serial = serial.Serial("/dev/ttyO1", baudrate=38400)
serial.write(b'\x56\x00\x26\x00')
resp = ""
time.sleep(1)
while(serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if "Init end\r\n" in resp:
                print "Ready"
                break

# Set image size to 640 x 480
serial.write(b'\x56\x00\x54\x01\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x54\x00\x00' in resp:
                print "Size set"
                break

# Take picture
serial.write(b'\x56\x00\x36\x01\x00')
resp = ""
time.sleep(2)
while(serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x36\x00\x00' in resp:
                print "Picture taken"
                break

#Get JPG size
serial.write(b'\x56\x00\x34\x01\x00')
resp = ""
time.sleep(1)
while(serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x34\x00\x04\x00\x00' in resp:
                msb = serial.read()
                lsb = serial.read()
                print "Image file size: %d bytes" % (ord(msb) << 8 | ord(lsb))

# Write image to file
serial.write(b'\x56\x00\x32\x0C\x00\x0A\x00\x00\x00\x00\x00\x00%c%c\x00\x0A'
% (msb,lsb))
time.sleep(5)
now = datetime.datetime.now()
filename = "%d.%02d.%02d.%02d.%02d.%02d.jpg" % \
(now.year,now.month,now.day,now.hour,now.minute,now.second)
resp = serial.read(size=5)
if b'\x76\x00\x32\x00\x00' in resp:
        with open("/tmp/" + filename, 'wb') as f:
                while(serial.inWaiting() > 0):
                        data = serial.read()
                        f.write('%c' % data)
        print "Image written to /tmp/%s" % (filename)


Example Serial Communication between an Arduino & a Beaglebone Black (Beaglebone Black Side)

This is the Beaglebone Black portion of the example of serial communication between an Arduino Uno and a Beaglebone Black.  Click here for the Arduino portion of this example.  As noted in the Arduino posting, this example uses an RFID card reader (as part of a larger project), but it is intended as an example of serial communication, not as a complete RFID application.


Connections


See the Arduino portion of this example for information on how to connect the Arduino Uno and the Beaglebone Black (including the logic level converter).

To configure the UART/serial port on the Beaglebone Black, see this post.


Python Code


For this code to work, you need to have  the PySerial package installed. Use the command opkg install python-pyserial to install it (assuming that you are running Ångström Linux).

This program reads the data sent from the Arduino via the serial connection.  The RFID card data from the Arduino begins with a ^ and ends with \r\n.  As the code stands for now, the Beaglebone Black responds to to the received data by sending the card number back with the status message OK and the current date and time. The application will ultimately need to check the RFID tag number against a database and record the use of the tag, but this example is really just intended to show an example of serial communication.


import serial
import time
import datetime
import re

serial = serial.Serial("/dev/ttyO1", baudrate=38400)

resp = ""

while True:
        while (serial.inWaiting() > 0):
                data = serial.read()
                resp += data
                if "\r\n" in resp:
                        now = datetime.datetime.now()
                        timestamp = "%02d/%02d/%d %02d:%02d:%02d" % \
                        (now.month,now.day,now.year,now.hour,now.minute,now.second)
                        matchObj = re.match(r'\^([0-9A-F]+)\r\n', resp)
                        print matchObj.group(1)
                        resp = ""
                        serial.flush();
                        serial.write(matchObj.group(1) + " OK: " + timestamp + "\n")

Thursday, May 23, 2013

uart1.dts: Configuration File to Enable UART1 on Beaglebone Black


Configuring the pins on the Beaglebone Black is different (more complex?) than the configuration process on the Beaglebone. The following configuration file and notes on its use are taken from the new book, Bad to the Bone: Crafting Electronic Systems with the Beaglebone and Beaglebone Black by Steven F Barrett and Jason Kridner (pp. 219-20).  This is also available from various places on the Web, but I'm posting it here for my own reference (and for use by anyone who finds it here).

I've made a couple changes in the steps described in the notes because of a difference in a directory name.


/* Copyright (C) 2013 CircuitCo
 * Copyright (C) 2013 Texas Instruments
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Genral Public License version 2 as
 * published by the Free Software Foundation.
 */

/dts-v1/;
/plugin/;

/ {
    compatible = "ti,beaglebone", "ti,beaglebone-black";

    /* identification */
    part-number = "uart1";
    version = "00A0";

    fragment@0 {
        target = <&am33xx_pinmux>;
        __overlay__ {
            pinmux_serial1: pinmux_serial1_pins {
                pinctrl-single,pins = <
             0x184 0x20 /*P9_24(ZCZ ball D15) RX-enabled MODE 0*/
             0x180 0x20 /*P9_26(ZCZ ball D16) RX-enabled MODE 0*/
            >;
                };
            };
    };
    
    fragment@1 {
        target = <&ocp>;
        __overlay__ {
    serial1_pinmux_helper {
        compatible = "bone-pinmux-helper";
        status     = "okay";
        pinctrl-names = "default";
            pinctrl-0 = <&pinmux_serial1>;
            };
        };
    };
    
    fragment@2 {
        target = <&uart2>;   /* really uart1 */
        __overlay__ {
            status = "okay";
        };
    };
};

//***************************************************************************
//uart1.cpp - configures BeagleBone uart1 for transmission and 9600 Baud
// and repeatedly sends the character G via uart1 tx pin (P9, 24)
//
// To configure the UART first do:
// # dtc -O dtb -o uart1-00A0.dtbo -b 0 -@ uart1.dts
// # cp uart1-00A0.dtbo /lib/firmware/uart1-00A0.dtbo
// # echo uart1 > /sys/devices/bone_capemgr.9/slots
// # Path for the command above may vary -
// # echo uart1 > /sys/devices/bone_capemgr.8/slots
//
//Check that the pinmux has been configured via:
// # cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pinmux-pins
// pin 96 (44e10980): serial1_pinmiux_helper.14 (GPIO UNCLAIMED)
//function pinmux_serial1_pins group pinmux_serial1_pins
// pin 97 (44e10984): serial1_pinmux_helper.14 (GPIO UNCLAIMED)
//funcion pinmux_serial1_pins group pinmux_serial1_pins
//
//***************************************************************************

Note (June 10, 2013):  After rebooting the Beaglebone Black, the echo command needs to be run again. Including a line like this in a Python script runs the echo command. You may need to adjust the path, as noted above.

os.system("echo uart1 > /sys/devices/bone_capemgr.9/slots")

Wednesday, May 22, 2013

Taking Larger Pictures with a pcDuino & a LinkSprite JPEG Color Camera (TTL Interface)

I posted a couple days ago about using the LinkSprite JPEG Color Camera (TTL Interface) to take pictures with a pcDuino. The default image size is 320 x 240 pixels.  From reading some of the comments online, it sounded like some people had problems changing the image size. I have found, however, that I can switch the image size to 640 x 480 without any trouble.  The only change, in addition to issuing the command to change the image size, is the longer pause after the read image data command.

Here is the revised code for taking pictures measuring 640 x 480 pixels -


import serial
import time
import datetime

# Initialize camera
serial = serial.Serial("/dev/ttyS1", baudrate=38400)
serial.write(b'\x56\x00\x26\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
data = serial.read()
resp += data
if "Init end\r\n" in resp:
print "Ready"
break

# Set image size to 640 x 480
serial.write(b'\x56\x00\x54\x01\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x54\x00\x00' in resp:
                print "Size set"
                break


# Take picture
serial.write(b'\x56\x00\x36\x01\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
data = serial.read()
resp += data
if b'\x76\x00\x36\x00\x00' in resp:
print "Picture taken"
break

#Get JPG size
serial.write(b'\x56\x00\x34\x01\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
data = serial.read()
resp += data
if b'\x76\x00\x34\x00\x04\x00\x00' in resp:
msb = serial.read()
lsb = serial.read()
print "Image file size: %d bytes" % (ord(msb) << 8 | ord(lsb))

# Write image to file
serial.write(b'\x56\x00\x32\x0C\x00\x0A\x00\x00\x00\x00\x00\x00%c%c\x00\x0A' % (msb,lsb))
time.sleep(7)  # Increased to 7 seconds, otherwise image is clipped 
now = datetime.datetime.now()
filename = "%d.%02d.%02d.%02d.%02d.%02d.jpg" % \
(now.year,now.month,now.day,now.hour,now.minute,now.second)
resp = serial.read(size=5)
if b'\x76\x00\x32\x00\x00' in resp:
with open("/var/www/" + filename, 'wb') as f:
while (serial.inWaiting() > 0):
data = serial.read()
f.write('%c' % data)
print "Image written to /var/www/%s" % (filename)


Note that this approach to changing image size is not permanent - you will need to set the size every time.

While changing the image size does not pose any problems from what I have seen, changing the baud rate of the camera is a very different matter. I have read several posts online indicating that people have rendered the camera inoperable by trying to change the baud rate.

Sunday, May 19, 2013

Taking Pictures with a pcDuino & a LinkSprite JPEG Color Camera (TTL Interface)

Here is a very basic example showing how to use the LinkSprite JPEG Color Camera (TTL Interface) from Sparkfun with a pcDuino.

The user manual for the camera is available here.

Note (May 24, 2013): I have also gotten a TTL Serial JPEG Camera with NTSC Video from Adafruit. It is the same camera as the Linksprite Sparkfun (with some minor differences in the board and the connector).  The material presented below also works with the Adafruit camera. Adafruit Learning systems has a tutorial on using the camera with an Arduino and a utility for testing the camera.  They also have code on their GitHub site that includes some python examples apparently intended for the Raspberry Pi.

Connections


The labels for the connections on the camera board are just above the connector.

Camera pcDuino
TV     Not Connected
RXD    Digital Pin 1 (TX)
TXD    Digital Pin 0 (RX)
GND    GND
VCC    5V

Note: If you have problems with getting serial I/O to work on the pcDuino's 0 and 1 pins, try the setuart2 utility discussed in the pcDuino forum.

Python Code


The following code is designed to be run from the command line on the pcDuino. It just takes a picture and saves it to a file in the /tmp/ directory. The file name is made up of the current date and time (down to seconds).   

import serial
import time
import datetime

# Initialize camera
serial = serial.Serial("/dev/ttyS1", baudrate=38400)
serial.write(b'\x56\x00\x26\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if "Init end\r\n" in resp:
                print "Ready"
                break

# Take picture
serial.write(b'\x56\x00\x36\x01\x00')
resp = ""
time.sleep(2)
while (serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x36\x00\x00' in resp:
                print "Picture taken"
                break

#Get JPG size
serial.write(b'\x56\x00\x34\x01\x00')
resp = ""
time.sleep(1)
while (serial.inWaiting() > 0):
        data = serial.read()
        resp += data
        if b'\x76\x00\x34\x00\x04\x00\x00' in resp:
                msb = serial.read()
                lsb = serial.read()
                print "Image file size: %d bytes" % (ord(msb) << 8 | ord(lsb))

# Write image to file
serial.write(b'\x56\x00\x32\x0C\x00\x0A\x00\x00\x00\x00\x00\x00%c%c\x00\x0A' % (msb,lsb))
time.sleep(3)
now = datetime.datetime.now()
filename = "%d.%02d.%02d.%02d.%02d.%02d.jpg" % \
        (now.year,now.month,now.day,now.hour,now.minute,now.second)
resp = serial.read(size=5)
if b'\x76\x00\x32\x00\x00' in resp:
        with open("/tmp/" + filename, 'wb') as f:
                while (serial.inWaiting() > 0):
                        data = serial.read()
                        f.write('%c' % data)
        print "Image written to /tmp/%s" % (filename)


If you are interested in changing the image size, see this post