Category Archives: Electronics

Interfacing to an XBee Module from Python

In a previous post, I described how to talk to an XBee ZigBee module from a FRDM development platform. In this post, I describe how to do it from Python on e.g. a Windows PC.

First, one obviously has to have a Python environment set up on the computer. I use Python 2.7 and the IPython interactive shell. I will not describe how to install that, but it should not be too hard to do using the instructions on the IPython website.

Then we need to install two modules to enable communication with the XBee. The first one is simply called xbee and can be found here. Download, unpack (using e.g. 7-zip), start a cmd window, cd to the folder with the downloaded files and install it by typing:

python setup.py install

The second is pyserial. Download it from here and install it in a similar manner as described above. This module mentions that it is intended for 32-bit windows, but it has worked fine for me on 64-bit Windows 7.

I use a SparkFun XBee Explorer USB board to interface to the XBee module. This provides an FTDI serial port for communication with the XBee. I soldered an LED with a series resistor between DIO1 and GND to provide easy verification that I was able to control the I/Os of the XBee. The XBee needs to be in API mode. If it is not, the XCTU program from Digi can be used to upload a proper firmware to the module.

Here is the program I wrote to test communication with the XBee:

#! /usr/bin/python

# Demo to talk to an XBee ZigBee device
# Per Magnusson, 2015-07-28
 
from xbee import ZigBee
import serial
import serial.tools.list_ports
import time
import sys

# Look for COM port that might have an XBee connected
portfound = False
ports = list(serial.tools.list_ports.comports())
for p in ports:
    # The SparkFun XBee Explorer USB board uses an FTDI chip as USB interface
    if "FTDIBUS" in p[2]:
        print "Found possible XBee on " + p[0]
        if not portfound:
            portfound = True
            portname = p[0]
            print "Using " + p[0] + " as XBee COM port."
        else:
            print "Ignoring this port, using the first one that was found."

if portfound:
    ser = serial.Serial(portname, 9600)
else:
    sys.exit("No serial port seems to have an XBee connected.")

# Flash the LED attached to DIO1 of the XBee
try:
    xbee = ZigBee(ser)
    print "XBee test"

    xbee.at(command='D1', parameter='\x05') # Pin 1 high
    resp = xbee.wait_read_frame()
    print resp

    time.sleep(1)
    xbee.at(command='D1', parameter='\x04') # Pin 1 low
    resp = xbee.wait_read_frame()
    print resp

    # Try another AT command
    xbee.at(command='ID')
    resp = xbee.wait_read_frame()
    print resp
    print "Done"
    ser.close()
except:
    print "Error!"
    ser.close()

raw_input("Press Enter to continue...")

The program has some bells and whistles. First it looks at all the serial ports it can find and selects the first one that could be the XBee (indicated by the text FTDIBUS in the description of the port). It then tries to set up a connection to the ZigBee and issues three local AT commands. The first turns the LED on (then it waits for 1 second), the second turns the LED off and then it issues the ATID command. The response from these commands are printed. At last the serial port is closed and the program waits for the user to press enter to exit the program.

The output may look like this:

