Trying to apply configUSE_PORT_OPTIMISED_TASK_SELECTION to my PIC24 port

mqn wrote on Wednesday, March 16, 2016:

On adding…
'#'define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
to the FreeRTOSConfig.h of my PIC24FJ1024GB610 port. I get the following compiler errors from my XC16 compiler.

build/default/production/_ext/449926602/tasks.o(.text+0x48): In function .LBB2': : undefined reference to _portRESET_READY_PRIORITY’

I can see that this is because the this is not defined in the switched in parts of tasks.h. Why is this so? Is there another config I have to enable.
My project was working, using the generic example with my own CLI inserted. Apart from it would automatically reset after 130 seconds. Maybe that is a clue?
Mark

rtel wrote on Wednesday, March 16, 2016:

configUSE_PORT_OPTIMISED_TASK_SELECTION is not a valid option for all targets, and is not implemented for the PIC24.

mqn wrote on Wednesday, March 16, 2016:

Fantastic quick reply :slight_smile:
Ok thanks, I thought I read it could, but it looks like a assumed because the PIC24 support CLZ using y = builtin_fbcl(x);
Ho hum.
Any ideas why my demo is resetting every 130 seconds, when it does compile? Is there any reports of simarlar behavour? I’ll put a breakpoint on startup and look if there is any residual in the error registers, may it is stack.**

rtel wrote on Wednesday, March 16, 2016:

Have a look through the “My application does not run,
what could be wrong
” FAQ page, although not all of it applies to the
PIC24.

Specific to the PIC24:

Do you have all interrupts that make use of the FreeRTOS API running at
the lowest possible interrupt priority?

Do you have the tick running at the lowest possible interrupt priority.

Are all calls to portEND_SWITCHING_ISR/portYIELD_FROM_ISR used inside an
ISR the very last instruction in the ISR?

Is the watchdog disabled?

mqn wrote on Wednesday, March 16, 2016:

All very good guidense and questions. I will check now. Thanks again.

mqn wrote on Thursday, March 17, 2016:

My watchdog was enabled, with no periodic clear on its counter. So it was doing what it is designed to do :). I disabled it and the resets stopped. Thanks.

All looking good now appart from my interrupt latency is a longer than I would like. The raw latency for my edge triggered ISR is 1.6 uS, but when the semaphored call to my task is included it goes up to 40uS. It would be better if it was closer to 10uS. I am using this code in my ISR to pass on the interrupt control…

BaseType_t task_woken = 0;
xSemaphoreGiveFromISR(binary_sem_INT1,&task_woken);
if(task_woken)
vPortYield(); // FromISR not defined

my task is running at PRIORTY 3, which is one greater than my CLI task. The only other tasks I am running are the example FlashCORoutines PRIORTY 1 , which I have tried to remove but if I do, strangly, nothing works.

My original question about the configUSE_PORT_OPTIMISED_TASK_SELECTION was one attempt to speed things up. So any other suggestions on speeding it up would be very welcome.
IF I have reached a ceiling as reguards to latency, I will have to code a “mixed” OS where the high priorty control stuff remains in the raw ISRs and the lower priorty UI and MTM interfaces are in RTOS tasks. Do you think this is feasible, what would be the minimum time for isr activity to keep the Rtos happy?

Sorry there are a few questions in there.

Mark

davedoors wrote on Thursday, March 17, 2016:

Try using a task notify instead of the semaphore http://www.freertos.org/RTOS-task-notifications.html

mqn wrote on Thursday, March 17, 2016:

Yes, this looks really promising. Give me a while to impliment and I 'll tell how it worked out. Thanks again. Loving your response times :slight_smile:

mqn wrote on Thursday, March 17, 2016:

Oh dear…

The latency has gone up to 45us using Notify.
I am using this in the interrupt

 ulStatusRegister =  (uint32_t)(IFS1);  // PIC24 interupt register
    _INT1IF = 0; //Clear the INT1 interrupt flag or else
 xHigherPriorityTaskWoken = pdFALSE;
 xTaskNotifyFromISR( xINT1_ProcessHandle,
                        ulStatusRegister,
                        eSetBits,
                        &xHigherPriorityTaskWoken );
  if(xHigherPriorityTaskWoken)
            vPortYield(); // FromISR not defined
            
task init is like this
 xTaskCreate( INT1_ProcessInterrupt, "ISR INT1 Process", configMINIMAL_STACK_SIZE, NULL, uxPriority + 1, ( TaskHandle_t * ) &xINT1_ProcessHandle );
            
and this in the task

while(1)
    {
         uint32_t ulInterruptStatus;
         xTaskNotifyWait( 0x00,               /* Don't clear any bits on entry. */
                         0xffffffff,          /* Clear all bits on exit. */
                         &ulInterruptStatus, /* Receives the notification value. */
                         portMAX_DELAY );    /* Block indefinitely. */
      
         if( ( ulInterruptStatus & 0x0000000010 ) != 0x0000000000 ) // test for int1 bit
        {
            // show caught
             _LATA6 = 0; // signal interrupt completed for latency measurement
        }
    }

