I have an esp32 and i wish to use it to drive a HC-SR04 sonar module. I use interrupts to get information from sensors,then I use a queue to pass the data to a freertos task to output it. At first, it work and output the correct data, but after few second, it report an error and reboot.
Here is the error:
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x40084c90 PS : 0x00050631 A0 : 0x800d31c4 A1 : 0x3ffbf53c
A2 : 0x00000040 A3 : 0x00018040 A4 : 0x000637ff A5 : 0x3ffbf50c
A6 : 0x00000008 A7 : 0x00000000 A8 : 0x00000001 A9 : 0x4008bf6e
A10 : 0x00060b23 A11 : 0x3ffc4a14 A12 : 0x3ff44000 A13 : 0xffffff00
A14 : 0x00000000 A15 : 0x00000020 SAR : 0x0000001d EXCCAUSE: 0x0000001c
EXCVADDR: 0x800d31d0 LBEG : 0x400899a4 LEND : 0x400899ba LCOUNT : 0xffffffff
Backtrace: 0x40084c8d:0x3ffbf53c |<-CORRUPTED
Then I found that if I delete the code that were used to push the data to the queue, it will work normally. So I guass that is the problem,but I don't Know how to fix it.
Here is main:
radar radar0(25,35);
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.setDebugOutput(true);
radar0.start();
}
Here is how radar class define:
class radar
{
private:
uint8_t txPin,rxPin;
Ticker loopTrigger; //ticker that use to trigger loop
Ticker singalEnder; //ticker that use to generate a 1ms pulse
QueueHandle_t dstQueue; //queue that use to pass dst to coroutine
float previousDst;
bool enable;
unsigned long echoStartTime; //The time the echo start received
void loop();
void echoStartHandler(); //callback when the echo start
void echoEndHandler(); //callback when the echo end
void queueListener();
public:
radar(uint8_t txPin,uint8_t rxPin);
void start();
};
radar::radar(uint8_t txPin,uint8_t rxPin){
this->txPin=txPin;
this->rxPin=rxPin;
this->enable=true;
this->dstQueue = xQueueCreate(4,sizeof(float));
}
void radar::start(){
//set pin mode
pinMode(this->txPin,OUTPUT);
pinMode(this->rxPin,INPUT);
//low down the txPin
digitalWrite(this->txPin,LOW);
//Create a coroutine for listening to the dstQueue
auto fn = [](void *arg){static_cast<radar*>(arg)->queueListener();};
xTaskCreate(fn,"dstListener",1024,this,0,NULL);
//enable the radar
this->enable=true;
this->loop();
}
void radar::queueListener(){
float dst;
while (this->enable)
{
if (xQueueReceive(this->dstQueue,&dst,0)==pdFALSE){
//sleep 10ms if the queue is empty
vTaskDelay(10/portTICK_PERIOD_MS);
continue;
}
if (abs(dst-this->previousDst)>5){
Serial.println(dst);
this->previousDst=dst;
}
}
vTaskDelete(NULL);
}
void radar::echoStartHandler(){
this->echoStartTime = micros();
//Set rxPin pull-down interrupt
attachInterruptArg(rxPin,[](void* r){static_cast<radar*>(r)->echoEndHandler();},this,FALLING);
}
void radar::echoEndHandler(){
detachInterrupt(this->rxPin);
unsigned long echoEndTime = micros();
float pluseTime;
if (echoEndTime > this->echoStartTime){ //If the variable does not overflow
pluseTime = echoEndTime - this->echoStartTime;
}else{
pluseTime = echoEndTime + (LONG_MAX - this->echoStartTime);
}
float dst = pluseTime * 0.0173;
//push the dst to queue
BaseType_t xHigherPriorityTaskWoken;
xQueueSendFromISR(this->dstQueue,&dst,&xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken==pdTRUE){
portYIELD_FROM_ISR();
}
}
void radar::loop(){
if (!this->enable){
return;
}
//Set loop() to be triggered after 100ms
this->loopTrigger.once_ms<radar*>(100,[](radar* r){r->loop();},this);
//Generate a 1ms pulse at txPin
digitalWrite(this->txPin,HIGH);
this->singalEnder.once_ms<uint8_t>(1,[](uint8_t pin){digitalWrite(pin,LOW);},this->txPin);
//Set rxPin pull-up callback
attachInterruptArg(rxPin,[](void* r){static_cast<radar*>(r)->echoStartHandler();},this,RISING);
}
Thank for your help!
ps: Please forgive my poor English.I'm not a native speaker.
After hours of research, I found something in a post. It seems that in esp32 we can't use float in the interupt,because it will use the FPU , which is not allow to use inside an interrupt handler.
After remove float in my interrupt handler,the code finally work.