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.

TMS320F28379D: Time delay from ADC EOC to ADC interrupt execution

Part Number: TMS320F28379D


Hello,

I have a query regarding the time elapsed after the End of Conversion (EOC) of the ADC module until the actual execution of the ADC interrupt. As mentioned in the datasheet, "If the INTPULSEPOS bit in the ADCCTL1 register is set, t INT will coincide with the conversion results being latched into the result register". I have calculated the sample and hold time and the A/D conversion time as per the datasheet. However, When I measure the time from SOC to execution of the first line of the adc interrupt, there is some time unaccounted for. I have elaborated the problem below:

The ADCA module is configured to convert one pin. The acquisition window is set at 75 ns (t_SH). ADC clock is running at 50 MHz. System clock is running at 200 MHz. According to datasheet, the time t_EOC will be 10.3 ADCCLK cycles. This makes t_EOC 206 ns. So, t_SH + t_EOC = 281 ns.

The EPWM1 module is configured as ADC SOC. The SOC occurs at CTRU = CMPA. An action qualifier is configured to set the channel at CTR = zero and clear the channel at CTRU = CMPA. The EPWM channel is monitored on an oscilloscope.

A GPIO pin (GPIO93) is set at the first line of the ADC interrupt routine and cleared at the end of the routine. This pin is being monitored on the oscilloscope.

The time difference between the clearing of EPWM channel and the set of GPIO93 is measured as 410 ns. The time taken for the set instruction on a GPIO pin was measured approximately as 25 ns. The time unaccounted for is thus found out to be (410 - 25 - 281) ns = 104 ns. Even if I consider a couple of cycles more for the latching of the ADC results, there is still much time unaccounted for.

Please correct me if there is some mistake in the implementation or measurement. It will be helpful if I could get some reference document which explains the excess time.

Please let me know if any other information is required.