In [3]: %run xbee_prog.py
Found possible XBee on COM3
Using COM3 as XBee COM port.
XBee test
{'status': '\x00', 'frame_id': '\x01', 'command': 'D1', 'id': 'at_response'}
{'status': '\x00', 'frame_id': '\x01', 'command': 'D1', 'id': 'at_response'}
{'status': '\x00', 'frame_id': '\x01', 'parameter': '\x00\x00\x00\x00\x00\x00\x0
0\x01', 'command': 'ID', 'id': 'at_response'}
Done
Press Enter to continue...

In [4]:

Stupid mistake

While writing this program I made a stupid mistake that prevented it from working. I happened to name the program xbee.py and this made the line

from xbee import ZigBee

import the program itself, instead of the installed module. The error message was: ImportError: cannot import name ZigBee. Renaming the program from xbee.py to xbee_prog.py solved this issue.

Now that I realize that Python imported the program itself instead of the module, it is obvious why it could not find ZigBee inside it, but it took a while before I figured that one out.

 

Interfacing an XBee Module to a FRDM Board

I am prototyping a wireless sensor node based on a (cheap) FRDM-KL25Z board from Freescale containing an ARM Cortex-M0+ processor and a (not quite as cheap) XBee ZigBee module from Digi. This blog post briefly describes the first steps of the prototyping, namely to get to the point where the XBee is connected to the FRDM board and they talk to each other.

I decided to use the mbed environment to develop the program and in order to do that, I had to change the FRDM board firmware according to these instructions.

For the initial tests, I wanted to write AT commands to the XBee from a terminal on the PC via the FRDM board. The XBee can run any of a number of different firmwares and in order for it to understand AT commands, one of the AT firmwares need to be loaded. This is done using the XCTU program from Digi while the module is connected to a PC serial port, e.g. through the SparkFun XBee Explorer USB board. Below is a screenshot from XCTU showing the major steps to program an AT firmware into the XBee module.

In XCTU, connect to the XBee radio, select it in the left pane, click the button circled in red, select the desired AT firmware (e.g. Router AT) and click update.
In XCTU, connect to the XBee radio, select it in the left pane, click the button circled in red, select the desired AT firmware (e.g. Router AT) and click Update.

The XBee module interface is a 3.3 V serial port running at 9600 baud, and the Cortex-M0+ processor also runs at 3.3 V, so this should match nicely. However, I have the XBee mounted on a Sparkfun XBee Explorer board, which translates the 3.3 V serial port to 5 V levels. The translation is done via pass transistors and pull-up resistors (see the schematic), so it might be OK to connect them directly to the FRDM board, but just to play extra nice with the FRDM board I decided to mod the XBee explorer so that the pull-ups go to the 3.3 V supply instead of the to 5 V supply as shown in the schematic excerpt and the photo below:

Schematic view of the modification of the XBee explorer board to get 3.3 V serial port levels.
Schematic view of the modification of the XBee explorer board to get 3.3 V serial port levels.
Modification for 3.3 V serial port levels. Cut the 5-V track to the pull-up resistors and solder in a wire to 3.3 V instead.
Modification for 3.3 V serial port levels. Cut the 5-V track to the pull-up resistors and solder a wire to 3.3 V instead.

One easy way of physically getting a confirmation of successful communication with the XBee (apart from serial port responses to the AT commands) is to connect an LED to one of the digital I/O-pins. Below is a photo of how I connected an LED to XBee I/O-pin 1.

An LED with a series resistor has been connected to I/O-pin 1 of the XBee.
An LED with a series resistor has been connected to I/O-pin 1 of the XBee.

Now we need to connect the XBee to the FRDM board. There are several pins that can be used as serial I/Os on FRDM-KL25Z and based on the schematics, I happened to select PTE0 (also known as D14 and J2 pin 18) for UART1_TX and PTE1 (also known as D15 and J2 pin 20) for UART1_RX. This pin pair can also used for I2C bus 1, but if I later need to use that bus, I can route it out on PTC10 and PTC11, or I can use different pins for the UART. This page has a picture that may serve as a guide for pin selection. GND and 5V to supply the XBee is available on pins 10 and 12 respectively in the connector J9.

If I had used the simpler breakout board instead of the one with a regulator and level translation, I would not have needed the level translation patch and I would have used the 3.3 V supply from the FRDM board instead of the 5 V supply.

I soldered sockets to the FRDM board connectors J2 and J9 and pin headers to small pieces of prototype board. In one of these I placed a header for the XBee breakout board and then I connected 5V, GND, RX and TX. The whole thing may not be particularly mechanically robust, but it serves its purpose, see photo below.

XBee module connected to a FRDM-KL25Z board.
XBee module connected to a FRDM-KL25Z board.

A program for the FRDM board is of course needed as well. I made it very simple; characters coming from the serial port from the PC are sent on to the XBee and vice versa. Also, characters from the PC are echoed back to the PC. I also flash the RGB LED based on what is happening as further feedback. Here is the code:

#include "mbed.h" 

Serial pc(USBTX, USBRX); 
Serial xbee(PTE0, PTE1); 
DigitalOut redled(LED1); 
DigitalOut greenled(LED2); 
DigitalOut blueled(LED3); 

int main() { 
    char bufchar; 
    
    blueled = 0; // Turn blue led on
    pc.printf("Type what you want to transmit to the XBee.\n\r"); 
    xbee.baud(9600);
    greenled = 1; // Turn green led off
    redled = 1; // Turn red led off
    blueled = 1; // Turn blue led off
    while (1) { 
        if (pc.readable()) { 
            greenled = 0;
            bufchar = pc.getc(); 
            xbee.putc(bufchar); 
            pc.putc(bufchar); // Local echo
            greenled = 1; 
        } 
        if (xbee.readable()) { 
            redled = 0;
            bufchar = xbee.getc(); 
            pc.putc(bufchar); 
            redled = 1;
        } 
    } 
}

To be able to talk to the FRDM board as a USB serial port, a Windows driver is needed. This can be found on the mbed site. As a serial terminal program, I decided to use Tera Term, which is free. I set it up for communication at 9600 bauds with the serial port number that Windows assigned to the FRDM board serial port.

To get into AT command mode in the XBee module, three plus signs (+) must be sent guarded by at least a 1 second pause before and after. The module returns to transparent mode 10 seconds after the last activity on the serial port, so an AT command have to be sent within this time. To test the LED I connected to the XBee module, I use the command ATD14 (set XBee IO pin 1 low) and ATD15 (set XBee IO pin 1 high). For some reason these commands do not take effect until the module reverts to transparent mode, and in order to not have to wait the 10 seconds for a timeout, I issue the ATCN command, which forces the module to immediately go to transparent mode so that the LED update happens. I am not sure it is meant to work this way.

Below is a screenshot of the terminal window showing the commands and the response from the system.

Serial terminal session turning XBee LED on I/O 1 off and then on.
Serial terminal session turning XBee LED on I/O 1 off and then on.

The OK texts come from the XBee module.

So far so good. For the sensor application, I will not use AT commands, but instead use the API mode, but this exercise served as a stepping stone that allowed verification of the connection between the processor board and the XBee module.

Sportident Station with Pulverized Power Pins

While I was updating the firmware of many BSF8 Sportident stations to 6.23, I had a weird failure on a unit with serial number 112297. It may or mat not be related to the voltage measurement bug described on the last page of the release notes of the 6.23 firmware, http://www.sportident.com/images/software/si_boot_firmware_623_release_notes_en.pdf. If I recall correctly, the sequence of events was this:

  • The unit showed a very low voltage reading (2 V or so) and upgrading to 6.23 failed.
  • I opened it up to change the battery and measured the battery voltage with a DMM. It was indeed 2 V or thereabout.
  • Then the station died completely (I am unsure exactly when in the sequence of events this happened, maybe later).
  • I might then have desoldered the old battery and connected the station to an external power supply (3.5 V, limited to about 100 mA) to test it before I connected a new battery. I think I at first got it to work, but then it stopped working again.
  • I looked around the PCB under a microscope and noticed something weird at pin 60 of the microcontroller. Closer inspection showed that the pin was more or less pulverized. The processor datasheet said that it was one of the power supply pins (DVCC2).
  • I tried to repair it, but it turned out that no metal of the pin was sticking out of the package anymore, so there was nothing to solder to.
  • I then noticed that pin 100, AVCC, was also broken and that while pin 1 (DVCC1) was still in one piece, it also seemed to have been damaged since it was thinner than the other pins.

My guess is that a huge amount of current has for some reason flown through the power pins such that they have melted (!). I am pretty sure I did not hook up the external power supply with the wrong polarity and anyway it was current limited to 100 mA or so, so I do not think I caused this by reverse power polarity. Could it be that the processor entered into some kind of state that effectively shorted its supplies and thus consumed a large current?

I guess the reason for the bug behavior in the release notes (a voltage reading of about 2 V) might be caused by an unexpected large current consumption, so it is somewhat consistent with power pins getting destroyed. But it seems a bit unlikely that the relatively wimpy lithium thionyl chloride battery could deliver enough current for this to happen. And I am almost certain that the damage to the pins occurred before I connected an external supply. Quite mysterious.

Update on 2015-07-26

After a discussion through a few emails back and forth with Simon Harston, we have come up with a new hypothesis that could explain the state of the station while not requiring an unrealistically large current that could melt IC pins:

  • For some reason (maybe a manufacturing defect), the battery released corrosive gas/fumes.
  • The corrosive environment  inside the station may have been exacerbated by moisture leaking in.
  • Corrosive and conductive films formed at a number of places inside the station, including around the MCU pins.
  • Leakage current flowed through the film, particularly from the MCU pins with the most positive potential (the VCC pins) to the neighboring GND pins.
  • This current effectively made the VCC pins behave as sacrificial anodes in an impressed current system for cathodic protection and thus made them deteriorate, while the GND pins were unaffected.

If this hypothesis is correct, it explains why just the VCC pins were destroyed. Furthermore, it does not require a current that is probably much higher than the battery could ever deliver. The bluish debris that can be seen in some of the photos (e.g. on the bottom side of the board and near the resistor close to pin 1 of the MCU) might have gotten its blue color from copper ions from the corroding pins, provided the ions could somehow migrate from the pins to the other locations. The fact that the screws are clearly corroded supports the hypothesis that there was a corrosive environment inside the station at some point.

(End of update.)

Below are some pictures of the unit. Unfortunately, I do not have a really good way of taking pictures through a microscope, so most pictures are taken through regular lenses and the one taken through the microscope is blurrier than one could hope for.

The broken SI station.
Top side of the PCB of the broken SI station.
Bottom side of the PCB of the SI station.
Bottom side of the PCB of the SI station.
Bottom plastic cover with some mysterious blue material along the lower side.
Bottom plastic cover with some mysterious blue material along the lower side.
The processor with arrows pointing to the damaged pins.
The processor with arrows pointing to the damaged pins.
Closeup of pin 60 (after I desoldered the lower remains of the pin).
Closeup of pin 60 (after I desoldered the lower remains of the pin).
Pin 100 (AVCC) is broken.
Pin 100 (AVCC) is broken.
Microscope photo of pins 100 (left) and 1 (right). Pin 1 is narrower than the other pins.
Microscope photo of pins 100 (left) and 1 (right). Pin 1 is narrower than the other pins.
This battery with a cracked sleeve may have been in the faulty unit. I am not sure since I mixed up a number of discarded batteries.
This battery with a cracked sleeve may have been in the faulty unit. I am not sure since I mixed up six discarded batteries, two of which had cracked sleeves.