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.

CCS/TMS320F28388D: ADC v.s. CLA interrupt

Part Number: TMS320F28388D

Tool/software: Code Composer Studio

Hi support team,

I have two issues about ADC ISR and CLA ISR.

1).

The cyan curve is service time in CLA. The fuchsia one is CLA ISR. The blue one is ADC ISR.

The EOC event triggers the CLA task and ADC ISR. The CLA ISR is triggered by CLA task.

The C28x spends 65ns to respond ADC ISR  (shown in figure1). Why does it need to spend 251ns to respond to CLA ISR?

2). 

Why does it take 200ns for the CLA ISR to start after the CLA task triggers it?

  • Vince Lin said:
    Why does it need to spend 251ns to respond to CLA ISR?

    What is the C28x doing during that time - after it exits the ADC ISR. Is there anything during that time which could block the CLA ISR?  A higher priority ISR running, for example?  Is the CPU running from RAM or flash during that time?

    Vince Lin said:
    Why does it take 200ns for the CLA ISR to start after the CLA task triggers it?

    In this case I assume the ADC ISR is not running.  Same question as before - anything running that could block the CLA ISR? 

    Lori

  • Hi Lori,

    Thanks your reply.

    What is the C28x doing during that time - after it exits the ADC ISR. Is there anything during that time which could block the CLA ISR?  A higher priority ISR running, for example?  Is the CPU running from RAM or flash during that time?

    In this case, it has two interrupt routines. One is ADC ISR, the other is CLA ISR. So, I think after c28x exit the ADC ISR, it go back main loop. There is nothing in main loop now. The code (ADC ISR & CLA ISR) running from RAM. The EOC event triggers CLA task & ADC ISR. I presume that CLA task start timing as EOC event. The c28x only take 65ns to service ADC ISR. But the c28x take 251ns (feel it's too long) from exits the ADC ISR to entry the CLA ISR. I'm not sure that is correct or not.

    In this case I assume the ADC ISR is not running.  Same question as before - anything running that could block the CLA ISR? 

    Yes, it's right. In the seconded case, I disable the ADC ISR. So, the project only has one interrupt (CLA ISR). I want to measure time from the end of CLA task to CLA ISR. 

    In these case, I observed that the c28x takes 65ns go to ADC ISR from main loop. But it spends at least 200ns going CLA ISR. Why does c28x take time for the CLA ISR more than for the ADC ISR?

  • Thank you for the feedback, Vince.   

    For the ISRs - how are they defined in the project?  For FPU there are two types of interrupts:

    • High priority - use a fast context switch and cannot be nested
    • Low priority - require more context save/restore time

    This is described in http://www.ti.com/lit/spru514.  in section 6.10.16 - the INTERRUPT pragma.  Note that if the pragma hasn't been used then the interrupt will default to low priority. 

    It might be that the ADC is defined as a high priority ISR and the CLA as a low priority. 

    -Lori

  • Hi Lori,

    Thank you for the reply.

    • High priority - use a fast context switch and cannot be nested
    • Low priority - require more context save/restore time

    I got the answer.

    I want to used the CLA to help me improve ADC routine. It seem the CLA can't improve more. Because the c28x service the CLA ISR that it need more time. So in my project maybe only used the CLA to parallel computing. The CLA send the flag when it finished. A the CLA ISR can put some low priority event.

    By the way, Have any way to improve performance by using the pragma?

  • Vince Lin said:
    By the way, Have any way to improve performance by using the pragma?

    Vince,

    Did you try it?  If you are not nesting interrupts they can be high-priority.  

    Regards

    Lori

  • Hi Lori,

    In this project, I never used nesting interrupt.

    void setup_EOC_interrupt(void (*handler)(void)){
    
        ADC_disableContinuousMode(EOC_INTERRUPT_BASE, ADC_INT_NUMBER1);
        ADC_setInterruptSource(EOC_INTERRUPT_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER7);
        ADC_enableInterrupt(EOC_INTERRUPT_BASE, ADC_INT_NUMBER1);
        ADC_clearInterruptStatus(EOC_INTERRUPT_BASE, ADC_INT_NUMBER1);
    
        Interrupt_register(ADC_INTERRUPT_LINE, handler);
        Interrupt_enable(ADC_INTERRUPT_LINE);
    
    }
    void setup_ClaTask1(void (*handler)(void)){
    
        EALLOW;
    
    #pragma diag_suppress=770
        CLA_mapTaskVector(CLA1_BASE, CLA_MVECT_1, (uint16_t)&Cla1Task1);
    #pragma diag_warning=770
    
        CLA_enableIACK(CLA1_BASE);
        CLA_setTriggerSource(CLA_TASK_1, CLA_TRIGGER_ADCA1);
        CLA_enableTasks(CLA1_BASE, CLA_TASKFLAG_1);
    
        Interrupt_register(INT_CLA1_1, handler);
    
        Interrupt_enable(INT_CLA1_1);
    }
    #pragma CODE_SECTION(adcA1ISR, ".TI.ramfunc");
    __attribute__((interrupt )) void adcA1ISR(void){
    
    	GPIO_writePin(16, 1);
    
    	A1 = (AdcaResultRegs.ADCRESULT0 + AdcaResultRegs.ADCRESULT2 + AdcaResultRegs.ADCRESULT4 + AdcaResultRegs.ADCRESULT6) >> 2;
    	A2 = (AdcaResultRegs.ADCRESULT1 + AdcaResultRegs.ADCRESULT3 + AdcaResultRegs.ADCRESULT5 + AdcaResultRegs.ADCRESULT7) >> 2;
    	B1 = (AdcbResultRegs.ADCRESULT0 + AdcbResultRegs.ADCRESULT2 + AdcbResultRegs.ADCRESULT4 + AdcbResultRegs.ADCRESULT6) >> 2;
    	B2 = (AdcbResultRegs.ADCRESULT1 + AdcbResultRegs.ADCRESULT3 + AdcbResultRegs.ADCRESULT5 + AdcbResultRegs.ADCRESULT7) >> 2;
    	C1 = (AdccResultRegs.ADCRESULT0 + AdccResultRegs.ADCRESULT2 + AdccResultRegs.ADCRESULT4 + AdccResultRegs.ADCRESULT6) >> 2;
    	C2 = (AdccResultRegs.ADCRESULT1 + AdccResultRegs.ADCRESULT3 + AdccResultRegs.ADCRESULT5 + AdccResultRegs.ADCRESULT7) >> 2;
    	D1 = (AdcdResultRegs.ADCRESULT0 + AdcdResultRegs.ADCRESULT2 + AdcdResultRegs.ADCRESULT4 + AdcdResultRegs.ADCRESULT6) >> 2;
    	D2 = (AdcdResultRegs.ADCRESULT1 + AdcdResultRegs.ADCRESULT3 + AdcdResultRegs.ADCRESULT5 + AdcdResultRegs.ADCRESULT7) >> 2;
    
    	ADC_clearInterruptStatus(EOC_INTERRUPT_BASE, ADC_INT_NUMBER1);
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
    	GPIO_writePin(16, 0);
    }
    
    #pragma CODE_SECTION(cla1ISR, ".TI.ramfunc");
    __attribute__((interrupt )) void cla1ISR(void){
    	GPIO_writePin(17, 1);
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP11);
    	GPIO_writePin(17, 0);
    
    }

  • Vince Lin said:
    In this project, I never used nesting interrupt.

    Then both ISRs can be made "high priority" using the pragma.  This should reduce the number of registers that are stored during context save.

    Regards

    Lori

  • Hi Lori,

    Thanks your reply.

    I followed the C syntax of the pragma is "#pragma INTERRUPT ( func , HPI )"

    I’ve improved. The c28x serviced time for the ADC ISR improved 48.8%. The other improved 18.8%.

  • Hello,

    Did you use the pragma for both the ADC ISR and the CLA ISR?

    If the CLA task completes before the ADC ISR, then I would expect the time from the end of the ADC ISR to the CLA ISR would be about 2x (assuming everything is running in RAM). 

    Here is why

    • main loop  ADC ISR --> context save --> pin A high --> ADC ISR --> pin A low --> context restore
    • main loop for a few cycles  --> context save --> pin B high ---> CLA ISR --> pin B low --> contest restore

    From the ADC ISR to pin A high there is (1) context save (shown in red)

    From Pin A low to Pin B high there is a (1) context restore and (1) context save (shown in blue)

    I am assuming the CLA task is shorter than the ADC ISR, therefore the ISR has already been sent to the CPU when the ADC interrupt is complete.  Is that true?

    You can check the disassembly of the ISR to see what the context save/restore looks like (view--> disassembly).  Are they similar? 

    -Lori

  • Hello,

    I am assuming the CLA task is shorter than the ADC ISR, therefore the ISR has already been sent to the CPU when the ADC interrupt is complete.  Is that true?

    Yes. In CLA task only toggled GPIO (the ch-4 in latest waveform). So I think the c28x can immediate service the CLA ISR after ADC ISR finished.  I assumed the rising time of green curve as ADC triggered. The c28x take 35ns for context save to ADC ISR. However the c28x take 206ns for context switch(context restore to exit the ADC ISR + context save to entry the CLA ISR). Maybe my suppose was wrong.

    You can check the disassembly of the ISR to see what the context save/restore looks like (view--> disassembly).  Are they similar?

    Yes, They are similar.

    91 __attribute__((interrupt )) void adcA1ISR(void){
    adcA1ISR():


    00c000: 761B ASP
    00c001: ABBD MOVL *SP++, XT
    00c002: A8BD MOVL *SP++, XAR4
    00c003: A0BD MOVL *SP++, XAR5
    00c004: C2BD MOVL *SP++, XAR6
    00c005: C3BD MOVL *SP++, XAR7
    00c006: FFF0 PUSH RB
    00c007: E6700600 SAVE RNDF32=1,RNDF64=1
    00c009: 2942 CLRC OVM|PAGE0
    00c00a: 5616 CLRC AMODE
    00c00b: 761F002C MOVW DP, #0x2c

    508 gpioDataReg[GPIO_GPxSET_INDEX] = pinMask;
    00c00d: 8F010000 MOVL XAR4, #0x010000
    *
    *
    *
    504 gpioDataReg[GPIO_GPxCLEAR_INDEX] = pinMask;
    00c0b5: A8C5 MOVL *+XAR5[0], XAR4

    00c0b6: E562 RESTORE
    00c0b7: FFF1 POP RB
    00c0b8: C5BE MOVL XAR7, *--SP
    00c0b9: C4BE MOVL XAR6, *--SP
    00c0ba: 83BE MOVL XAR5, *--SP
    00c0bb: 8ABE MOVL XAR4, *--SP
    00c0bc: 87BE MOVL XT, *--SP
    00c0bd: 7617 NASP
    00c0be: 7602 IRET

    --------------------------------------------------------------------------

    116 __attribute__((interrupt )) void cla1ISR(void){
    cla1ISR():


    00c151: 761B ASP
    00c152: ABBD MOVL *SP++, XT
    00c153: A8BD MOVL *SP++, XAR4
    00c154: A0BD MOVL *SP++, XAR5
    00c155: C2BD MOVL *SP++, XAR6
    00c156: C3BD MOVL *SP++, XAR7
    00c157: FFF0 PUSH RB
    00c158: E6700600 SAVE RNDF32=1,RNDF64=1
    00c15a: 2942 CLRC OVM|PAGE0
    00c15b: 5616 CLRC AMODE

    824 HWREGH(base + ADC_O_INTFLGCLR) = 1U << (uint16_t)adcIntNum;
    00c15c: 9A01 MOVB AL, #0x
    *
    *
    *
    504 gpioDataReg[GPIO_GPxCLEAR_INDEX] = pinMask;
    00c16c: A8C5 MOVL *+XAR5[0], XAR4

    00c16d: E562 RESTORE
    00c16e: FFF1 POP RB
    00c16f: C5BE MOVL XAR7, *--SP
    00c170: C4BE MOVL XAR6, *--SP
    00c171: 83BE MOVL XAR5, *--SP
    00c172: 8ABE MOVL XAR4, *--SP
    00c173: 87BE MOVL XT, *--SP
    00c174: 7617 NASP
    00c175: 7602 IRET

  • Thank you Vince.  I am not sure why it is taking so much longer.  Let me investigate and get back to you before end of Wednesday US time.

  • Vince - an update.  I have this on my todo for the first thing Thursday.  I apologize for the delay.  

  • Hi Lori,

    Thanks your support.

  • Vince,

    I spent some time today putting together a simple project:

    • Running on a F2837xD at 200MHz.  This is very similar to the F28388 C28x side.
    • C28x fires a CLA Task through Software.
    • The CLA task in-turn interrupts the C28x. 
    • The C28x ISR is marked as high-priority. 
    • Everything is running in RAM. 
    • I made sure the C28x is not doing anything that would block the interrupt for a long time.  

    I believe this is the same scenario as #2 in your original post. 

    The time from the CLA task completing (marked A1) to the C28x CLA ISR start (marked A2) is 160ns. 

    • For a 200MHz device that is about 32 cycles.
    • There are about 4 cycles at the end of the CLA task after the GPIO is written (shown below)
    • There are about 14 cycles of context save + setup to write to GPIO (shown below). 
    0000a04a:   74E07F04    MMOV32     @0x7f04, MR2   <- write to pin
    0000a04c:   7FA00000    MNOP       
    0000a04e:   7FA00000    MNOP       
     62           {
              $C$L2:
    0000a050:   7FA00000    MNOP       
    0000a052:   7F800000    MSTOP      

            cla1Isr1():
    00b70f:   761B        ASP          
    00b710:   ABBD        MOVL         *SP++, XT
    00b711:   A8BD        MOVL         *SP++, XAR4
    00b712:   A0BD        MOVL         *SP++, XAR5
    00b713:   C2BD        MOVL         *SP++, XAR6
    00b714:   C3BD        MOVL         *SP++, XAR7
    00b715:   FFF0        PUSH         RB
    00b716:   E6700600    SAVE         RNDF32=1,RNDF64=1
    00b718:   2942        CLRC         OVM|PAGE0
    00b719:   5616        CLRC         AMODE
     597        gpioDataReg[GPIO_GPxSET_INDEX] = pinMask;
    00b71a:   BE02        MOVB         XAR6, #0x02
    00b71b:   8F007F02    MOVL         XAR4, #0x007f02
    248         for (claIsrProcessing = 0; claIsrProcessing < 100; claIsrProcessing++)
    00b71d:   B600        MOVB         XAR7, #0x00
    00b71e:   761F0240    MOVW         DP, #0x240
    00b720:   0264        MOVB         ACC, #100
     597        gpioDataReg[GPIO_GPxSET_INDEX] = pinMask;
    00b721:   C2C4        MOVL         *+XAR4[0], XAR6

    While this is better than your results, it doesn't match what you observed for the ADC which I don't have an answer for. 

  • Vince,

    Due to holidays in the US next week, I will not be able to look at this further until the first week of December. 

    Regards

    Lori

  • Hi Lori,

    Thanks your reply.

    I compare with your shared file. And I found a place maybe made the delay into CLA ISR.

    I used ADC_EOC trigger CLA task. So I need to clear ADC interrupt status in CLA ISR.

    Seem that the compiler clear interrupt status first. Then set the GPIO to high.

    That is why, I have longer delay.

  • Thank you for the feedback.  Please let me know if you consider the question resolved?

  • Hi Lori,

    I think we can close this thread. Lastly, I have some conclusions. 

    I hope I can used the CLA do some thing to share c28x loading. However, the CLA has some limitation about software development (Like function pointers  etc.). But the response time form end of CLA task to CLA ISR is longer than c28x service ADC ISR. So I should re-design the program. Use the CLA support to simplicity algorithm in parallel computing to improve performance. And the CLA ISR can put some behavior layer code. Instead of urgent request code.

    In other hand, the "#pragma INTERRUPT ( func , HPI )" is work. thanks your suggest.

    And I think this discuss is useful in high-frequency application.

    Thanks your support.

     

  • Hi Vince,

    Glad to see your thread appears to be resolved.  Feel free to post additional questions when they arise.

    Good luck in your project! 


    Thank you,
    Brett