Plans for ThinkClamp v0.7

ThinkClamp Pre-Ultimatum

In version 0.7, the ThinkClamp hardware and firmware will be completely re-designed.

It will use an inverter RC circuit to reset the TrackPoint using the clock line instead of a pin. This opens up the UART port which allows the MCU to talk to various Bluetooth modules. If this does not work well, the user will have the option to connect the RX line back to the TrackPoint’s reset line like before. Bluetooth communication should not be interfered as many of these Bluetooth modules mostly listens for commands instead of sending out any. Bluetooth modules that can be soldered onto the board includes HC-05, HC-06 and HM-10, in which HID firmware can be programmed.

The board will feature a single cell LiPo charging station with JST 2.0mm connector, which is the battery connector for many remote controlled airplanes and helicopter batteries. Just go to a model shop and try out the batteries until one fits. LEDs are included on-board to indicate whether if battery charging status. Charging will be done through connecting the board to a power source through the micro-USB connector. If a battery is not used, the header next to the BSL button may be connected to allow 5V from the USB to flow straight to the circuit.

The microcontroller is chosen to be compatible with a MSP430F5510 and MSP430F5508. With different firmwares, the board can function as a Bluetooth keyboard and mouse combo or a USB keyboard and mouse combo. The footprint will be TQFP with 0.5mm pitch, which is much easier to solder compared to QFN like the F5502 used in v0.6. The crystal used for USB functions has been replaced with a cheap resonator.

The rows and columns of the keyboard adapter will be connected to different pins on the MSP430, hoping to use its interrupts to save power when user is not typing.

There will be two ways to program the MSP430 as well as the Bluetooth on-board such as the HM-10 using a custom firmware. Debuggers can be connected to the 2.54mm headers or using a TagConnect cable.

HID firmware on HC-06 Bluetooth modules


For educational purposes, I’ve been playing with these HC-05, HC-06 Bluetooth modules. They are cheap, widely available and their firmware can be changed. But the best thing about these modules is the microcontroller BC417 that is used to handle all their logic, the CSR Bluecore4-Ext, which shall be referred to from now as BC4-Ext.

CSR BC4 is available in different flavours, so far I’ve heard of BC4-Ext and BC4-ROM. The ‘Ext’ uses an external ROM to store some data, what, I can’t remember. These guys are the core of many Bluetooth modules, including the ones from Bluegiga and Roving Networks.

I have been learning to program these modules to handle UART communication to send HID key codes but it was difficult. The resources on this is quite limited and since Bluetooth 2.0 was so 2004, CSR Support website wasn’t of much help.

I wrote a custom firmware for the HM-10 CC2540/1 but it requires Bluetooth 4.0. For a keyboard and mouse, what good would Bluetooth 4.0 do. Bluetooth 2.0 is much more suitable as it is compatible with almost all Bluetooth devices that has been around for the last 10 years. In slight frustration, I gave in and bought a BlueSmirf RN-42-HID from Sparkfun. After reading the datasheet, however, it turns out they also use CSR BC4-Ext! This is great news.

The BlueSmirf arrived yesterday. After searching for the pinout of the RN-42, I soldered some jumper cables to its SPI pins and used a USB SPI programmer that is CSR-compatible and dump the firmware with BlueFlash. After flashing this firmware onto a HC-06 module, voilà, I now have an exact copy of a RN-42-HID in firmware.

There is still the issue of conflicting Bluetooth addresses, but may that be resolved by changing the PSR settings. Byron’s blogpost gives some steps on how this can be done. And of course, the firmware of the RN-42-HID will not be shared.

Saving a pin with an inverter buffer and a RC circuit

Up to now, I’ve been connecting the ThinkPad keyboard’s TrackPoint RESET line straight to the microcontroller. This takes up a pin and has been preventing me from adding features to the adapter, like Bluetooth or maybe some external serial communication.

Using an RC circuit to create a RESET is not new, but I just thought of it recently and finally got time to try it out. The test circuit below includes some insight into how the circuit works. The capacitor’s value of 20uF is the minimum, it can be higher, or the resistor value can be increased. Either way, increasing either will increase the time required to charge/discharge the RC circuit.

