ESP32 FreeRtos Queue invokes [Guru Meditation Error: Core 0 panic'ed (LoadProhibited)] - queue

I have encountered a pretty strange problem while I was exploring the capabilities of FreeRtos on a ESP32 Wrover module. Currently, I have two tasks in my program. The first task will be used to collect some data, and the second one will be dedicated to print out debug messages to the serial monitor. These task use a queue to exchange data. Since I want to create a few more tasks in the system, the data collector task recieves the queue as part of a parameter struct. Here is my problem: if the data collector task sends only one message to the queue, the program works perfectly. But if I tried to add another message to the queue (as shown in the last piece of code), it forced the CPU to encounter a "LoadProhibited" exception. From what I have read in other topics, this problem is usually caused by accessing a NULL pointer somewhere in the program. But as you can see in the code below, I tried to add some protection by checking the pointers before adding anything to the queue. I also tried to raise the amount of allocated memory of the tasks, and pinning both task to core 1. I still got the same result.
Here is the main:
static QueueHandle_t debugMsgQueue = NULL;
static QueueHandle_t sensorDataBufQueue = NULL;
TaskHandle_t debugTaskHandle = NULL;
TaskHandle_t sensorTaskHandle = NULL;
uint32_t sensorTaskWatchdog;
ESP32Time rtc;
void StreamDebugger(void* pvParameters) {
char debugMsg[_debugDataLength];
while (1) {
if (debugMsgQueue != NULL) {
if (xQueueReceive(debugMsgQueue, (void*)debugMsg, portMAX_DELAY) == pdPASS) {
Serial.print(debugMsg);
}
}
}
}
void setup(){
Serial.begin(115200);
EEPROM.begin(_eepromSize);
/*CREATING GLOBAL DATA BUFFERS*/
debugMsgQueue = xQueueCreate(5, sizeof(char[_debugDataLength]));
sensorDataBufQueue = xQueueCreate(2, sizeof(char*));
if (debugMsgQueue == NULL || sensorDataBufQueue == NULL) {
Serial.print("\r\nCouldn't create dataBuffers. Aborting operation.");
}
BaseType_t xReturned;
/*DEBUG MESSAGE HANDLER TASK*/
xReturned = xTaskCreate(StreamDebugger, "DEBUG", 2048, NULL, 1, &debugTaskHandle);
if (xReturned != pdPASS) {
Serial.print("\r\nCouldn't create DEBUGTASK. Aborting operation.");
}
/*MEASURMENT HANDLER TASK*/
const ReadSensorsParameters sensorTaskDescriptor{ &debugMsgQueue,&sensorDataBufQueue,&sensorTaskWatchdog,rtc};
xReturned = xTaskCreate(ReadSensors, "GETDATA", 4096, (void*)&sensorTaskDescriptor, 1, &sensorTaskHandle);
if (xReturned != pdPASS) {
Serial.print("\r\nCouldn't create GETDATATASK. Aborting operation.");
}
}
void loop(){
}
This is the struct which is used by the sensor data collector task:
typedef struct READSENTASKPARAMETERS {
QueueHandle_t* debugQueue;
QueueHandle_t* dataQueue;
uint32_t* watchdog;
ESP32Time &systemClock;
}ReadSensorsParameters;
This is the data collector task, the one that works:
void ReadSensors(void* pvParameters) {
ReadSensorsParameters* handlers = (ReadSensorsParameters*) pvParameters;
char debugMsg[_debugDataLength];
char dataMsg[_msgDataMaxLength];
strcpy(debugMsg, "READSENSORTASK");
if (debugMsg != NULL && *handlers->debugQueue != NULL) {
xQueueSend(*handlers->debugQueue, (void*)debugMsg, portMAX_DELAY);
}
vTaskDelete(NULL);
}
And here is the modified task, which, for some reason does not work at all:
void ReadSensors(void* pvParameters) {
ReadSensorsParameters* handlers = (ReadSensorsParameters*) pvParameters;
char debugMsg[_debugDataLength];
char dataMsg[_msgDataMaxLength];
strcpy(debugMsg, "READSENSORTASK");
if (debugMsg != NULL && *handlers->debugQueue != NULL) {
xQueueSend(*handlers->debugQueue, (void*)debugMsg, portMAX_DELAY);
}
if (debugMsg != NULL && *handlers->debugQueue != NULL) {
xQueueSend(*handlers->debugQueue, (void*)debugMsg, portMAX_DELAY);
}
vTaskDelete(NULL);
}
And here is the error message I recieve:
rst:0xc (SW_CPU_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:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
READSENSORTASKGuru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400d0e5c PS : 0x00060d30 A0 : 0x800889dc A1 : 0x3ffb2f80
A2 : 0x00000000 A3 : 0x3f400fad A4 : 0x3ffc07b8 A5 : 0x3ffb8058
A6 : 0x00000000 A7 : 0x00000000 A8 : 0x800d0e5a A9 : 0x3ffb2f70
A10 : 0x3ffb2f8a A11 : 0x3f400fbc A12 : 0x000000ff A13 : 0x0000ff00
A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000010 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x4000142d LEND : 0x4000143a LCOUNT : 0xfffffff3
Backtrace: 0x400d0e5c:0x3ffb2f80 0x400889d9:0x3ffb2fe0
Does anyone have any idea?

SOLVED! Turned out (after a few sleepless nights) that
static const MyTaskParameters sensorTaskDescriptor{
&debugMsgQueue,
&sensorDataBufQueue,
&sensorTaskWatchdog,
rtc,
&sensorTaskWatchdogSemaphore,
&rtcSemaphore
};
had to be declared as a static variable. What I think had happened was that when READSENSORTASK was created, it immediately started running and was able to place data into the output buffer. After the first context switch the SETUP task was deleted automatically, and therefore this sensorTaskDescriptor variable was also deleted that is why next message placement invoked the LoadProhibited message. What is still weird for me is that I was trying to check all to pointers not to be NULL. I guess the faulty call was somewhere inside the xQueueSend function.
Anyways, I hope this thread helps someone.

Related

unity network variabe occasional writing permission error

I am new to unity netcode and I am trying to implement a grabbing/dropping mechanism for a 3rd person game.
But my network variable occasionally throws a confusing error out at the host side when client side "drop" something:
[Netcode] Client wrote to NetworkVariable`1 without permission. No more variables can be read. This is critical. => NetworkObjectId: 5 - GetNetworkBehaviourOrderIndex(): 1 - VariableIndex: 0
Sometimes it throws 1 of this error, sometimes it throws 2 and in rare case it doesn't throw error at all.
What is the possible reason for this?
Basically my approach is:
(below using clientNetworkTransform)
Grab:
calling grabServerRpc( callerClientId ) in the Grabbable object by the local player
passing the ownership of the Grabbable setting the network variable grabbedClientId to callerClientId in grabServerRpc()
in the OnValueChange delegate for every player, check if LocalPlayerId == grabbedClientId
if equal, set the local targetTransform to the grabbing point of the player and serval more properties to complete the grab
(the OnValueChange also check if grabbedClientId == Default value before doing anything to prevent execution due to dropServerRpc())
Drop:
unset the properties to drop it.
call the dropServerRpc() in the Grabbable
removeOwnership() in the dropServerRpc()
restore the grabbedClientId to default value to complete the drop
public void grab(ulong grabbedClientId){
this.grabServerRpc(grabbedClientId);
}
[ServerRpc(RequireOwnership = false)]
private void grabServerRpc(ulong grabClientId){
if (this.grabbedClientId != TPNetworkGrabbable.GRABBED_CLIENT_DEFAULT) return;
this.networkObject.ChangeOwnership(grabClientId);
this.grabbedClientId = grabClientId;
print("grabbed");
return;
}
private void OnGrab(ulong previous, ulong current){ // OnValueChange for grabbedClientId
if (this.grabbedClientId == TPNetworkGrabbable.GRABBED_CLIENT_DEFAULT) return; // prevent calling due to changes in drop()
if (this.grabbedClientId != NetworkManager.LocalClientId) return;
TPNetworkGrabbingControl grabbingControl = NetworkManager.LocalClient.PlayerObject.GetComponent<TPNetworkGrabbingControl>();
this._targetTransform = grabbingControl.grabPosition;
this.rigidbody.useGravity = false;
this.transform.rotation = Quaternion.Euler(0, 0, 0);
this.rigidbody.freezeRotation = true;
}
public void drop(){
if (this.grabbedClientId != NetworkManager.LocalClientId) return;
if (this.grabbedClientId == TPNetworkGrabbable.GRABBED_CLIENT_DEFAULT) return;
this._targetTransform = null;
this.rigidbody.useGravity = true;
this.rigidbody.freezeRotation = false;
this.dropServerRpc();
}
[ServerRpc(RequireOwnership = false)]
private void dropServerRpc(){
this.networkObject.RemoveOwnership();
this.grabbedClientId = TPNetworkGrabbable.GRABBED_CLIENT_DEFAULT;
print("dropped");
}
what I have done:
global searched my project and every single modification to any network variable are already done in [ServerRpc] and they are server write authoritive by default.
Googled and found basically nothing related to this specific error, except this:
though the solution seems to not apply to my case and the example does not exist anymore.

How does wakeup(void *chan) works in xv6?

I'm learning about osdev and looking up xv6 code, currently - the console code in particular. Basically, I don't get how the console launches a process.
in console.c there is a function:
void consoleintr(int (*getc)(void)) {
....
while((c = getc()) >= 0) {
switch(c) {
....
default:
....
if(c == '\n' || c == C('D') || input.rightmost == input.r + INPUT_BUF) {
wakeup(&input.r);
}
}
}
So I get it, when the line ends (or the length of the buffer exceeds maximum), it launches wakeup(&input.r)
Then there is this in proc.c:
// Wake up all processes sleeping on chan.
// The ptable lock must be held.
static void wakeup1(void *chan)
{
struct proc *p;
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
if(p->state == SLEEPING && p->chan == chan)
p->state = RUNNABLE;
}
// Wake up all processes sleeping on chan.
void wakeup(void *chan)
{
acquire(&ptable.lock);
wakeup1(chan);
release(&ptable.lock);
}
What is happening here? Why is it comparing address of a console buffer and proc's chan? What is this chan?
It is for processes who waiting (sleeps) for console input. See here:
235 int
236 consoleread(struct inode *ip, char *dst, int n)
...
251 sleep(&input.r, &cons.lock);
The code you have mentioned wakeups this sleeping processes, because data have came from console and is available now for processing.
chan - is a channel. You can wait (sleep) for different things. This channel is for console input data.

Java_java_net_PlainSocketImpl_socketSetOption

in open-jdk-8 :
this jin function : Java_java_net_PlainSocketImpl_socketSetOption:
/*
* SO_TIMEOUT is a no-op on Solaris/Linux
*/
if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
return;
}
file: openjdk7/jdk/src/solaris/native/java/net/PlainSocketImpl.c
does this mean , on linux setOption of SO_TIMEOUT will be ignored ?
I am can't found the jin for linux. but the solaris's code seems also works for linux .
No, it just means it isn't implemented as a socket option. Some platforms don't support it. On those platforms select() or friends are used.
The source inside solaris folder is also used for Linux.
SO_TIMEOUT is ignored in Java_java_net_PlainSocketImpl_socketSetOption0. But timeout is kept as a field when AbstractPlainSocketImpl.setOption is called:
case SO_TIMEOUT:
if (val == null || (!(val instanceof Integer)))
throw new SocketException("Bad parameter for SO_TIMEOUT");
int tmp = ((Integer) val).intValue();
if (tmp < 0)
throw new IllegalArgumentException("timeout < 0");
// Saved for later use
timeout = tmp;
break;
And timeout is used when doing read in SocketInputStream:
public int read(byte b[], int off, int length) throws IOException {
return read(b, off, length, impl.getTimeout());
}

Erasing page on stm32 fails with FLASH_ERROR_WRP

I am trying to erase one page in flash on an STM32F103RB like so:
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR | FLASH_FLAG_OPTERR);
FLASHStatus = FLASH_ErasePage(Page);
However, FLASH_ErasePage fails producing FLASH_ERROR_WRP
Manually enabling/disabling write protection in the stm32-linker tool doesn't fix the problem.
Basically FLASH_ErasePage fails with WRP error without trying to do anything if there's previous WRP error in the status register.
What comes to your FLASH_ClearFlag call, at least FLASH_FLAG_BSY will cause assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG)); to fail (though I'm not really sure what happens in this case).
#define IS_FLASH_CLEAR_FLAG(FLAG) ((((FLAG) & (uint32_t)0xFFFFC0FD) == 0x00000000) && ((FLAG) != 0x00000000))
What is your page address ? Which address are you trying to access ?
For instance, this example is tested on STM32F100C8 in terms of not only erasing but also writing data correctly.
http://www.ozturkibrahim.com/TR/eeprom-emulation-on-stm32/
If using the HAL driver, your code might look like this (cut'n paste from an real project)
static HAL_StatusTypeDef Erase_Main_Program ()
{
FLASH_EraseInitTypeDef ins;
uint32_t sectorerror;
ins.TypeErase = FLASH_TYPEERASE_SECTORS;
ins.Banks = FLASH_BANK_1; /* Do not care, used for mass-erase */
#warning We currently erase from sector 2 (only keep 64KB of flash for boot))
ins.Sector = FLASH_SECTOR_4;
ins.NbSectors = 4;
ins.VoltageRange = FLASH_VOLTAGE_RANGE_3; /* voltage-range defines how big blocks can be erased at the same time */
return HAL_FLASHEx_Erase (&ins, &sectorerror);
}
The internal function in the HAL driver that actually does the work
void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)
{
uint32_t tmp_psize = 0U;
/* Check the parameters */
assert_param(IS_FLASH_SECTOR(Sector));
assert_param(IS_VOLTAGERANGE(VoltageRange));
if(VoltageRange == FLASH_VOLTAGE_RANGE_1)
{
tmp_psize = FLASH_PSIZE_BYTE;
}
else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)
{
tmp_psize = FLASH_PSIZE_HALF_WORD;
}
else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)
{
tmp_psize = FLASH_PSIZE_WORD;
}
else
{
tmp_psize = FLASH_PSIZE_DOUBLE_WORD;
}
/* If the previous operation is completed, proceed to erase the sector */
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
FLASH->CR |= tmp_psize;
CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);
FLASH->CR |= FLASH_CR_SER | (Sector << POSITION_VAL(FLASH_CR_SNB));
FLASH->CR |= FLASH_CR_STRT;
}
Second thing to check. Is interrupts enabled, and is there any hardware access between the unlock call and the erase call?
I hope this helps

Mutual Exclusion Problem

Please take a look on the following pseudo-code:
boolean blocked[2];
int turn;
void P(int id) {
while(true) {
blocked[id] = true;
while(turn != id) {
while(blocked[1-id])
/* do nothing */;
turn = id;
}
/* critical section */
blocked[id] = false;
/* remainder */
}
}
void main() {
blocked[0] = false;
blocked[1] = false;
turn = 0;
parbegin(P(0), P(1)); //RUN P0 and P1 parallel
}
I thought that a could implement a simple Mutual - Exclution solution using the code above. But it's not working. Has anyone got an idea why?
Any help would really be appreciated!
Mutual Exclusion is in this exemple not guaranteed because of the following:
We begin with the following situation:
blocked = {false, false};
turn = 0;
P1 is now executes, and skips
blocked[id] = false; // Not yet executed.
The situation is now:
blocked {false, true}
turn = 0;
Now P0 executes. It passes the second while loop, ready to execute the critical section. And when P1 executes, it sets turn to 1, and is also ready to execute the critical section.
Btw, this method was originally invented by Hyman. He sent it to Communications of the Acm in 1966
Mutual Exclusion is in this exemple not guaranteed because of the following:
We begin with the following situation:
turn= 1;
blocked = {false, false};
The execution runs as follows:
P0: while (true) {
P0: blocked[0] = true;
P0: while (turn != 0) {
P0: while (blocked[1]) {
P0: }
P1: while (true) {
P1: blocked[1] = true;
P1: while (turn != 1) {
P1: }
P1: criticalSection(P1);
P0: turn = 0;
P0: while (turn != 0)
P0: }
P0: critcalSection(P0);
Is this homework, or some embedded platform? Is there any reason why you can't use pthreads or Win32 (as relevant) synchronisation primitives?
Maybe you need to declare blocked and turn as volatile, but without specifying the programming language there is no way to know.
Concurrency can not be implemented like this, especially in a multi-processor (or multi-core) environment: different cores/processors have different caches. Those caches may not be coherent. The pseudo-code below could execute in the order shown, with the results shown:
get blocked[0] -> false // cpu 0
set blocked[0] = true // cpu 1 (stored in CPU 1's L1 cache)
get blocked[0] -> false // cpu 0 (retrieved from CPU 0's L1 cache)
get glocked[0] -> false // cpu 2 (retrieved from main memory)
You need hardware knowledge to implement concurrency.
Compiler might have optimized out the "empty" while loop. Declaring variables as volatile might help, but is not guaranteed to be sufficient on multiprocessor systems.