Wednesday, November 21, 2012

Watchdog timer again

The last post outlined a code change that pinged a watchdog timer periodically so that when the program hung the system would reboot. That has been working well so far.

However, it also allowed the system to be reset/rebooted via a command, which I was unable to do via any previously known method. Simply put, to reset the board, while the /dev/watchdog file is still open, simply delay for more than the timer timeout period (about 60 seconds.) The timer will go off and cause a board reset.

I added a command, sent via a text message, that causes just this timeout and subsequent reset/reboot. So, now I can reset/reboot the board by simply sending that command.

Monday, November 5, 2012

Further Bullet Proofing: watchdog timer

Having implemented the previously described circuit and associated code to reset the GSM modem via a USB power cycle when communications with it shut down, there were still occasions when the beaglebone board would lock up, and cease further communications with either the network or the USB-based terminal gadget.

So, I decided that a watchdog timer would provide a last line defense against this sort of "crash." The beaglebone has a special watchdog timer that can be used for just this purpose. When the file /dev/watchdog is open, absence of a write to it for more then about one minute will cause the entire board to reset and reboot.

I added code to beagelgsm.tcl that opened the file just after startup, and then wrote to it once each main loop, which seemed from inspection to provide much more frequent writes than required to keep the watchdog timer from timing out and resetting the board. I added code to measure loop time and log any times greater than about 30 seconds, to get a sense of what the loop times were.

The system is now up and running, as of about 6 PM November 5, 2012.

Tuesday, August 14, 2012

Beaglebone Analog Input read() results in 4 bytes

After writing some C code to read the analog inputs, it became clear that reading analog inputs via the file system (.../ain1, etc.), the system returns 4 bytes for each read. The bytes are the ASCII characters for the digits 0-9 (values got from 0-4095), and if the reading is less than 4 digits, the byte = \x00 is placed in trailing locations. The \x00 byte is the string terminator for C, and is not present for readings that are 4 digits long. This could explain why channels shift when reading the analog values via Tcl reads: the area the 4-byte value is read into might not have a string terminator.

So, the technique is to read into a buffer of 5 or more bytes, then make sure the 5th byte is a \x00 by either setting the whole area to \x00 first or storing \x00 there after the read, then the C string will be properly terminated.

Friday, August 10, 2012

Recoding Analog and GSM Modem drivers in C

I have referred to problems with the analog inputs shifting channels and GSM modem hangups often in the blog. Since I've been coding in Tcl, I thought that it might be hiding some behavior or data behind its own layer of software. To investigate this I recoded the analog input and GSM modem interface in C language. Since I've done so I've not seen any problems, but then I've only written test programs. I still need to rewrite the bulk of the monitor in C.

I've been off doing other stuff here in New Hampshire and will not be back to this for a week or so. More then hopefully.

Monday, July 23, 2012

Very strange Beaglebone analog input behavior

As mentioned some time ago, the analog channels seem to shift with time. The input connected to channel 3 (ain3) for instance shifts to ain4 after some time (maybe days.) Rebooting the beaglebone seems to restore correct operation. This shifting makes the board analog inputs worthless for reading sensors, due to the unreliability.

I tried various workarounds, and the latest is to read each channel twice in a row, separated by an 'lseek()' on the channel. It works so far.

Here's the code (tcl) for a library with two functions that read 7 analog inputs, returning either raw bits (0-4095) or voltages (0-1.8V):


;# Read 7 analog inputs of beaglebone board and
;# return as either list of 8 decimal values as voltages,
;# or list of raw bit values from 0-4095.
;# Note pin on P9 vs ain* and return list index correspondence:
;#
;# 0 ain1  Not connected to pin
;# 1 ain2  P9-39
;# 2 ain3  P9-40
;# 3 ain4  p9-37
;# 4 ain5  p9-38
;# 5 ain6  p9-33
;# 6 ain7  p9-36
;#...

package provide beagleio 0.1
namespace eval beagleio {

    variable initialized 0
    variable fds

    # Open all analog 'channels' (actually files in Angstrom)

    proc init {} {
        variable fds
        for {set i 1} {$i < 7} {incr i} {
            set fds($i) [open /sys/devices/platform/tsc/ain$i r]
        }
    }