I have put this into the configuration too

define configUSE_TASK_NOTIFICATIONS 1

all ends up taken an extra 5 or more us

only things I can think is I am not calling the Notify from the isr in the most efficient way or, is there is something wrong with the PortYield?

Mark

rtel wrote on Thursday, March 17, 2016:

I can’t see any reason for the latency to go up - you just need to look at the amount of code executing to see it should be faster, plus it is a point to point path rather than going through an intermediate object (the semaphore).

Using the notify “give” and notify “take” variants of the functions would be simpler, but that doesn’t explain what you are seeing.

mqn wrote on Thursday, March 17, 2016:

I changed the call to xTaskNotifyFromISR with eSetBits to eNoAction and then passed a NULL instead of &ulInterruotStatus into xTaskNotifyWait, with the test on the bit commented out below it.
It sped up by 2 us, but still slower than the semaphore.

mqn wrote on Thursday, March 17, 2016:

I changed the call to xTaskNotifyFromISR with eSetBits to eNoAction and then passed a NULL instead of &ulInterruotStatus into xTaskNotifyWait, with the test on the bit commented out below it.
It sped up by 2 us, but still slower than the semaphore.

mqn wrote on Thursday, March 17, 2016:

Someting else going on here, because I have put back my semaphore method and that is now 45 us ??? I’ll get back to you when I have worked out what I have done wrong.

mqn wrote on Thursday, March 17, 2016:

I must have misread/quoted my first latency value for the semaphore method.
Anyhow, here is the final result
Latency using binary semaphor 44.8 us
Latency using notify 43.6 us
Latency of raw irq 1.6 us

mqn wrote on Thursday, March 17, 2016:

Is there a way of increasing the speed of the scheduler so the latency goes down? Can I take stuff out of it to make it faster? I assume the schedular it self does not run off and interrupt, or does it?

rtel wrote on Thursday, March 17, 2016:

This link:

http://www.freertos.org/FAQMem.html#ContextSwitchTime

describes the configuration for taking an optimal measurement.

The context switch code saves all the register then restores a new set
of registers (the code can be seen in the portasm_pic24.s in the port
layer). Lets say that is approximately 70 or so instructions if you
include the C function call too. If you are running at 16MHz, and
assuming most instructions use a single cycle, then that would be about
(1/16000000)*70=4.4us (I think?). Then perhaps triple it as you are
measuring the notify give and take functions too - gives you about 13us

  • which is a long way off your measured time. Perhaps instructions take
    two cycles, or you are running the clock slower?

mqn wrote on Thursday, March 17, 2016:

I should be running at 32MHz!

mqn wrote on Friday, March 18, 2016:

Morning
I have been doing some more timings and they are quite interesting.
I have configured my interrupt routine to either trigger the task via binary semaphore or or notification and have put ticks around each function so I can get accurate scope timings.
Here are my results

Set up for semiphore : here are the timing to call and return from
xSemphoreGiveFromISR 8.1us
PortYield 94.9us
Time for the task to recieve the Semaphore after the start of the PortYield 34.5us

Set up for notify : here are the timing to call and return from
xTaskNotifyGiveFromISR 6.1us
PortYield 73.9us
Time for the task to recieve the Notification after the start of the PortYield 35 us

So it looks like whatever is going on in PortYield is the cause of the long timings.
Should there be a PortYieldFromISR which is a little more friendly to interupts?
Could it be that I have badly configured priorities for my and the schedular interupts?
What interrupt(s), other the the 1 ms timer, is the schedular using and which should I set to the highest priority?
Regards Mark

rtel wrote on Friday, March 18, 2016:

Be careful with how you are taking measurements as you are probably not
measuring what you think (this is why we normally stipulate no published
measurements!).

If I recall correctly on the PIC24 when you call yield you will get a
switch out of the ISR into the task immediately. You will then not
effectively (conceptually) return from the yield until the task that was
yielded away from next executes. So if you are measuring before and
after the yield you are measuring the entire time the task took to
execute and a switch back to the original task to be performed - not the
time of the yield.

mqn wrote on Friday, March 18, 2016:

Thats what I was just thinking it must be doing, this seams to indicate that I may as well do my data processing in the raw isr and not use tasks for that purpose, as the PortYield is causing the the interupt to persist as long as its invoked process + all of the rtos context switching time. All my task is doing atm is clearing a pin, 70 to 90 us to do that is much too much. So the question still remains, what is causing the 35us delays before the task triggers? Could this be down to my set priorities being wrong? I have looked for hidden interupts firing but not seen. Above you say is should be taking 2 or 3 us with my clock speeds.