_From @jt040-jetnet on November 21, 2017 10:21_
i am using esp32 in arduino core
i am using touch key feature in interrupt
getting below error and my esp32 gets restart ,
please suggest how to fix it,
Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed)
Register dump:
PC : 0x400d13f4 PS : 0x00060034 A0 : 0x40082388 A1 : 0x3ffc0bf0
A2 : 0x00000000 A3 : 0x3ffc3590 A4 : 0x00000001 A5 : 0x40086408
A6 : 0x00000003 A7 : 0x00060e23 A8 : 0x80081142 A9 : 0x04000c01
A10 : 0x00060e23 A11 : 0x00000000 A12 : 0x00060023 A13 : 0x3ffc0bd0
A14 : 0x3ffc0c18 A15 : 0x00000001 SAR : 0x0000001e EXCCAUSE: 0x00000007
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
Backtrace: 0x400d13f4:0x3ffc0bf0 0x40082385:0x3ffc0c10 0x4008f54f:0x00000000
Rebooting...
ets Jun 8 2016 00:22:57
rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0010,len:4
load:0x3fff0014,len:716
load:0x40078000,len:0
load:0x40078000,len:11572
entry 0x40078a14
_Copied from original issue: espressif/esp-idf#1299_
Fwiw, this looks like it is caused by interrupt firing while cache is disabled, see https://github.com/espressif/arduino-esp32/issues/489.
the code that was triggered by the interrupt did not have the IRAM_ATTR attribute.
Most O/S library function cannot be called from an ISR. Review your code, make sure that every function it calls is local. and has the IRAM_ATTR attribute. For example, you Cannot call Serial.print() from an ISR.
Chuck.
sorry to say but i didnt get how to fix the issue as i am using arduino ide
Read through this info for a more detailed discussion:
The function you attach to the interrupt:
static volatile uint16_t intTriggerCount=0; // this variable will be changed in the ISR, and Read in main loop
// static: says this variable is only visible to function in this file, its value will persist, it is a global variable
// volatile: tells the compiler that this variables value must not be stored in a CPU register, it must exist
// in memory at all times. This means that every time the value of intTriggeredCount must be read or
// changed, it has be read from memory, updated, stored back into RAM, that way, when the ISR
// is triggered, the current value is in RAM. Otherwise, the compiler will find ways to increase efficiency
// of access. One of these methods is to store it in a CPU register, but if it does that,(keeps the current
// value in a register, when the interrupt triggers, the Interrupt access the 'old' value stored in RAM,
// changes it, then returns to whatever part of the program it interrupted. Because the foreground task,
// (the one that was interrupted) has no idea the RAM value has changed, it uses the value it 'know' is
// correct (the one in the register).
void IRAM_ATTR isr(){ //IRAM_ATTR tells the complier, that this code Must always be in the
// ESP32's IRAM, the limited 128k IRAM. use it sparingly.
intTriggeredCount++;
}
void setup(){
Serial.begin(115200);
pinMode(5,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(5),isr,FALLING);
}
void loop(){
// magic happens her
static uint16_t old_Value=0; // this variable is only visible inside loop(),
// but it is persistent, It is only init'ed
// once, and each time through loop() it remembers its prior value
if(old_Value != intTriggeredCount){
old_Value = intTriggeredCount; // something to compare against
Serial.printf(" Someone grounded pin 5 again, it is the %d's time! Better call the Cops!",intTriggeredCount);
}
Chuck.
thanks stickbreaker
IRAM_ATTR works for my application

Thanks stickbreaker!
Also working in our case!
Closed due it was solved =)
@stickbreaker @igrr : I logged an issue #1352 . Could you kindly look at it to see if its similar to #855 ? The IRAM_ATTR solution mentioned here didn't work though.
Beware, not only the ISR (Interrupt) has to be in IRAM!
Every function called from the ISR also needs to be declared as IRAM_ATTR yourFunction() {}.
I made the mistake of using a normal function in my ISR and my ESP32 kept panicing when my code wanted to use the Preferences library (saving data to flash memory). I fixed it by also writing IRAM_ATTR before those function names.
Edit: It still happened and I found that you can't use analogRead() in the ISR either. I fixed it by setting a flag for it in the ISR. Now my code reads the pin in the superloop. A disadvantage is, that the value lags behind by 1 ISR.
@freemind64 Please edit your post, put three backticks(left apostrophe) on a separate line before your code, and three backticks on a new line after your code. It makes it easier to read.
Chuck.
sorry, I couldn't edit that code. the main issue are these function:
void IRAM_ATTR doEncoderA()
void IRAM_ATTR doEncoderB()
when I test encoder in a separate program , it doesn't show any error .
esp_encoder.zip
but in this one :
gsm_esp32_gc.zip
when I want to start calibration process, esp32 begin to reset with error in this topic.
please help me about this error, thank you.
@freemind64
//====================================
void doEncoderA() {
// look for a low-to-high on channel A
if (digitalRead(encoder0PinA) == HIGH) {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
else // must be a high-to-low edge on channel A
{
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
void doEncoderB() {
// look for a low-to-high on channel B
if (digitalRead(encoder0PinB) == HIGH) {
// check channel A to see which way encoder is turning
if (digitalRead(encoder0PinA) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
// Look for a high-to-low on channel B
else {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinA) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
//====================================
These two functions need to be resident in IRAM whenever the interrupt occurs. The ESP32 stores code in FLASH ROM, but it has to copy it into RAM before it can execute it. It uses a small RAM cache (64kB) as a buffer scratch pad, normal code is automatically copied from FLASH to ICACHE when needed, but interrupt code is assumed to always be present in RAM. So, You must tell the compiler to place these functions, and all the code they execute into IRAM. This is accomplished by:
void ATTR IRAM doEncoderA() {
//cut
void ATTR IRAM doEncoderB() {
//cut
Something else you might consider, I have see comments about pin interrupts triggering on CHANGE even though you have specified RISING or FALLING. I have not had time to test these conjectures, but since it would effect your code you might want to test it.
I would create two static booleans to hold the last state of the pins and compare it to the supposed new state:
static volatile bool lastState0A=false; //persistent, will be changed during interrupt
static volatile bool lastState0B=false;
static volatile int encoder0Pos=0; // Why did you define pos as a FLOAT? it is an integer value?
void ATTR IRAM doEncoderA() {
bool currentState = digitalRead(encoder0PinA);
if(currentState == lastState) return; // glitch nothing to do
lastState0A = currentState; // Store current pin0 State
// look for a low-to-high on channel A
if (currentState == HIGH) {
// check channel B to see which way encoder is turning
if (lastState0B == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
else{ // must be a high-to-low edge on channel A
// check channel B to see which way encoder is turning
if (lastState0B == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
Chuck.
Using this
void ATTR IRAM doEncoderA() {
and define encoder0Pos as an int solved my problem.
I know its an int but is there any deference to save any variable except the space they needed?
but I used old function in my program.
thanks @stickbreaker stickbreaker
@freemind64 The major difference between integer and float data types is speed of execution.
The ESP32 has a FPU(floating Point Unit), basically a sub processor to handle floating point math, but there is a performance penalty initializing, handing data off, waiting for results.
A float is a complex structure, that stores an approximation of a number. It usually cannot exactly record a value.
simple explanation of internal FLOAT storage
better explanation of FLOAT storage
Both of these explanations show how complex FLOATs are. Think about how you would code a function to update the bit value of a FLOAT directly, it is tough. So, unless you need decimal value approximations, use integer types for performance.
Chuck.
@stickbreaker again another problem that might be about this issue.
in function
void gc()
I want to control a dc motor position but the code in the while loop didn't work.
prr is the setpoint
gpr in motor position
while (prr != gpr);
{
gpr = (int)(abs(encoder0Pos) * anglm);
Serial.println("pr > gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
}
even serial print didn't work.
gsm_esp32_gc.zip
@freemind64 use three backtick's ``` on a line by themselves to bracket your code.
What was the while loop supposed to do? Did it not compile? Did it not loop?
If you want my help you are going to have to make it easy for me. Why would you expect me to correctly guess what you expected the code to do? Without even telling me what you observed the code doing?
Couple of comments please?
what is gc,gp,aglm,gpr,prr,pr,dpr.
You do realize that vowels do not cost extra?
What are you trying to achieve with:
void gc() {
void doEncoderA();
void doEncoderB();
Full text of function:, Snarky comments added by me
void gc() {
void doEncoderA();
void doEncoderB();
int dpr = 0; // depreciation rate
int z = 0; // last letter of the alphabet
encoder0Pos = (int)(gp / anglm); // reduce gross product by angular mass
gpr = gp; // set gross product rate to gross product
prr = pr * 10000; // set prior rate to prior times ten thousand?
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
if (prr < gpr) { // if prior rate less than gross product rate then cow it.
cw();
do {
gpr = (int)(abs(encoder0Pos) * anglm) ;
dpr = gpr - prr;
Serial.println("pr < gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
} while (dpr == 0);
stp();
Serial.println(gpr);
}
if (prr > gpr) {
ccw();
Serial.println("pr > gp");
while (prr != gpr); {
gpr = (int)(abs(encoder0Pos) * anglm);
// dpr = prr - gpr;
Serial.println("pr > gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
}
Serial.print("gp:"); Serial.println(gpr);
stp();
}
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
encoder0Pos = 0;
EEPROM.writeInt(30, gp);
EEPROM.commit();
}
//=============================
Chuck.
ok.
first ,thanks to teach me to ask my question in right way.
gc() is the function to control the motor position.
anglm is the (100/anglt) and anglt is total motor angular rotation from close to open.
dpr is the difference between setpoin (pr*10000=prr) and gp (gate position = gpr) . I used prr and gpr to be same as encoder0Pos.
prr = pr * 10000; because doing everything in integer .
when you send the set point command , it stored in pr. ( for example 10 % ).
then we want potion of 10 % openning.
```
void gc() {
int dpr = 0; // dpr is the difference between setpoin (pr=prr) and gp (gate position = gpr)
encoder0Pos = (int)(gp / anglm); //anglm is the (100/anglt) and anglt is total motor angular
//rotation from close to open.
gpr = gp; // gate position = gpr
prr = pr * 10000; // setpoin (pr=prr) / because doing everything in integer .?
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
if (prr < gpr) { // if set point is less than gate position then
cw(); // clockwise rotation
do {
gpr = (int)(abs(encoder0Pos) * anglm) ;
dpr = gpr - prr;
Serial.println("pr < gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
} while (dpr == 0);
stp();
Serial.println(gpr);
}
if (prr > gpr) { //if set point is greatar than gate position then
ccw(); // counter clockwise rotation
Serial.println("pr > gp");
while (prr != gpr); {
gpr = (int)(abs(encoder0Pos) * anglm);
// dpr = prr - gpr;
Serial.println("pr > gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
}
Serial.print("gp:"); Serial.println(gpr);
stp();
}
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
encoder0Pos = 0;
EEPROM.writeInt(30, gp);
EEPROM.commit();
}
@freemind64
The way I would code this function is a little different.
static volatile int32_t currentPos=0; // init to 0
static volatile bool motorRunning=false; // motor is not moving
static volatile bool lastStateA = false;
static volatile bool lastStateB = false;
#define clockWiseLimitPin 15 //when gpio15 is low, limitswitch is active.
#define counterClockWiseLimitPin 16 //when gpio16 is low, limitswitch is active.
#define encoderAPin 17
#define encoderBPin 18
bool ATTR IRAM stopRotation(){ //IRAM because this function can also be called from Interrupt
// actually control the motor here. If successful, mark motorRunning state.
motorRunning = false;
return !motorRunning;
}
bool rotateClockWise(){
// actually control the motor here. If successful, mark motorRunning state.
motorRunning = true;
return motorRunning;
}
void ATTR IRAM encoderA(){ // a/b rotation encoder,
bool currentState = digitalRead(encoderAPin); //
if ( lastStateA == currentState) return; // spurious interrupt, ignore it
lastStateA = currentState;
if ( currentState ) { //pin went high
if( !lastStateB ) { // clockWise rotation, because B is Low
currentPos++; // increment position
if( !digitalRead(clockWiseLimitPin)) { // limit is active, stop motor
stopRotation();
}
}
else { // counterClockWise rotation
currentPos--; // decrement position
if( !digitalRead(counterClockWiseLimitPin)) { // limit is active stop motor
stopRotation();
}
}
}
else { // pin went low
if( lastStateB ){ // clockWise Rotation, because B is high and A went Low
currentPos++;
if( !digitalRead(clockWiseLimitPin)) { // limit is active, stop motor
stopRotation();
}
}
else { // counterClockWise rotation
currentPos--;
if( !digitalRead(counterClockWiseLimitPin)) { // limit is active stop motor
stopRotation();
}
}
}
}
bool gotoPosition(int32_t newPos, uint32_t timeOut){
uint32_t tick=millis(); // movement starting tick, in milliseconds
bool successfulMove = false;
If (newPos > currentPos){ // move clockwise
if (!rotateClockWise()) { // motor failed when attempting clockwise rotation
// this failure could be because the motor is at the clockWise limit also
return false;
}
while(((millis()-tick)<timeOut) && (newPos > currentPos) && motorRunning){
// motorRunning is volatile, updated if rotation limit exceeded.
// currentPos is volatile, updated by encoder interrupts.
// timeOut will handle millis() overflow
yield(); // wait for motor to move enough
}
if (!stopRotation()){ // Motor stop failed
return false;
}
successfulMove = (currentPos <= newPos);
}
else if ( newPos < currentPos){
if (!rotateCounterClockWise()) { // motor failed when attempt counterClockWise rotation
return false;
}
while(((millis()-tick)<timeout) && (newPos < currentPos) && motorRunning){
yield();
}
if (!stopRotation()){ // Motor stop failed
return false;
}
successfulMove = (currentPos<=newPos);
}
else { // newPos == currentPos, so nothing to do
successfulMove = true;
}
return successfulMove;
}
Calculate the new position before you pass it to the function, all the angular scaling should happen
at a higher level of code. Make your motor driver calls as primitive as possible.
Short, simple and descriptive.
Don't use abbreviate variable names.
Think about how you would support this code in 10 years. I have code I wrote in 1986 in Pascal on a
PC/XT that I still support. That was 32 years ago. Every few years I have to relearn it just to support it.
Chuck.
thanks Chuck. It was helpful, just you have to know entire rotation from close to open, when you want to write control loop to reach new position.
the hardware design is :
gpio 12 : close limit switch ---> input pin
gpio 13 : open limit switch ---> input pin
gpio 18 : L298 in1 ---> output pin in1=1, in2=0 to clockwise / in1=0 in2=0 to stop
gpio 19 : L298 in2 ---> output pin in1=0, in2=1 to counter clockwise
gpio 34: encoder phase A
gpio 35: encoder phase B
we need a calibration process to know entire rotation , then we know current position as you wrote in your code.
what are these pins?
#define clockWiseLimitPin 15 //when gpio15 is low, limitswitch is active.
#define counterClockWiseLimitPin 16 //when gpio16 is low, limitswitch is active
they control rotation or limits of motor because they are different.
In Arduino-IDE we must use this IRAM_ATTR ,your code is ATTR IRAM.
much thanks for your precious time.
@freemind64 You call them close limit switch and open limit switch.
I don't know your circuit, so I just created two LOW active switches that activate when a clockwise or counterclockwise limit is reached. I just wanted to show that the limits switches should be monitored inside the encoder interrupt routine. That way the limits are enforced immediately, if a limit is reached the motor should stop. Also, you should add a limit check before you start moving the motor. If the motor is at a clockwise limit, you should not move the motor clockwise. Have the CW() Return an error.
Good catch on the IRAM.
Chuck.
@stickbreaker , the code was ok and worked for me , just to complete the issue .
use interrupt for encoder purpose and have the "Guru Meditation Error".
setup :
void doEncoderA();
void doEncoderB();
// encoder pin on interrupt 0 (pin 2)
attachInterrupt(34, doEncoderA, RISING);
// encoder pin on interrupt 1 (pin 3)
attachInterrupt(35, doEncoderB, RISING);
encoder position :
void IRAM_ATTR doEncoderA() {
// look for a low-to-high on channel A
if (digitalRead(encoder0PinA) == HIGH) {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
else // must be a high-to-low edge on channel A
{
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
void IRAM_ATTR doEncoderB() {
// look for a low-to-high on channel B
if (digitalRead(encoder0PinB) == HIGH) {
// check channel A to see which way encoder is turning
if (digitalRead(encoder0PinA) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
// Look for a high-to-low on channel B
else {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinA) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
and control function :
bool gotoPosition(int32_t newPos, uint32_t timeOut) {
timeOut = 20000;
gp = EEPROM.readInt(30);
encoder0Pos = (int32_t)(gp * anglt / 100);
newPos = (int32_t)(pr * anglt / 100);
uint32_t tick = millis(); // movement starting tick, in milliseconds
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
Serial.print("gp:"); Serial.println(gp);
Serial.print("newPos:"); Serial.println(newPos);
bool successfulMove = false;
if (newPos > encoder0Pos) { // move clockwise
cw();
if (!rotateClockWise) { // motor failed when attempting clockwise rotation
// this failure could be because the motor is at the clockWise limit also
return false;
}
while (((millis() - tick) < timeOut) && (newPos > encoder0Pos) && motorRunning) {
// motorRunning is volatile, updated if rotation limit exceeded.
// currentPos is volatile, updated by encoder interrupts.
// timeOut will handle millis() overflow
yield(); // wait for motor to move enough
}
Serial.print("encoder0Pos: "); Serial.println(encoder0Pos);
Serial.print("tick: "); Serial.println(tick);
Serial.print("gp-cw: "); Serial.println(gp);
EEPROM.writeInt(30, pr);
EEPROM.commit();
stp();
if (!stopRotation()) { // Motor stop failed
return false;
}
successfulMove = (encoder0Pos <= newPos);
}
else if ( newPos < encoder0Pos) {
ccw();
if (!rotateCounterClockWise) { // motor failed when attempt counterClockWise rotation
return false;
}
while (((millis() - tick) < timeOut) && (newPos < encoder0Pos) && motorRunning) {
yield();
}
Serial.print("encoder0Pos: "); Serial.println(encoder0Pos);
Serial.print("tick: "); Serial.println(tick);
Serial.print("gp-ccw: "); Serial.println(gp);
EEPROM.writeInt(30, pr);
EEPROM.commit();
stp();
if (!stopRotation()) { // Motor stop failed
return false;
}
successfulMove = (encoder0Pos <= newPos);
}
else { // newPos == currentPos, so nothing to do
successfulMove = true;
}
return successfulMove;
}
Hi, @stickbreaker
I got the
Cache disabled but cached memory region accessed
Crash error.
I checked my ISR functions. I use ESP.getCycleCount() in it, and it doesn't get the IRAM_ATTR.
I'm wondering if ESP.getCycleCount()is the problem?
And the crash sometimes happens not 100% happens.
Is ESP32's Cached not always disabled or enabled?
Is ESP32 only crashes when cache disabled? So it is not a certain crash?
@human890209, the esp32 has to disable the iCache(instruction Cache, the RAM buffer used to execute code stored in the external FLASH chip) whenever it needs to programmatically access the Data in the FLASH chip(SPIFFS, NVS, PREFERENCES).
The problem occurs because changing data in the FLASH is a 3 step process, first read the PAGE(4kB) into the iCache buffer, that needs to be changed. Second, tell the FLASH chip to erase the selected PAGE(takes about 32ms for the chips hardware to accomplish). Third, apply the changes to the iCache buffer image, then write this updated page(4kB) back to the FLASH.
During this entire sequence NO code can be executed from iCache, only code in IRAM, or ROM is available.
Your ISR(interrupt service routine) must not call any code in iCache. You have to Verify all code you call is in IRAM. AND IRAM is only 128kB total. IRAM is used by the FreeRTOS core, and all of the hardware drivers. So, only a small amount is free for user code.
Chuck
Hi, @stickbreaker
Thanks a lot. I made an ESPMOD.getCycleCount() and add the IRAM_ATTR, there is no more Crash.
IRAM is only 128kB total. IRAM is used by the FreeRTOS core, and all of the hardware drivers. So, only a small amount is free for user code.
I see these 2 lines in the table which is displayed after compiling. I see about 46k of IRAM usage. Are all the drivers and FreeRTOS codes in this 46k or it's only a total sum of user code?
section size addr
.iram0.vectors 1024 1074266112
.iram0.text 46464 1074267136
@human890209 should be all of the resident code, this is the recipe from 'tools/sdk/ld/esp32.common.ld'
.iram0.text :
{
/* Code marked as runnning out of IRAM /
_iram_text_start = ABSOLUTE(.);
*(.iram1 .iram1.)
libfreertos.a:(.literal .text .literal. .text.)
*libheap.a:multi_heap.(.literal .text .literal.* .text.)
*libheap.a:multi_heap_poisoning.(.literal .text .literal.* .text.)
*libesp32.a:panic.(.literal .text .literal.* .text.)
*libesp32.a:core_dump.(.literal .text .literal.* .text.)
*libapp_trace.a:(.literal .text .literal. .text.)
*libxtensa-debug-module.a:eri.(.literal .text .literal.* .text.)
*librtc.a:(.literal .text .literal. .text.)
*libsoc.a:rtc_.(.literal .text .literal. .text.)
*libsoc.a:cpu_util.(.literal .text .literal.* .text.)
*libhal.a:(.literal .text .literal. .text.)
*libgcc.a:lib2funcs.(.literal .text .literal.* .text.)
*libspi_flash.a:spi_flash_rom_patch.(.literal .text .literal.* .text.)
*libgcov.a:(.literal .text .literal. .text.*)
INCLUDE esp32.spiram.rom-functions-iram.ld
_iram_text_end = ABSOLUTE(.);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
The more code placed in IRAM the less RAM available for data.
Chuck.
Hi folks,
I have same problem and I did set up my function like this:
void ATTR IRAM nextsong(){
// my code...
}
But I am getting error: error: expected initializer before 'IRAM'
What could be problem?
Thanks.
@markosole it's missing a underscore, the correct is IRAM_ATTR
Thanks a lot that works now. Here is sample which may be handy for someone.
interruptNextSong is than used in Loop and has been checked.
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR handleInterruptNext() {
portENTER_CRITICAL_ISR(&mux);
interruptNextSong++;
portEXIT_CRITICAL_ISR(&mux);
}
Thanks guys.
@felixqueisler I have the same problem with the preferences library, that麓s why I want to ask if you could share the code you talked about in your post? This is the first time i have encountered such a problem as i am fairly new to ESP32, that麓s also why i couldn麓t quite understand the solutions posted in this thread. Please, your help would be greatly appreciated.
Thank you.
@felixqueisler I have the same problem with the preferences library, that麓s why I want to ask if you could share the code you talked about in your post? This is the first time i have encountered such a problem as i am fairly new to ESP32, that麓s also why i couldn麓t quite understand the solutions posted in this thread. Please, your help would be greatly appreciated.
Thank you.
You have an interrupt function defined...
Inside that function you only do the bare minimum. You check for a condition and when it's true you either set a boolean = true or an integer ++; In the main loop you then check for those flags to execute more code and then set the flag false or -- or 0.
Most helpful comment
Read through this info for a more detailed discussion:
General Notes
The function you attach to the interrupt:
Chuck.