OTA hangs when using I2C

theGtknerd
Posts: 6
Joined: Tue May 25, 2021 1:48 pm

OTA hangs when using I2C

Postby theGtknerd » Tue May 25, 2021 2:19 pm

I am not altogether new to C++ or the ESP32, but I am running up against a problem too big for me. When trying to perform an OTA (AsyncElegantOTA if it matters), my code is also using I2C, which causes the ESP32 to throw a lot of errors like:

Code: Select all

[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbe454
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb844c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffde80c bits=112
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffde840
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffd0120
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:311] i2cDumpDqData(): Debug Buffer not Enabled
[I][esp32-hal-i2c.c:354] i2cDumpInts(): Debug Buffer not Enabled
[I][esp32-hal-i2c.c:1138] i2cProcQueue(): Bus busy, reinit
On some OSes like Windows 10, this will ultimately cause a watchdog reset. On Linux it does perform the OTA most of the time. Since I am using FreeRTOS, I used this code, but it doesn't change a thing:

Code: Select all

if( xSemaphoreTake( i2cMutex, 1000 ) == pdTRUE ) {
  // do I2C here
  xSemaphoreGive( i2cMutex );
}
So I tried:

Code: Select all

if( xSemaphoreTake( i2cMutex, 1000 ) == pdTRUE ) {
  wheelAngleTmp = ads.readADC_Differential_0_1();
  if( Wire.lastError() != 0 ){
    vTaskDelete( NULL );
  }
  xSemaphoreGive( i2cMutex );
}
Which works, but it seems horribly hacky. I am looking for a more elegant way to detect an OTA update being done, so that I can shut down the I2C task. Or what are my other options? As far as I can tell, the OTA uses the I2C bus. There's a bit of reports of the OTA hanging problem across the Interweb, I suspect they might be related.

username
Posts: 528
Joined: Thu May 03, 2018 1:18 pm

Re: OTA hangs when using I2C

Postby username » Wed May 26, 2021 2:50 am

In your OTA routine when it detects your doing OTA, you kill all other threads that are running.

theGtknerd
Posts: 6
Joined: Tue May 25, 2021 1:48 pm

Re: OTA hangs when using I2C

Postby theGtknerd » Wed May 26, 2021 11:36 am

That's the problem, I'm using a library. So what you are telling me is that I need to use my own OTA routine. I was hoping for a holistic solution other people could also use with AsyncElegantOTA.

username
Posts: 528
Joined: Thu May 03, 2018 1:18 pm

Re: OTA hangs when using I2C

Postby username » Wed May 26, 2021 11:49 am

Gotcha. Well, FWIW I copied the OTA source into my project, and just inserted a few lines.

User avatar
Vader_Mester
Posts: 300
Joined: Tue Dec 05, 2017 8:28 pm
Location: Hungary
Contact:

Re: OTA hangs when using I2C

Postby Vader_Mester » Wed May 26, 2021 1:10 pm

theGtknerd wrote:
Wed May 26, 2021 11:36 am
That's the problem, I'm using a library. So what you are telling me is that I need to use my own OTA routine. I was hoping for a holistic solution other people could also use with AsyncElegantOTA.
Maybe you are not required to modify the library.
First you must create a FreeRTOS task that calls AsyncElegantOTA.loop();

Code: Select all

static void otaSuperVisor(void *pVparams)
{
	while(1)
	{
	AsyncElegantOTA.loop();
	vTaskDelay(5000/portTICK_PERIOD_MS);
	}
}
How often are you using I2C? Are you using it as a fixed frequency, or code decides to call it?

Code: Select all

task_t coffeeTask()
{
	while(atWork){
		if(!xStreamBufferIsEmpty(mug)){
			coffeeDrink(mug);
		} else {
			xTaskCreate(sBrew, "brew", 9000, &mug, 1, NULL);
			xSemaphoreTake(sCoffeeRdy, portMAX_DELAY);
		}
	}
	vTaskDelete(NULL);
}

