Tuesday 31 January 2012

Bluetooth, Teensy and Linux

Notes on integrating a BTM400-6B Bluetooth module from Hong Kong Electronics on ebay, with a Teensy 2.0. The bluetooth module is currently USD$7. Here's what I did:

  1. Soldered the Bluetooth module to the breakout board supplied by the vendor. This breaks out GND, 5V, Tx, Rx, PIO8/State (wired to a status led on the board) and PIO11/Key - when this is high the board is in "command mode", when it's low it's in data mode. Unfortunately RESET isn't broken out, so I've soldered an additional wire onto that pin.
  2. Wired as follows:
    • Teensy P7 - BTM400 Tx
    • Teensy P8 - BTM400 Rx
    • Teensy P13 - BTM400 PIO11/Key
    • Teensy P14 - BTM400 Reset
    • plus 5V and GND to both - BT module is 3.3V but the breakout board includes a voltage regulator
  3. Wrote a quick echo app for the Teensy
#define LED 11
#define BTKEY 13
#define BTRESET 14

HardwareSerial bt = HardwareSerial();
boolean command = true;
int plus = 0;

void setup() {
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  pinMode(BTKEY, OUTPUT);
  pinMode(BTRESET, OUTPUT);
  digitalWrite(LED, command ? HIGH : LOW);
  digitalWrite(BTKEY, command ? HIGH : LOW);
  digitalWrite(BTRESET, HIGH);
  bt.begin(38400);
}

void loop() {
  int c;
  
  if (Serial.available() > 0) {
    c = Serial.read();
    if (c == 27 && command) {
      Serial.println("Resetting!");
      digitalWrite(BTRESET, LOW);
      delay(10);
      digitalWrite(BTRESET, HIGH);
    } else if (c == '+') {
      if (command) {
        Serial.write(c);
      }
      if (++plus == 3) {
        command = !command;
        digitalWrite(BTKEY, command ? HIGH : LOW);
        digitalWrite(LED, command ? HIGH : LOW);
        Serial.println(command ? "Entering command mode" : "Leaving command mode");
        plus = 0;
      }
    } else { 
      while (plus > 0) {
        bt.write('+');
        plus--;
      }
      bt.write(c);
      if (command) {
        Serial.write(c);
      }
      // BT module will continue sending response until it gets 0x10
      if (c == '\r') {
        bt.write('\n');
        if (command) {
          Serial.write('\n');
        }
      }
    }
  }

  if (bt.available() > 0) {
    c = bt.read();
    Serial.write(c);
  }
}

This will start the module in command mode, and relay input from the USB to the BT module (echoing the input). An input of "+++" will switch the module to data mode, and another "+++" from the USB end will switch it back to command - old school modem stuff (technically I should check for a ½ second delay before and after +++). If I press ESC while in command mode, the BT module will do a hard reset by dropping RESET for 10ms. Finally the Teensy 2.0 LED on P11 is lit when in command mode.

USB Comms

Communicating with this was done using "screen", which is on OS X and Linux. Nothing else seemed to work properly. Broadly, with device wired in as described fire up
screen /dev/cu.usbmodem12341 9600
on OS X to connect (your USB dev might be elsewhere, and this is after installing the Teensy dev environment and drivers, as described here). This will connect you to the USB end of the link. Type "AT" then enter and you should get back "OK". Here's a dialog of one session
AT
OK
AT+VERSION?
+VERSION:2.0-20100601
OK
AT+INIT
OK
AT+CLASS?
+CLASS:0
OK
AT+ROLE?
+ROLE:0
OK
AT+IAC?
+IAC:9e8b33
OK
AT+INQM?
+INQM:1,9,48
OK
AT+PSWD?
+PSWD:1234
OK
AT+UART?
+UART:9600,0,0
OK
AT+CMODE?
+CMOD:0
OK
AT+BIND?
+BIND:0:0:0
OK
AT+POLAR?
+POLAR:0,1
OK
AT+MPIO?
+MPIO:900
OK
AT+SNIFF?
+SNIFF:0,0,0,0
OK
AT+SENM?
+SENM:0,0
OK
AT+ADCN?
+ADCN:2
OK
AT+MRAD?
+MRAD:15:83:15a310
OK
AT+STATE?
+STATE:INITIALIZED
OK
AT+INQ
OK
AT+INQM=1,9,48
OK
AT+INQ
OK
AT+CLASS=0
OK
AT+INQ
OK
AT+INQC
OK
OK
AT+STATE
+STATE:PAIRED
OK
AT+ADCN?
+ADCN:2
OK
Of note is that AT+INQ doesn't find any devices. However switch it into Master role with AT+ROLE=1 then AT+INQ finds my Macbook:
AT+ROLE=1
OK
AT+INQ
+INQ:58B0:35:XXXXXX:3A010C,FFBA
+INQ:58B0:35:XXXXXX,3A010C,FFBD
+INQ:58B0:35:XXXXXX,3A010C,FFBB
+INQ:58B0:35:XXXXXX,3A010C,FFBA
+INQ:58B0:35:XXXXXX,3A010C,FFBB
+INQ:58B0:35:XXXXXX,3A010C,FFB9
+INQ:58B0:35:XXXXXX,3A010C,FFBC
OK
That's one device - last field is signal strength, suitably strong given the two devices are next to eachother. Now to get it talking over the radio.

