Posted 21 June 2026
After getting OTA via Bluetooth to the onboard HC-05 going for the 2-wheel robot, I had an epiphany; For vision processing the 2-wheel robot uses an on-board Raspberry Pi5 with a Wi-Fi connection to my local network (and thence to my PC), so why use the HC-05 link at all? The Wi-Fi connection is much more robust than the BT/HC-05 link and is available throughout the house. The pi5 has a serial port, so in theory I could simply write a small python script to pipe characters back and forth between its Wi-Fi port and its serial port, just as the HC-05 does between its BT port and its serial port. How hard could it be?
Grok Code and I have been working on this issue for a while now and have gotten to the point where we can transfer the .HEX file from the pi5 to the Teensy once, but not multiple times. This indicates that the firmware update did not happen correctly. Also, we haven’t yet figured out how to automatically transfer the HEX file resulting from a Visual Studio compile to the pi5 so that it can be passed to the Teensy via the pi5’s serial port so we are bypassing this step by using SCP (or a copy/paste using VS Code) to create a duplicate of the HEX file on the pi5; then all the pi5 script has to do is pass lines from the local HEX file to the Teensy via serial.
Grok Code and I have been trying to troubleshoot this problem, and we don’t seem to be getting anywhere. Grok does not really know how to troubleshoot in an organized manner – it is more of a ‘random walk’ process. This post is intended to document my own troubleshooting efforts.
First, what is the basic problem? The basic problem is that multiple transfers of a HEX firmware file to the Teensy using the established BT/HC-05/Serial2 succeed, but the same process using the Wi-Fi/pi5/Serial1 link appears to succeed the first time but fails on the second attempt. Since the firmware HEX files in the two cases are identical, the problem must be somewhere in the pi5 script, either in the way lines are read from the local HEX file or in the way lines are transferred to the Teensy.
A basic assumption in the above is that the HEX file transferred to the Teensy via BT/HC-05 and the HEX file transferred to the Teensy via Wi-Fi/Pi5 are identical, so I decided to start there. Are they really identical?
- Compiled firmware on VS, copy/pasted (using VS Code) from “C:\Users\Frank\Documents\Arduino\Wifi_OTA_Demo\obj\x64\Debug\Wifi_OTA_Demo.hex” to “/home/pi/my_vision_robot/tests/Wifi_OTA_Demo/Wifi_OTA_Demo.hex”. Then I copy/pasted from the pi5 file to notepad++ and compared with the original – they matched perfectly.
- I modified FxUtil.cpp’s update_firmware() to add the line “out->println(line);” then updated Teensy firmware using USB connector to establish ‘known-good’ baseline. Then used pi5 script to transfer its local copy of the firmware to the Teensy, logging the transfer via VS serial monitor. The file as logged going into the Teensy and the source file on the pi5 also match perfectly. This pretty much eliminates a corrupted file transfer as the source of the problem.
- Then I performed the same procedure except using the BT/HC-05 channel instead of the Wifi/Pi5 channel.
Here’s the Wifi_OTA_Demo.ino file used to run the above tests:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
// Generated on: 2026-06-17 14:30:00 UTC // Wifi_OTA_Demo.ino - UART OTA Test via Pi5 Serial1 #include "FXUtil.h" extern "C" { #include "FlashTxx.h" } #define USING_HC05 //needed for compile-time switching char c; uint32_t buffer_addr, buffer_size; void setup() { Serial.begin(115200); // USB debug #ifdef USING_HC05 Serial2.begin(115200); // UART to HC05 Serial2.println("\n=== Wifi_OTA_Demo - UART OTA Ready ==="); Serial2.println("Send 'U' from TeraTerm on Serial2 to trigger OTA update"); #else Serial1.begin(115200); // UART to Pi5 //Serial1.println("\n=== Wifi_OTA_Demo - UART OTA Ready ==="); //Serial1.println("Send 'U' from Pi5 on Serial1 to trigger OTA update"); #endif pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); } void loop() { #ifdef USING_HC05 if (Serial2.available()) { c = Serial2.read(); Serial2.printf("Received %c on Serial2: '\n", c); if (c == 'U' || c == 'u') { Serial2.println("\nStart Program Update - Send new HEX file!"); digitalWrite(LED_BUILTIN, LOW); // visual feedback delay(500); //uint32_t buffer_addr, buffer_size; if (firmware_buffer_init(&buffer_addr, &buffer_size) == 0) { Serial2.println("Failed to init buffer"); digitalWrite(LED_BUILTIN, HIGH); return; } Serial2.println("Calling update_firmware() on Serial2..."); while (Serial2.available()) Serial2.read(); // clear buffer update_firmware(&Serial2, &Serial2, buffer_addr, buffer_size); } #else if (Serial1.available()) { c = Serial1.read(); Serial1.printf("Received %c on Serial1: '\n", c); Serial1.print(c); } if (c == 'U' || c == 'u') { Serial.println("\nStart Program Update - Send new HEX file!"); digitalWrite(LED_BUILTIN, LOW); // visual feedback delay(500); //uint32_t buffer_addr, buffer_size; if (firmware_buffer_init(&buffer_addr, &buffer_size) == 0) { Serial.println("Failed to init buffer"); digitalWrite(LED_BUILTIN, HIGH); return; } //} while (Serial1.available()) Serial1.read(); // clear buffer Serial.println("Calling update_firmware() on Serial1..."); //update_firmware(&Serial1, &Serial1, buffer_addr, buffer_size); update_firmware(&Serial1, &Serial, buffer_addr, buffer_size); //firmware_buffer_free(buffer_addr, buffer_size); //Serial.println("Firmware update call completed. About to REBOOT..."); //delay(1000); // Give time for the message to be sent #endif //firmware_buffer_free(buffer_addr, buffer_size); #ifdef USING_HC05 Serial2.println("after update_firmware"); firmware_buffer_free(buffer_addr, buffer_size); Serial2.println("Firmware update call completed. About to REBOOT..."); #else Serial.println("after update_firmware"); firmware_buffer_free(buffer_addr, buffer_size); Serial.println("Firmware update call completed. About to REBOOT..."); #endif delay(1000); // Give time for the message to be sent REBOOT; } } |