Tasks triggering tick ISR on dsPIC33CH

Hello,

I am trying to use FreeRTOS on a dsPIC33CH512MP508 MCU, but I am experiencing some weird behavior.
At the moment I am testing a dummy project to simply blink two LEDs every 5 (LED0) and 15 ms (LED1) respectively using a tick time base of 1 ms. However, it seems every time one of these two tasks is resumed to toggle its related output line, this somehow causes the tick interrupt to be triggered a second time. This in turn causes the LED periodicity to be early.

In the attached image you can find an oscilloscope screenshot showing the issue. The yellow and green signals represent LED0 and LED1 respectively. In its first cycle LED0 is early (4 ms) since one LED1 edge occured in between. Similarly, LED1 is early (12 ms) since several LED0 events occured during its cycle.
Plus, the blue signal is a debug toggling line placed inside the tick-timer ISR. As can be seen, each time an LED task is resumed, the ISR is for some reason retriggered.

I also tried multiple variations, but the behavior remains the same:

  • try to increase the tick time base;
  • try to completely reset (i.e. disable and re-enable) the timer inside the tick ISR;
  • try to create task delay through vTaskDelay, vTaskDelayUntil and xTimerCreate;

Moreover, I noticed if I disable all tasks (except for the idle one) the tick ISR (blue signal) is executed periodically every 1 ms as expected.

Do you have any clue about this issue?

Thanks in advance,
Filippo

Hard to tell without the related code…

I think there is some inapproriate code there which causes the unwanted behaviour.

Maybe, but all my code is just this:

int main( void ){
    Init_Clock();      // boot clock to 90 MHz
    Init_GI();           // enable global interrupt
    xTaskCreate( Blink_LED0, "LED0", 4*MIN_STACK_SZ, NULL, PRT_LED0, NULL );                                             
    xTaskCreate( Blink_LED1, "LED1", 4*MIN_STACK_SZ, NULL, PRT_LED1, NULL );
    vTaskStartScheduler();  
    return 0; 
}

void Blink_LED0( void *pvParameters ){
    TRISBbits.TRISB15 = xOUTPUT;
    LATBbits.LATB15 = xHIGH;
    while( 1 ){
        vTaskDelay(pdMS_TO_TICKS(5));
        if( PORTBbits.RB15 == xHIGH ){
            LATBbits.LATB15 = xLOW;
        } else {
            LATBbits.LATB15 = xHIGH;
        }
    }
}

void Blink_LED1( void *pvParameters ){
    TRISBbits.TRISB14 = xOUTPUT;
    LATBbits.LATB14 = xHIGH;
    TickType_t xLastWakeTime = xTaskGetTickCount();
    while( 1 ){
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(15));
        if( PORTBbits.RB14 == xHIGH ){
            LATBbits.LATB14 = xLOW;
        } else {
            LATBbits.LATB14 = xHIGH;
        }
    }
}

__attribute__(( weak )) void vApplicationSetupTickTimerInterrupt( void ){
    Config_T1();
}

void __attribute__((__interrupt__, auto_psv)) configTICK_INTERRUPT_HANDLER( void ){
	if( xTaskIncrementTick() != pdFALSE ){
		portYIELD();
	}
    IFS0bits.T1IF = 0;
}

Not really sure, if it is applicable in your case, but you can you try clearing the interrupt early as suggested by @richard-damon in this post:

void __attribute__((__interrupt__, auto_psv)) configTICK_INTERRUPT_HANDLER( void ){
    IFS0bits.T1IF = 0;
	if( xTaskIncrementTick() != pdFALSE ){
		portYIELD();
	}
}

Also, why do you declare vApplicationSetupTickTimerInterrupt as weak?

Regarding the weak attribute, i did not touch it. It was already like this from the original demo project i downloaded from Microchip GitHub. You suggest to change it?

Anyway, thank you so much! The position where I clear the flag was indeed the issue. Even though it is still not really clear to me why… I mean, the scheduler takes just something like few tens of microseconds to execute, so how can that cause the interrupt to be re-triggered if not immediately cleared?

This function is declared weak in the port layer to ensure that the application can override it. You should not declare it weak when overriding because when you have more than one weak functions (and no strong one), any one of those can be used. So, yes, remove weak.

@richard-damon has provided a possible explanation in the post I mentioned above, though I could not find it mentioned in dsPIC33 docs.