【问题标题】:ESP32 Freertos: SPI task blocks other task (even on different core!!)ESP32 Freertos:SPI 任务阻塞其他任务(即使在不同的内核上!!)
【发布时间】:2021-08-03 17:59:17
【问题描述】:

我正在开发基于 ESP32 和 freeRTOS 的高频 DAQ。将有 2 个任务,第一个任务将在核心 0 上运行,与传感器通信以 4000SPS 收集数据,使用 SPI 总线。任务 2 将在核心 1 上运行,从第一个任务接收数据并通过 TCP 异步发送。理想情况下,任务 2 应该在任务 1 收集最新数据的同时发送数据(双核,对吗?) 当我进行测试运行时,我让 SPI 总线尽可能快地运行,但它只是阻止任务 2 一直运行!!我不想使用 vTaskDelay(1),因为它会影响收集数据的速度。我现在应该怎么做,让两个任务同时运行?谢谢!!

   void inFromSensor(void *parameter)
{
    for (;;)
    {
        SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
      //  digitalWrite(SS, LOW);
        SPI.write(0b000011100);
        SPI.write(0b000011100);
        SPI.write(0b000011100);
        SPI.endTransaction();
        // vTaskDelay(1000/portTICK_PERIOD_MS);
        // for (int i = 0; i < 88; i++)
        // {
        //     testBuffer1[i] = 8;
        //     itoa(testBuffer1[i], &buffer1[i], 10);
        // }
        // buffer1[0] = '1';
        // buffer1[87] = '\n';

        // UBaseType_t res = xRingbufferSend(buf_handle, buffer1, sizeof(buffer1), pdMS_TO_TICKS(1000));
        // if (res != pdTRUE)
        // {
        //     printf("Failed to send item\n");
        // }
        
        TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
        TIMERG0.wdt_feed = 1;
        TIMERG0.wdt_wprotect = 0;
    }
    vTaskDelete(NULL);
}
void outToTCP(void *parameter)
{
    for (;;)
    {
        Serial.println("a");
        WiFiClient client = wifiServer.available();
        if (client)
        {
            Serial.println("client connected");
            while (client.connected())
            {
                unsigned long start = millis();
                while (millis() - start < 5000)
                {
                    size_t item_size;
                    char *item = (char *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000));
                    if (item != NULL)
                    {
                        client.write(item);
                        //Return Item
                        vRingbufferReturnItem(buf_handle, (void *)item);
                    }
                    else
                    {
                        //Failed to receive item
                        printf("Failed to receive item\n");
                    }
                }
                Serial.println("done");
                return;
            }

            client.stop();
            Serial.println("Client disconnected");
        }
        
        TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
        TIMERG0.wdt_feed = 1;
        TIMERG0.wdt_wprotect = 0;
    }
    vTaskDelete(NULL);
}
void setup()
{
    Serial.begin(112500);
    WiFi.begin(ssid, password);
    SPI.begin(SCK, MISO, MOSI, SS);
    pinMode(SS, OUTPUT);
    digitalWrite(SS, HIGH);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(1000);
        Serial.println("Connecting to WiFi..");
    }
    wifiServer.begin();

    buf_handle = xRingbufferCreate(50280, RINGBUF_TYPE_NOSPLIT);
    if (buf_handle == NULL)
    {
        printf("Failed to create ring buffer\n");
    }
    Serial.println("ready");
    xTaskCreatePinnedToCore(
        inFromSensor,      /* Task function. */
        "lowPriorityTask", /* name of task. */
        15000,             /* Stack size of task */
        NULL,              /* parameter of the task */
        4,                 /* priority of the task */
        NULL,              /* Task handle to keep track of created task */
        1);
    delay(500);



xTaskCreatePinnedToCore(
    outToTCP,           /* Task function. */
    "highPriorityTask", /* name of task. */
    15000,              /* Stack size of task */
    NULL,               /* parameter of the task */
    6,                  /* priority of the task */
    NULL,               /* Task handle to keep track of created task */
    0);
delay(500);

Serial.println("ready");}

【问题讨论】:

    标签: esp32 freertos arduino-esp32


    【解决方案1】:

    请发布串行输出。

    无论如何,我的猜测是任务 1 占用了运行 WiFi 堆栈的核心,因此 WiFi 永远没有机会连接。然而,任务 2 取决于要连接的 WiFi。此外,任务 2 正在等待环形缓冲区中的数据可用,但您的代码不会在那里发布任何内容。

    无论如何,这将受益于计时器。如果您需要以特定间隔运行采样过程,请配置一个带有间隔的计时器,在中断中进行采样并将其发布到您的处理线程。这比循环旋转、占用整个核心更具确定性。另外,它会将空闲周期留给那些需要它们的任务(除了您的代码之外还有很多)。

    【讨论】:

    • 您好,感谢您的意见。我添加了串行输出的屏幕截图,但它确实连接到了 Wifi。
    • 更多信息:即使我将任务 1 中的所有内容都包装在非阻塞延迟 if(millis()-start >=1000) {} 下,将 taskYield() 放在下面,任务 2 仍然没有运行。
    【解决方案2】:

    解决了!我只是切换了任务的创建顺序(xTaskCreatedPinnedToCore()),先创建任务2,然后创建任务1。看起来在第一种情况下,任务1,创建后继续运行,因此任务2从来没有机会成为已创建!

    【讨论】:

      【解决方案3】:
      void inFromSensor(void *parameter)
      {
           VTaskDelay(NULL) // this will prevent task from running right after it is initialised, NULL parameter known that it is asking itself to delay.
          for (;;)
          {
          }
      }
      
      void setup()
      {
      xTaskCreatePinnedToCore(inFromSensor,"lowPriorityTask", 15000, NULL,4,Task1,1);// give task handle such as Task1 and you will have to declare this on top.
      
      delay(500);
      // You can then here control the order of resuming the task
      vTaskResume(Task1);// this will start the task and you should do this ideally
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-20
        • 2021-09-07
        • 2022-10-06
        • 1970-01-01
        • 2012-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多