Thank you.

  • Somenath,

    Please give me another day to respond to your question, I believe I have all the info I need.

    Best,

    Matthew

  • Somenath,

    I'm going to refer to the timing diagram on page 1581 of the TRM https://www.ti.com/lit/pdf/spruhm8 for the below calculations.

    The above page has timings in terms of SYSCLK, so it will be simpler as we can use 5ns period below.  For 50MHz ADC Clock I'm assuming ADCCTL2.PRESCALE = 6 which would give 200/4 = 50MHz

    According to this table the time in SYSCLK from the end of the sample to Tlatch = 44 cycles.  So this would be 44 * 5ns = 220ns.  Adding back the acquisition time of 75ns we get 220ns+75ns = 295ns of total time from when the trigger is received.

    If we look at the figure there is also a marker for the ADCTRIG signal to get latched by the ADC, this would be the EPWM ADCSOC in your case, let's assume the worse case of 2 extra SYSCLK cycles for this to happen, so we would then have

    2ns(time to latch the trigger) + 75ns(Sample and Hold Time) + 220ns(conversion and latch time) = 297ns

    We still have a gap in what we should observe and what the o-scope is capturing

    297ns + 25ns(GPIO toggle time) = 322ns  

    410ns(observed) - 322ns(expected) = 88ns.

    There is still some cycles we need to account for regarding the action that happens when the device processes an ISR.  When this occurs the C28x CPU will have to flush its instruction pipeline(completing whatever operations have already entered the D2 phase of the pipeline https://www.ti.com/lit/SPRU430) as well as push register contents to the stack

    Basically we will incur an 8 cycle penalty before we will fetch the ADC ISR, so we now have:

    322ns+(8*5ns) = 362ns

    410ns-362ns = 48ns delta time.

    At this point we have ~10 CPU cycles unaccounted for. I believe that it will take an extra 4-5 CPU cycles for the instruction of the ADC ISR to get executed once fetched, not sure if this is already counted in your GPIO timing though.

    Can you comment if your ADC ISR is running from Flash or RAM memory?  If we are running from flash, at 200MHz it has 3WS for timing reasons, so this could be adding a few extra cycles that we haven't included

    Another possibility is that the code that was running when the ADC ISR comes to the C28x is taking cycles to complete its operation either from Flash or RAM.

    Let me know if you have any additional questions on the above.

    Best,

    Matthew

  • Matthew,

    Thank you for your elaborate and prompt response.

    Replying to your question, I am running the code from RAM memory.

    What I gather from the above discussion is if we are able to ensure that the CPU is idle when the ADC interrupt is triggered, then it may be possible to get the least time required to start servicing the ADC ISR. I will run an empty infinite loop in the main while waiting for the interrupt. This should ensure that the CPU is not working on any instructions when the interrupt is being triggered. I will report my findings for the same.

    Please let me know if I should proceed otherwise.

    Thank you,

    Somenath.

  • Somenath,

    You are correct, if you ensure the CPU is idle that will give the best response time to service the ISR.

    Best,

    Matthew

  • Matthew,

    I have implemented the modifications I had mentioned in my previous reply. Now the infinite loop has no instructions inside it. This has indeed resulted in reduction of the measured time. Now the total time has reduced from 410 ns to 395 ns. I am using a while(1) loop for this purpose.

    Thank you,

    Somenath.

  • Somenath,

    I think we are right there in terms of expected behavior.  I found an error in my earlier calculation, the time to latch the ADCINT from the PWM is 2 SYSCLK cycles, not 2ns.  So without any ISR overhead we should be at 370ns.  So we now have

    395(measured)-370ns(expected) = 25ns or 5 cycles of delta.  I think this is likely accounted for in the time it will take to execute that first instruction from the ADCISR after the CPU pipeline fetches that program code address.

    Best,

    Matthew

  • Matthew,

    I think the 25ns or 5 cycles for execution of the first line of ADC ISR (in this case the toggling of the GPIO pin) is being considered twice in the above calculation.

    Summarizing the discussion so far, the timings are:

    2 cycles for latching of the trigger from EPWM SOC : 10 ns

    Sample and hold time : 75 ns

    Conversion and latch time (44 cycles to latch the ADC results) : 220 ns

    8 cycle penalty before fetching ADC ISR : 40 ns

    Time to execute the first line of ISR (in this case 5 cycles for GPIO toggling) : 25 ns

    Total time (calculated) : 370 ns

    Measured time from o-scope : 395 ns

    I also have a doubt regarding the consideration of 44 cycles for conversion and latch time. Referring to the same document, the time t_INT is mentioned as 41 cycles. What I gather from the information is after the 41st cycle, the ADC interrupt trigger is set. However, the results from the conversion take 44 cycles to get latched to the result register. I think that in our calculation, we should consider 41 cycles instead of 44 cycles. This is because the 8 cycle penalty should start after the CPU gets the ADC interrupt trigger (which is at the 41st cycle).

    Please correct me if my calculation and assumptions are incorrect.

    Thank you,

    Somenath.

  • Somenath,

    I noticed that as well, let me check with some others to see if this is 41 or 44.

    Best,

    Matthew

  • Somenath,

    Appreciate your patience here.  I've confirmed that the timing listed in the table is correct, so 41 CPU cycles from end of sample to conversion complete.  The late ADCINT will fire at this time as well, which will help counteract the ISR cycle/pipeline flush we talked about earlier.

    This also means I have addition 3 CPU cycles unaccounted for, or 15ns.

    So we have 395ns measured vs 355ns expected, or 40ns/5ns = 8 CPU cycles lost.

    I'd like to try to measure this with the Code Composer cycle count to compare that with the scope.  In order to do this we also need to change the ADC trigger from PWM to just using the ADCSOCFRC bit in SW.  We can set a BP at that instruction and another at the first instruction of the ADC ISR and observe the cycle count we get.  We can then move the BP post the GPIO toggle, etc and then compare to the o-scope.

    I've screen capped CCS to show how to enable this.  Once you do this you should see a small clock in the lower right of the CCS window.  You can double click on the clock to reset it once you hit the BP.  This will give cycle count from C28x CPU perspective and we can back out the time knowing the CPU clock.

    I just want to remove as much variability as possible and then we can work our way backward to add more code(PWM trigger, etc) and make sure we are getting the correct counts and how that relates to the o-scope.

    Best,

    Matthew

  • Matthew,

    Thank you for your effort in investigating the issue. I did try your suggestion. I am attaching the code I used for this purpose.

    #include "F28x_Project.h"
    //
    // Function Prototypes
    //
    void ConfigureADC(void);
    void SetupADC(void);
    interrupt void adca1_isr(void);
    
    void main(void)
    {
        InitSysCtrl();
    
        DINT;
        InitPieCtrl();
        IER = 0x0000;
        IFR = 0x0000;
    
        InitPieVectTable();
    
        EALLOW;
        PieVectTable.ADCA1_INT = &adca1_isr; //function for ADCA interrupt 1
        EDIS;
    
        ConfigureADC();
    
        SetupADC();
    
        IER |= M_INT1; //Enable group 1 interrupts
        EINT;  // Enable Global interrupt INTM
        ERTM;  // Enable Global realtime interrupt DBGM
        PieCtrlRegs.PIEIER1.bit.INTx1 = 1;
    
        DELAY_US(10000);
    
        AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1;
    
        while(1)
        {
    
        }
    
    }
    
    void ConfigureADC(void)
    {
        EALLOW;
        AdcaRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
        AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
        AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;
        AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;
        DELAY_US(1000);
        EDIS;
    }
    void SetupADC(void)
    {
        EALLOW;
        AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0;  //SOC0 will convert pin A0
        AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; //sample window 75ns
        AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0; //trigger by S/W only
        AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; //end of SOC0 will set INT1 flag
        AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;   //enable INT1 flag
        AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
        EDIS;
    }
    
    interrupt void adca1_isr(void)
    {
        DELAY_US(10000);
        AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag
        PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    }

    I hope this serves the purpose of what you suggested. Please correct me if there is some mistake in the implementation.

    I had set a BP at the line "AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1;" and the next BP at "DELAY_US(10000);" line inside the adc isr. I had reset the ccs clock to 0 at the first breakpoint. The reading of the clock at the next BP was 93.

    I gather this means there was 465 ns between the two BPs (since the system clock is set at 200 MHz). This is higher than the 395 ns measured on the o-scope. I guess maybe there was a lag between the EPWM SOC trigger (in the original implementation) and the actual reflection of the compare event on the o-scope.

  • Somenath,

    Thanks for doing this, exactly what I wanted to see.  As you have noted we are now seeing a larger time delay than before and what is expected, which is a bit surprising to be honest.  After you hit the BP in the ADC ISR, can you open a dis-assembly window to see/confirm that we haven't executed any additional instructions?

    For the code placement, can you confirm the RAM addresses the code is executing from?  I need to check to make sure all the RAM is 0WS on this device(I think it is), but this will help me narrow down if there are any concerns with that.

    Best,
    Matthew

  • Matthew,

    I did observe the disassembly at both breakpoints. I am attaching the snapshots of the disassembly window for both instants.

    I am observing 17 instructions between the entry into adc isr and the first line of code inside the isr. However, I am not able to understand the purpose of these instructions.

    As for the code placement, I am attaching the portion of code responsible for the RAM assignments in the linker file. Pardon me if I got you wrong, but I gather you meant to see where the components of the code are being stored in the memory.

    SECTIONS
    {
       codestart        : > BEGIN,     PAGE = 0
       .text            : >>RAMM0 | RAMD0 |  RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3 | RAMLS4,   PAGE = 0
       .cinit           : > RAMM0,     PAGE = 0
       .pinit           : > RAMM0,     PAGE = 0
       .switch          : > RAMM0,     PAGE = 0
       .reset           : > RESET,     PAGE = 0, TYPE = DSECT /* not used, */
    
       .stack           : > RAMM1,     PAGE = 1
       .ebss            : > RAMLS5,    PAGE = 1
       .econst          : > RAMLS5,    PAGE = 1
       .esysmem         : > RAMLS5,    PAGE = 1
       Filter_RegsFile  : > RAMGS0,	   PAGE = 1
    
       ramgs0           : > RAMGS0,    PAGE = 1
       ramgs1           : > RAMGS1,    PAGE = 1
    

    Hope this helps.

    Thank you,

    Somenath.

  • Somenath,

    Appreciate the screen captures.  Those 17 instructions are part of any ISR context save(you will also see the restore at the end of the ISR).  These are auto-generated when any function is declared as an ISR and I had not accounted for that in my earlier calculations.

    If you could set a BP at the beginning and end of those and measure the CPU cycle count, I think this will resolve the time delta we have from theoretical to real world.  If I assume single CPU instruction for each (which is optimistic) I get a total of 435ns vs the 465ns you see or 6 cycle difference.  As I mention I think a few of these instructions may take more than one cycle, but the profile should reveal that.

    Another option, to optimize the delay from ADC conversion to read would be to use the early interrupt(that occurs at after the signal is sample, but not converted).  We can use the above info to determine when the new ADC result would be ready once we get to your code in the ISR and delay those few cycles as needed(or do other system operations).

    Best,

    Matthew

  • Matthew,

    Thank you for the insight regarding the context save. I do see them at the end of the ISR also. So I did place BPs at the beginning and end of those 17 instructions. However, the clock count at the bottom right reads 17 in this case. So I guess they are all single cycle instructions. I have attached a screen cap with the placement of the BPs in the disassembly and the cycle count at the bottom.

    I have also measured the cycle count for the latching of ADCSOCFRC by placing a BP at ADCSOCFRC and the next at the while(1) line. This takes 4 cycles.

    Summarizing the discussion so far: 

    4 cycles for latching of ADCSOCFRC

    15 cycles for Sample and hold time

    41 cycles for the ADC conversion and triggering of ADC interrupt

    8 cycle penalty before fetching ADC ISR

    17 cycles for context save

    Total cycles accounted for : 85 cycles

    Measured no. of cycles from ADCSOCFRC to first line of ISR : 93 cycles

    Please let me know if I am missing something from before.

    Also I appreciate the suggestion to use the early interrupt, I will definitely try that.

    Thank you,

    Somenath.

  • Somenath,

    Appreciate you breaking out the cycles.  Let me loop in a few others to see if we can explain the 8 cycle delta from silicon to specification.

    Best,

    Matthew

  • Somenath,

    We've had some internal discussions on this and now have the following breakdown of cycles to more accurately account for the CPU pipeline flush/reload that occurs when ISR is triggered.

    4 cycles for latching of ADCSOCFRC

    15 cycles for Sample and hold time

    41 cycles for the ADC conversion and triggering of ADC interrupt

    14 cycle penalty before fetching ADC ISR(pipe-line flush, HW context save of main CPU registers, and fetch/call ISR vector )

    17 cycles for context save inside the ISR

    91 CPU cycles vs 93 cycles measured

    At this point, I think we can feel confident you are getting the best/predictable turn-around time with the late ADCINT. 

    As for the 2 cycles, I think this is dependent on what the CPU is doing when the ADC ISR comes into the C28x CPU, realizing we have some idle loop here, but if we look at the dis-assembly we likely will see some type of branch instruction which will introduce its own dis-continuity to the pipeline.

    Best regards,
    Matthew

  • Matthew,

    Thank you for patiently resolving the query. The timing summary provided by you did actually give me some insight in the process.

    Thank you again,

    Somenath.