Psion Bluetooth surgery project

Since Psion has two serial UARTs (capable of 230400 bps, full-duplex mode) it seemed logical to use wireless networking device that provides a serial UART interface and wire it up to one of Psion's UARTs. One UART is connected to serial port on the back of Psion, the other one is wired to IRDA transmitter. I can't afford to lose a serial port, that meant IRDA had to go...

Bluetooth module

After a brief research (unfortunately purely "theoretical", since I was severely limited by lack of funding and time to do any practical testing), I decided to try a CSR BlueCore2-external bluetooth module for this project. Here's a short list of reasons which are explained in more details below:

I already had two cheap USB bluetooth dongles to choose from. Both are generic no-name parts which sell for $15 or so a pop here in the US. Both had clear bluish plastic casing thru which you can see internals - small module with two chips located next to each other. That's CSR BlueCore2-external module, and the chips are: BC2 chip itself and a companion flash memory chip. One module was bought back in 2002, the other - quite recently, in May of 2004. Suprisedly, as it turned out, both modules were running the same old version of firmware - build 373 (0x175) which is HCI 14.7 firmware, released by CSR back in June 2002. I opened up the casing (being very careful to not damage PCB and surface-mounted componets) and you can see its internals on the picture below:

As you can see, both modules look very similar. The older one (bottom picture) seems to be a CSR reference design (it has CSR part# BC2MOD2C marking on PCB), the newer one (top picture) looks to be very close to it (maybe another variation of the reference design?), but bears some signs of apparent manufacturing cost-reduction process, i.e. 50Om balun was replaced by copper tracing on dongle's PCB. Both modules feature CSR BC2 chip. Flash memory chips are made by AMD and Eon. These are 4Mbit 3.3V parts.

CSR doesn't provide any "end-user" technical suppport. However, there're literally tons of technical documentation published by CSR which can be found on their suport website . CSR also runs usenet newsgroups which are available to general public. There're some friendly and knowledgable CSR folks monitoring these newsgroups and answering technical questions.

Firmware upgrades

Unfortunately, CSR doesn't allow public access to firmware upgrades, it's limited to developers who bought their SDKs and Casira development kits. Also, firmware can optionally be signed with a key to control future upgrades. Luckly, both of my USB dongles had no problems upgrading ancient HCI 14.7 firmware to more recent Casira's HCI 16.14 firmware that I have obtained from one of the dongle's manufacturer. Firmwares 16.x are the last ones which fit into 4Mbit flash memory. There're firmware release notes available on CSR suport website with list of improvements, bug fixes, known problems, etc.

Power consumption and serial protocol

Power consumption is important to consider when using mobile devices, such as Psion. CSR module supports so-called "Deep Sleep" mode in which it halts its fast crystal clock (16MHz) and most of its digital and analog circuity, including UART. The chip then runs on very slow (only 1KHz) clock to wake up periodically to check for attention condition. During Deep Sleep mode the power consumption falls from ~2.5mA (in idle) to ~0.06mA (DeepSleep). Once the chip detects wake-up condition (i.e. UART RX line becomes active), it leaves Deep Sleep mode.

The following keys control the Deep Sleep behavior and needs to be checked (and possibly adjusted):

There're some technical limitations which need to be considered before starting using Deep Sleep mode, though. Since BC2 runs on slow clock, it could take ~10ms for it to detect condition and wake up. Depending on uart baud rate, there's a possibility of loosing the data on UART RX line during that time. Thus, H4 uart protocol can't really be used, since it doesn't provide means for reliable connection (doesn't have packet acknowledgments and doesn't try to retransmit the data if there's no acknowledgments received).

But it wouldn't be much sense for Deep Sleep if it can't be used with UART, would it? So CSR came up with their own proprietary serial protocol - BlueCore Serial Protocol (BCSP). BCSP can coexist with Deep Sleep quite nicely, since it has a mechanism for recovering from lost or corrupted data. If BlueCore receives a BCSP packet while in Deep Sleep mode, packet still can be lost or corrupted, but RX line activity wakes the chip up, and since BCSP supports CRC checksums and packet retransmission, the packet gets re-sent after certain time-out (normally 250ms, adjustable via PSKEY_UART_SEQ_TIMEOUT (0x405) key), by which time the chip is awake and ready to receive. There's a work-around against loosing 250ms on every retransmission - after long period of inactivity just send a short neutral packet to wake it up (i.e. BCSP ACK packet), wait for 10ms and then start transmitting the data. Or alternatively, use PIO or CTS lines to signal condition and wake the chip up instead of sending wake-up packet to UART. Of course, there're drawbacks of using BCSP too, one of them is protocol overhead that consumes some of the bandwidth. I guess that's the price to pay for reliable connection.

Converting USB dongle into serial dongle

The CSR BlueCore2-external module supports communication over USB, UART H4 or BCSP protocols. Which one to use is controlled by the keys in the persistent store area. When BC2 boots up it reads the keys and configures itself accordingly. Of course, all USB dongles came configured to use USB as their default factory setting. To force module to use UART BCSP, the following keys need to be changed:

Here's the description of PSKEY_HOSTIO_UART_PS_BLOCK (0x191):

0       1       2       3       4       5       6       7       8       9

3B0     A8      FA      14      4       0       4       1E      64      A

0. PSKEY_UART_BAUD_RATE (0x204): UART clock divisor. It's calculated by the following
   formula: divisor = (baud_rate*64+7812)/15625. Set it according to the baud rate choosen, 
   0x3B0 == 230400 bps
   0x1D8 == 115200 bps
1. PSKEY_UART_CONFIG (0x205): A bit field that represents various UART settings. The bits are:

   0: 0 (one stop bit)		1 (two stop bits)
   1: 0 (no parity bits)	1 (one parity bit)
   2: 0 (odd parity)		1 (even parity)
   3: 0 (no CTS/RTS flow ctrl)	1 (CTS/RTS flow control)
   4: 0 (no automatic RTS)	1 (automatic RTS)
   5:    RTS position (on which bit turn RTS on)
   6: 0 (no TX zero)		1 (TX zero)
   7: 0 (BCSP hardware)		1 (non-BCSP hardware)
   8:    RX rate delay (LSB)
   9:    RX rate delay (MSB)
   Bit [7] controls BCSP hardware, it should be unset for BCSP protocol, and set otherwise.
   Here're a few examples:
   0xA8 == CTS/RTS hardware flow control, RTS on 1st bit, non-BCSP hardware (default for H4)
   0x06 == even parity, BCSP hardware (default for BCSP)
2. PSKEY_UART_SEQ_TIMEOUT (0x405): Time-out in milliseconds to wait before trying to resend
   BCSP packet. Only relevant when using BCSP protocol.

   0xFA == 250ms (default value)

3. PSKEY_UART_SEQ_RETRIES (0x406): The number of retries for BCSP packet retransmission.
   After this number reached, BC2 gives up and marks BCSP link as broken and then reboots.
   Only relevant when using BCSP protocol.
   0x14 == 20 retries (default value). To retry indefinitely set it to 0.
4. PSKEY_UART_SEQ_WINSIZE (0x407): The number of unacknowledged packets that can be sent
   before waiting for an acknowledgment. Only relevant when using BCSP protocol.

   4 (default value)
5. PSKEY_UART_USE_CRC_ON_TX (0x408): Whether to use CRC checksums (protecting both header and
   payload) for BCSP packets. It allows to detect bit error in payload (good in case UART 
   line exhibits many errors). The other side of the communication link should supports CRC 
   checksums as well. Both BlueZ and Affix do (OpenBT probably does too). Only relevant when 
   using BCSP protocol.
   0 (disabled) or 1 (enabled)
6. PSKEY_UART_HOST_INITIAL_STATE (0x409): When BC2 boots up it will judge the state
   of the other end of communication link based on this value:
   0 (normal operation)
   1 (requires waking up before starting communication)
   2 (we need to wake it up)
   3 (can doze after waking up and before we send data)
   4 (never sleeps). Since we don't want to wake up Psion, we leave it at default 4.
7. PSKEY_UART_HOST_ATTENTION_SPAN (0x40A): The time in seconds the other end of 
   communication link falls asleep after receiving the data. Not relevant if 
   0x1E == 30 seconds
8. PSKEY_UART_HOST_WAKEUP_TIME (0x40B): Time in milliseconds the other end of
   communication link requires to wake up before it gets ready to receive the data.
   Not relevant if PSKEY_UART_HOST_INITIAL_STATE == 4.
   0x64 == 100ms
9. PSKEY_UART_HOST_WAKEUP_WAIT (0x40C): Time in milliseconds BC2 needs to wait 
   before sending the data after the other side of communication line has woken up.
   Not relevant if PSKEY_UART_HOST_INITIAL_STATE == 4.
   0xA == 10ms

Having a donor USB dongle in my hands with aim to prove the concept, I wired UART RX and TX, module's +3.3V and ground lines from USB dongle with flying leads to TTL<-->RS232 transceiver (old cell phone serial cable collecting dust in my closet was donating the transceiver chip and DB9 connector assembly). The CSR module was still soldered to dongle's PCB (and powered up from USB lines). The transceiver chip was powered from CSR module. On initial bootup, BC2 configures itself to use USB protocol. Then I reprogrammed it over USB bus to use UART BCSP protocol by writing new key values into RAM persistent store (that is important to notice, since programming keys into RAM can't damage module permanently - if something goes wrong, power-cycling would erase RAM and old keys (from flash memory) will be used again. After changing protocol to BCSP, warm reset (which doesn't erase RAM) was issued and viola! I can get BCSP sync packets and establish BCSP connection over serial line! The patient is still on life support, but at least it can breath! ;) Please see pictures below...

Programming the module into UART BCSP mode:

Found CSR USB device:           VID=0A12, PID=0001
CSR firmware build ID:          0x33C
read:PSKEY_BDADDR:              00-10-60-A2-CB-8E

read:PSKEY_HOSTIO_UART_PS_BLOCK:        3b0 a8 fa 14 04 00 04 1e 64 0a
write:PSKEY_HOSTIO_UART_PS_BLOCK:       1d8 06 fa 00 04 00 04 1e 64 0a
read:PSKEY_HOSTIO_UART_PS_BLOCK:        1d8 06 fa 00 04 00 04 1e 64 0a
read:PSKEY_HOST_INTERFACE:              2
write:PSKEY_HOST_INTERFACE:             1
read:PSKEY_HOST_INTERFACE:              1
read:PSKEY_DEEP_SLEEP_STATE:            1
read:PSKEY_UART_SLEEP_TIMEOUT:          1000 ms
read:PSKEY_WD_PERIOD:                   3000 ms
read:PSKEY_WD_TIMEOUT:                  5000 ms

!!!!  Rebooting device.... It should come up in UART BCSP mode now  !!!!


The dongle hooked up to RS232 transceiver:

Affix running on Psion 5mx:

Linux bluetooth ptotocol stacks

OpenBT, BlueZ and Affix all support BCSP protocol, so on first look it should work pretty straight forward. The only challenge could be to avoid overruns at 230400 bps and to deal with relatively slow speed of Psion's CPU (36MHz). UARTs are like 16C550 and have FIFO's of 16 bytes in length.

While I didn't have a chance to try OpenBT, originally I had issues with both BlueZ and Affix. Initially I started with BlueZ, but ran into a problem when hciconfig was timing out on reading local device name. Packet dump showed that HCI completion event was received, so it looked more like some timing issue in scheduler. Also, another thing I didn't quite like about BlueZ is that BCSP link was established outside of kernel space by hciattach utility. That means if BC2 reboots, the link can't be automatically re-sync'ed by the device driver and userland intervention would be required. These are minor issues and probably could be patched quite easily, but I decided to give Affix a try and see how it would fire up against BlueZ...

On the other hand, Affix worked fine with HCI commands, however any attempt to connect to socket failed. Being curious as of why this is happening, I've tried to dig it out, and after a few hours of debugging it turned out that Affix code is very sensetive to gcc code generation options. After it was fixed, Affix was running solid stable on my Psion.

Staffing bluetooth module inside Psion's casing



The sample application to switch BC02 module from USB into UART BCSP mode can be found here. Please note that it comes with absolutely no support of any kind and would require a C development environment for Win32 in order to be built.