2023-09-14 08:22 PM
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?
All of my `write` methods should be called from the CDC incoming ISR.