Because of the Thanksgiving holiday in the U.S., TI E2E™ design support forum responses may be delayed from November 25 through December 2. Thank you for your patience.

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.

ADC triggering by PRU: Minimum distance between system events

I am using the system events from PRU0 to trigger ADC conversions.

ADC conversions are triggered by system event #16 of PRU0, and routed via PRU INTC to TSC_ADC event. With this setup I can trigger an ADC conversion by writing __R31 = 0x20 inside the PRU0. Everything works but I need to take care of a minimum delay between sytem events, otherwise the ADC conversion is not properly triggered.

ADC clock is 24MHz (test setup is a beaglebone black), and ADC_CLKDIV=0, STEPDELAY of TSC_ADC is set to 0x08000000, so ADC speed is not the cause (I verified the timing and as expected I can see the ADC conversion takes less than 2µs from trigger to EOC interrupt)

The following code works (__delay cycles causes 40µs delay between ADC triggers), and gives the results of 2 ADC conversions in ADC FIFO0 as expected:

__R31 = 0x20; // generate System event #16, routed to ext_hw_event of TSC_ADC

__delay_cycles(8000);

__R31 = 0x20;

However when I reduce the delay value to 2000 (10µs delay between ADC triggers), most of the time (>99%) only the first ADC conversion is triggered. I get a conversion result about 2µs after the first system event, but no second conversion result after the second system event.

Is there any limitation for subsequent SW triggered system events in the PRU? TRM paragraph 4.4.1.2.2 states that generating a system event by R31 "creates a pulse on the output of the corresponding pr1_pru_mst_intr[x]_intr_req INTC system event". If the width of this pulse was in the range of some 10s of µs this would explain the behaviour, but the length of the pulse is not specified anywhere. Another cause could be the width of the generated pulse by the PRU INTC at the ext_hw_event to TSC_ADC, but this is also not mentioned anywhere.

