I have TLS running, once a minute. It runs at a low priority, but grabs the CPU totally for up to 3 seconds.
Pre-emption is enabled in FreeRTOS, and this rather complex product does all work great.
This runs in a loop with osDelay(10) so every 10ms it yields to the RTOS and allows other tasks to run (tasks of all priorities)
This happens because the osDelay(10) lets in any task for as long as it wants.
Pre-emption is enabled in FreeRTOS,
Priorities often cause more problems than they solve.
why is your low priority task preventing higher priority tasks from running?
Are you disabling the scheduler in the TLS task e.g. do you have an extremely long critical section?
This doesn't sound quite right either, osDelay(10) will yield for 10ms, not necessarily every 10ms unless the execution time of the task is negligible.
You need to make sure than on exit from the serial port ISR, the high priority task that is waiting on the interrupt fifo is marked runnable, and that the scheduler schedules it next rather than returning to the TLS code.
void vCopyser1(void *pvParameters)
{
uint8_t buffer[256];
uint16_t tomove;
uint16_t bytes1;
uint16_t bytes2;
// Initial startup delay.
osDelay(1000);
while(1)
{
// Get data from 1st port into temp buffer and output it to the 2nd port
bytes1 = serial_get_ipqcount(copyser1_port1);
bytes2 = serial_get_opqspace(copyser1_port2);
// Run this only if the data can be copied without blocking anywhere
if ( (bytes2>=bytes1) && (bytes1>0) )
{
tomove = MIN(bytes1,sizeof(buffer));
serial_receive(copyser1_port1, buffer, tomove);
serial_transmit(copyser1_port2, buffer, tomove);
}
// And in the other direction
bytes1 = serial_get_ipqcount(copyser1_port2);
bytes2 = serial_get_opqspace(copyser1_port1);
// Run this only if the data can be copied without blocking anywhere
if ( (bytes2>=bytes1) && (bytes1>0) )
{
tomove = MIN(bytes1,sizeof(buffer));
serial_receive(copyser1_port2, buffer, tomove);
serial_transmit(copyser1_port1, buffer, tomove);
}
osDelay(10); // give time for other RTOS tasks run
}
}
QuotePriorities often cause more problems than they solve.
I agree totally; relying on a complicated priority hierarchy is a great way to get into a mess eventually. For a long time on this project I had it running great with everything in IDLE priority (and interrupt-driven I/O, obviously) so basically the RTOS was switching round-robin at 1kHz, but eventually this had to be partly abandoned because stuff like ETH and USB needed faster servicing.
OK how could one troubleshoot this?
OK I put in some GPIO waggling and ...
OK I put in some GPIO waggling and I find the loop continues to run during the 3 secs. What is happening is that there is a brief pause when TLS starts the processing and that causes the data loss.
That makes a lot more sense.
I will report on what I find.
I now suspect the issue is deeper because that loop (which BTW runs in a max of 10us in the case of worst-case data transfers) never actually gets held up. The data loss, 15 bytes out of a 500 byte packet, occurs at the onset of the 3 sec TLS operation. Just bizzarre.
I have TLS running, once a minute. It runs at a low priority, but grabs the CPU totally for up to 3 seconds.
Pre-emption is enabled in FreeRTOS, and this rather complex product does all work great.
This doesn't make a lot of sense, why is your low priority task preventing higher priority tasks from running? Are you disabling the scheduler in the TLS task e.g. do you have an extremely long critical section?
And the rx ISR-driven buffer never overflows (data is never discarded) - I checked that with a breakpoint.
serial data loss unless I have an interrupt driven rx buffer big enough for 3 secs at max baud rate, which is too much RAM
Does the serial port hardware have a HW fifo overflow flag?
Have you actually tried that: making the buffer impractically large? Does that actually work?
Hard to debug too, with TLS running infrequently.
while(1)
{
...
...
...
osDelay(10);
}
and this produces a 100Hz rate around the loop. The code in the loop takes a relatively negligible time. It is checking for data in the rx fifo, space in the tx fifo, and if these are met it moves data no bigger than the size of a local buffer (256).
// If USBD_CDC_ReceivePacket was skipped (in CDC_Receive_FS) and there is useful
// room in the circular buffer for more data, then run it now. USB CDC packets are 0-64 bytes
// so we make sure there is 100 bytes space before re-enabling more data reception.
// Must run with ints disabled.
__disable_irq();
if ( (CDC_rx_blocked) && ( (CDC_RX_BUFFER_SIZE - CDC_get_ipqcount_2()) > 100) )
{
// Enable reception of next packet from Host
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
CDC_rx_blocked=false;
}
__enable_irq();