Declaring global variables in different tab

If you create an Arduino project with the principal .INO file and a few other .INO files in the same folder the Arduino IDE will load the principal file first and then load the others in alphabetical order. A global variable will be visible in all files loaded after the file in which it is declared but not in files loaded before. So the best place for global variables is in the principal file.

Source: Declaring global variables in different tab

Declaring global variables in different tab was last modified: December 6th, 2018 by Jovan Stosic

What is and when to use IRAM_ATTR ? – ESP32 Forum

The ESP32 is based on a harvard architecture which means that there are two buses … one for instructions and one for data. Loosely, address space south of 0x4000 0000 is taken from the data bus while address space (if I remember correctly) from 0x4000 0000 to 0x4FFF FFFF is from the instruction bus.

Now imagine a 64K page of RAM. Unlike in other environments where that page of RAM “just exists” at a fixed address space location, on the ESP32 we have MMU (Memory Mapping Unit) which can make that 64K page of real RAM be mapped to distinct address locations. This means that we can have RAM that can be read from the data bus or have RAM read from the instruction bus.

That then begs the question, what would you put in RAM that can be read from the instruction bus? The answer is (if I understand correctly) … instructions (executable code).

When we compile a C source file we end up with an object file that is then linked to produce an executable. During compilation, the different “sections” of the compiled C are placed in different “sections” of the object file. For example, code goes into the “.text” section and initialized data goes into the “.data” section. By flagging a piece of code with the “IRAM_ATTR” we are declaring that the compiled code will be placed in a section called “.dram.text” (I’m making that up as I don’t have a reference to hand). What this means is that instead of an executable having just “.text” and “.data” sections, there are additional sections. The ESP32 bootloader, upon startup, will copy those “.dram.text” sections into real RAM at startup before giving control to your application. The RAM is then mapped into the instruction area address space (> 0x4000 0000). This means that control can be passed to this code (as normal) from within your running app and it will “work” because the code lives in the instruction bus address space.

What now remains is “why” you would want to do this? The answer is to consider the alternative. If the code you want to run is NOT in RAM, then where else could it be? The answer is “flash” … if it is in flash, then when a request to execute that code is received, the code has to be executed from there. Flash on the ESP32 is much slower than RAM access … so there is a memory cache which can be used to resolve some of that … however we can’t be assured that when we branch to a piece of code that it will be present in cache and hence may need a slow load from flash.

And now we come to the kicker … if the code we want to run is an interrupt service routine (ISR), we invariably want to get in and out of it as quickly as possible. If we had to “wait” within an ISR for a load from flash, things would go horribly wrong. By flagging a function as existing in RAM we are effectively sacrificing valuable RAM for the knowledge that its access will be optimal and of constant time.

Source: What is and when to use IRAM_ATTR ? – ESP32 Forum

What is and when to use IRAM_ATTR ? – ESP32 Forum was last modified: December 4th, 2018 by Jovan Stosic

Crash when using external interrupt

A couple of changes, you need to tell the compiler to always have the ISR in RAM. This processor ESP32 loads program from FLASH into RAM where it executes it. It only has 128Kbytes of RAM for ICACHE (instruction cache) so it switches out unused code on the fly. When an interrupt is triggered it bypasses the Cache load operation and jumps right to the specified code (ISR) location. If that ISR is not in RAM it panics.

Source: https://github.com/espressif/arduino-esp32/issues/954

Crash when using external interrupt was last modified: December 4th, 2018 by Jovan Stosic

EEPROM: EEPROM.end() crashes and reboots

The ESP32 only has 520kB of RAM, a small part ~128kB is the instruction cache. It loads program code from the 4MB FLASH, then executes from this RAM. The EEPROM() library emulates the EEPROM in a AVR processor by allocating a RAM buffer of the Requested Size (multiple of 4096 bytes, because the FLASH has to ERASE 4kB at a time). It then applies your EEPROM.write() to this RAM buffer, when you commit() it Disables Cache because it has to Take control of the FLASH, (background code loading is frozen) Issues the Flash Erase command (which can take a long Time, tens to hundreds of ms). Since this task is held waiting for the Hardware, FreeRTOS finds another task that it can release, or in your case, BLE issues a callback. But, since you did not tell the compiler to always keep the callback in RAM, the Callback code is still in the FLASH which is eraseing a sector for EEPROM(). Since the background instruction loading function needs to use the cache and the FLASH to service this callback. It explodes.

Callbacks, Interrupts, any code that can execute out of order needs to always reside in the limited 128kB instructionRam. So any code that can be called out of order needs ATTR_IRAM which forces the compiler to keep it in RAM forever. AND, every call from that code must ALSO be in RAM at all times. So, be parsimonious about which code you call.

Source: https://github.com/espressif/arduino-esp32/issues/928

EEPROM: EEPROM.end() crashes and reboots was last modified: December 4th, 2018 by Jovan Stosic