I'm working on sketches uploading over BLE. I had to write my own uploader (looking at avrdude sources with one eye) so i can change uploading behaviour as needed and it's working over USB just perfect but it does not get response from bootloader if trying over Bluetooth LE.
My hardware:
- Arduino Uno (and i'm having Arduino Mega2560)
- HM-10 BLE module
As HM-10 does not support DTR/RTS i had to add my own software reboot:
In brief: it reads incoming bytes on interrupt event and compares to reset command passed in ble_setup. If it's equal then it uses watchdog timer to reboot the board. If it's not equal it stores byte in byffer, then sketch loop() just returns incoming byes back ("echo").
#include <avr/wdt.h>
const char *ble_reset_cmd;
int ble_reset_index = 0;
int ble_available = 0; // chars available
int ble_byte; // income buffer as 1 char
int *ble_bytes = &ble_byte; // income buffer
boolean delete_ble_bytes = false;
//#define BLE_DEBUG
// reboot Arduino board using Watchdog timer
void reboot() {
// #ifdef BLE_DEBUG
Serial.println("rebooting ...");
// #endif
// digitalWrite(13, HIGH);
// delay(2000);
wdt_enable(WDTO_15MS);
while(1) { };
}
void ble_setup(int baud, const char *reset_cmd) {
Serial.begin(baud);
ble_reset_cmd = reset_cmd;
}
int Serial_available() {
return ble_available;
}
int Serial_read() {
if (ble_available < 0)
return -1;
int inByte = ble_bytes[--ble_available];
if (ble_available == 0 && delete_ble_bytes) {
// restore buffer as 1 char buffer
delete[] ble_bytes;
ble_bytes = &ble_byte;
delete_ble_bytes = false;
}
return inByte;
}
void serialEvent() {
if (Serial.available() <= 0)
return;
int inByte = Serial.read();
if (inByte == ble_reset_cmd[ble_reset_index]) {
// entered char is cmd character
if (ble_reset_cmd[++ble_reset_index] == 0)
reboot();
#ifdef BLE_DEBUG
Serial.write("ble_index = ");
Serial.print((byte)ble_reset_index);
Serial.write('\n');
#endif
} else {
// entered char is NOT cmd character
if (ble_reset_index > 0) {
// got character not from cmd, so we should to return characters
// starting ble_reset_cmd until current index and then this character
ble_available = ble_reset_index + 1;
ble_reset_index = 0;
#ifdef BLE_DEBUG
Serial.print("Copy ");
Serial.print((byte)(ble_available - 1));
Serial.println(" bytes");
#endif
// recreate input buffer using cmd characters
ble_bytes = new int[ble_available + 1];
delete_ble_bytes = true;
ble_bytes[0] = inByte;
for (int i=0; i<(ble_available-1); i++) {
ble_bytes[i + 1] = ble_reset_cmd[ble_available - i - 2];
}
ble_bytes[ble_available] = 0; // null-terminated array
#ifdef BLE_DEBUG
Serial.print("input buffer now contains ");
Serial.print(ble_available);
Serial.println(" bytes");
#endif
} else {
#ifdef BLE_DEBUG
Serial.println("ble_index = 0");
#endif
// pass inByte next ...
ble_available++;
ble_byte = inByte;
}
}
}
// -----------------------------------
int led = 13;
int ledHIGH = 0;
void setup() {
ble_setup(9600, "AT+RESET");
Serial.print("ready\n");
pinMode(led, OUTPUT);
}
void loop() {
while (Serial_available() > 0) {
int inByte = Serial_read();
// Serial.write('>');
// Serial.write(inByte);
// Serial.write('\n');
ledHIGH = 1- ledHIGH;
digitalWrite(led, ledHIGH);
Serial.write(inByte); // echo
}
}
As i said it's working good for USB uploading: right after rebooting bootloader waits for upload commands and start to reply:
015-04-07 21:22:10.860 Apploader[11226:303] Apploader v0.1
2015-04-07 21:22:12.772 Apploader[11226:303] DTR/RTS supported by Serial, resetting
2015-04-07 21:22:13.075 Apploader[11226:303] draining ...
2015-04-07 21:22:13.327 Apploader[11226:303] drain done
2015-04-07 21:22:13.328 Apploader[11226:303] Send: 0 [0x30] [0x20]
2015-04-07 21:22:13.328 Apploader[11226:303] draining ...
2015-04-07 21:22:13.723 Apploader[11226:303] drain done
2015-04-07 21:22:13.724 Apploader[11226:303] Send: 0 [0x30] [0x20]
2015-04-07 21:22:13.724 Apploader[11226:303] draining ...
2015-04-07 21:22:13.977 Apploader[11226:303] drain done
2015-04-07 21:22:13.978 Apploader[11226:303] Send: 0 [0x30] [0x20]
2015-04-07 21:22:13.979 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:13.980 Apploader[11226:303] Recv: . [0x10]
2015-04-07 21:22:13.980 Apploader[11226:303] Send: A [0x41] . [0x81] [0x20]
2015-04-07 21:22:13.984 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:13.984 Apploader[11226:303] Recv: . [0x04]
2015-04-07 21:22:13.985 Apploader[11226:303] Recv: . [0x10]
2015-04-07 21:22:13.985 Apploader[11226:303] Send: A [0x41] . [0x82] [0x20]
2015-04-07 21:22:13.988 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:13.988 Apploader[11226:303] Recv: . [0x04]
2015-04-07 21:22:13.989 Apploader[11226:303] Recv: . [0x10]
2015-04-07 21:22:13.989 Apploader[11226:303] Send: B [0x42] . [0x86] . [0x00] . [0x01] . [0x00] . [0x01] . [0x01] . [0x01] . [0x03] . [0xff] . [0xff] . [0xff] . [0xff] . [0x00] . [0x80] . [0x04] . [0x00] . [0x00] . [0x00] . [0x80] . [0x00] [0x20]
2015-04-07 21:22:13.996 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:13.997 Apploader[11226:303] Recv: . [0x10]
2015-04-07 21:22:13.997 Apploader[11226:303] Send: E [0x45] . [0x05] . [0x04] . [0xd7] . [0xc2] . [0x00] [0x20]
2015-04-07 21:22:14.000 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:14.001 Apploader[11226:303] Recv: . [0x10]
2015-04-07 21:22:14.003 Apploader[11226:303] Send: P [0x50] [0x20]
2015-04-07 21:22:14.004 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:14.008 Apploader[11226:303] Recv: . [0x10]
But when trying over BLE bootloader stops listening in 200ms and then launches sketch, i can see sketch setup() started as it prints "ready". Also i can see it actually reboots the board as it sends "rebooting".
015-04-07 21:23:30.287 Apploader[11253:303] Apploader v0.1
2015-04-07 21:23:30.296 Apploader[11253:1503] CBCentralManager state is 5
2015-04-07 21:23:31.297 Apploader[11253:303] BleSerialDevice: open()
2015-04-07 21:23:31.298 Apploader[11253:303] Waiting for peripheral to be discovered ...
2015-04-07 21:23:31.591 Apploader[11253:1503] Found peripheral: <CBPeripheral: 0x100401940 identifier = D92ECAAB-51A5-44D5-8C6C-536CD797867E, Name = "Ardu", state = disconnected>
2015-04-07 21:23:31.593 Apploader[11253:1503] Stop scanning
2015-04-07 21:23:31.595 Apploader[11253:1503] Connecting to <CBPeripheral: 0x100401940 identifier = D92ECAAB-51A5-44D5-8C6C-536CD797867E, Name = "Ardu", state = disconnected>
2015-04-07 21:23:32.025 Apploader[11253:1503] Connected to peripheral <CBPeripheral: 0x100401940 identifier = D92ECAAB-51A5-44D5-8C6C-536CD797867E, Name = "Ardu", state = connected>
2015-04-07 21:23:32.041 Apploader[11253:1503] Discovered services for peripheral <CBPeripheral: 0x100401940 identifier = D92ECAAB-51A5-44D5-8C6C-536CD797867E, Name = "Ardu", state = connected>
2015-04-07 21:23:32.042 Apploader[11253:1503] Discovered service <CBService: 0x103701450>
2015-04-07 21:23:32.043 Apploader[11253:1503] Discovered service <CBService: 0x1037015f0>
2015-04-07 21:23:32.043 Apploader[11253:1503] Discovered service <CBService: 0x103701630>
2015-04-07 21:23:32.044 Apploader[11253:1503] Discovered characteristics for service <CBService: 0x103701630>
2015-04-07 21:23:32.044 Apploader[11253:1503] Discovered characteristic <CBCharacteristic: 0x1037005c0>
2015-04-07 21:23:32.045 Apploader[11253:1503] Subscribed to Rx value
2015-04-07 21:23:32.046 Apploader[11253:303] Connected successfully
2015-04-07 21:23:33.342 Apploader[11253:303] BleSerialDevice: open()
2015-04-07 21:23:33.343 Apploader[11253:303] already connected, exiting
2015-04-07 21:23:33.343 Apploader[11253:303] DTR/RTS supported by Serial, resetting
2015-04-07 21:23:33.594 Apploader[11253:303] Within interval
2015-04-07 21:23:33.595 Apploader[11253:303] Perform reset
2015-04-07 21:23:33.596 Apploader[11253:303] Send: A [0x41] T [0x54] + [0x2b] R [0x52] E [0x45] S [0x53] E [0x45] T [0x54]
2015-04-07 21:23:33.647 Apploader[11253:303] Skip draining after reset
2015-04-07 21:23:33.648 Apploader[11253:303] Send: 0 [0x30] [0x20]
2015-04-07 21:23:33.648 Apploader[11253:303] Draining for 200 ms ...
2015-04-07 21:23:33.649 Apploader[11253:303] Start reading
2015-04-07 21:23:33.712 Apploader[11253:1503] Rx value received 15 bytes: r [0x72] e [0x65] b [0x62] o [0x6f] o [0x6f] t [0x74] i [0x69] n [0x6e] g [0x67] [0x20] . [0x2e] . [0x2e] . [0x2e] . [0x0d] . [0x0a]
2015-04-07 21:23:33.713 Apploader[11253:1503] _characterRead = true
2015-04-07 21:23:33.780 Apploader[11253:1503] Rx value received 6 bytes: r [0x72] e [0x65] a [0x61] d [0x64] y [0x79] . [0x0a]
2015-04-07 21:23:33.780 Apploader[11253:1503] _characterRead = true
2015-04-07 21:23:33.850 Apploader[11253:303] Finish reading
2015-04-07 21:23:33.851 Apploader[11253:303] Drained 21 bytes
2015-04-07 21:23:33.852 Apploader[11253:303] Send: 0 [0x30] [0x20]
2015-04-07 21:23:33.853 Apploader[11253:303] Draining for 200 ms ...
2015-04-07 21:23:33.853 Apploader[11253:303] Start reading
2015-04-07 21:23:33.982 Apploader[11253:1503] Rx value received 2 bytes: 0 [0x30] [0x20]
2015-04-07 21:23:33.983 Apploader[11253:1503] _characterRead = true
2015-04-07 21:23:34.054 Apploader[11253:303] Finish reading
2015-04-07 21:23:34.055 Apploader[11253:303] Drained 2 bytes
2015-04-07 21:23:34.056 Apploader[11253:303] Send: 0 [0x30] [0x20]
2015-04-07 21:23:34.056 Apploader[11253:303] Reading 1 bytes ...
2015-04-07 21:23:34.057 Apploader[11253:303] Start reading
2015-04-07 21:23:34.057 Apploader[11253:303] _characterRead = false
2015-04-07 21:23:34.184 Apploader[11253:1503] Rx value received 1 bytes: . [0x00]
2015-04-07 21:23:34.185 Apploader[11253:1503] _characterRead = true
2015-04-07 21:23:34.186 Apploader[11253:303] Finish reading
2015-04-07 21:23:34.186 Apploader[11253:1503] Rx value received 2 bytes: 0 [0x30] [0x20]
2015-04-07 21:23:34.186 Apploader[11253:1503] _characterRead = true
2015-04-07 21:23:34.186 Apploader[11253:303] Recv: . [0x00]
2015-04-07 21:23:34.187 Apploader[11253:303] stk500_getsync() attempt 1 of 5: not in sync: resp=0x00
Once again - bootloader stops listening in 200 ms instead of 1-1.5 secons as over USB:
2015-04-07 21:23:33.596 Apploader[11253:303] Send: A [0x41] T [0x54] + [0x2b] R [0x52] E [0x45] S [0x53] E [0x45] T [0x54]
...
2015-04-07 21:23:33.780 Apploader[11253:1503] Rx value received 6 bytes: r [0x72] e [0x65] a [0x61] d [0x64] y [0x79] . [0x0a]
I expect bootloader to reply with 0x14 0x10 as over USB:
2015-04-07 21:22:13.978 Apploader[11226:303] Send: 0 [0x30] [0x20]
2015-04-07 21:22:13.979 Apploader[11226:303] Recv: . [0x14]
2015-04-07 21:22:13.980 Apploader[11226:303] Recv: . [0x10]
As you can see later communication over Bluetooth is working good, as i receive exactly what was sent (0x30 0x20)
So when sketch is launched it's ok.
My ideas what's wrong:
- baud rate
Since serial.begin(N) is invoked after bootloader stops and launch sketch bootloader by default uses another baud rate? Is it correct? HM-10 default daud rate is 9600 and in sketch i also use 9600.
- wrong wire connection?
Bluetooth-arduino: rx -> tx tx -> rx Since its working for sketch i believe it's ok. Do i need any capacitors or resistors?
Any thoughts are highly appreciated!
UPDATE:
It seems i've found Uno bootloader source code and bootloader baud rate is 19200 by default
/* set the UART baud rate */
/* 20060803: hacked by DojoCorp */
//#define BAUD_RATE 115200
#ifndef BAUD_RATE
#define BAUD_RATE 19200
#endif
UPDATE2:
I'm in stuck as in this tutorial 115200 is used: http://makezine.com/projects/diy-arduino-bluetooth-programming-shield/
in step 8. "build the programmer circuit" R1 2.2K is set on arduino rx pin. Why? Another thing i can't understand is that SoftwareSerial baud rate is set to 38400 but BT module baud rate is set 115200 using "AT" command. why?