GPIO bit-banging - what are the actual limitations and sources of interference?

MartyMacGyver
Posts: 56
Joined: Sun Dec 18, 2016 9:17 pm

GPIO bit-banging - what are the actual limitations and sources of interference?

Postby MartyMacGyver » Fri Feb 10, 2017 11:58 pm

[Though this question refers to Arduino-ESP32 it's more of a general question about the ESP32 platform.]

When speaking of Arduino below, I'm using Arduino-ESP32 - however, as that simply runs

Code: Select all

xTaskCreatePinnedToCore(loopTask, "loopTask", 4096, NULL, 1, NULL, 1);
and loopTask is quite simple in itself (effectively whatever code you specify in setup() and loop()), that part should translate easily to a non-Arduino setup.

My question is, given a simple program that simply bit-bangs a GPIO pin, what are some sources of interruption or unexpected delay that would cause that to vary in terms of timing? As this is run on CPU 1, would WiFi or Bluetooth (not in-use for my little sketch) be interrupting things? Is there some memory caching going on that leads to timing variances? Are other things still happening on CPU1 in this regime?

I realize there are other ways to deal with this (e.g., RMT) - though they aren't in wide use when it comes to Arduino-ESP32 and in general mean a fair amount of code refactoring. For those times when bit-banging may be preferable it'd be useful to know what the actual limitations and sources of interference and delay are when it comes to GPIO bit-banging and the ESP32.

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: GPIO bit-banging - what are the actual limitations and sources of interference?

Postby kolban » Sat Feb 11, 2017 12:40 am

Howdy,
My 2 cents ... I would imagine that if you are running just "one core" then interrupts are occurring all the time. When an interrupt occurs, the code that was running is preempted and control is given to another section of code which runs until it releases and then we return back to the original code that was currently in progress OR ... we return to a completely different area of code. In the ESP-IDF, we are running on a multi-tasking preemtive environment. This means that we can create many more tasks than we have cores. If I have two tasks and two cores (ignoring interrupts) then each task will have 100% of the CPU all the time. However if I have three tasks and two cores, we will context switch between the tasks at will ... usually based on a time slice value or when a task voluntarily relinquishes control. As such, we should never believe that any two instructions in code that run will "actually" run sequentially. When one instruction finishes we may context switch somewhere else before returning.

This is why so much time critical work is handed off to the ESP32 hardware level (eg. I2C, SPI, UART, RMT, LEDC etc) so that preemption at the software level shouldn't affect the operation of the timing at the ESP32 hardware level which (I believe) has precedence over everything to ensure accuracy in timings.

Now if your software isn't "too" concerned about timings, you can us the vTaskDelay() and vTaskDelayUntil() APIs to block tasks ... but your accuracy is only a few milliseconds. If you are bit-banging I2C (as an example) with a period of 100KHz, then you are looking to toggle pins at the microsecond level. Thankfully, even then you might be safe as I2C and SPI both use a synchronized clock so if you are are "preempted" in the middle of I2C banging, you might still be okay as the clock transition could also be delayed.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

MartyMacGyver
Posts: 56
Joined: Sun Dec 18, 2016 9:17 pm

Re: GPIO bit-banging - what are the actual limitations and sources of interference?

Postby MartyMacGyver » Sat Feb 11, 2017 1:16 am

As far as I can tell Arduino-ESP32 runs code only on one core - that call to xTaskCreatePinnedToCore specifically pins the running loop to to CPU1.

What's very peculiar is how (using predictable code) the same few pixels are consistently incorrect (either during the initial pass through loop or through all passes - see below) - thus the data they are receiving is ill-formed. And the pixels aren't broken - the native code using RMT runs flawlessly.

That said, I strongly suspect the same exact issues would be seen on native code as well when bit-banging: I've seen other references to similar complaints, but I've yet to see a definitive answer as to what would interrupt a task this way, especially when it's the only nominal task on the device and is pinned to a particular core. Thus this question.

Given the way the "consistent inconsistency" can sometimes vary in a very particular way (namely, first loop() pass versus all subsequent ones, for a loop that is static) I wonder if caching is part of the problem. Either way, it's worth knowing what sources of variation might account for this - it doesn't seem to be context switches in that case.

MartyMacGyver
Posts: 56
Joined: Sun Dec 18, 2016 9:17 pm

Re: GPIO bit-banging - what are the actual limitations and sources of interference?

Postby MartyMacGyver » Sat Feb 11, 2017 12:09 pm

Followup: I got the RMT version of the WS2812 driver working in Arduino-ESP32 (the problem of driving NeoPixels is what prompted me to look into all this, though I still hope to gain more insight into the limits and quirks of GPIO):

https://github.com/MartyMacGyver/ESP32- ... ED-Drivers

Who is online

Users browsing this forum: No registered users and 125 guests