The idea is to have a number of transmitters broadcast an esp-now message every seconds.
The receiving watch will wakeup from softsleep every 5 - 10 seconds and listen for the esp-now message.
If nothing needs to be displayed, it will return to light sleep.
So I created a thread on core O that is resumed to receive the messages.
- xTaskCreatePinnedToCore( pager_main_sync_Task, /* Function to implement the task */
- "pager main sync Task", /* Name of the task */
- 5000, /* Stack size in words */
- NULL, /* Task input parameter */
- 2, /* Priority of the task */
- &_pager_main_sync_Task, /* Task handle. */
- 0 ); /* Core to which the task is tied */
Wifi is initialised like this:
- void pager_app_main_init_wifi()
- {
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
- ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
- if (esp_wifi_set_storage(WIFI_STORAGE_RAM) != ESP_OK)
- {
- log_e("Error setting wifi storage area in ram");
- }
- esp_wifi_set_mode (WIFI_MODE_STA);
- if(esp_wifi_start() != ESP_OK){
- log_e("Error initialising Wifi");
- }
- esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N|WIFI_PROTOCOL_LR);
- esp_wifi_set_promiscuous(true);
- //here we need the correct channel
- uint8_t primaryChan = WIFI_CHANNEL;
- wifi_second_chan_t secondChan = WIFI_SECOND_CHAN_NONE;
- esp_wifi_set_channel(primaryChan, secondChan);
- esp_wifi_set_promiscuous(false);
- esp_wifi_stop();
- esp_wifi_set_mode(WIFI_MODE_NULL);
- }
- void pager_main_sync_Task( void * pvParameters ) {
- int32_t retval = -1;
- uint64_t t_now_us;
- uint64_t t_early_us;
- uint64_t late_us;
- uint64_t t_start,t_ff;
- bool receive_on;
- log_i("start pager main task, heap: %d", ESP.getFreeHeap() );
- while (1)
- {
- //we wait until we need to receive a message
- vTaskSuspend(_pager_main_sync_Task);
- pager_set_event(PAGER_RECEIVING);
- //if powermgm didnt have a proper wakeup time
- //this likely won't be synced with the transmitter
- if (powermgm_get_event(POWERMGM_PAGER_LOST))
- {
- powermgm_clear_event( POWERMGM_PAGER_LOST );
- log_e("powermgm resync forced");
- pager_app_main_force_resync();
- }
- receive_on = false;
- t_now_us = esp_timer_get_time();
- // this means that the predictive receive moment has passed (is normal)
- if (t_now_us > pager_app_main_sync.t_predicted_receive)
- {
- // it's not normal it has passed over a minute
- if ((t_now_us - pager_app_main_sync.t_predicted_receive) > 60000000)
- {
- log_e("pager_app_main_sync.t_predicted_receive has elapsed a minute");
- pager_app_main_sync.t_predicted_receive = t_now_us + (2 * 1000000);
- }
- else
- {
- //if it has passed more than 25ms we should reschedule
- late_us = t_now_us - pager_app_main_sync.t_predicted_receive;
- //this was 25000
- if (late_us > 100000)
- {
- log_e("pager_app_main_sync.t_predicted_receive has elapsed.. reschedule");
- log_e("t_now_us = %lu",t_now_us);
- log_e("pager_app_main_sync.t_predicted_receive = %lu",pager_app_main_sync.t_predicted_receive);
- //we should schedule a new receive moment and call it a day
- while(t_now_us > pager_app_main_sync.t_predicted_receive)
- {
- pager_app_main_sync.t_predicted_receive = pager_app_main_sync.t_predicted_receive + (2 * 1000000);
- }
- if ((pager_app_main_sync.t_predicted_receive - t_now_us) < 150000000)
- {
- pager_app_main_sync.t_predicted_receive = pager_app_main_sync.t_predicted_receive + (2 * 1000000);
- }
- //temporary to see if it fixes our issues
- //pager_app_main_sync.t_predicted_receive = t_now_us + (2 * 1000000);
- }
- else
- {
- receive_on = true;
- }
- }
- }
- else
- {
- t_now_us = esp_timer_get_time();
- //we are here before the expected receive moment
- //kind of strange unless it's due to another wakeup
- t_early_us = pager_app_main_sync.t_predicted_receive - t_now_us;
- //more than 2 seconds early
- if (t_early_us > 2000000)
- {
- log_e("t_early_us > 2000000 == %lu",t_early_us);
- //we should go to sleep again till the moment is there
- //so likely we got here due to another wakeup reason.
- }
- else
- {
- log_e("t_early_us = %lu",t_early_us);
- //we just snooze a little before we start consuming power
- //log_e("we delay from %lu",esp_timer_get_time());
- vTaskDelay((t_early_us / portTICK_RATE_MS) / 1000);
- //log_e("After delay %lu",esp_timer_get_time());
- late_us = 0;
- receive_on = true;
- }
- }
- //disable
- // receive_on = false;
- if (receive_on == true)
- {
- //we are early like 100 ms
- //so we just wait some ms of those
- //this gives the rest of the hw time to start up
- //we will compensate for being late by waiting shorter
- //compensate for clock speed
- if (!pager_app_main_sync.highspeed)
- {
- late_us += 20000;
- log_e("compensating for 80mhz clock");
- }
- vTaskDelay( (PRE_RECEIVE_SUSPEND -(late_us /1000))/ portTICK_RATE_MS);
- t_start = esp_timer_get_time();
- pager_clear_event(PAGER_RECEIVED_OK);
- /*
- if (esp_wifi_set_storage(WIFI_STORAGE_RAM) != ESP_OK)
- {
- log_e("Error setting wifi storage area in ram");
- }
- */
- esp_wifi_set_mode(WIFI_MODE_STA);
- if(esp_wifi_start() != ESP_OK){
- log_e("Error initialising Wifi");
- }
- if (esp_now_init() != ESP_OK) {
- log_e("Error initializing ESP-NOW");
- }
- ESP_ERROR_CHECK( esp_now_register_send_cb(pager_app_send_cb) );
- ESP_ERROR_CHECK( esp_now_register_recv_cb(pager_app_recv_cb) );
- pager_app_main_sync.t_start_receiver = esp_timer_get_time();
- if (pager_app_main_sync.t_start_receiver > pager_app_main_sync.t_predicted_receive)
- {
- log_e("at start receive offset = %lu",pager_app_main_sync.t_start_receiver - pager_app_main_sync.t_predicted_receive);
- }
- else
- {
- log_e("at start receive offset = -%lu",pager_app_main_sync.t_predicted_receive - pager_app_main_sync.t_start_receiver );
- }
- log_e("routine execution time = %lu",pager_app_main_sync.t_start_receiver - t_start);
- log_e("waiting for message... fingers crossed");
- //we should calculate how much time this took and add it to our receive_gate
- //as it will be longer wen we switch frequency from 240 to 80 Mhz
- //this will prevent a timeout at the switch
- if (pager_wait_event(PAGER_RECEIVED_OK,pager_app_main_sync.t_receive_gate))
- {
- log_e ("esp now message received................................");
- pager_app_main_sync.t_prev_message_received = pager_app_main_sync.t_message_received;
- pager_app_main_sync.t_message_received = esp_timer_get_time();
- // we calculate the time we need to be ready for the next reception
- // we wakeup 100 ms earlier and just delay before we start wifi.
- // so things should stay in sync if the wakeup is due to siomething different.
- pager_app_main_sync.t_predicted_receive = pager_app_main_sync.t_message_received + (10 * 1000000) - RECEIVE_TIME_BOARDING;
- powermgm_set_rectime(pager_app_main_sync.t_predicted_receive);
- pager_app_main_sync.receive_timeout = 0;
- pager_app_main_sync.t_receive_gate = RECEIVE_TIME_NORMAL;
- //this is for info
- if (pager_app_main_sync.tot_receive_ok < 99999)
- {
- pager_app_main_sync.tot_receive_ok++;
- }
- if (pager_app_main_sync.resync)
- {
- //we got our first rx
- pager_app_main_sync.resync = false;
- //pager_app_main_sync.t_sleep = 4090000;
- pager_app_main_sync.t_sleep = SLEEP_TIME_NORMAL;
- //pager_app_main_sync.t_receive_gate = RECEIVE_TIME_NORMAL;
- }
- else
- {
- pager_app_main_sync.t_offset = (pager_app_main_sync.t_message_received - pager_app_main_sync.t_start_receiver);
- log_e("receive gate = %lu",pager_app_main_sync.t_offset);
- //log_e("receive timeouts = %lu total timeouts = %lu\n",pager_app_main_sync.receive_timeout,pager_app_main_sync.tot_receive_timeout);
- log_e("receive_interval = %lu",pager_app_main_sync.t_message_received - pager_app_main_sync.t_prev_message_received);
- }
- //once PAGER_RECEIVED_OK is set we will not touch the contents of our receive buffer
- //so we can read it out and use it how we like
- pager_clear_event(PAGER_RECEIVED_OK);
- //the message contains how much messages we can expect
- //and also it's order in the message queue
- //so you can calculate how long to wait for the last message
- //but why would you unless you need to sent something back
- }
- else
- {
- //we didn't receive a thing
- //timeout
- //maybe we should disable wifi here already
- //this is for timeout info
- if (pager_app_main_sync.tot_receive_timeout < 99999)
- {
- pager_app_main_sync.tot_receive_timeout++;
- }
- //this is for resync
- if (pager_app_main_sync.receive_timeout <= RETRIES_BEFORE_RESYNC)
- {
- pager_app_main_sync.receive_timeout++;
- // 5 times no reception
- if (pager_app_main_sync.receive_timeout > RETRIES_BEFORE_RESYNC)
- {
- pager_app_main_sync.resync = true;
- pager_app_main_sync.t_sleep = SLEEP_TIME_LONG;
- pager_app_main_sync.t_receive_gate = RECEIVE_TIME_LONG;
- log_e("resyncing pager due to signal lost.....");
- if (pager_app_main_sync.tot_resync < 99999)
- {
- pager_app_main_sync.tot_resync++;
- }
- }
- }
- pager_app_main_sync.t_offset = (esp_timer_get_time() - pager_app_main_sync.t_start_receiver);
- log_e("receive gate at timeout = %lu",pager_app_main_sync.t_offset);
- // log_e("receive timeouts = %lu",pager_app_main_sync.tot_receive_timeout);
- //we calculate a receive time
- //so that a non received message doesn't desync
- //we missed a message received so the timer is still on previous
- if (!pager_app_main_sync.resync)
- {
- // we wait for 2 seconds and try again
- // receive_time boarding was already calculated in t_predicted_receive
- // so we don't calculate that in again
- // basically our timing should still be correct
- pager_app_main_sync.t_predicted_receive = pager_app_main_sync.t_predicted_receive + (2 * 1000000);
- }
- else
- {
- pager_app_main_sync.t_predicted_receive = esp_timer_get_time() + (120 * 1000000);
- }
- powermgm_set_rectime(pager_app_main_sync.t_predicted_receive);
- //if 2 many timeouts we should resync
- //and maybe set the interval to 30 seconds
- //as we should,open the gate for a larger period
- }
- esp_now_deinit();
- esp_wifi_stop();
- esp_wifi_set_mode(WIFI_MODE_NULL);
- //so if pager info is showing it should update
- pager_set_event(PAGER_INFO_VALID);
- }
- // we didn't attempt to receive
- // so the next tx interval was already calculated
- else
- {
- powermgm_set_rectime(pager_app_main_sync.t_predicted_receive);
- }
- pager_set_event(PAGER_STANDBY_WAIT);
- // this will block sleep
- pager_clear_event(PAGER_RECEIVING);
- if (powermgm_get_event(POWERMGM_PAGER_WAKEUP))
- {
- powermgm_set_event( POWERMGM_STANDBY_REQUEST );
- }
- log_e("receive ok = %lu receive timeouts = %lu total timeouts = %lu resync = %lu",pager_app_main_sync.tot_receive_ok,pager_app_main_sync.receive_timeout,pager_app_main_sync.tot_receive_timeout,pager_app_main_sync.tot_resync);
- log_e("Expected wakeup time = %lu\n",pager_app_main_sync.t_predicted_receive);
- }
- log_i("finish pager main task, heap: %d", ESP.getFreeHeap() );
- vTaskDelete( NULL );
- }
This routine runs fine for 2000 - 3000 times and all of sudden throws up a panic:
[E][pager_app_main.cpp:543] pager_main_sync_Task(): compensating for 80mhz clock
Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed)
Core 0 register dump:
PC : 0x4009e5cf PS : 0x00060334 A0 : 0x8008c29b A1 : 0x3ffe5500
A2 : 0x0000a3a0 A3 : 0x3ffe560c A4 : 0x00000020 A5 : 0x00000000
A6 : 0x00000000 A7 : 0x00000000 A8 : 0x00000004 A9 : 0x7c000000
A10 : 0x3ff42020 A11 : 0x0000a3a0 A12 : 0x3ffe560c A13 : 0x00000020
A14 : 0x3ffe57d0 A15 : 0x00000000 SAR : 0x00000000 EXCCAUSE: 0x00000007
EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0x00000000
Backtrace: 0x4009e5cf:0x3ffe5500 0x4008c298:0x3ffe5520 0x4015a881:0x3ffe5590 0x40159145:0x3ffe55b0 0x40159785:0x3ffe55d0 0x4015839d:0x3ffe5650 0x4015844c:0x3ffe56d0 0x40157502:0x3ffe5730 0x40157a3d:0x3ffe5770 0x40142ffb:0x3ffe5790 0x40143420:0x3ffe5800 0x401437ee:0x3ffe5830 0x401663f8:0x3ffe5860 0x401664fb:0x3ffe5890 0x4016681a:0x3ffe58c0 0x40162ada:0x3ffe58f0 0x4009a2df:0x3ffe5910 0x400934f9:0x3ffe5950
#0 0x4009e5cf:0x3ffe5500 in esp_rom_spiflash_read at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/spi_flash/spi_flash_rom_patch.c:541
#1 0x4008c298:0x3ffe5520 in spi_flash_read at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/spi_flash/flash_ops.c:567
#2 0x4015a881:0x3ffe5590 in nvs::nvs_flash_read(unsigned int, void*, unsigned int) at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_ops.cpp:70
#3 0x40159145:0x3ffe55b0 in nvs::Page::readEntry(unsigned int, nvs::Item&) const at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_page.cpp:849
#4 0x40159785:0x3ffe55d0 in nvs::Page::readItem(unsigned char, nvs::ItemType, char const*, void*, unsigned int, unsigned char, nvs::VerOffset) at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_page.cpp:849
#5 0x4015839d:0x3ffe5650 in nvs::Storage::readMultiPageBlob(unsigned char, char const*, void*, unsigned int) at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_storage.cpp:557
#6 0x4015844c:0x3ffe56d0 in nvs::Storage::readItem(unsigned char, nvs::ItemType, char const*, void*, unsigned int) at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_storage.cpp:557
#7 0x40157502:0x3ffe5730 in nvs_get_str_or_blob(unsigned int, nvs::ItemType, char const*, void*, unsigned int*) at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_api.cpp:521
#8 0x40157a3d:0x3ffe5770 in nvs_get_blob at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/nvs_flash/src/nvs_api.cpp:525
#9 0x40142ffb:0x3ffe5790 in load_cal_data_from_nvs_handle at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/phy_init.c:428
#10 0x40143420:0x3ffe5800 in esp_phy_load_cal_data_from_nvs at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/phy_init.c:457
#11 0x401437ee:0x3ffe5830 in esp_phy_load_cal_and_init at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/phy_init.c:613
#12 0x401663f8:0x3ffe5860 in wifi_rf_phy_enable at ??:?
#13 0x401664fb:0x3ffe5890 in wifi_hw_start at ??:?
#14 0x4016681a:0x3ffe58c0 in wifi_start_process at ??:?
#15 0x40162ada:0x3ffe58f0 in ieee80211_ioctl_process at ??:?
#16 0x4009a2df:0x3ffe5910 in ppTask at ??:?
#17 0x400934f9:0x3ffe5950 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)
Rebooting...
I understood that wifi stored some information into flash and that this could cause the panic, but I thought that
if (esp_wifi_set_storage(WIFI_STORAGE_RAM) != ESP_OK)
{
log_e("Error setting wifi storage area in ram");
}
would solve that issue.
I tried to change the code so that the working thread only enables wifi with
esp_wifi_set_mode(WIFI_MODE_STA);
and disables it again with
esp_wifi_set_mode(WIFI_MODE_NULL);
this works untill the system enters and resumes light sleep mode. After that, nothing is received anymore.
Once syncronised with the transmitter, the receiver will only be turned on for 200ms. If nothing is received for 10 times, the system will wait for a minute and turn the receiver on for a little over one second. (To prevent battery drainage when being out of range of the transmitting esp modules.
My apologies for the long post. I hope it contains enough information to pinpoint the issue and find a way to prevent it.
Thanks in advance.