vTaskDelete understanding problem

mailgoe wrote on Monday, January 07, 2019:

Hello,

I’m new to FreeRTOS and trying to simulate a Garage Door Opener, using one button to iterate between 5 states.

Usual behaviour for the garage door started by a button press would be:
Open --> Closing --> Closed
Closed --> Opening --> Open

However while moving you can stop the garage door with another button press and start again moving in the opposite direction with another press:
Closing / Opening --> Stopped
Stopped --> Opening / Closing

The button is handled with an interrupt. When the button gets pressed while moving, I want the previous opened task button_callback to be deleted, since otherwise it will not stay in the state “stopped”. Somehow I must use the xTaskCreate, xTaskDelete and the according TaskHandle wrong, since the serial console of my ESP8266 is giving the following errors:

Console output:

Waiting for button press interrupt on gpio 10...
Button pressed!
State = OPENING
State = OPEN

Task exists!
Fatal exception (28):
epc1=0x40216e92

0x40216e92: uxListRemove at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/list.c:183

epc2=0x00000000
epc3=0x402035c1

0x402035c1: prvIdleTask at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/tasks.c:4687

excvaddr=0x00000004
depc=0x00000000
excsave1=0x4020384f

0x4020384f: vTaskDelete at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/tasks.c:4687

Registers:
a0 4020384f a1 3fff4910 a2  3fff254c a3  00000000

0x4020384f: vTaskDelete at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/tasks.c:4687

a4  3fff0e38 a5  3fff0e38 a6  00000000 a7  00000000
a8  00000000 a9  60000000 a10 00000000 a11 0000000a
a12 3fff2548 a13 3fff0fb4 SAR 00000000

Stack: SP=0x3fff4910
0x3fff4910: ffffff38 3fff123c 00003430 4021501c

0x4021501c: button_task at /Volumes/case-sensitive/esp-homekit-demo/examples/sonoff_dual_garage_door/main.c:191

0x3fff4920: 00003430 00000000 00000000 00000000
0x3fff4930: 00000000 00000000 00000000 00000000
0x3fff4940: 00000000 00000000 00000000 00000000
0x3fff4950: 00000000 a5a5a5a5 0000014c fffffffc
0x3fff4960: 3fff48c0 091c47b9 3fff0eb8 3fff0eb8
0x3fff4970: 3fff4960 3fff0eb0 0000000d 3ffee50c
0x3fff4980: 3ffee50c 3fff4960 00000000 00000002

Free Heap: 49744
_heap_start 0x3fff1688 brk 0x3fff6f78 supervisor sp 0x40000000 sp-brk 37000 bytes
arena (total_size) 22768 fordblks (free_size) 12744 uordblocks (used_size) 10024

Code:

void gpio_intr_handler(uint8_t gpio_num);
TaskHandle_t buttonTaskHandle = NULL;
enum {OPEN, CLOSED, OPENING, CLOSING, STOPPED};
bool lastState;

/* initialize button */
void button_init() {

    // enable button and enable pullup
    gpio_enable(button_gpio, GPIO_INPUT);
    gpio_set_pullup(button_gpio, true, true);

    // initialize queue which holds timestamp
    tsqueue = xQueueCreate(1, sizeof(uint32_t));

    // start button_task
    xTaskCreate(button_task, "buttonTask", 1024, &tsqueue, 2, NULL);
}

static QueueHandle_t tsqueue;

void gpio_intr_handler(uint8_t gpio_num)
{
    uint32_t now = xTaskGetTickCountFromISR();
    xQueueSendToBackFromISR(tsqueue, &now, NULL);
}

void button_task(void *pvParameters)
{
    printf("Waiting for button press interrupt on gpio %d...\r\n", button_gpio);
    QueueHandle_t *tsqueue = (QueueHandle_t *)pvParameters;
    gpio_set_interrupt(button_gpio, GPIO_INTTYPE_EDGE_NEG, gpio_intr_handler);

    uint32_t last = 0;
    while(1) {
        uint32_t button_ts;
        xQueueReceive(*tsqueue, &button_ts, portMAX_DELAY);
        button_ts *= portTICK_PERIOD_MS;
        if (last < button_ts-200) {
            last = button_ts;

            if (buttonTaskHandle != NULL) {
                printf("Task exists!\n");
                vTaskDelete(buttonTaskHandle);
            }
            xTaskCreate(button_callback, "buttonCallback", 2048, NULL, 2, &buttonTaskHandle);
        }
    }
}