Inverter RC Circuit

Here’s the circuit in action. As you can see, during normal data transfer, RESET line remains LOW. There’s a small jitter after the TrackPoint is reset, but increasing the values of the resistor-capacitor circuit would fix this easily.

Logic Analyzer Test

During planning, I used various online calculators for charging and discharging time. Why bother doing manual calculations. The calculated time is ideal. It can be slightly higher or slightly lower. In this case, the charging and discharging time is slightly higher. Instead of 600us, the time taken to charge is measured to be 633us.

Bluetooth HID Firmware Tested on HM-10

Months ago, I wrote a firmware to convert any HM-10 to a Bluetooth Low Energy HID device. The HM-10 arrived and today I finally have some spare time to test it out. Flashing the HM-10 wasn’t straightforward as I thought it would be, due to the confusing VDD lines from the CC Debugger. So here’s how mine’s connected:

CC Debugger - HM-10


The LED on the CC Debugger should lit green, indicating it has found the CC2541 or CC2540 on the HM-10. After that, Texas Instruments SmartRF Flash Programmer was used to program the chip.

A MSP430 Launchpad was used with this test program:

#include <msp430.h>
#include <stdint.h>
#include "KBD_HUT.h"

void printf(char *format, ...);
void pressKey(uint8_t keyCode);
void releaseKey(uint8_t keyCode);
void sendKbdReport(void);
void sendMouseReport(void);
void buildMouseReport(void);

