B4R Question Problems with SELECT CASE

Gerardo Tenreiro

Active Member
Licensed User
Hello Forum,
I've been working on an ESP32 application for months, the application has a lot of code, so I was generating the different modules separately and testing them.

Apparently all the modules work correctly separately but now when joining them in an application I see that every certain random time, 10 or 15 minutes, the ESP32 restarts with this error message:
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.

I start to eliminate modules and each time the problem appears in another area of the program without meaning, but it is always where there are SELECT CASE instructions, for example in this program block:

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'
' Gestion del Menu 100 al 199
'
Private Sub Gestion_del_Menu_100_199
Private M1 As Byte ' Memoria Inicial del Menu de Display
Private M2 As Byte ' Memoria Inicial del SubMenu de Display


' Memoriza el Numero de menu
M1 = DISPLAY.Menu_Display
' Memoriza el SubMenu
M2 = DISPLAY.SubMenu_Display
' Segun en la Pantalla que Esta Asi actuan las Teclas
Select Case DISPLAY.Menu_Display
Case 100 ' Inicio Menu Tecnico
If F_T_Mas = True Then
DISPLAY.SubMenu_Display = DISPLAY.SubMenu_Display + 1
End If
If F_T_Menos = True Then
DISPLAY.SubMenu_Display = DISPLAY.SubMenu_Display - 1
End If
' Si Se Pulsa Enter
If F_T_Enter = True Then
' Segun el Sub Menu Seleccionado Asi Actual
Select Case DISPLAY.SubMenu_Display
Case 0 ' Pruebas
DISPLAY.SubMenu_Display = 0
DISPLAY.Menu_Display = 103
Case 1 ' Parametros VF
DISPLAY.SubMenu_Display = 0
DISPLAY.Menu_Display = 113
Case 2 ' PLC
DISPLAY.SubMenu_Display = 0
DISPLAY.Menu_Display = 111
Case 3 ' Mas

Case 4 ' Atras
DISPLAY.SubMenu_Display = 0
DISPLAY.Menu_Display = 3
End Select
End If
Case 104 ' Menu Principal de Pruebas
If F_T_Mas = True Then
DISPLAY.SubMenu_Display = DISPLAY.SubMenu_Display + 1
End If
If F_T_Menos = True Then
DISPLAY.SubMenu_Display = DISPLAY.SubMenu_Display - 1
End If
' Si Se Pulsa Enter
If F_T_Enter = True Then
' Segun el Sub Menu Seleccionado Asi Actual
Select Case DISPLAY.SubMenu_Display
Case 0 ' Pruebas Salidas Digitales
DISPLAY.Aux_BY = 0
DISPLAY.Aux_Bi = 0
DISPLAY.Aux_V = False
DISPLAY.Menu_Display = 107
Case 1 ' Pruebas Salida Analogica 1
DISPLAY.Aux_By = 1
DISPLAY.Menu_Display = 109
Case 2 ' Pruebas Salida Analogica 2
DISPLAY.Aux_By = 2
DISPLAY.Menu_Display = 109
Case 3 ' Mas
'DISPLAY.Aux_BY = 1
'DISPLAY.SubMenu_Display = 0
'DISPLAY.Menu_Display = 21
DISPLAY.SubMenu_Display = 0
DISPLAY.Menu_Display = 121

Case 4 ' Atras
DISPLAY.SubMenu_Display = 0
DISPLAY.Menu_Display = 99
End Select
End If

Case 108 ' Pruebas Salidas Digitales

This piece of code has several SELECT CASE chained inside each other, but the error is not always generated in this module, it is a continuous module but I shorten it.

If I cancel this piece of code the error continues in other code that contains the SELECT CASE statement. it's a random thing.

I can't find an explanation for the malfunction of the code.

Someone is suffering the same problem.

Thank you so much
 

Gerardo Tenreiro

Active Member
Licensed User
#Region Project Attributes
#AutoFlushLogs: True
#CheckArrayBounds: True
#StackBufferSize: 8192
In the program I have some verification points of the use of the stack with the instruction:
Log("Minuto=",RELOJ.Minuto,". RAM=",AvailableRAM, ". Pila = ",StackBufferUsage,"...",Menu_Display)
and the result never exceeds 25

The funny thing is that if I cancel any block, it doesn't matter which one, the time between restarts increases, although after one or two hours it ends up restarting anyway.
It is as if it were gradually accumulating a value and it overflows, but all the variables check their limits before assigning any value and there is none that can overflow.
It is also very curious that there are modules of the program that are not being executed because they are not being called because a condition is not met, but they still give an error.

I'm still totally lost with this problem.
Thanks for the help
 
Upvote 0

janderkan

Well-Known Member
Licensed User
Longtime User
Every command will use the stack.
So if you check stackbuffersize before and after the look ok.
But the command can make your stackbuffer overflow.
Best way to find the stackbuffersize, is to increase until the error disappears and add 20%
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Add some Sleep(1) in the code of repetitive tasks (or run an inline C yield( ); function).
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Also break the code in several subs in order to create a better memory managment. Local variables in the sub are destroyed when you exit the sub and thus the memory is freed...
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Add some Sleep(1) in the code of repetitive tasks (or run an inline C yield( ); function).