theGtknerd
Posts: 6
Joined: Tue May 25, 2021 1:48 pm

Re: OTA hangs when using I2C

Postby theGtknerd » Wed May 26, 2021 5:26 pm

How often are you using I2C? Are you using it as a fixed frequency, or code decides to call it?
It's set up using

Code: Select all

void sensorWorker10HzPoller( void* z ) {
  constexpr TickType_t xFrequency = 100;
  TickType_t xLastWakeTime = xTaskGetTickCount();

  for( ;; ) {
    // I2C here
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
}

xTaskCreate( sensorWorker10HzPoller, "sensorWorker10HzPoller", 2048, NULL, 5, NULL );

theGtknerd
Posts: 6
Joined: Tue May 25, 2021 1:48 pm

Re: OTA hangs when using I2C

Postby theGtknerd » Wed May 26, 2021 5:31 pm

Gotcha. Well, FWIW I copied the OTA source into my project, and just inserted a few lines.
I may have to roll with that and be happy. It's just odd this problem hasn't surfaced before and gotten a proper fix. If I knew more about callbacks, I would be tempted to add a callback to the OTA library, and use that to shut down the I2C tasks. That would be a nice way for future people to hook into.

User avatar
Vader_Mester
Posts: 300
Joined: Tue Dec 05, 2017 8:28 pm
Location: Hungary
Contact:

Re: OTA hangs when using I2C

Postby Vader_Mester » Thu May 27, 2021 5:41 am

theGtknerd wrote:
Wed May 26, 2021 5:31 pm
Gotcha. Well, FWIW I copied the OTA source into my project, and just inserted a few lines.
I may have to roll with that and be happy. It's just odd this problem hasn't surfaced before and gotten a proper fix. If I knew more about callbacks, I would be tempted to add a callback to the OTA library, and use that to shut down the I2C tasks. That would be a nice way for future people to hook into.
You don't want to run the OTA server all the time, just when you want to deploy a new firmware.
This OTA lib already needs a server. You don't call ota.begin() in the setup() function. You register a server request to it.
It is also advised to create the OTA loop task in setup().

Then your loop task will be:

Code: Select all

static void otaLoopTask(void *pVparams)
{
        vTaskSuspend(NULL); //suspend ourselves
        vTaskDelay(1); //Delay for 1tick is needed so that the idle task properly suspends this task and we won't enter the while loop
	while(1)
	{
	     AsyncElegantOTA.loop();
	     vTaskDelay(5000/portTICK_PERIOD_MS);
	}
}
Then you register the request to enable OTA:
Like

Code: Select all

  server.on("/iwannaota", HTTP_GET, [](AsyncWebServerRequest *request) {
     request->send(200, "text/plain", "Activating OTA platform");
     AsyncElegantOTA.begin(&server);
     vTaskResume(otaLoop); //Handle for the otaLoopTask must be used here
  });
This will activate the OTA function, and resume the loop task.
You just type into your browser: http://esp32.ipaddress/iwannaota and your OTA webpage will be avalable for use afterwards.
You can of course make a simple site hosted by the ESP, on which you just place a button to do the same thing.
This way the OTA is only running when you say so, but does nothing as long as it is not needed.

Code: Select all

task_t coffeeTask()
{
	while(atWork){
		if(!xStreamBufferIsEmpty(mug)){
			coffeeDrink(mug);
		} else {
			xTaskCreate(sBrew, "brew", 9000, &mug, 1, NULL);
			xSemaphoreTake(sCoffeeRdy, portMAX_DELAY);
		}
	}
	vTaskDelete(NULL);
}

theGtknerd
Posts: 6
Joined: Tue May 25, 2021 1:48 pm

Re: OTA hangs when using I2C

Postby theGtknerd » Thu May 27, 2021 10:46 am

Thanks, @Vader_Mester. That looks promising. It's a bit of code to digest, but I'll work on it. :D

Who is online

Users browsing this forum: No registered users and 48 guests