SuperHouse / esp-open-rtos

Open source FreeRTOS-based ESP8266 software framework
BSD 3-Clause "New" or "Revised" License
1.53k stars 491 forks source link

TaskNotifyWait and PWM trigger WD #555

Closed ThomasSchemmer closed 6 years ago

ThomasSchemmer commented 6 years ago

Hi everyone.

I currently want to have two processes that communicate witch each other. One that handles Wifi/UDP, the other PWM for a servo. I want to send the duty cycle to the ESP via the UDP process and handle it in the servo process. As long as I dont use the pwm_set_duty function, the handling works fine. As soon as I do though it throws the following errors:

ets Jan 8 2013,rst cause:2, boot mode:(1,6) ets Jan 8 2013,rst cause:4, boot mode:(1,6)

(which apparently is the soft and then the hard WD).

My code is as follows:

TaskHandle_t servoTaskHandle = NULL;

void servoTask(void *pvParameters){

    uint8_t pins[1];
    pins[0] = 4;
    pwm_init(1, pins);
    pwm_set_freq(1000);
    pwm_set_duty(UINT16_MAX/2);
    pwm_start();

    uint32_t ulADCValue = 0;
    BaseType_t xResult;
    const TickType_t timeout = pdMS_TO_TICKS( 10 );
    while(1) {
        xResult = xTaskNotifyWait(0, 0, &ulADCValue, timeout);
        if(xResult == pdPASS){
            printf("duty cycle set to %d\r\n", ulADCValue);
            pwm_set_duty(ulADCValue); 
            printf("duty c set"); //never gets called, crashed / restarts before
        }

    }
}

void wirelessTask(void *pvParameters){
    /* setup and connect to PC..*/
    while(1){
      err = netconn_recv(conn, &buf);
      if (err == ERR_OK) {
          netbuf_copy(buf, buffer, buf->p->tot_len);
          buffer[buf->p->tot_len] = '\0';
          //convert part i want
          uint16_t convert = atoi(&buffer[2]);
          xTaskNotify(servoTaskHandle,  convert, eSetValueWithOverwrite);
          netbuf_delete(buf); 
      }
    }
}

void user_init(void)
{
    uart_set_baud(0, 115200);

    xTaskCreate(servoTask, "servoTask", 256, NULL, 1, &servoTaskHandle);
    xTaskCreate(wirelessTask, "wirelessTask", 2024, NULL, 1, NULL);   
}

If I dont use the xTaskNotifyWait construct the pwm_set_duty works without causing the WD to trigger, so I guess it might be some form of race condition? Might be related to Issue #40 and follow ups. My question is now: How can I fix this error? Is there a better way for interprocess communication, aka "dont use TaskNotify and PWM at the same time"?

Thanks for your help Thomas

Zaltora commented 6 years ago

Normal that the wireless Task don't get a infinite loop ? It is explain the crash when you send data.

while(1) 
{
    err = netconn_recv(conn, &buf);
    if (err == ERR_OK) {
        netbuf_copy(buf, buffer, buf->p->tot_len);
        buffer[buf->p->tot_len] = '\0';
        //convert part i want
        uint16_t convert = atoi(&buffer[2]);
        xTaskNotify(servoTaskHandle,  convert, eSetValueWithOverwrite);
        netbuf_delete(buf); 
    }
}
ThomasSchemmer commented 6 years ago

@Zaltora sorry, that part is missing. It is in an infinite loop. Will edit my code example. But even if it would not have an infinite loop, it does not really explain why the other process crashes directly (instead of infinitely waiting for a second input).

Zaltora commented 6 years ago

if the task don't get infinite loop, FreeRTOs will go outside of the memory task and it will crash anyway. netconn_recv(conn, &buf); will block your task until it is receive data through the wifi. After receive data, it will notify your servo task, then crash. the servo task will never be unlock by the new data.

The servo task crash with "wirelessTask" Disable ?

ThomasSchemmer commented 6 years ago

Thats true, the WifiTask would crash and the servo task would not get any updates, so the servo would timeout each time. That still should not cause a Watchdog reset, as the timeout is at 10ms. After modifying the Wifi task to

xTaskNotify(servoTaskHandle,  100, eSetValueWithOverwrite);
vTaskDelayUntil(&ticks, xDelay10ms);

it works flawlessly. So it might truly be the blocking Wifi function. So i added a timeout to the netconn socket according to api. LWIP_SO_RCVTIMEO is defined as 1. netconn_set_recvtimeout (conn, 10); But it still causes the WD reset. What am I missing? Is the software watchdog to low? Idk the default setting, but 10ms seems weird, especially since the wireless task works in combination with any other, just not with the notify/wait construct.

ourairquality commented 6 years ago

Would it be possible to come up with an example that does not use the network, so just scanning the values of duty cycle that it is generating?

Zaltora commented 6 years ago

You do not have to use timeout if you want. FreeRTOS IDLE task reset WD. ( or maybe in each tick ?) So your servo task can use:
xResult = xTaskNotifyWait(0, 0, &ulADCValue, portMAX_DELAY); You don't need to take care about WD in your task with esp-open-rtos. Just take care about Starvation Your taks need enter in BLOCKED State to lets IDLE task run and do backround jobs like WD reset. That mean than you can keep your old wireless task. Your test program will wait forever until a Wifi UDP paquet incoming. ( The IDLE task will run ) If i think netconn_recv is "non blocking" function. Your wireless task Never STOP. Use vTaskDelay(100 / portTICK_PERIOD_MS); to see waht happen.

while(1) 
{
    err = netconn_recv(conn, &buf);
    if (err == ERR_OK) {
        netbuf_copy(buf, buffer, buf->p->tot_len);
        buffer[buf->p->tot_len] = '\0';
        //convert part i want
        uint16_t convert = atoi(&buffer[2]);
        xTaskNotify(servoTaskHandle,  convert, eSetValueWithOverwrite);
        netbuf_delete(buf); 
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
}
ThomasSchemmer commented 6 years ago

_I fixed it. I just added an extra pwm_stop() call before, and a pwm_start() after the pwm_setduty() function. This should not be necessary, as the source restarts anyway. EDIT: Turns out it actually wasnt a fix. I had an old version of pwm.c, updated, now it works. The apparent fix only worked if you set duty to above ~(int)(freq/100), otherwise it would result to the above. Will close this issue, thanks for your help @Zaltora thanks for the hint regarding the portMAX_DELAY :)