Probably you will need more than one Sleep(1) / yield ( ); functions in each repetition.
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Probably you will need more than one Sleep(1) / yield ( ); functions in each repetition.

Sorry, Delay(1) not Sleep(1)...
 
Upvote 0

Gerardo Tenreiro

Active Member
Licensed User
Hello again

I check the stack size in each module at start and end, it never uses more than 25. so the stack is not

The program does not have long repetitive ships, the longest is a FOR of 30 repetitions


Eliminate some SELECT CASE from several modules, change it to IF THEN and now the program takes more than two hours without stopping, but this is not normal. There is no logical explanation why a SELECT CASE of 200 "CASE" works and another of 30 "CASE" crashes after 15 minutes.
Either something in the program is not being cleaned up properly or the SELECT CASE statement is not working correctly

I continue without a clear explanation of what is happening so any contribution will be very welcome
Thank you so much
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
The problem according to what I have faced in the past with Espressif chips is that it manages from the same thread (???) your program and chip administrative tasks/checks and if it does not get attention in the time it needs it then it breaks... Thus you will need more tnan one Delay(1)/yield( ); which give control to the chip for its tasks.
 
Upvote 0

Gerardo Tenreiro

Active Member
Licensed User
Thank you, I also suffered from it in another project, it cost me a lot to get it to work correctly.
This project works by time, let me explain.
There is a main routine that runs every 10ms, this routine takes 2ms to run.
There is another routine that is executed every 12ms, it is an RS485 communication to different elements. This routine takes less than 2.8ms to execute.
There is another SPI communication routine with the TFT and the remote control, this routine is executed every 250ms, display refresh time
There are two other communication turns that work alternately, every 7ms
and finally there is a continuously running main loop that checks the limits and flags of the rest of the routines. This main routine runs about 45,000 times per second and is where the system is refreshed so it is never in a loop.

My opinion is increasingly focused on how the compiler treats SELECT CASE instructions and the resources it uses for it. It's the only thing that comes to my mind at the moment.

çNow the program has been running for more than 3:30:00 without stopping and the only thing I did was change many SELECT CASE statements to IF THEN. So this confirms my hypothesis.

I attach an analysis of the communication lines of the program so that it can be seen that it works in a non-synchronous way.


1692356976978.png


Thank you very much for the help
and see if I locate the error in a patient way.
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
That is correct. Trial and error is always the best option. Just out of curiosity. Why don't you keep the Millis before SELECT CASE and the Millis after END SELECT logging the difference to see if this helps you...
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Also I would consider the case of a state machine to give to the chip the option to yield( ); regularly. In the AddLooper Sub use this for your stuff and after SELECT CASE / END SELECT use the same logic (instantly leave or execute code if the IF condition is true) to yield();/delay(1) regularly. Have a look here:

 
Last edited:
Upvote 0

Gerardo Tenreiro

Active Member
Licensed User
Hello
Place a call "RunNative("yld", Null)" in the main routine and 5 in the longest routine, the one that takes 2.4ms to execute.
At the moment it takes 10 minutes without stopping.
The time he was the longest without giving an error was 4 hours and 12 minutes.

Now it's time to wait to see if this solves

Thank you so much
 
Upvote 0

Gerardo Tenreiro

Active Member
Licensed User
Hello
The instruction "RunNative("yld", Null)" does not solve the problem
Put a lot of instructions in every module, the beginning, at 25%, at 50% and at the end. The result the same as always, the same error.
It may take more or less but the error always appears.
If I delete many modules and only leave two or three active, the error does not appear, regardless of the modules that I leave active. That means that the error is not in any module.
I am totally lost with this problem.
Some help
Thank you
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Upvote 0

Gerardo Tenreiro

Active Member
Licensed User
It cannot be a code error, each module was tested independently and works correctly.

Also, it doesn't matter which module I cancel in the program, if I have more than approximately 200 SELECT CASE active in the program, even though they are not being executed, the program ends up giving this error

Right now I am retesting by analyzing some modules that have many select CASE and everything works correctly.

What's more, some modules that when they are active generate the error if I change the SELECT CASE to IF THEN the problem is solved.

Did anyone use a lot of SELECT CASE?
Thank you

😰😰😰
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
No code error. When I was fixing something with continuous repetitions, I faced this but in an ESP8266 chip. When setting in a variable array something it turns that some times it is overwritten by a later calculation and when you try to access an item of the array you get wrong data or it breaks. Also transfer immediately in a local variable.
 
Upvote 0

Gerardo Tenreiro

Active Member
Licensed User
Does not use variable length arrays I only use fixed length arrays and always check the value of the array before reading or writing that it is not outside the size of the array.

I am running the modules from the first onwards for 30 minutes to verify that there is no error in the module, let me explain, I have about 60 modules and at the moment I have half working without the error appearing. So I will follow this method so that when a module is activated and the error occurs, I will analyze said module in depth and comment on where the error appears.

By the way, after each module I execute the instruction "RunNative("yld", Null)" which I will later remove to verify where they are needed.

Thank you so much.
 
Upvote 0

hatzisn

Well-Known Member
Licensed User
Longtime User
Please let us know if you find what is wrong...
 
Upvote 0
Top