void button_callback() {

    if (local_current_state == OPEN) {
        printf("Button pressed!\nState = CLOSING\n");
        local_current_state = CLOSING;
        vTaskDelay(garage_runtime / portTICK_PERIOD_MS);
        printf("State = CLOSED\n\n");
        local_current_state = CLOSED;
    }

    else if (local_current_state == CLOSED) {
        printf("Button pressed!\nState = OPENING\n");
        local_current_state = OPENING;
        vTaskDelay(garage_runtime / portTICK_PERIOD_MS);
        printf("State = OPEN\n\n");
        local_current_state = OPEN;
    }

    else if (local_current_state == CLOSING || local_current_state == OPENING) {
        lastState = local_current_state-2;
        printf("Button pressed!\nState = STOPPED\n\n");
        local_current_state = STOPPED;
    }

    else if (local_current_state == STOPPED) {
        printf("Button pressed!\nState = %d\n", !lastState+2);
        local_current_state = !lastState+2;
        vTaskDelay(garage_runtime / portTICK_PERIOD_MS);
        printf("State = OPEN\n\n");
        local_current_state = !lastState;
    }

    vTaskDelete(buttonTaskHandle);
}

rtel wrote on Monday, January 07, 2019:

As far as I can see - you delete the task but never set its handle to NULL.

vTaskDelete( buttonTaskHandle );
buttonTaskHandle = NULL; // Add this line.

Watch out for race conditions though.

Creating and deleting tasks in this way would not be an optimal way of
implementing this, but I assume this is more of an academic exercise
rather than a real door opener.

mailgoe wrote on Monday, January 07, 2019:

Thank you for your answer. When I add your line, the first button click (after initialization of the door state to closed) as before opens the door. When I try to close it, e.g. press the button a second time I get the same error:

Waiting for button press interrupt on gpio 10...
Button pressed!
State = OPENING
State = OPEN

Task exists!
Fatal exception (28):
epc1=0x40216e96

0x40216e96: uxListRemove at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/list.c:183

epc2=0x00000000
epc3=0x402035c4

0x402035c4: prvIdleTask at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/tasks.c:4687

excvaddr=0x00000004
depc=0x00000000
excsave1=0x4020384f

0x4020384f: vTaskDelete at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/tasks.c:4687

Registers:
a0 4020384f a1 3fff4910 a2  3fff254c a3  00000000

0x4020384f: vTaskDelete at /Volumes/case-sensitive/esp-open-rtos/FreeRTOS/Source/tasks.c:4687

a4  3fff0e38 a5  3fff0e38 a6  00000000 a7  00000000
a8  00000000 a9  60000000 a10 00000000 a11 0000000a
a12 3fff2548 a13 3fff0fb4 SAR 00000000

Stack: SP=0x3fff4910
0x3fff4910: ffffff38 3fff123c 00003d90 40215020

0x40215020: button_task at /Volumes/case-sensitive/esp-homekit-demo/examples/sonoff_dual_garage_door/main.c:191

0x3fff4920: 00003d90 00000000 00000000 00000000
0x3fff4930: 00000000 00000000 00000000 00000000
0x3fff4940: 00000000 00000000 00000000 00000000
0x3fff4950: 00000000 a5a5a5a5 0000014c fffffffc
0x3fff4960: 3fff48c0 091c47f9 3fff0eb8 3fff0eb8
0x3fff4970: 3fff4960 3fff0eb0 0000000d 3ffee50c
0x3fff4980: 3ffee50c 3fff4960 00000000 00000002

Free Heap: 49744
_heap_start 0x3fff1688 brk 0x3fff6f78 supervisor sp 0x40000000 sp-brk 37000 bytes
arena (total_size) 22768 fordblks (free_size) 12744 uordblocks (used_size) 10024

ets Jan  8 2013,rst cause:1, boot mode:(1,7)

^CTraceback (most recent call last):
  File "/Volumes/case-sensitive/esp-open-rtos//utils/filteroutput.py", line 105, in <module>
    main()
  File "/Volumes/case-sensitive/esp-open-rtos//utils/filteroutput.py", line 87, in main
    line = port.readline()
  File "/usr/local/lib/python2.7/site-packages/serial/serialposix.py", line 483, in read
    ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
KeyboardInterrupt
make: *** [test] Error 1

Do you know how to get rid of this? Or what other way would you suggest to implement a button interrupt, breaking the prior task / action?