My project is using CAN bus with CAN Rx on GPIO-4, and CAN Tx on GPIO-5.
The goal is to have the ESP go into deep sleep when CAN activity stops, and then when CAN activity is detected, wake-up the ESP32 and start normal operation.
When I want the ESP32 to go to sleep, I have the ESP32 set GPIO-4 (CAN Rx) to act as the hardware interrupt for wakeup.
As a CAN message comes in, the CAN Rx pin changes state, which causes the ESP32 to wake up. I know that using this method might result in one or two missed CAN messages while the ESP32 wakes up and starts the main loop again, but Im not worried about that.
Everything works perfectly upon first boot, the ESP32 prints all the correct CAN messages that Im sending to it, then Ill stop sending CAN messages, then goes to sleep, and once its asleep, Ill then send out a couple more CAN messages to it...the ESP32 then wakes up properly...HOWEVER....after wakeup, the CAN controller doesnt re-initialize correctly. You have to cycle power or press the hardware reset button to get CAN bus working again.
After lots of searching, I found out that once a rtc_GPIO is set to be a hardware interrupt/wakeup, after the ESP32 has been woken up by a change in state of the GPIO, you have to manually reset the rtc_GPIO to be a standard digital GPIO again. I assume thats what is happening here, the ESP32 restarts upon wake up, and CAN doesnt initialize and start working because GPIO-4 is still set as an rtc_GPIO.
I found that
rtc_gpio_deinit(gpio_num)
will reset the pin back to being a normal GPIO.
However, it doesnt seem to be working correctly, maybe I have some wrong syntax, or not using the function correctly?
In this simple example, for bench testing purposes and proof of "sleep/wake up on CAN receive" concept, Im basically just having the ESP go to sleep after a set period of time (counter), and then once its asleep, I send it some CAN frames. Im using Arduino if that makes any difference?
Code: Select all
int counter = 0;
CAN_device_t CAN_cfg = {
.speed=CAN_SPEED_500KBPS, // CAN Node baudrade
.tx_pin_id = GPIO_NUM_5, // CAN TX pin
.rx_pin_id = GPIO_NUM_4, // CAN RX pin
.rx_queue=NULL, // FreeRTOS queue for RX frames
};
char HSmsgString[128];
void setup() {
Serial.begin(115200);
esp_err_t rtc_gpio_deinit(GPIO_NUM_4); // reset the rtc_GPIO wake up pin to be a normal digital GPIO-4 again
CAN_cfg.rx_queue = xQueueCreate(10,sizeof(CAN_frame_t));
//start CAN Module
CAN_init();
}
void loop() {
CAN_frame_t rx_frame;
if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
sprintf(HSmsgString, "HS-CAN Standard ID: 0x%.3lX DLC: %1d Data:",rx_frame.MsgID, rx_frame.FIR.B.DLC);
Serial.print(HSmsgString);
for(byte r = 0; r<len; r++){
sprintf(HSmsgString, " 0x%.2X", rx_frame.data.u8[r]);
Serial.print(HSmsgString);
}
Serial.println(); // print the received CAN traffic to the serial terminal
}
counter++;
if (counter > 2000){ // wait a couple seconds, then put the ESP32 to sleep
Serial.println("going to sleep!");
delay(2000);
CAN_stop();
delay(5);
esp_sleep_enable_ext0_wakeup(GPIO_NUM_4, LOW); // enable the external wakeup on GPIO 4 (which is tied to CAN Rx)
esp_deep_sleep_start(); // ESP32 goes to sleep until it sees GPIO-4 (CAN Rx) change state as a "wake up" message comes in
}
}
Thanks