Bluetooth comms to OS X

Type "+++" to drop PIO11 and put the device into slave pairing mode. Then on OS X, open Bluetooth, add device - the device should appear (called HC-05 for me) then pair it with the code 1234 (the default). This created the character special file /dev/cu.HC-05-DevB and you can connect up to this with screen in another terminal with

screen /dev/cu.HC-05-DevB 9600
Now, with luck, typing in one screen will appear in the other and vice versa.

Bluetoooth comms to Linux

On Ubuntu 11.04 (Natty) with a BT dongle plugged in, after a bit of fiddling the steps appear to be as follows (assuming 00:11:12:09:XX:XX is the BT module address, as discovered by hcitool scan)

hcitool scan
bluez-simple-agent hci0 00:11:12:09:XX:XX
rfcomm bind rfcomm0 00:11:12:09:XX:XX
screen /dev/rfcomm0

hcitool scan should list your BT dongle - if not, check the state (from AT+STATE) is "PAIRING" and that the red light is flashing fast. You should be able to get there with AT+RESET, AT+INIT and AT+ROLE=0.

Step two is bluez-simple-agent which does the initial pairing. This should only need to be done once - it will ask you for the pin code. If the pairing has been deleted on the device, you can force a repairing by passing "remove" in as the third argument.

Step three is rfcomm bind, which connects to the Bluetooth module and creates the file /dev/rfcomm0. From there you should be able to run screen to connect. Once you're done, run rfcomm release 0 to drop the connection.

Issues & Notes

  • If you're sending commands to the device, they're executed immediately on 0x13 (\r), however you must send an 0x10 (\n) immediately after. If you don't the device will repeatedly send you the response until you do.
  • AT+RESET must be followed by an AT+INIT in order to do anything useful (ie become pairable). This is despite AT+STATE returning INITIALIZED
  • BT module sometimes came up in a weird slave mode where the characters relayed to the USB serial aren't what's sent - for instance, sending "eeee" gives an "x" then various bytes > 0x7F. Flicking back and forth to command mode, unplugging & replugging seems to work. This was before I'd wired in the hard reset pin so perhaps it's fixed - I haven't been able to reproduce it since.
  • Device seems to hold several pairings - how many?
  • If you're in command mode when the pairing is established, you get an unprompted "OK". If you're in commend mode on disconnect you get an unprompted "+DISC:SUCCESS" then "OK". You can enter command mode while paired, but leaving it again will drop the connection.
  • According to this page PIO9 is high iff device is paired. I haven't played with the other pins yet, no doubt there's stuff to experiment with.
  • There are lots of pins on the BT module board which don't apply to this firmware, so don't get your hopes up with the Audio I/O pins.
  • The BT module is powered at 3.3V, but I've hooked it up to the Teensy running on 5V - so the BT module' RX pin is receiving 5V and it's sending 3.3V back to the Teensy. This seems to be OK, they're still talking and nothing has started smoking.

Conclusion

A two-way radio data connection that works perfectly with Linux and OS X? Seven bucks well spent

7 comments:

  1. Nice inexpensive solution. With something like this, could you have the Teensy send keyboard strokes to the connected computer system (PC, MAC, Linux, iPhone, Android), acting sort of like another keyboard?

    ReplyDelete
  2. Didn't see this one come in John, sorry.

    No, this chip can't be used for BlueTooth HID - or rather the silicon is undoubtedly capable of it but the firmware doesn't support it, or if it does it's undocumented.

    A colleague had the same question and the cheapest we could find for HID interface was the RN-42, which you can get on a breakout board from Sparkfun: http://www.sparkfun.com/products/10938. It's a lot more expensive.

    ReplyDelete
  3. I'm very interessted in your stuff perhaps you can contact me via email: manfred@lamplmair.eu

    Thank you

    ReplyDelete
  4. Talking about the Bluetooth module. Many latest trends are coming into the field that enable the Bluetooth to cover the night range plus the data communication.

    ReplyDelete
  5. Thank you for a great article!
    I hope you can help me:
    I have 3 HC-05 boards now *sic* and each of them
    exhibits the same "error":

    "AT+ROLE=1"
    -> OK
    "AT+INIT"
    -> OK
    "AT+INQM=1,9,48"
    -> OK
    "AT+INQ"
    -> And now it simply goes out of AT mode, and the LED starts flashing rapidly, and I cant get any info out of it...

    Thinking it was a faulty board, I have now bought 3, but to no avail...

    ReplyDelete
    Replies
    1. I have made a Stack Overflow about the issue. Really hope you can help... http://stackoverflow.com/questions/23221336/hc-05-bluetooth-rssi-not-working-with-arduino

      Delete
    2. No idea, sorry - haven't looked at this in years. Have you tried +++ to get back to AT mode?

      Delete