typedef struct {
 uint8_t buttons;
 uint8_t dX;
 uint8_t dY;
 uint8_t dZ;

uint8_t index = 1;
MOUSE_REPORT mouseReport = { 0, 0, 0, 0 }; // HID report, to be sent to the PC.

const int8_t tableSinCosLookUp[16][2]; 

void main(void) {
 WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer


 //setup UART
 P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD
 P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD
 // 1000000 Hz 57600 bps
 UCA0BR0 = 0x11;
 UCA0BR1 = 0x00;
 UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**

 //setup LED
 P1OUT = 0;
 P1DIR |= BIT0;
 //setup button
 P1DIR &= ~BIT3;
 P1OUT |= BIT3; //pull-up, active low
 P1REN |= BIT3;

 while(1) {
 if((P1IN & BIT3) == BIT3) {
 P1OUT &= ~BIT0;
 } else {
 if((P1IN & BIT3) != BIT3) {
 P1OUT |= BIT0;


void buildMouseReport(void) {
 mouseReport.dX =
 (tableSinCosLookUp[index][0] -
 tableSinCosLookUp[index - 1][0]) >> 1;
 mouseReport.dY =
 (tableSinCosLookUp[index][1] -
 tableSinCosLookUp[index - 1][1]) >> 1;

 if (index++ >= 90){
 index = 1;

void pressKey(uint8_t keyCode) {
 printf("KD%c\r\n", keyCode); //send keycode as a character

void releaseKey(uint8_t keyCode) {
 printf("KU%c\r\n", keyCode); //send keycode as a character

void sendKbdReport(void) {

void sendMouseReport(void) {

const int8_t tableSinCosLookUp[16][2] = {

The test program demonstrates the Bluetooth HID firmware’s keyboard capability beautifully but there’s still a hiccup with the mouse movement, definitely because of that poor looking look-up table.

I shall have the TrackPoint setup and tested in a few days. Until then, thanks for reading and have fun!

ThinkClamp v0.6 Support: FAQ and Customizing Keyboard Matrix

This blog post answers a few frequently asked questions and describes the difference between the two firmwares provided as well as outlines the steps to obtain the matrix of a ThinkPad keyboard connected to the computer via a ThinkClamp PCB, for both version 0.6.2 and version 0.6.1 Rev 1.1.

Frequently Asked Questions

  1. Will the board design and source code be made open-source? No.
  2. What are the maximum dimensions of a populated board? 50x50x6.5mm.
  3. Will you be making a case? Yes, but in a very distant future.
  4. Will there be a Bluetooth version? Yes, the Bluetooth implementation is currently in progress.
  5. I am only interested in using the TrackPoint as a mouse, how do I use it with your board? If you are only interested in the TrackPoint, there’s no need to get my boards. Grab an Arduino Micro or Leonardo and load in Felix Klee’s TrackPoint example.
  6. Where can I get the components? Local electronic parts shop, element14, Digikey, RS, Mouser…
  7. How do I flash the firmware? The steps to flash the firmware is provided on the product page, but here are the steps anyway.
    • Download TI MSP430 USB Firmware Upgrade Example
    • Start the program, click Next, read and accept the terms
    • Unplug USB cable if it’s plugged in
    • Hold down BSL button while re-inserting the cable
    • Release the BSL button. The software should now detect the device
    • Choose ‘Select firmware’ and browse to the firmware downloaded. Difference outlined in Customizing firmware’s keyboard matrix section below.
    • Click ‘Upgrade firmware’ to flash the device
  8. A lot of keys are not showing up, what’s going on? Resolder the MSP430. Make sure all the pins are soldered.
  9. Some of the pin are not showing up and I’ve made sure all the pins are soldered? You may have a different keyboard matrix. Keep reading this blog post.

Customizing firmware’s keyboard matrix

In the firmware folder on Mediafire, you will find two text files: ThinkClamp_v0.6.txt and ThinkClamp_v0.6_datapipe.txt. These two firmware will send keyboard and mouse reports to the computer and allow the module to function as a normal keyboard. However, beside sending keyboard and mouse to the computer, ThinkClamp_v0.6_datapipe will also send a string consisting of the row and column of the pressed key to the computer via a generic 64-byte report (more information on report format can be found in Texas Instruments’ USB HID Datapipe documentation).

Using ThinkClamp_v0.6_datapipe, matrix of any ThinkPad keyboard can be found, providing the keyboard’s plug fit into the receptacle provided. The steps to get the matrix are as follow:

  1. Flash the firmware onto the chip via USB BSL or SBW
  2. Download TI’s Java_HID_Demo. If the link is broken, find the zip from MSP430 USB Developers Package page.
  3. Extract and run HidDemo.jar
  4. Click OK as we will be entering a different PIDoops
  5. Enter 0x0967 into the PID input box and click “Set VID PID”. The window will become:
  6. Click on the button above “Not Initialized”. The cross icon will become a green tick. The log window will print “Connected to device VID: 8263 PID 2407″.
  7. Now, as you type, printable and non-printable keys, the row and column pair will be printed (as row,col) in which both row and column starts at 0

You may want to wait a bit between each key presses as there seems to be a small delay between when a key is pressed and when its row and column is displayed. This latency only appears when in used matrix is being found.

To create a new firmware with this newly found matrix, the keys found need to be converted to its corresponding hex value in the USB HID Usage Table’s keyboard values on page 53. For example, this is my ThinkPad US T60 keyboard matrix:

NADA correspond to a 0x00. This means there is no key at this matrix position. After matching the keys to its corresponding key codes, it is then organized into a 8×16 matrix and written into the firmware text file after address F000 as follows. FN3QIJ5HW4OJQFA

Bluetooth HID Keyboard & Mouse Bridge

Just keeping you up to date, I’ve written a firmware for Texas Instruments CC2540 Bluetooth Low Energy IC that sends keyboard & mouse reports to the host using a few UART commands that works similarly to Arduino Keyboard’s press() and release() commands, except it will send raw HID keycodes instead of printable characters. As for the mouse, a UART command with button states, X, Y, Z bytes can be used at the same time as well.
The firmware isn’t as good as if it is programmed by professional software engineers and if IAR Workbench was free so I can spend an infinite amount of time tweaking, but it does the job. The advantage to using a CC2540 with my firmware means you can turn any cheap eBay HM-10 serial Bluetooth module into a HID Bluetooth keyboard & mouse bridge! The disadvantage would be that to write a new firmware, you would need to use IAR Embedded Workbench for 8051 which is free for 30 days or cost $3k if you buy it. However, for just flashing, IAR is not needed. So as an end-user, there are essentially no disadvantages.

The  UART commands are sent to the CC2540 via UART at 57600bps with 8 data bits and no parity. They must end with a carriage return (0x0D, ‘\r’) or a line termination character (0x0A, ‘\n’), or both.

The commands include:

  • KU(keycode): a key is released with the keycode (keycode)
  • KD(keycode): a key is pressed with the keycode (keycode)
  • M(status)(X)(Y)(Z): sending buttons and mouse coordinates
  • KUPDATE: send report to host

(___) are 8-byte characters, and you don’t send the brackets, just the
value inside the brackets.

The (keycode) used are from USB HID usage table 1.12 in the keyboard section. Since I haven’t made a full keyboard board, the module will ask the host for pin, which is 000000. There is also another firmware that advertise the device with containing a keyboard so the user must use the keyboard to enter the pin, but a test board is needed thus this has not been tested.

Here is a pretty 3D render of the board I’ve whipped up.
It uses a MSP430 to handle the keyboard scanning and TrackPoint polling. The entire top left portion of the board is dedicated to power management. Battery used can be of any types in the range of 3V-5V. If the battery is a rechargeable Li-Po or Li-Ion single cell, the Micro USB can be used to recharge it. There are 2 LEDs (Green and Yellow) indicating if external power is present and whether the battery is being charged.
On this board, the battery connector used is a JST-PH 2.0mm 2-pin right angle connector. It is used for many battery packs for Remote Controlled toys though I have found that there is also 1.5mm, 1.25mm and 2.5mm. It just happens that the 2.0mm is cheap and available.
Beep beep boop, forgot to include a link to the released source code and binaries. Here it is:

UART ISR and custom printf() function with CC2540

I recently got started learning Texas Instruments CC2540 Bluetooth Low Energy chip to write a HID keyboard and mouse bridge to pair up with a MSP430 microcontroller and make my ThinkPad keyboard wireless.

Besides getting started with the CC2540 in general, I found using UART a major hurdle even though it turned out to be quite easy using the HAL driver supplied. When I wrote ‘easy’ I meant to pair it with ‘by using ISR (interrupts)’ instead of ‘DMA’. I have not had a stab at DMA yet and given that my 30-day license is expiring in a few days, I would love to finish writing the firmware as soon as possible.

So may this be a quick trot down of how I went with UART and tiny modified printf() function over UART based on oPossum’s tiny printf for the MSP430 platform.

I found it beneficial to read over Design Note DN112 as it gives a basic understanding of how UART works in the CC2530, which is quite similar to CC2540.

In general, to use UART, it can be as followed:

Setting up UART
- To use UART, HAL_UART=TRUE, preferrably POWER_SAVING is not enabled (xPOWER_SAVING)
- To use interrupts, HAL_UART_ISR = (1 or 2), HAL_UART_DMA=FALSE
- To use DMA, HAL_UART_ISR = 0, HAL_UART_DMA = (1 or 2)


Check _hal_uart_isr.c for more information.

For keyfob, USART 0 alt. 1 is being used:
For HM-10, USART 1 alt. 2 is being used:


For my project, I am using the CC2540 keyfob and am using USART 0 Alt. 1:

//UART test variable
uint8 *rxBuffer;
uint8 rxBufferIndex = 0;

static void setupUART(void) {

 halUARTCfg_t uartConfig;

 // configure UART
 uartConfig.configured = TRUE;
 uartConfig.baudRate = HAL_UART_BR_57600;
 uartConfig.flowControl = HAL_UART_FLOW_OFF;
 uartConfig.flowControlThreshold = 0;
 uartConfig.rx.maxBufSize = 128;
 uartConfig.tx.maxBufSize = 128;
 uartConfig.idleTimeout = 1; //1ms timeout
 uartConfig.intEnable = TRUE;
 uartConfig.callBackFunc = (halUARTCBack_t)uartCallback;

 //start UART
 //assumes no issues with starting UART
 (void)HalUARTOpen(HAL_UART_PORT_0, &amp;uartConfig);

 rxBuffer = osal_mem_alloc(128); //assumes there is no problem with getting this block of memory

static void uartCallback(uint8 port, uint8 event) {
 uint16 len;
 uint8 buf[8];
 uint8 i;

 switch(event) {
 len = Hal_UART_RxBufLen(HAL_UART_PORT_0);
 HalUARTRead(HAL_UART_PORT_0, buf, len);
 for(i = 0; i &lt; len; i++) {
 //in this application, all lines sent to CC2540 ends with a carriage return (0x0D)
 if(buf[i] != 0x0D) rxBuffer[rxBufferIndex++] = buf[i];
 else {
 processBuffer(); //do stuff with rxBuffer using rxBufferIndex as the length of the rxBuffer


setupUART() is placed in the application’s Init() function after all the other initializations. For example:

#if defined( CC2540_MINIDK )
   //some initializations specific to the keyfob

//UART init

//setup a delayed profile startup...

The callback function is called anytime there is an event related to UART is fired. Through printing text onto UART with HalUARTWrite(), I found that only HAL_UART_RX_TIMEOUT matters for receiving data. I’m not sure if this is the correct approach but so far it seems to work fine.

Next up, based on oPossum’s tiny printf(),  one can be implemeted for CC2540 to send data easily over UART: Printf.c:

#include &quot;stdarg.h&quot;
#include &quot;hal_uart.h&quot;
#include &lt;string.h&gt;
#include &quot;hal_types.h&quot;

static void sendByte(unsigned char byte) {
 HalUARTWrite(HAL_UART_PORT_0, &amp;byte, 1); //change port to suit your needs

static void putc(unsigned char c) {

static void puts(uint8 *str) {
 HalUARTWrite(HAL_UART_PORT_0, str, strlen((const char*)str)); //change port to suit your needs

static const unsigned long dv[] = {
 // 4294967296 // 32 bit unsigned max
 1000000000,// +0
 100000000, // +1
 10000000, // +2
 1000000, // +3
 100000, // +4
 // 65535 // 16 bit unsigned max
 10000, // +5
 1000, // +6
 100, // +7
 10, // +8
 1, // +9

static void xtoa(unsigned long x, const unsigned long *dp) {
 char c;
 unsigned long d;
 if (x) {
 while (x &lt; *dp)
 do {
 d = *dp++;
 c = '0';
 while (x &gt;= d)
 ++c, x -= d;
 } while (!(d &amp; 1));
 } else

static void puth(unsigned n) {
 static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
 '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 putc(hex[n &amp; 15]);

void printf(char *format, ...)
 char c;
 int i;
 long n;

 va_list a;
 va_start(a, format);
 while(c = *format++) {
 if(c == '%') {
 switch(c = *format++) {
 case 's': // String
 puts(va_arg(a, char*));
 case 'c':// Char
 putc(va_arg(a, char));
 case 'i':// 16 bit Integer
 case 'u':// 16 bit Unsigned
 i = va_arg(a, int);
 if(c == 'i' &amp;&amp; i &lt; 0) i = -i, putc('-');
 xtoa((unsigned)i, dv + 5);
 case 'l':// 32 bit Long
 case 'n':// 32 bit uNsigned loNg
 n = va_arg(a, long);
 if(c == 'l' &amp;&amp; n &lt; 0) n = -n, putc('-');
 xtoa((unsigned long)n, dv);
 case 'x':// 16 bit heXadecimal
 i = va_arg(a, int);
 puth(i &gt;&gt; 12);
 puth(i &gt;&gt; 8);
 puth(i &gt;&gt; 4);
 case 0: return;
 default: goto bad_fmt;
 } else
 bad_fmt: putc(c);

With printf() declared in <Application>.h (so there’s no need to make a Printf.h)

extern void printf(char *format, ...);

Here’s a screenshot of the CC2540 sending a number counting up at 5ms apart (through use of a timer based on SimplePeripheral project):

CC2540 printf()

Staying away from QFNs, my first Android app plus some Bluetooth

So, exams are finally over, the results are out and I scraped through. No supplements, none failed.

Over the past 2 weeks, I have learnt a valuable lesson: I cannot solder QFN packages. Out of 10 chips, I burnt 9. It’s horrible. It might be that I’m not using enough flux or maybe not enough solder but the solder will not melt below the many of the pins. One of my F550x break-out board arrived yesterday. Double sided, it fits perfectly onto a breadboard, but sadly, the QFN that is on the bottom is burnt and the board doesn’t work. I was playing with my phone’s camera software and applied a sketch art effect. Unfortunately, there was no undo.

F550x break-out


So I shall be staying away from QFNs in general from now on. The leaded packages may be much more expensive than non-leaded, but the convenience is definitely worth it, for me.

A few weeks ago, my dad asked me to write an application that lets him send his current GPS location to his colleagues using SMS and the like. Of course, there are plenty or maybe hundreds of apps that do this already. To name a few: Viber, Whatsapp, Google Maps, Tango… Location messaging is integrated into the apps. But what if you don’t have internet and you haven’t found this function in your chatting map, or maybe, you just don’t have time to search for it. Introducing GPS Share.



With its simplistic design, with a few seconds, you can send your current GPS coordinates via SMS. With internet connection, the application finds out the address of your location and it lets you share this information through e-mails. It also lets you copy the location information to the clipboard so you may paste it into any application you want. The time it takes from opening the app to sending a SMS packed with your current location is 4 seconds. I tried it out today after parking the car. It’s great. Link to Play Store.

And lastly, Bluetooth. This time, I’m taking a break from MSP430 and learn some C2000 and Bluetooth. I’ve got CC2540 mini dev-kit and I made a break-out board for the BC417. Unfortunately, the PIO is the wrong way around. but the code works well enough. The programmer is a clone I got from goodluckbuy. Free shipping. It works beautifully. Before receiving my programmer, I used TIVA C Launchpad and flashed it with CsrUsbSpiDeviceRE TIVA by Richard Aplin. It worked like a charm. But since I’ve got a programmer, I may just use it and reserve the TIVA for future learning.

BC417-BO board 1


So far, I’ve made a Blinky program and a Hello World program. Just the basics and following CSR’s very limited tutorials, but at least there is no time limit on the IDE, unlike the 30-day IAR Embedded Workbench for 8051 for TI CC2540.

ThinkPad USB Keyboard Project – It’s over

2014-06-07 06.33.07

This is the final PCB run of my ThinkPad USB Keyboard adapter project. It has a BSL button to upload firmware via USB using TI’s MSP430 Firmware update software, saving end-user lots of money from having to invest on a programmer.

Originally, I planned to write a custom USB flashing software on the PC that allows users to create their own matrices and keyboard combinations. However, due to lack of time, it is dropped.

Firmware wise, the keyboard scanning is pretty fast. All the keycodes are supported. Num Lock works, remote wake-up supported. It works just like a normal keyboard, except this one you can customize the matrix and add key combinations, at least I can.

Of course, the aesthetic of the PCB can be improved. Via holes can be smaller and not covering text, something like this:


But for functionality, all is well. Anyway, that’s it. No more ThinkPad keyboard adapters for me.  Here’s quick video of the board in action:

I have made the left-over boards avaiable for purchase from Tindie. Two flavours are available. Have your pick:

Soldered up and… a pin isn’t soldered

So last week I got my v0.6.1 PCBs from DirtyPCBs and I decided to solder one of the boards and see how it improves upon version 0.6.0. This is my second time working with 0603 and QFNs. The first time didn’t work so well that this time I had to get a stencil and solder  paste. It turned out to be a pretty good experience. A quick swipe of paste onto the board, placed a few components, just hot air the boards and it was done in less than an hour! Shiny and everything.

Got it hooked to the computer, BSLed fine, loaded the firmware, keyboard detected, every keys works, except for F1, 2, W, CapsLock, S and X :(. Well that sucked. Turns out a pin wasn’t soldered under the QFN chip, This has become a bit annoying. Maybe the change to QFN to save $2.50 on cost isn’t exactly worth it.

2014-05-24 22.24.47