What could be the cause for the limitation of subsequent ADC conversions?

  • I will ask the PRU experts to comment.
  • The maximum clock rate you can operate the ADC is 3MHz which provides up to 200ksps when operating in continuous mode.  You need to set ADC_CLKDIV = 7 when using a 24MHz clock.

    Regards,
    Paul

  • I followed this post regarding sampling speed:
    e2e.ti.com/.../1349287

    However I tried to set ADC_CLKDIV=7 to verify. Even with ADC_CLKDIV=7 I have to wait at least ~32µs between the HW triggers to get two ADC conversions (I can see conversion takes longer with ADC_CLKDIV=7, but it is finished far before I can star a new one).
    32µs delay corresponds to about 30ksps which is far below the 200ksps specified. The delay seems independent of the ADC_CLKDIV setting but depends on some other timing constraint that I do not know.

    I also do not use continuous conversions at this speed. I am measuring only 2-4 samples every 1ms, but I need to control the timing very exactly, this is why I use PRU with HW triggering for this.
    When I use SW triggering (=enable the steps as one shot instead of generating a HW trigger) i can trigger consecutive conversions much faster without any loss. But I cannot use SW trigger for end application because latency between trigger and sampling start varies a lot with SW trigger.

    Regards
    Thomas
  • The maximum sample rate of 200ksps assumes operating the ADC in continuous mode.  Your use case may have non-deterministic time variables that would limit the maximum sample rate.

    I would like to better understand your use case.

    You configure the ADC to perform a conversion using a hardware enabled step with PR1_HOST_INTR0 sourcing the EXT_HW_EVENT input to the ADC.  You have confirmed the first PRU interrupt always triggers the hardware enabled step because the you detect the END_OF_SEQUENCE interrupt from the ADC in about 2us. How are you detecting and measuring this interrupt occurs in 2us? Are you returning the END_OF_SEQUENCE interrupt to the PRU?

    The next ADC conversion is missed if you shorten the delay of the next ICSS interrupt from 8000 clock cycles to 2000 clock cycles.  I’m concerned the time it takes to clear the first END_OF_SEQUENCE interrupt may limit the minimum time between conversions.  How are you clearing the first END_OF_SEQUENCE interrupt from the ADC? Are you using code executing in the PRU to perform this task?

    Regards,
    Paul  

  • Yes, I use the ADC to perform conversions triggered by hardware enable step. All of this is done in PRU0 (no host code involved). To do this, I set TSC_ADC_CTRL=0x0106 and TSC_ADC_STEPCONFIG1=0x00003, so that the TSC_ADC is set to hw triggered continuous conversion mode.
    To get the HW trigger from PRU software to the TSC_ADC I configure the INTC to route Software event 0 to Host event 2.
    In the main loop I only trigger the adc by event and use one direct GPIO (R30 Bit 0) as debug output that I can view on the scope.
    The triggering is always done twice, with some delay between. Everything is looped every 1ms:
    while (1)
    {
    __R30 |= 0x01;
    __R31 = 0x20; // generate System event #16, routed to ext_hw_event of TSC_ADC
    __R30 &= 0xfffffffe;
    __delay_cycles(8000);
    __R30 |= 0x01;
    __R31 = 0x20;
    __R30 &= 0xfffffffe;
    __delay_cycles(200000);
    }
    To get an exact view of conversion timing and results I use PRU1. The TSC_ADC FIFO0 IRQ is mapped by INTC to Host Event 0.
    PRU1 runs a loop to show when conversion is complete and a value is in the FIFO. It then fetches the data and acknowledges the interrupt.
    Also a direct GPIO is used so that I can view everything on a connected scope.
    while (1)
    {
    if (__R31 & 0x80000000) {
    __R30 |= 0x01;
    temp = TSC_ADC_FIFO0DATA: // get data
    ADC_IRQSTATUS = 0x04; // acknowledge TSC_ADC IRQ
    __delay_cycles(100);
    CT_INTC.SECR1 = 1 << (53-32);
    __delay_cycles(100);
     __R30 &= 0xfffffffe;
    }
    }
    The __delay_cycles (100) were found to be necessary because the write latency to the interrupt acknowledge registers.
    What I can see on the scope is that ADC conversions are always triggered twice (two pulses on PRU0 R30.0 output), and, if the value of __delay_cycles is set to 8000, two conversion results are received by PRU1 (represented by 2 pulses on PRU1 R30.0).
    When I reduce the delay_cycles value from 8000 to 2000, most of the time only the first HW trigger leads to a conversion result, and the second one is ignored.

    If I use SW triggering in PRU0 (that means set STEPCONFIG to single SW conversion instead of using HW event by __R31 = 0x20 in PRU0 code) I can reduce the delay_cycles value even to 1000 and always get two conversion results.

    Regards

       Thomas

  • If it makes things easier I can supply the used test code for both PRUs. But I would not like to post all the code in a public forum - if you can supply an email or something else I could submit the code.
  • I want to confirm your understanding of operating the ADC in hw triggered continuous conversion mode. Do you realize the hardware event will start a sequence that continues until software stops it? I do not see your code stopping the sequence, so it continued to run filling the FIFO beyond the threshold that generates the interrupt to the PRU.

    Regards,
    Paul
  • I set HW synchronized continuous mode (mode bits in STEPCONFIG register set to "11").
    What I can see is that every hw event is triggering one ADC conversion as expected (when I set HW synchronized one-shot mode I have to enable the step by STEPENABLE after each conversion because it is cleared by the TSC_ADC after each conversion in one-shot mode).
    I can not confirm that stopping the sequence is necessary. HW triggered continuous mode causes one conversion per trigger. This is also how I understand "Figure 12-3. Sequencer FSM" in TRM

    Regards
    Thomas
  • I think you are correct. I found another document that provided a better description of the hardware trigger.

    The EXT_HW_TRIGGER input signal which can be sourced from a device input terminal. When this option is selected, the hardware event will be triggered after the EXT_HW_TRIGGER input signal transitions from low to high and is held high for a period greater than two cycles of ocp_clock. This hardware event will only schedule one complete sequence, even for continuous mode. If HW Enabled steps need to be executed again, a new hardware event must be generated after the previously triggered sequence has completed.

    I do not know what could be happening in your use case, but maybe we can find another way to accomplish the task.

    Your software monitors the FIFO0_threshold interrupt rather than the End_Of_Sequence interrupt. Do you get a different result is you use the End_Of_Sequence interrupt? I’m not sure why you need to use the FIFO threshold interrupt since you control the number of conversions. The FIFO threshold interrupt is typically used when operating in continuous mode and software needs to know when to read the FIFO before it is over-run.

    If you are trying to do a burst of conversions every 1ms, could you configure additional steps? This way the ADC would automatically perform them in sequence. This method would allow you to perform up to 16 conversions and you could use the OPENDELAY counter to adjust the time between each step/conversion.

    Regards,
    Paul
  • I also tried End_Of_Sequence Interrupt, but there is no difference. The reason why I use FOFO threshold interrupt is the conversion data fetch that I trigger by this interrupt . TRM chapter 12.4 says "An END_OF_SEQUENCE interrupt is generated after the last active step is completed before going back to the IDLE state. The END_OF_SEQUENCE interrupt does not mean data is in the FIFO (should use the
    FIFO interrupts and FIFOxCOUNT register).".
    Just for a test I used a hardware timer to trigger the adc hw event, and did not notice any timing restrictions on triggering, so I assume the delay needed between conversions is caused by the PRU, not by the TSC_ADC.
    The end application controls some pins by direct GPIO and needs to measure voltages in close timing relationship to these sw controlled direct GPOs (variable timing, so fixed adc steps do not work).
    At the moment I use sw triggering, that means writing a "1" into the STEPENABLE bit that corresponds to the step I want to measure, and set the step to sw triggered one shot mode. This also works on the BBB. The reason why I would prefer hw triggering is that sw triggering has some latency (when the PRU writes ADC registers it takes some time to go through interconnects from L3 to L4WKUP), which is not specified and/or not deterministic. I found some latency values here:
    processors.wiki.ti.com/.../AM335x_PRU_Read_Latencies
    But these are read latencies and only best case. I can see write delays in the range up to 500ns here which would also be OK (up to 1us are no problem), but I am not aware how these latency values will change with system load or host software usuage.

    Regards
    Thomas
  • Is your code checking to see if the FIFO interrupt was cleared before generating the next trigger? If not, the write latency from the PRU to the ADC may have prevented the previous interrupt from being cleared before you generate the next trigger.

    Regards,
    Paul
  • Yes, I wait some amount of time after each IRQ (~2µs). I noticed that there is some write latency which causes the interrupt flag in the PRU to disappear only after some time after the data is requested. Without waiting I got the effect that the PRU sometimes read an empty fifo due to the irq flag still set.

    Regards
    Thomas