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.

Trigger DMA with an external signal

Hi,

I'm currently working with TMS570/RM48HDK andI need to striclty syncronize two unit on an external clock. Can I trigger the DMA with an external pin, using an external clock to generate a DMA request? Looking on the table 4-33 (DMA Request Line Connection) of the datasheet I don't see this possibility but perhaps I'm miising something or this way can be achieved passing throght another device (for example the RTI).

Note that this clock is a high rate one (1MHz or more) so using interrupt or other ways involving CPU is not a realistic way. The event must be HW driven with no CPU intervention.

Thank you

  • Matteo,

    The first thing that comes to mind is N2HET since N2HET can both detect edges on a pin and generate DMA requests under N2HET program control.

    But >1MHz is a high rate.  You will need to be careful with the size of the N2HET program.

    Also, I would be equally concerned about:

     a) what is your criteria for synchronization - and is it between 2 TMS570/RM48 chips?

    b) what are the source/dest locations of your DMA transfer if you are trying to sustain transfers at 1M transfer/s?
       (EMIF might be problematic here for example)

  • The DMA is used to generate a complex square wave pattern to feed an external sensor whose data are aquired via ADC. The DMA reads a buffer, 32 bit a time, and writes directlty to DOUT ports. The source buffer is designed to describe this square wave pattern in terms of bits. This generation actually must run at 2Mhz becaus the faster wave required is 1MHz.

    Actually I'm using RTI comparator to generate the DMA request at desired frequency and I've tested all until 2MHz.

    The sync is now required because I must strictly sinchronize two sensors driven by two TMS570 (or RM48). The two square waves trains must then be triggered by the same clock (thus an external one).

    My solutions could be:

    • generate DMA requests using a pin feed with the external clock (in a similar way as the ADC can be triggered using HTE1_8, for example)
    • setting the RTI comparator to work with an external clock instead of the internal RTI clock (this wolud be the preferred way requiring the minimum changes on my code)

    But obviously I'm not sure if and how similar solution can be implemented.

  • A note: using HET could be a problem because I'm actually using the HET1 ports as output for my square waves (DOUT ports are written by DMA) and the HET2 to generate some pwm required by another part of my application (temperature control using peltier cells).

  • Matteo,

    Ok, I feel better about the DMA rate knowing it's reading/writing to internal peripherals and that the ADC has a buffer.

    I guess then - you're saying that you *currently* use the RTI Compare to trigger this process, but now you need to *change* to an external trigger,  *or* find a way that you can synchronize the two RTI clocks across the two devices.
    It that accurate?

    Side note - we do need to know within what window you need synchronization i.e. within 1us, 100ns, 10ns, etc.

    Best Regards,

    Anthony

  • Antony,

    I'm glad you feel better ;-)

    1uS seems be more than enough (to be sure I need to ask to my HW counterparts) but the drift (if syncronizing only the start event relying on two independent clocks) should be less than 10ppm because the acquisition must run continuosly for long time.

    "find a way that you can synchronize the two RTI" could be a solution but in this case I'd neet to syncronize the start event too (actually the start is given by a network signal so uses a software way).

    The first solution ("*change* to an external trigger") would be the best because in that case my sw start does not require a strict sync because the real start is given by the external clock start (which I can accomodate to start with a grace time).


    What about using an external source for the RTI comparator?

  • Matteo,

    RTI has an NTU function that allows synchronization over FlexRay but that is probably overkill for what you're trying to do.

    Unfortunately there isn't any way to get an external source into the RTI comparator other than the NTU.  And I believe the NTU has to come from the FlexRay module.  There would be a simpler approach to doing this if you're not using FlexRay, which is the second option I'd propose below but do it over SPI or CAN...  

    I think the best option here is to look at N2HET.  I know you mentioned this is problematic, but if you use one device as the trigger generator and the other to 'receive' the trigger then you won't have any issue with relative drift of one mcu compared to the other... just some jitter due to sampling of the event.

    It should only take one instruction (WCAPE for example) to generate a DMA request on the occurence of a pin event assuming you don't actually care about the timestamp or the event count of the WCAPE and just want the DMA request function.  Hopefully you can fit this into one of your programs and have the loop resolution be fast enough to catch your incoming request signals.

    The other option I can think of would be to continue to use the RTI compare registers to trigger the DMA requests on both devices, but then periodically synchronize the two RTIs together using a SPI or CAN message carrying an IEEE1588 type message.  One of our FAE's has tried this before and was able to keep two parts toggling pins within a few 100ns of each other over a long term.  So we could get you in touch with him for more information on how this was done.   This sort of solution is more complex but maybe it would be generally useful in your application and therefore worth the trouble.

     

  • Antony,

    the HET solution seems the more practical. Can you suggest me the code to load in the HET to obtain it (I've never used the HET programming)?

    About the HET:  there will be some conflict if I continue to use the HET ports to output my square waves (accessing these pins direclty writing the DOUT register) while the same HET executes the program to read one pin and generate DMA requests? Can HET pins be written using DOUT while the HET program is running?

    The other possibility would be to use the other HET (HET2) but I'm currently using this as PWM generator and in this case I'm quite sure this will provoke some slowdown.

    A third solution would be to find some other way to generate PWM on the Hercules and in this way release the HET2 to perform the DMA request, but I don't see which other device could be used to generate PWM.

    Matteo

  • Matteo,

    No conflict to worry about.  Both the CPU and N2HET can access the same pins simultaneously.  There is no concept of GIO mode versus functional pin mode for the N2HET pins.   When the timer wants to set a pin high it sets the DOUT register, the CPU can change the pin by writing something else on top of the DOUT register.

    The program you need is probably 2 lines of HET code.

    1st is a WCAP and 2nd is a BR back to start.  But you should go through the tuturials in the HET IDE first, to get a feel for how the HET works.  Then I think this will make more sense.

     

  • You could try this HET code (I haven't tested it but it's how I would start...)

    Start   CNT { reg=A,comp=GE,max=10,data=0};
    L1   WCAPE { reqnum=4,request=GENREQ,pin=0,event=RISE,reg=A};
    L2   BR { next=START,cond_addr=START,event=NOCOND};

    The WCAPE at L1 is the instruction that would generate the DMA request.

    It is set to generate DMA request 4 from the HET.   You might want to go through section 20.2.9 N2HET Requests to DMA and HTU to see how this works.   The DEFAULT value of the HETREQDS register is such that the N2HET DMA requests will go to the HTU, so you will need to change this.  (HTU could work but only if one of the source or destination is in the HET RAM... which I don't think it is from what you describe.  So you need the DMA). You'll need to set TDS[4] to '1'.

    Next you need to look at the DMA controller DMA Request Line Connection in the device datasheet.

    For the LS3137,  the N2HET1 DMAREQ[4] is *output* is driving the DMAREQ[20] input of the DMA controller.

    So that's the DMA request that you will want to configure your DMA controller to respond to.  

    Of course you could change the DMA request number you are using from 4 to something else in case you need DMA from DCAN3 which shares the channel to the DMA with the N2HET request 4...     if you do this just remember to change both the 'reqnum' field in the instruction L1,  the TDS bit number that you set, and the DMA request channel that you use so that they all match.

  • Hi Antony,

    thank you for the detailed answer. That's what I need. I'll try to take advantage of your kindness with some more questions (I'm new to the NHET programming, so be patient):

    1) Why the program cannot symply be something like:

    L1   WCAPE {next=L1, reqnum=4,request=GENREQ,pin=0,event=RISE};

    2) What is register 'A' used for in your program?

    3) Perhaps your program permit to demultiply the input (so generating a DMA request every N pin0 fronts) and mine (possibly wrong) doesn't? In this case how can I access the HET code form my C code after have it loaded to the NHET RAM?

  • Hi Matteo,

    Good questions.

    The N2HET works based on a concept of loop resolution.   Think of this as one 'clock' of a hardware counter.   During this clock, all of your instructions execute.   But they only execute once per 'clock' (loop resolution period). 

    Then when your program is finished it has to branch back to address 00000  in the HET RAM (hence the branch to start) with *at least* one cycle to spare before the end of the loop resoltion period.   But usually it can be many more cycles.

    The N2HET sees the branch back to address 0000 and then stops excuting your program until the beginning of the next 'clock' (beginning of the next loop resolution period).

    This is a good feature in the sense that you know your instructions execute periodically and the period doesn't vary depending on how many cycles you instructions take to execute.  If it did then you would have a hard time writing PWM code and knowing the actual period...   since depending on the path through the program each loop might take a different # of cycles.

    So then the key point is that your program needs to leave address 0000 and then branch back to address 0000 in order to make the N2HET program work at all.

    Now your simple event trigger to DMA function really only requires +1 instruction (WCAPE) but if there's nothing else that the HET is doing then you need some dummy stuff around it to make a minimal loop.

    I put a CNT instruction first, just to make the WCAPE functional.   I am not sure you actually need the branch but it won't hurt.  I'd start with this and if you want to you can take it out but I don't think the program will run any faster, as you'll be down near the minimum loop resolution anyway with either 2 or 3 cycles of instruction execution.

    Yes, you can make the program trigger the DMA request every N events.   You can actually implement this all in HET code, you would move the GENREQ out of the WCAPE instruction and into some instruction that is executed only after the WCAPE event count reaches the value N that you want.    I'd suggest getting the simple WCAPE running first though and then trying this out.

    When you assemble your N2HET program, the output includes a .h file that defines all of your instructions symbolically,  using any 'label' that you put on the instruction as part of the name.

    For example, if you put a label "START' on the first line of HET code, you will see something like this in the header file:

    #define HET_START_0 (e_HETPROGRAM0_UN.Program0_ST.START_0)
    #define pHET_START_0   0

    And you can refer to the data field of this instruction in your driver code like this:

       nhetRAM1->Instruction[pHET_START_0].Data = 1;

    Hope that helps.