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.

TMS570LS0714: Using DMA for CAN1 Tx

Expert 1965 points
Part Number: TMS570LS0714

I'm thinking if and how I would use DMA for a multi-buffer automatic sending on CAN1. And I'm not sure how to set this up, and if it possible (and if it would speed up things..).

First thing I don't understand is,  is it possible to setup one DMA channel for sending on single or multiple CAN message boxes / different messages ids. ..? Visually :

[ buffer with messages with different CAN ID's ]   --->  DMA  one channel -->   CAN1.

Even if using same message box,  I don't understand how can I use DMA here, as I would need to update message ID _every_  single message - per the DCAN API, which kind of defeats the purpose ..
And, seems same/or worse if I have to pass each message to different message box. Feels awkward to interact with this CAN interface, or I don't understand how to use it with DMA.
(Is there a direct CAN RAM mode here with DMA, where it can just transfer direct to DCAN1 memory without the use of command registers ...?)

How can one set this up so that you do not have to interrupt every single CAN message you have in buffer, but only once when it's all sent?

Any good example code please.

  • Hello v01d,

    I suggest to use IF3 for DMA transfer. The IF3 register set can automatically be updated with received message objects without the need to initiate the transfer from Message RAM by CPU. The intention of this feature of IF3 is to provide an interface for the DMA to read packets efficiently.

    I will organize a example for you later.

  • can automatically be updated with received message

    note,  I'm asking for TX, _sending_, not receiving. 

    Any example would of course be appreciated.

  • Ok, IF3 can not be used for transferring data into message objects.

    Attached example is for DCAN to receive data using DMA. The received data is transferred to different locations in RAM based on the message ID. You can use this example as a reference.

    TMS570LS0914PZ_DCAN_IF3_DMA.zip

  • Thanks for getting back to me on this, I really appreciate it , and the example code.

    So does your reply mean, it is NOT possible in principle to use DMA for Tx / transferring data auto(magically) into the message objects..?

    (I seems don't understand that , I guess, there is nothing to gain from such a setup or .. ?)

  • Only IF3 can be automatically updated with received message objects without the need to initiate the transfer from Message RAM by CPU. 

    To transmit data, IF1 or IF2 should be used, and the transfer from IF1/2 registers to message RAM is initiated by CPU.

  • Ok, so it is not possible  (odd.).

    Could you clarify this note (not DMA related) :

    This is under CAN message transfer. section.

    So is it possible then, to fill -in data  for say 10 TX objects,  and trigger their transfer _once_ , so DCAN then transmits them all in order ? (higher to lower priority / lower to higher number).

    ..And, to generate only one Tx complete interrupt.   

    Cannot seems set this up too. I can pre-fill all objects, but  transmission stops on first  that i set to transmit. 

    EDIT: actually this is not clear too :

    Does this imply that , you can somehow configure several multiple message to one message object .. ?

  • 2. If several transmit messages should be assigned to one message object, the whole message object has to be configured before the transmission of this message is requested.

    You can use one message object or one mailbox to transfer messages with different data length, different message ID.

  • So is it possible then, to fill -in data  for say 10 TX objects,  and trigger their transfer _once_ , so DCAN then transmits them all in order ?

    Yes, it is possible. While the CAN bus is busy, you transfer 10 messages to 10 message objects in message RAM through IF1 or IF2, and TxRqst of all messages is set. All 10 messages will be in pending until the CAN bus is free. After the CAN bus becomes free, the message with highest priority (lowest object number) will be transmitted first. The message object with the lowest number has the highest priority. 

  • I have now checked your example in detail. 

    Ok, sorry but Have to ask based on the manual:

    .. data sheet :

    So .. I should be able to use IF1/2 as well  .. ? I mean there are channels, and even CAN CNTRL channel allows me to select IF1/2 to trigger DMA

    I don't understand , are these just for fun ?  Why an I limited to IF3 _and_ only for Receiving  (RX on CAN) .. ?

    Tried now to setup IF2 DMA interrupt on sending, and I get nothing - no DMA interrupt...  

  • Here is my attempt to setup to get DMA interrupt on DCAN1 IF2 - which is used for transmit channel, i.e  from IF2 to an Object.

         g_dmaCTRL g_dmaCTRLPKT;
        
        dmaReqAssign(DMA_CH8, 8);
    
        g_dmaCTRLPKT.SADD      = (uint32)(&dumm_msg.data);              /* source address             */
        g_dmaCTRLPKT.DADD      = (uint32)(&canREG1->IF1DATx[0]);              /* destination  address       */
        g_dmaCTRLPKT.CHCTRL    = 0;                 /* channel control            */
        g_dmaCTRLPKT.FRCNT     = 1;                 /* frame count                */
        g_dmaCTRLPKT.ELCNT     = 1;             /* element count              */
        g_dmaCTRLPKT.ELDOFFSET = 0;                 /* element destination offset */
        g_dmaCTRLPKT.ELSOFFSET = 0;                 /* element source offset      */
        g_dmaCTRLPKT.FRDOFFSET = 0;                 /* frame destination offset   */
        g_dmaCTRLPKT.FRSOFFSET = 0;                 /* frame source offset        */
        g_dmaCTRLPKT.PORTASGN  = 4;                 /* port b                     */
        g_dmaCTRLPKT.RDSIZE    = ACCESS_64_BIT;     /* read size                  */
        g_dmaCTRLPKT.WRSIZE    = ACCESS_64_BIT;     /* write size                 */
        g_dmaCTRLPKT.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
        g_dmaCTRLPKT.ADDMODERD = ADDR_FIXED;        /* address mode read          */
        g_dmaCTRLPKT.ADDMODEWR = ADDR_FIXED;        /* address mode write         */
        g_dmaCTRLPKT.AUTOINIT  = AUTOINIT_OFF;      /* autoinit                   */
    
    
        /* - setting dma control packets for transmit */
        dmaSetCtrlPacket(DMA_CH8,g_dmaCTRLPKT);
    
        dmaSetChEnable(DMA_CH8, DMA_HW);    // <--- If i just use DMA_SW trigger, then I get one interrupt in,  but that's of no use
    
        /* Just set them all .. I want to get _ANY at this stage .. */
        dmaEnableInterrupt(DMA_CH8, FTC);
        dmaEnableInterrupt(DMA_CH8, BTC);
        dmaEnableInterrupt(DMA_CH8, LFS);
        dmaEnableInterrupt(DMA_CH8, HBC);
    
        dmaEnable();
    
        canREG1->CTL |= 0x41U;
        canREG1->CTL |= (1 << 18U);
        canREG1->CTL &= ~(uint32)(0x41U);
    
        while(1)
        {
           canTransmit(canREG1, 1U, &dummy_msg);
           vTaskDelay(10);
        }
        

    I do get canMessageNotification() callback, when message is Tx'ed, but I don't get any of dmaGroupANotification() if I use as above, with HW trigger.  ( I do get that ISR if i use SW trigger once, for testing).

    Any ideas ?

  • Yes, it is possible. While the CAN bus is busy, you transfer 10 messages to 10 message objects in message RAM through IF1 or IF2, and TxRqst of all messages is set. All 10 messages will be in pending until the CAN bus is free. After the CAN bus becomes free, the message with highest priority (lowest object number) will be transmitted first. The message object with the lowest number has the highest priority. 

    That is , seems not what I asked.  What you described above is essentially,  you just canTransmit() in sequence to a range of mboxes. 

    I was wondering if you can pre-fill them, and then later trigger just with _one_ call, sending them all out  (without using IF1/2  N times again to trigger send !) 

  • Hello,

    We can pre-fill the message boxes through IF1 or IF2 without setting the TxRqst. To start the transmission, the application has to set TxRqst through IF1 or IF2.

    I don't know how to trigger several message boxes to transmit with just one call. 

  • Hello 

    Thanks so much for your replying again.  

    I think I'm almost all good with using the peripheral, and at least I think I understand mostly how it was designed to be used.

    Can I just ask you to help me with the DMA question again, as the last thing on this thread.

    If you see above, I saw in the manual, that all IFx - 1, 2 & 3 - can be used as triggers to DMA. At least the manual for device family says. So does the datasheet for specific device - 07x,09x,122x i have all list IF1,2,3 has options to DMA channel triggers. 

    But I couldn't make IF2, as I setup for sending (not receiving, note) , to trigger my DMA setup (see above my post).

    What's missing?  

  • The code you posted is for IF1 rather than IF2

        g_dmaCTRLPKT.DADD      = (uint32)(&canREG1->IF1DATx[0]);  

    For CAN1 IF2, the DMA request line 6 (DMAREQ[6]) is used: dmaReqAssign(DMA_CH8, 6);

  • That was because none work, so I was trying both - IF1, and IF2. I was getting nothing, no DAM interrupts anywhere.

    I will go over it & double check.

  • Hi,

    Have you resolved the CAN DMA issue?

  • no sorry still need to try out again with DMA

  • Okey, so your example is for IF3, and that's Ok for now, as I'm just setting up _any_ CAN DMA to work.

    So I've downloaded your project as-is, it builds but it absolutely does not tick - no interrupts generated, and the cpu just stuck at 

      /* Wait for the DMA interrupt ISR to set the Flag */
        while(DMA_Comp_Flag != 0x5555AAAA);

    No CAN, No DMA notifications... So something you may have forgotten to add.  Havn'et debugged this

  • I have modified your example to make it work without loopback and using IF3.

    For now I have DMA working only through IF3, and for rx - as this is what it was designed best for seems.

    Closing thread & if I need for IF1/2, I will open new one.

    Thank you