I'm working on a project that needs to save data in a permanent storage (in the form of an external I2C EEPROM) when powered down.
To achieve that, I have an interrupt set up on IO34 that notifies me when voltage is falling before is too late. I have approximately 200 ms from the interrupt to complete loss of power, which should be plenty to save a few dozen bytes.
From a similar work I did last year I know I cannot do i2c operations from an interrupt thread, so I launch an high priority task that just waits on a queue for a message and saves the data when one is received.
The interrupt is fired and the task wakes up, but upon beginning I2C operations the execution is disrupted by an exception:
Code: Select all
Poweroff
second print
W (181381) pwoff: Saving!
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400852df PS : 0x00060031 A0 : 0x8008568c A1 : 0x3ffb09c0
0x400852df: i2c_master_cmd_begin_static at /home/maldus/Source/esp-idf/components/driver/i2c.c:854
A2 : 0x00000000 A3 : 0x3ffbda28 A4 : 0x00000000 A5 : 0x00000001
A6 : 0x00060023 A7 : 0x00060723 A8 : 0x3ffc6128 A9 : 0x6001301c
A10 : 0xffffffff A11 : 0x00000000 A12 : 0x00000000 A13 : 0x0000010b
A14 : 0x3ffc6140 A15 : 0x00060723 SAR : 0x00000013 EXCCAUSE: 0x0000001c
EXCVADDR: 0xffffffff LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0xffffffff
Core 0 was running in ISR context:
EPC1 : 0x400852df EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000
0x400852df: i2c_master_cmd_begin_static at /home/maldus/Source/esp-idf/components/driver/i2c.c:854
Backtrace: 0x400852df:0x3ffb09c0 0x40085689:0x3ffb09f0 0x40082401:0x3ffb0a20 0x4000bfed:0x3ffbb330 0x4008ea3a:0x3ffbb340 0x400d1790:0x3ffbb360 0x400d29b0:0x3ffbb390 0x400d0fc2:0x3ffbb890 0x4008e039:0x3ffbb8b0
0x400852df: i2c_master_cmd_begin_static at /home/maldus/Source/esp-idf/components/driver/i2c.c:854
0x40085689: i2c_isr_handler_default at /home/maldus/Source/esp-idf/components/driver/i2c.c:854
0x40082401: _xt_lowint1 at /home/maldus/Source/esp-idf/components/freertos/xtensa_vectors.S:1154
0x4008ea3a: vTaskExitCritical at /home/maldus/Source/esp-idf/components/freertos/tasks.c:4590
0x400d1790: esp_task_wdt_reset at /home/maldus/Source/esp-idf/components/esp32/task_wdt.c:322
0x400d29b0: app_main at /home/maldus/Projects/HSW/StiroRotondi/main/source/main.c:110
0x400d0fc2: main_task at /home/maldus/Source/esp-idf/components/esp32/cpu_start.c:494
0x4008e039: vPortTaskWrapper at /home/maldus/Source/esp-idf/components/freertos/port.c:403
CPU halted.
Code: Select all
extern char *revision;
void IRAM_ATTR lowVoltageSave(void *queue) {
gpio_set_level(GPIO_NUM_2, 0);
ets_printf("Poweroff\n");
xQueueHandle handle = *((xQueueHandle *)queue);
xQueueSendFromISR(handle, NULL, 0);
ets_printf("second print\n");
}
void task_lowVoltageSave(void *queue) {
xQueueHandle handle = *((xQueueHandle *)queue);
xQueueReset(handle);
portBASE_TYPE res;
while (1) {
res = xQueueReceive(handle, NULL, 10000 / portTICK_RATE_MS);
if (res == pdTRUE) {
ESP_LOGW("pwoff", "Saving!");
esp_err_t ret;
i2c_cmd_handle_t cmd;
uint8_t ControlByte = EEPROM_ADD;
uint8_t HighAdd = ADD_REV_HIGH;
uint8_t LowAdd = ADD_REV_LOW;
ControlByte &= 0xF1;
ControlByte |= HighAdd << 1;
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ControlByte, 1);
i2c_master_write_byte(cmd, LowAdd, 1);
i2c_master_write(cmd, (uint8_t*)revision, 11, 1);
i2c_master_stop(cmd);
gpio_set_level(GPIO_NUM_25, 0); // Write protect
ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_NUM_25, 1);
i2c_cmd_link_delete(cmd);
ets_delay_us(1000*1000);
ESP_LOGW("LOW VOLTAGE SAVE", "Not Powered Off");
}
}
vTaskDelete(NULL);
}
xQueueHandle lowvoltagequeue;
void init_low_voltage_save() {
lowvoltagequeue = xQueueCreate(1, 0);
gpio_set_intr_type(LOW_VOLTAGE_SAVE, GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(LOW_VOLTAGE_SAVE, lowVoltageSave, (void *)lowvoltagequeue);
xTaskCreate(task_lowVoltageSave, "task_lowVoltageSave", 4096, (void *)&lowvoltagequeue, 8, NULL);
}