cancel
Showing results for 
Search instead for 
Did you mean: 

Problems with CDC and FreeRTOS streams

bdill.1
Associate

I'm experiencing a weird race condition / hangup with an application that I've built for my STM32F407VGTx. Basically I connect to the device via a USB cable and open a terminal to type commands on the device like a CLI. Everything works fine until I paste a large buffer into the console - at which point it locks up and seems to get frozen in some FreeRTOS related calls.

in my CDC callback i have this:

 

 

void CDCSystem::halalCDCReceiveFSCallback(uint8_t* data, uint32_t* length) {
  if (this->protocol == nullptr) {
    return;
  }
  this->protocol->handleIncoming(data, *length);
}

 

The `handleIncoming` method parses the incoming data and will likely print return characters to the console. I'm using a FreeRTOS stream buffer for the outgoing data, here's the write method:

 

void CDCSystem::write(uint8_t* data, std::size_t length) {
  std::size_t consumed = 0;
  while (consumed < length) {
    BaseType_t pxHigherPriorityTaskWoken;
    bool isr = halal_IS_ISR();
    auto crit = halal_ENTER_CRITICAL();
    if (isr) {
      consumed += xStreamBufferSendFromISR(outputBuffer, data + consumed, length - consumed, &pxHigherPriorityTaskWoken);
    } else {
      consumed += xStreamBufferSend(outputBuffer, data + consumed, length - consumed, 10);
    }
    halal_EXIT_CRITICAL(crit);
    halal_YIELD_FROM_ISR(pxHigherPriorityTaskWoken);
  }
;
}

 

I then have a FreeRTOS task that consumes the data written to this stream and writes it back out to the CDC device: 

 

void StartCDCSystemTask(void *argument) {
  auto cdcSystem = CDCSystem::getInstance();

  outputBuffer = xStreamBufferCreate(HALAL_CDC_SYSTEM_OUTPUT_BUFFER_SIZE, std::max(1, HALAL_CDC_SYSTEM_OUTPUT_BUFFER_SIZE / 2));
  uint8_t readBuffer[HALAL_CDC_SYSTEM_OUTPUT_BUFFER_READ_SIZE];

  while (true) {
    std::size_t read = xStreamBufferReceive(
        outputBuffer,
        &readBuffer[0],
        HALAL_CDC_SYSTEM_OUTPUT_BUFFER_READ_SIZE,
        10);
    if (read == 0) {
      continue;
    }

    uint8_t iterations = 0;
    uint8_t result;
    do {
      result = CDC_Transmit_FS(&readBuffer[0], read);
      iterations++;
    } while (result != USBD_OK
        && iterations < HALAL_USB_SERIAL_SYSTEM_MAX_SEND_ITERATIONS
        && cdcSystem->isUsbConnected());

    if (iterations >= HALAL_USB_SERIAL_SYSTEM_MAX_SEND_ITERATIONS) {
      app_fault_raise(APP_ERROR_MAX_ITERATIONS_DURING_SEND);
    }
  }

}

 

It seems to get stuck in the `write` method because it's unable to write all of the data to the stream (`xStreamBufferSendXXX` returns 0) - so my loop continues infinitely trying to write that data to the stream. I would expect that the task processing said stream would drain it enough so that eventually the `write` method would be able to put data into the stream.

The other thing I noticed is that when I pause the application in MXCubeIDE the `CDCSystemTask` seems to be stuck in the `write` method... (i can see that in the stack), but it should have never gotten to that method because it never does that... I assume this has something to do with YIELD and preemption?

Screenshot 2023-09-14 at 8.21.27 PM.png

 All of my `write` methods should be called from the CDC incoming ISR.

0 REPLIES 0