I have a dramatic performance improvement to share that reduces latency between receiving a frame and transmitting a response from around several milliseconds down to <80us (most of the time <10us which is the resolution with which my Kvaser CAN device can measure). It doesn't do too much in the CAN Rx interrupt and does not increase the RTOS tick rate from 100Hz. I will follow it with a question about transmitting on a busy CAN bus.
I have not produced a modified driver or example as my project is now quite different, but the changes are simple:
At the beginning of CAN_isr
Code: Select all
BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
then:
Code: Select all
xQueueSendFromISR(CAN_cfg.rx_queue,&__frame,0);
needs the final parameter to be changed to &xHigherPriorityTaskWoken and at the end of the ISR,
Code: Select all
if( xHigherPriorityTaskWoken ) portYIELD_FROM_ISR ();
is needed. This is as I understand the correct way to wake up a blocked task in FreeRTOS. Usually there is only 260us between CAN Rx and CAN Tx timestamps, but about 10% of the time is 340us which I've not managed to reduce with different core affinity or task priority, it may simply be a jitter related to FreeRTOS overhead.
Code: Select all
if(xQueueReceive(CAN_cfg.rx_queue,&__RX_frame, 3*portTICK_PERIOD_MS)==pdTRUE)
should have its final parameter as portMAX_DELAY I think too so that the task is always blocked and immediately unblocks when the queue has an item. It is presently in the example code just a loop anyway.
The question I have is how to improve CAN_write_frame because it makes no check whether the transmit buffer is available, so if you send frequently you lose frames because they are overwritten. Instead I have used a queue with:
Code: Select all
if(xQueueReceive(tx_queue, p_frame, portMAX_DELAY))
{
while (!MODULE_CAN->SR.B.TCS){}
but would like to avoid wasting cycles in the while loop waiting for transmit complete or transmit buffer to be available. I tried adding task notification or event group between the CAN interrupt and the CAN_write_frame code, but the former did not work because of an assert as they are not supported on the dual core CPU yet I think, and the latter produced a few milliseconds of latency, so I seek a better solution that will not lose transmit frames. I'm reading the SJA1000 docs to see what I can fathom.