This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28386D: Is it possible to nest the FreeRtos timer isr? Interfering with Control Loop ISR

Part Number: TMS320F28386D
Other Parts Discussed in Thread: MG2, C2000WARE

Tool/software:

I'm developing a control loop system and facing a priority issue with interrupts. My setup is as follows:

1. The control loop ISR (triggered by ADC) should have the highest priority.
2. Other tasks are managed using FreeRTOS. 
3. It is running in the c28x core.

Problem:
I've noticed that the control loop ISR is experiencing a delay of approximately 1.8us each 1ms, coinciding with the FreeRTOS timer ISR trigger.

Current Considerations are:
- Removing FreeRTOS and implementing a custom solution.
- Exploring ways to optimize within the FreeRTOS framework

Questions:
1. How can I ensure that the control loop ISR maintains the highest priority without being interrupted by FreeRTOS?
2. Is it possible to enable nesting of the FreeRTOS timer ISR to minimize its impact on the control loop?
3. Are there any FreeRTOS configurations or best practices to address this kind of timing-sensitive scenario?

I'd greatly appreciate any insights, suggestions, or alternative approaches to resolve this issue while maintaining the benefits of using FreeRTOS.

Thanks in Advance

Kind Regards

Agustin J. Gomez

  • Hello Agustin ,

    I am working on similar topic:

    Highest priority ISRs:

    150kHz ADC A1, ADC C1

    2nd priority ISR:

    50kHz ADC C2

    3rd priority ISR:

    LIN comm

    4th priority ISR:

    1ms Timer1

    lowest ISR:

    FreeRTOS portTick (Timer2)

    +

    FreeRTOS 1ms/10ms/100ms tasks

    ========================================

    What I did is following the "interrupt_ex3_sw_prioritization" example and modify the 2nd/3rd/4th ISRs and "portasm.asm" to allow nesting.

    ========================================

    You may compare to original "portasm.asm"

    _portTICK_ISR:

    ; Nesting Enable
    AND IER, #0x1225
    NOP
    CLRC INTM


    ; Save context
    ASP

    .....

    MOV32 STF, *--SP
    MOVL XAR7, *--SP
    MOVL XAR6, *--SP
    MOVL XAR5, *--SP
    MOVL XAR4, *--SP
    MOVL XAR3, *--SP
    MOVL XAR2, *--SP
    MOVL XT, *--SP
    POP RPC
    POP AR1H:AR0H
    POP RB
    NASP


    ; Nesting End
    SETC INTM


    IRET

    ================================================


    // FILE: sw_prioritized_isr_levels.h

    #ifdef __cplusplus
    extern "C" {
    #endif

    //
    // Mask for interrupt groups
    //
    #define M_INT1 0x0001 // INT1 Mask
    #define M_INT2 0x0002 // INT2 Mask
    #define M_INT3 0x0004 // INT3 Mask
    #define M_INT4 0x0008 // INT4 Mask
    #define M_INT5 0x0010 // INT5 Mask
    #define M_INT6 0x0020 // INT6 Mask
    #define M_INT7 0x0040 // INT7 Mask
    #define M_INT8 0x0080 // INT8 Mask
    #define M_INT9 0x0100 // INT9 Mask
    #define M_INT10 0x0200 // INT10 Mask
    #define M_INT11 0x0400 // INT11 Mask
    #define M_INT12 0x0800 // INT12 Mask
    #define M_INT13 0x1000 // INT13 Mask
    #define M_INT14 0x2000 // INT14 Mask
    #define M_DLOG 0x4000 // DLOGINT Mask
    #define M_RTOS 0x8000 // RTOSINT Mask

    //
    // Interrupt Enable Register Allocation:
    // Interrupts can be enabled/disabled using the CPU interrupt enable register
    // (IER) and the PIE interrupt enable registers (PIEIER1 to PIEIER12).
    //

    //
    // Set "Global" Interrupt Priority Level (IER register):
    //
    // The user must set the appropriate priority level for each of the CPU
    // interrupts. This is termed as the "global" priority. The priority level
    // must be a number between 1 (highest) to 16 (lowest). A value of 0 must
    // be entered for reserved interrupts or interrupts that are not used.
    //
    // Note: The priority levels below are used to calculate the IER register
    // interrupt masks MINT1 to MINT16.
    //
    // Note: The priority levels shown here may not make sense in a
    // real application. This is for demonstration purposes only!!!
    //
    // The user should change these to values that make sense for
    // their application.
    //
    // 0 = not used
    // 1 = highest priority
    // ...
    // 16 = lowest priority
    //
    #define INT1PL 1 // Global Priority for Group1 Interrupts
    #define INT2PL 0 // Global Priority for Group2 Interrupts
    #define INT3PL 3 // Global Priority for Group3 Interrupts
    #define INT4PL 0 // Global Priority for Group4 Interrupts
    #define INT5PL 0 // Global Priority for Group5 Interrupts
    #define INT6PL 4 // Global Priority for Group6 Interrupts
    #define INT7PL 0 // Global Priority for Group7 Interrupts
    #define INT8PL 0 // Global Priority for Group8 Interrupts
    #define INT9PL 0 // Global Priority for Group9 Interrupts
    #define INT10PL 2 // Global Priority for Group10 Interrupts
    #define INT11PL 0 // Global Priority for Group11 Interrupts
    #define INT12PL 0 // Global Priority for Group12 Interrupts
    #define INT13PL 7 // Global Priority for INT13 (TINT1)
    #define INT14PL 8 // Global Priority for INT14 (TINT2)
    #define INT15PL 0 // Global Priority for DATALOG
    #define INT16PL 0 // Global Priority for RTOSINT

    //
    // Set "Group" Interrupt Priority Level (PIEIER1 to PIEIER12 registers):
    //
    // The user must set the appropriate priority level for each of the PIE
    // interrupts. This is termed as the "group" priority. The priority level
    // must be a number between 1 (highest) to 16 (lowest). A value of 0 must
    // be entered for reserved interrupts or interrupts that are not used.
    //
    // Note: The priority levels below are used to calculate the following
    // PIEIER register interrupt masks:
    // MG1_1 to MG1_16
    // MG2_1 to MG2_16
    // MG3_1 to MG3_16
    // MG4_1 to MG4_16
    // MG5_1 to MG5_16
    // MG6_1 to MG6_16
    // MG7_1 to MG7_16
    // MG8_1 to MG8_16
    // MG9_1 to MG9_16
    // MG10_1 to MG10_16
    // MG11_1 to MG11_16
    // MG12_1 to MG12_16
    //
    // Note: The priority levels shown here may not make sense in a
    // real application. This is for demonstration purposes only!!!
    //
    // The user should change these to values that make sense for
    // their application.
    //
    // 0 = not used
    // 1 = highest priority
    // ...
    // 16 = lowest priority
    //
    #define G1_1PL 1 // ADCA1_INT
    #define G1_2PL 1 // ADCC1_INT
    #define G1_3PL 0 // Reserved
    #define G1_4PL 0 // XINT1_INT
    #define G1_5PL 0 // XINT2_INT
    #define G1_6PL 0 // SYS_ERR_INT
    #define G1_7PL 4 // TIMER0_INT
    #define G1_8PL 0 // WAKE_INT

    #define G2_1PL 0 // EPWM1_TZ_INT
    #define G2_2PL 0 // EPWM2_TZ_INT
    #define G2_3PL 0 // EPWM3_TZ_INT
    #define G2_4PL 0 // EPWM4_TZ_INT
    #define G2_5PL 0 // EPWM5_TZ_INT
    #define G2_6PL 0 // EPWM6_TZ_INT
    #define G2_7PL 0 // EPWM7_TZ_INT
    #define G2_8PL 0 // Reserved

    #define G3_1PL 0 // EPWM1_INT
    #define G3_2PL 0 // EPWM2_INT
    #define G3_3PL 0 // EPWM3_INT
    #define G3_4PL 0 // EPWM4_INT
    #define G3_5PL 0 // EPWM5_INT
    #define G3_6PL 0 // EPWM6_INT
    #define G3_7PL 0 // EPWM7_INT
    #define G3_8PL 0 // Reserved

    #define G4_1PL 0 // ECAP1_INT
    #define G4_2PL 0 // ECAP2_INT
    #define G4_3PL 0 // ECAP3_INT
    #define G4_4PL 0 // Reserved
    #define G4_5PL 0 // Reserved
    #define G4_6PL 0 // Reserved
    #define G4_7PL 0 // Reserved
    #define G4_8PL 0 // Reserved

    #define G5_1PL 0 // EQEP1_INT
    #define G5_2PL 0 // EQEP2_INT
    #define G5_3PL 0 // Reserved
    #define G5_4PL 0 // Reserved
    #define G5_5PL 0 // Reserved
    #define G5_6PL 0 // Reserved
    #define G5_7PL 0 // Reserved
    #define G5_8PL 0 // Reserved

    #define G6_1PL 0 // SPIA_RX_INT
    #define G6_2PL 0 // SPIA_TX_INT
    #define G6_3PL 0 // Reserved
    #define G6_4PL 0 // Reserved
    #define G6_5PL 0 // LINA_0_INT
    #define G6_6PL 0 // LINA_1_INT
    #define G6_7PL 0 // DCC0_INT
    #define G6_8PL 0 // Reserved

    #define G7_1PL 0 // Reserved
    #define G7_2PL 0 // Reserved
    #define G7_3PL 0 // Reserved
    #define G7_4PL 0 // Reserved
    #define G7_5PL 0 // Reserved
    #define G7_6PL 0 // Reserved
    #define G7_7PL 0 // PMBUSA_INT
    #define G7_8PL 0 // Reserved

    #define G8_1PL 0 // I2CA_INT
    #define G8_2PL 0 // I2CA_FIFO_INT
    #define G8_3PL 0 // I2CB_INT
    #define G8_4PL 0 // I2CB_FIFO_INT
    #define G8_5PL 0 // SCIC_RX_INT
    #define G8_6PL 0 // SCIC_TX_INT
    #define G8_7PL 0 // Reserved
    #define G8_8PL 0 // Reserved

    #define G9_1PL 0 // SCIA_RX_INT
    #define G9_2PL 0 // SCIA_TX_INT
    #define G9_3PL 0 // SCIB_RX_INT
    #define G9_4PL 0 // SCIB_TX_INT
    #define G9_5PL 0 // CANA0_INT
    #define G9_6PL 0 // CANA1_INT
    #define G9_7PL 0 // MCANSS0_INT
    #define G9_8PL 0 // MCANSS1_INT

    #define G10_1PL 0 // ADCA_EVT_INT
    #define G10_2PL 0 // ADCA2_INT
    #define G10_3PL 0 // ADCA3_INT
    #define G10_4PL 0 // ADCA4_INT
    #define G10_5PL 0 // ADCC_EVT_INT
    #define G10_6PL 0 // ADCC2_INT
    #define G10_7PL 0 // ADCC3_INT
    #define G10_8PL 0 // ADCC4_INT

    #define G11_1PL 0 // Reserved
    #define G11_2PL 0 // Reserved
    #define G11_3PL 0 // Reserved
    #define G11_4PL 0 // Reserved
    #define G11_5PL 0 // Reserved
    #define G11_6PL 0 // Reserved
    #define G11_7PL 0 // Reserved
    #define G11_8PL 0 // Reserved

    #define G12_1PL 0 // XINT3_INT
    #define G12_2PL 0 // XINT4_INT
    #define G12_3PL 0 // XINT5_INT
    #define G12_4PL 0 // Reserved
    #define G12_5PL 0 // FMC_INT
    #define G12_6PL 0 // VCRC_INT
    #define G12_7PL 0 // INT_MCANSS_WAKE_AND_TS_PLS
    #define G12_8PL 0 // INT_MCANSS_ECC_CORR_PLS


    //
    // Include the header file with software interrupt prioritization logic
    //
    #include "sw_interrupt_prioritization_logic.h"

    #ifdef __cplusplus
    }
    #endif /* extern "C" */

    #endif // eof

    //
    // End of file
    //

    =================================================

    interrupt void IsrAdcA2(void)
    {
    IsrAdcA2_Enter_ticks++;

    // Set the global and group priority to allow CPU interrupts
    // with higher priority
    IER &= MINT10;


    // Enable Interrupts
    __asm(" NOP");
    EINT;

    ..........

    DINT;
    /* Clear the interrupt flag*/
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT2 = 1;

    /* Acknowledge the interrupt*/
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP10;

    }

  • Hi Xianzhi, Thanks for sharing!

    I was kind of avoiding to touch the assembly but your solution seems pretty good.

    I will analyze your answer to understand how does it work and how does it fits to me.

    AND IER, #0x1225

    0x1225 is THE number to do it or is it application dependent? is it possible to define it externally to make it more general? I will check that to allow reusing the port. I think I will understand it better after I check the example you told me.

    Thanks again! 

    Kind Regards

    Agustin J. Gomez

  • Hi Agustin, 

    The FreeRTOS port in C2000Ware does not directly support nesting but can be modified as discussed earlier in the thread. You can check out this link for further explanations about C28x interrupt nesting.

    Thanks,

    Arnav