Thursday 25 February 2016

Working with cheap bluetooth BTLE4 devices HM-10 BLE-CC41A

We recently got hold of some cheap bluetooth modules off eBay to create simple wireless serial communication between our hardware and a Unity app. They were listed as HM-10/ CC2540 /CC2541 serial wireless modules. At just over two quid each, they seemed too cheap to leave on the shelf!

The first thing, when using a module like this, is to try out some straight-to-serial AT commands. Our device had a six-pin connector rather than the four-pin shown. As it turned out, the outer pins are not strictly needed to make the device work (though it took a lot of messing about with the pin labelled EN - looking like an enable pin - before we worked this out and got any kind of response to our AT commands)

Like many of these kinds of plug-n-play type modules, interfacing with it is relatively simple, but there are a couple of gotchas to be aware of to get it up and running reliably. Getting the device to respond to AT commands was problematic at first. It didn't help that different online sources suggest trying them at different baud rates. We had the curious EN pin, and tried with that pulled high, pulled low and left floating, and still nothing worked.

The silkscreen on the back of the device says it needs a 3.6v-6v power supply, but the TX/RX pins are labelled with a legend saying level 3.3v

So we tried the device on a 3.3v usb-to-serial adapter. It was barely enough to power the bluetooth device - it definitely needed more than 3.3v on the Vcc pin to get it to power up! But at 5v, we still had no response on the serial monitor/putty window. We tried using a level shifter and even set our serial adapter to run at 3.3v, while providing a dedicated 5v supply to the bluetooth board (ensuring that we had a common ground between the two). Still no reponse to our AT commands.

In a fit of desperation, we tried the HMComAssistant exe from some random chinese website, which appears to be little more than a serial monitor type application. Still nothing. Then, entirely by accident, we sent an AT command and got the response OK.

It turns out that our device only responds if the AT command is immediately followed by a carriage return/line feed combination. Suddenly we were up and running! AT+HELP (followed by CrLf) returned the following list of commands:

Command Description
AT Check if the command terminal work normally
AT+RESET Software reboot
AT+VERSION Get firmware, bluetooth, HCI and LMP version
AT+HELP List all the commands
AT+NAME Get/Set local device name
AT+PIN Get/Set pin code for pairing
AT+PASS Get/Set pin code for pairing
AT+BAUD Get/Set baud rate
AT+LADDR Get local bluetooth address
AT+ADDR Get local bluetooth address
AT+DEFAULT Restore factory default
AT+RENEW Restore factory default
AT+STATE Get current state
AT+PWRM Get/Set power on mode(low power)
AT+POWE Get/Set RF transmit power
AT+SLEEP Sleep mode
AT+ROLE Get/Set current role.
AT+PARI Get/Set UART parity bit.
AT+STOP Get/Set UART stop bit.
AT+START System start working.
AT+IMME System wait for command when power on.
AT+IBEA Switch iBeacon mode.
AT+IBE0 Set iBeacon UUID 0.
AT+IBE1 Set iBeacon UUID 1.
AT+IBE2 Set iBeacon UUID 2.
AT+IBE3 Set iBeacon UUID 3.
AT+MARJ Set iBeacon MARJ .
AT+MINO Set iBeacon MINO .
AT+MEA Set iBeacon MEA .
AT+NOTI Notify connection event .
AT+UUID Get/Set system SERVER_UUID .
AT+CHAR Get/Set system CHAR_UUID .
Note: (M) = The command support slave mode only.
For more information, please visit
Copyright@2013 All rights reserved.

+VERSION=Firmware V3.0.6,Bluetooth V4.0 LE

After a bit of wire-swapping, we discovered that the device is entirely 5v tolerant, and runs just fine off a usb-to-serial adapter, running at 5v without any external power supply, nor requiring any level shifters on the tx/rx lines. We used the command AT+NAMEChrisBLE and successfully changed the name of our bluetooth device - so when a phone scans, it appears with our custom name. That's pretty nice already! But the list of commands don't look anything like the those in the official HM-10 datasheet.

After lots of scrabbling about on the net we eventually found this article ( which explains that our devices were in fact BLE-CC41a clones. The biggest giveway to this is because they are missing the crystal on the corner nearest the antenna - something "genuine" HM-10 modules have, but - as chinese clone manufacturers are wont to do in their drive for cutting costs (and, seemingly, corners) at every opportunity - these ones don't.

Knowing all this made finding the datasheet much easier!

Having got our bluetooth device up and running, and responding to AT commands, the next job is to connect and transfer data via serial. After all, that's what these things are for! So we booted up our trust old Galaxy phone and ran the BLEGattList app.

There's our (renamed) BLE4 device!

A list of all services on our bluetooth module

The device exposes four lots of service information. Just at the moment, we're not entirely sure what all these mean. From experience with our darts app, we know that somewhere in this little lot should be a couple of services for sending and receiving data. Cue a couple of hours poking about trying lots of long strings of GUIDs with our earlier bluetooth code, trying to establish a connection.

After trying the generic access service (and successfully connecting, but failing to exchange data) it turns out that it's our Unknown Service that we need to connect to. This service exposes just one characteristic

Unlike the BLEMini from RedBearLab, this module's UUIDs do actually follow the framework described for generic bluetooth serial devices (namely a pattern that matches 0000-xxxx-1000-8000-00805F9B34FB whereas the BLEMini is nothing like this!). The hardest job we had was finding both the read and write characteristics for the module.

Using the BTLE4 module from Unity's Asset store, we already had a simple framework for connecting our phones to bluetooth devices - simply "plug in" the device/connect, read and write characteristic UUIDs and the module does all the clever work, passing data to and from the bluetooth device.

With the RedBear module, everything works fine. Except the module is written specifically for modules that have different UUIDs for their read and write characteristics. Modules - like our cheap clone - that use the same characteristic UUID for both read and write don't work fully with the Unity libraries, as written. If you're using the same Unity libraries for bluetooth (and, at less than a tenner to easily add bluetooth support to your iOS and Android apps, why not?) the offending lines are inside the void connectBluetooth function:

if (IsEqual (characteristicUUID, _readCharacteristicUUID)) {
     _readFound = true;
} else if (IsEqual (characteristicUUID, _writeCharacteristicUUID)) {
     _writeFound = true;

The fix is simple enough to do (but took a good few hours to track down and fix!).
Without this change, it's possible to put data into your app and get it to appear on the bluetooth module, but not get it back the other way. The ELSE part of the IF statement is the culprit. So let's just take it out!

if (IsEqual (characteristicUUID, _readCharacteristicUUID)) {
     _readFound = true;

if (IsEqual (characteristicUUID, _writeCharacteristicUUID)) {
     _writeFound = true;

And with this code in place, we're able to send and receive data via our app to our new, cheap, chinese-knock-off bluetooth modules!

Now we can add wireless serial comms using bluetooth (and ultimately app-based support) for hardware for about the cost it would take with those nasty, unreliable 433MHz radio modules. That's the cost of cheap radio serial, with the reliability and speed associated with wifi, without the messy SSID/password set up.
Look out for bluetooth being shoved into just about everything from now on.......


  1. Hi!, I put to sleep te module in Master Role, and it doesn't wake with anything, i tried send mora than 80 bytes, and the enable, and the button, but dont get anything. Do you know how i wake up de module?

  2. Where do I find the below lines mentioned by you in flutter blue?
    if (IsEqual (characteristicUUID, _readCharacteristicUUID)) {
    _readFound = true;
    } else if (IsEqual (characteristicUUID, _writeCharacteristicUUID)) {
    _writeFound = true;