    proc beaglearead_v {} {
        variable fds
        variable initialized
        if {$initialized == 0} {
            beagleio::init
            set initialized 1
        }
        set vl {}
        for {set i 1} {$i < 7} {incr i} {
            ;# Who the hell knows why we need to do this twice to read the right channel
            ;# consistently? But we do...
            seek $fds($i) 0
            set val [read $fds($i)]
            seek $fds($i) 0
            set val [read $fds($i)]
            ;#puts "Debug: beaglearead_b: read (length [string length $val]) value $val from channel $i"
            ;# delete characters = 0x0 ,since these get sent back when analog file is read.
            regexp {(\d+)} $val all val
            ;#puts "Debug: beaglearead_b: modified value (length [string length $val]) is $val from channel $i"
            ;# Convert to voltages: 0-4095 full scale = 1.8 volts.
            lappend vl [format %6.3f [expr 1.8 * $val/4096]]
        }
        return $vl
    }
    proc beaglearead_b {} {
        variable fds
        variable initialized
        if {$initialized == 0} {
            beagleio::init
            set initialized 1
        }
        set vl {}
        for {set i 1} {$i < 7} {incr i} {
            # Who the hell knows why we need to do this twice to read the right channel
            # consistently? But we do...
            seek $fds($i) 0
            set val [read $fds($i)]
            seek $fds($i) 0
            set val [read $fds($i)]
            #puts "Debug: beaglearead_b: read (length [string length $val]) value $val from channel $i"
            ;# delete characters = 0x0 ,since these get sent back when analog file is read.
            regexp {(\d+)} $val all value
            ;#regsub -all {\x000} $val {} val
            ;#puts "Debug: beaglearead_b: modified value (length [string length $val]) is $val from channel $i"
            lappend vl $value
        }
        return $vl
    }
}


Tuesday, July 17, 2012

Connecting to Beaglebone USB Serial port from Ubuntu


Open a Ubuntu termial window, resize it to whatever you want it to be while logged on to the Beaglebone, find the LINES and COLUMNS ($ echo $LINES $COLUMNS) and remember them, then run screen command to get connection to Beaglebone USB serial port:

john@john-ThinkPad-T42:~$ screen /dev/ttyUSB1 115200
.---O---.                                          
|       |                  .-.           o o       
|   |   |-----.-----.-----.| |   .----..-----.-----.
|       |     | __  |  ---'| '--.|  .-'|     |     |
|   |   |  |  |     |---  ||  --'|  |  |  '  | | | |
'---'---'--'--'--.  |-----''----''--'  '-----'-'-'-'
                -'  |
                '---'

The Angstrom Distribution beaglebone ttyO0

Angstrom v2012.03-core - Kernel 3.2.13

beaglebone login: 


After logging on, run the 'stty' command to set lines and columns, like:


$ stty rows 30
$ stty columns 109 


When logging on using ssh, if Beaglebone is on the network, the stty commands are unnecessary. BTW, I use and Asus portable wireless access point connected to the Beaglebone ethernet connector to get on the net.

Wednesday, July 4, 2012

Upgrade notes

Problems with reading analog channels consistently made the current system unreliable. So, I tried a new Angstrom drop (dated June 18th, 2012.) That did not work due to GSM modem (/dev/ttyHS*) problems, whereby the system somehow kept doing something to the Icon modem keeping it from registering with AT&T. The new drop was:

Angstrom-Cloud9-IDE-GNOME-eglibc-ipk-v2012.05-beaglebone-2012.06.18.img.xz

So, I decided to just try upgrading the current system. I copied an image of the current working system from the 4GB microSD card to a new card (using linux 'dd if=/dev/sdb of=/dev/sdc', where /dev/sdb is the original microsd card and /dev/sdc is the new fresh card) , then tried doing 'opkg update', 'opkg upgrade' with the new microsd card copy. I moved the new kernel (3.2.14) to the right place as discussed in this blog previously. Then I installed from ipk files tcl, tcllib and modeswitch. Modeswitch install  failed due to problems with the names of perl package files, so I added perl package links:

ln -s /var/lib/opkg/info/perl-module-build.list /var/lib/opkg/info/perl-module-build.pm.list
ln -s /var/lib/opkg/info/perl-module-load.list /var/lib/opkg/info/perl-module-load.pm.list


which made the modeswitch opkg install of modeswitch work.
 

After all that, the analog channel shifting seems to still be a problem. So, on the hunch that a delay was needed between reading channels I added 0.1 seconds in the loop that reads channels. We will see how this turns out.


Later: Badly. Problem still there. Channel 1 is at ain1 at first, then ain2 later.  So, on the hunch that the problem had something to do with the files descriptor pointer, I tried doing a 'seek()' to rewind file and that has worked so far.