Out of pure maximalism, I configured my HC-06 Bluetooth (slave) module to a baud rate of 1,382,400 baud with the AT+BAUDC command. Ever since the Arduino connected to it was not able to use the module with SoftwareSerial library. I tried to restore the baud rate with Arduino's hardware serial (pins 0 & 1) with no luck.
I also tried to Google the topic without finding a passable solution. Maybe using a computer's built in serial port could have been a solution (with 12V to 3V3 logic level shifting), but my computer does not have this obsolete port, so I had to come up with another solution.
Step 1: What You Will Need
- Arudino/Genuino board with the default Atmel ATMEGA328P-PU MCU (@16MHz).
- A HC-06 Bluetooth module listening on 1,382,400 baud
- Basic arduino IDE from https://www.arduino.cc
Step 2: The Solution
Please note that this Instructable and the solution is made for 1,382,400 baud (AT+BAUDC) scenario. The solution will not work for any other baud rates. To handle other cases please refer to steps starting from Step 3.
The solution is really simple.
- Connect HC-06's VCC pin to 5V pin of Arduino.
- Connect HC-06's GND pin to GND pin of Arduino.
- Connect HC-06's RXD pin to pin 2 of Arduino.
- Leave HC-06's TXD pin unconnected (or connect to pin 8).
- Upload hc06reset.ino sketch.
- The program will set HC-06 into 115,200 baud mode (AT+BAUD8).
- Use your recovered HC-06 module as before.
Step 3: Behind the Scenes...
The SoftwareSerial library that comes with Arduino IDE is capable of transmitting at most 115,200 bits/second, so it is not fast enough to communicate on the desired 1,382,400 baud rate. Given that a default Arduino board runs on 16MHz, the theoretical uncompressed maximum bitrate is 16,000,000 bits/sec. We're good so far!
Based on my understanding of SoftwareSerial.cpp, the seial communication is done by setting an output pin High (=1) or Low (=0) with respect to a delay (that comes from the baud rate) between the changes.
- The output pin is high by default (means no data), then
- a Start bit is transmitted (which pulls the pin low), then
- 8 bits of data transmitted from LSB to MSB, (+5V when the bit 1 and 0 otherwise) then
- a Stop bit is transmitted (which pulls the pin high)
This way 1 byte is transmitted using10 bits.
The message we have to send is AT+BAUD8 (without \n, \r at the end). This command sets the HC-06 back to 115,200 baud rate which can be handled by regular libraries.
In order to send bits with 1,382,400 bits/sec speed, for each bit we have 1/1,382,400 seconds time (that's roughly 723.38 ns) for each bit. Arduino runs on 16,000,000 Mhz, so each cycle lasts 1/16,000,000 seconds - that is 62.5 ns per cycle.
Using AVR assembly code we can use the OUT command to set output pin high or low and NOP to wait exactly one CPU cycle. Both commands eat up exactly 1 cpu cycle. This way the 723.38 ns bit time can be covered by 11 to 12 arduino instructions per transmitted bit. One thing to consider: the OUT command sets an entire byte at once, so we have to select a PORTx where this is not a problem. Using ATMEGA328P-PU for example PORTD (arduino pins 0-7) is perfect for this condition. After setting the bit, only the proper time has to elapse which is done by 10 to 11 NOPs and that's it.
You can find calculation details in the Excel file below. This file generated the required assemly instructions for the program. Only a few replaces had to be made after pasting the generated code.