Hello everyone,
I am having an issue performing an OTA update using I2C. I have 2 boards, a master and a slave. The master is connecting to the internet via Ethernet (project requirement). The master is communicating with the Slave via I2C. There are some situations where I may need to update the firmware to the slave. However, the slave can't connect out to the internet. My thinking is that I want to sent the firmware via I2C.
I have 98% of the code working. The 2% is one bug that I am trying to figure out. The logic works. But, when I add in the code for writing the flash, that is where things start to break down. Basically what happens is that the slave gets a Buffer overflow error on the I2C line. However, when I comment that part out (writing to the flash) everything works as it is suppose to.
My most educated guess is that somehow the writing to flash is happening so slowly that it is messing everything up. I am not sure how I can fix this issue hence, I am posting on the forum. Below is a code example:
The checkI2Ccomms function gets called in my loop function:
void checkI2CComms()
{
if(slaveUpdateMode && fwByteNeedProcessed){
// Calculate the CRC32 checksum and write the bytes to flash
for (int i = 0; i < bytesRead; i++) {
crc.update(firmwareReceiveBuffer[i]);
//InternalStorage.write();
//Wire.readBytes(firmwareReceiveBuffer, I2C_FW_BUFFER_SIZE);
}
firmwareSize -= bytesRead;
if (firmwareSize <= 0) {
slaveUpdateMode = false;
firmwareSize = 0;
InternalStorage.close();
uint32_t checksum = crc.finalize();
// Check the checksum
if (checksum == firmwareCRCValue) {
printStatus(F("Checksums match"));
//InternalStorage.apply();
} else {
printStatus(F("Checksums do not match"));
}
// transmit something to confirm to master ending Slave OTA update
printStatus(F("Firmware update complete"));
delay(100); // Give status text time to send out
//reset();
} else {
fwPrintBytesCounter++;
if (fwPrintBytesCounter >= 100) {
Serial.print("Bytes: ");
Serial.println(firmwareSize);
fwPrintBytesCounter = 0;
}
}
fwByteNeedProcessed = false;
}
// Just a placeholder function
}
And this is the code for the I2Crecieve event:
void i2cRecieveEvent(int bytesToRead)
{
if(!slaveUpdateMode){
memset(receivedMessage, 0, I2C_READ_BUFFER * sizeof(char));
int bytesRead = Wire.readBytesUntil('/', receivedMessage, I2C_READ_BUFFER);
printStatus(String(receivedMessage));
if (!channelConfigIsComplete){
if (String(receivedMessage).indexOf("end") != -1){
printStatus("end received");
channelConfigIsComplete = true;
//Serial.println("Locked off");
} else {
receivedMessage[bytesRead] = '/';
printStatus("Processing line: ");
printStatus(receivedMessage);
ParseSDCardFile(receivedMessage);
}
} else {
parseEthernetCommands(receivedMessage);
}
} else {
esp_task_wdt_reset(); // Just to make sure that the WDT doesn't hit
//printStatus("Slave Update Mode");
uint8_t tempArray[I2C_FW_BUFFER_SIZE];
// Read up to 32-bytes of data and store in the read buffer
memset(firmwareReceiveBuffer, 0, I2C_FW_BUFFER_SIZE * sizeof(uint8_t));
memset(tempArray, 0, I2C_FW_BUFFER_SIZE * sizeof(uint8_t));
bytesRead = Wire.readBytes(tempArray, I2C_FW_BUFFER_SIZE);
memcpy(firmwareReceiveBuffer, tempArray, bytesRead);
// Set the flag to indicate that bytes have arrived for the fw upload
fwByteArrived = true;
fwByteNeedProcessed = true;
}
}
Some useful globals:
uint8_t firmwareReceiveBuffer[I2C_FW_BUFFER_SIZE];
int bytesRead = 0;
uint32_t firmwareUpdateSize = 0;
bool fwByteArrived = false; // Set whenever a byte is received during the firmware update process
bool fwByteNeedProcessed = false;
There are some additional functions like getting the CRC and getting the firmware size, that is handled by a separate communication scheme. I am not too worried about the amount of time it will take to update the firmware on the slave. My first step is to get it to work