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.

Errors result about TMS570LC43x CAN&DMA

Other Parts Discussed in Thread: HALCOGEN

Hello,

I'm trying to send some data with DMA and DCAN1 on Hercules,TMS570LC43X  launchapd ,but have a problem.

I  try to send some data with DMA and DCAN1,but couldn't send data with DMA.

/** @file HL_sys_main.c 
*   @brief Application main file
*   @date 05-Oct-2016
*   @version 04.06.00
*
*   This file contains an empty main function,
*   which can be used for the application.
*/

/* 
* Copyright (C) 2009-2016 Texas Instruments Incorporated - www.ti.com  
* 
* 
*  Redistribution and use in source and binary forms, with or without 
*  modification, are permitted provided that the following conditions 
*  are met:
*
*    Redistributions of source code must retain the above copyright 
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the 
*    documentation and/or other materials provided with the   
*    distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/


/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "HL_sys_common.h"

/* USER CODE BEGIN (1) */
#include "HL_sys_dma.h"
#include "HL_sci.h"
#include "HL_can.h"
#include "stdio.h"
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
#define size 8

/* Tx and Rx data buffer */
uint8_t TX_DATA[size], RX_DATA[size] = {0};

/* Addresses of CAN1 IF1 and IF2 8-bit TX/Rx data */
#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
#define CAN1_TX_ADDR ((uint32_t)(&(canREG1->IF1DATx[0])))
#define CAN1_RX_ADDR ((uint32_t)(&(canREG1->IF2DATx[0])))
#else
#define CAN1_TX_ADDR ((uint32_t)(&(canREG1->IF1DATx[0])) + 3)
#define CAN1_RX_ADDR ((uint32_t)(&(canREG1->IF2DATx[0])) + 3)
#endif

#define DMA_CAN1_TX  DMA_REQ8
#define DMA_CAN1_RX  DMA_REQ6

/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
	uint32 CAN1TxData;
	int i;
	g_dmaCTRL g_dmaCTRLPKT1;

	/*Load source data*/
	for (i=0; i<size; i++)
	{
		TX_DATA[i] = i;
	}

	/*Initialize CAN*/
	canInit();
	/* Enable CAN loopback */
	canEnableloopback(canREG1,Internal_Lbk);
	//Enable DE1 bit in CTL register to trigger DMA when IF1  data
	canREG1->CTL |= (1U << 18U);
	/*Assign DMA request DCAN1 IF1 transmit to Channel 0*/
	dmaReqAssign(DMA_CH0, DMA_CAN1_TX);
	CAN1TxData = CAN1_TX_ADDR;
	/*Configure control packet for Channel 0*/
	g_dmaCTRLPKT1.SADD      = (uint32_t)TX_DATA;	/* source address             */
	g_dmaCTRLPKT1.DADD      = CAN1TxData;		    /* destination  address       */
	g_dmaCTRLPKT1.CHCTRL    = 0;                	/* channel control            */
	g_dmaCTRLPKT1.FRCNT	   = size;                  /* frame count                */
	g_dmaCTRLPKT1.ELCNT     = 1;             	    /* element count              */
	g_dmaCTRLPKT1.ELDOFFSET = 0;                	/* element destination offset */
	g_dmaCTRLPKT1.ELSOFFSET = 0;		          	/* element destination offset */
	g_dmaCTRLPKT1.FRDOFFSET = 0;		          	/* frame destination offset   */
	g_dmaCTRLPKT1.FRSOFFSET = 0;                	/* frame destination offset   */
	g_dmaCTRLPKT1.PORTASGN  = PORTA_READ_PORTB_WRITE;
	g_dmaCTRLPKT1.RDSIZE    = ACCESS_8_BIT;		    /* read size                  */
	g_dmaCTRLPKT1.WRSIZE    = ACCESS_8_BIT;	 	    /* write size                 */
	g_dmaCTRLPKT1.TTYPE     = FRAME_TRANSFER;  	    /* transfer type              */
	g_dmaCTRLPKT1.ADDMODERD = ADDR_INC1;        	/* address mode read          */
	g_dmaCTRLPKT1.ADDMODEWR = ADDR_FIXED;      	    /* address mode write         */
	g_dmaCTRLPKT1.AUTOINIT  = AUTOINIT_OFF;      	/* autoinit                   */
	/*Set control packet for channel 0 */
	dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT1);
	/*Set dma channel 0  to trigger on hardware request*/
	dmaSetChEnable(DMA_CH0, DMA_HW);
	/*Enable DMA*/
	dmaEnable();
	/*transmit message*/
	canREG1->IF1CMD = 0x87U;
	canREG1->IF1NO =1;
	while(1);

/* USER CODE END */
}


/* USER CODE BEGIN (4) */
/* USER CODE END */

 

please check my code!

I would appreiate if someone could reply to my question.

  • Hi,

      I think the problem is with your FRCNT and ELCNT. You want to transfer 8 bytes, right? So you should change to ELCNT = size like below and keep the FRCNT to 1. You should also change the ADDMODEWR  to ADDR_INC1. Try if it makes a difference.

        g_dmaCTRLPKT1.SADD      = (uint32_t)TX_DATA;    /* source address             */
        g_dmaCTRLPKT1.DADD      = CAN1TxData;           /* destination  address       */
        g_dmaCTRLPKT1.CHCTRL    = 0;                    /* channel control            */
        g_dmaCTRLPKT1.FRCNT     = 1;                  /* frame count                */
        g_dmaCTRLPKT1.ELCNT     = size;                    /* element count              */
        g_dmaCTRLPKT1.ELDOFFSET = 0;                    /* element destination offset */
        g_dmaCTRLPKT1.ELSOFFSET = 0;                    /* element destination offset */
        g_dmaCTRLPKT1.FRDOFFSET = 0;                    /* frame destination offset   */
        g_dmaCTRLPKT1.FRSOFFSET = 0;                    /* frame destination offset   */
        g_dmaCTRLPKT1.PORTASGN  = PORTA_READ_PORTB_WRITE;
        g_dmaCTRLPKT1.RDSIZE    = ACCESS_8_BIT;         /* read size                  */
        g_dmaCTRLPKT1.WRSIZE    = ACCESS_8_BIT;         /* write size                 */
        g_dmaCTRLPKT1.TTYPE     = FRAME_TRANSFER;       /* transfer type              */
        g_dmaCTRLPKT1.ADDMODERD = ADDR_INC1;            /* address mode read          */
        g_dmaCTRLPKT1.ADDMODEWR = ADDR_INC1;           /* address mode write         */
        g_dmaCTRLPKT1.AUTOINIT  = AUTOINIT_OFF;         /* autoinit                   */
  • I'm sad to say that it makes no difference.
  • I think the problem is that the DMA did not receive a DMA request trigger. You can check by looking the PEND and FTCFLAG registers in the DMA module. If they show zero then it means the DMA is waiting.

    You setup the DMA and the DMA is waiting for a request. While waiting, you have written canREG1->IF1NO =1; which is to start the message transmission. At this time the IF1DATx is still empty. So you are transmitting 0 on the bus. As an experiment you can write some non-zero data to the IF1DATx registers first to prove. After the transmission the DCAN will then assert the DMA request. So what you need to do is to start a dummy transmission initiated by the CPU first. After the dummy transmission, the DCAN will assert DMA request and the request will trigger the DMA to start transferring data for the next transmission.

    BTW, you should change to #define CAN1_TX_ADDR ((uint32_t)(&(canREG1->IF1DATx[0])) + 0) because the destination address mode is changed to increment mode. You have eight 8-bit elements to transfer. You want the destination address to start at 0 and let it increment to 7.
  • /* USER CODE BEGIN (2) */
    #define size 8
    
    /* Tx and Rx data buffer */
    uint8_t TX_DATA[size], RX_DATA[size] = {0};
    
    /* Addresses of CAN1 IF1 and IF2 8-bit TX/Rx data */
    #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
    #define CAN1_TX_ADDR ((uint32_t)(&(canREG1->IF1DATx[0])))
    #define CAN1_RX_ADDR ((uint32_t)(&(canREG1->IF2DATx[0])))
    #else
    #define CAN1_TX_ADDR ((uint32_t)(&(canREG1->IF1DATx[0])) + 0)
    #define CAN1_RX_ADDR ((uint32_t)(&(canREG1->IF2DATx[0])) + 0)
    #endif
    
    #define DMA_CAN1_TX  DMA_REQ8
    #define DMA_CAN1_RX  DMA_REQ6
    
    /* USER CODE END */
    
    int main(void)
    {
    /* USER CODE BEGIN (3) */
    	uint32 CAN1TxData;
    	int i;
    	g_dmaCTRL g_dmaCTRLPKT1;
    
    	/*Load source data*/
    	for (i=0; i<size; i++)
    	{
    		TX_DATA[i] = i;
    	}
    
    	/*Initialize CAN*/
    	canInit();
    	/* Enable CAN loopback */
    	canEnableloopback(canREG1,Internal_Lbk);
    	//Enable DE1 bit in CTL register to trigger DMA when IF1  data
    	canREG1->CTL |= (1U << 18U);
    	/*Assign DMA request DCAN1 IF1 transmit to Channel 0*/
    dmaEnableInterrupt(DMA_CH0, BTC,DMA_INTB); dmaReqAssign(DMA_CH0, DMA_CAN1_TX); CAN1TxData = CAN1_TX_ADDR; /*Configure control packet for Channel 0*/ g_dmaCTRLPKT1.SADD = (uint32_t)TX_DATA; /* source address */ g_dmaCTRLPKT1.DADD = CAN1TxData; /* destination address */ g_dmaCTRLPKT1.CHCTRL = 0; /* channel control */ g_dmaCTRLPKT1.FRCNT = 1; /* frame count */ g_dmaCTRLPKT1.ELCNT = size; /* element count */ g_dmaCTRLPKT1.ELDOFFSET = 0; /* element destination offset */ g_dmaCTRLPKT1.ELSOFFSET = 0; /* element destination offset */ g_dmaCTRLPKT1.FRDOFFSET = 0; /* frame destination offset */ g_dmaCTRLPKT1.FRSOFFSET = 0; /* frame destination offset */ g_dmaCTRLPKT1.PORTASGN = PORTA_READ_PORTB_WRITE; g_dmaCTRLPKT1.RDSIZE = ACCESS_8_BIT; /* read size */ g_dmaCTRLPKT1.WRSIZE = ACCESS_8_BIT; /* write size */ g_dmaCTRLPKT1.TTYPE = FRAME_TRANSFER; /* transfer type */ g_dmaCTRLPKT1.ADDMODERD = ADDR_INC1; /* address mode read */ g_dmaCTRLPKT1.ADDMODEWR = ADDR_INC1; /* address mode write */ g_dmaCTRLPKT1.AUTOINIT = AUTOINIT_OFF; /* autoinit */ /*Set control packet for channel 0 */ dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT1); /*Set dma channel 0 to trigger on hardware request*/ dmaSetChEnable(DMA_CH0, DMA_HW); /*Enable DMA*/ dmaEnable(); canREG1->IF1CMD|= 0x87U; canREG1->IF1STAT|=0x40;//trigger DMA_ACTIVE /*transmit message*/ while(dmaGetInterruptStatus(DMA_CH0, BTC) != TRUE); canREG1->IF1NO =1; while(1); /* USER CODE END */ }

    I add code "canREG1->IF1STAT|=0x40";(//trigger DMA_ACTIVE),but can't get result as former(I think DMA_ACTIVE bit is to start the message transmission ),

    and can't trigger BTC interrupt.

  • I add code "canREG1->IF1STAT|=0x40";(//trigger DMA_ACTIVE),but can't get result as former(I think DMA_ACTIVE bit is to start the message transmission ),

    and can't trigger BTC interrupt.
  • Hi,
    Sorry I was out of office.

    Can you dump the content of the DMA registers?

    Are you using write-through cache scheme or write-back cache scheme? If you are using write-back scheme can you change to write-through instead? Let me know if it makes a difference.
  • I think I'm using the  write-through scheme!and now the problem is that i can't trigger a  dma chancel pending.

    My code as follow,I would appreiate if you could check my code.

    1513.Project9.zip

  • Can you show the complete DMA registers?

    Also as I mentioned in the earlier reply I think you need to have a dummy write to start off the DMA process. Below was what I said in my earlier reply.

    You setup the DMA and the DMA is waiting for a request. While waiting, you have written canREG1->IF1NO =1; which is to start the message transmission. At this time the IF1DATx is still empty. So you are transmitting 0 on the bus. As an experiment you can write some non-zero data to the IF1DATx registers first to prove. After the transmission the DCAN will then assert the DMA request. So what you need to do is to start a dummy transmission initiated by the CPU first. After the dummy transmission, the DCAN will assert DMA request and the request will trigger the DMA to start transferring data for the next transmission.
  • I use the IF3 and get it working!but I still can't get corret result by using IF1.
    IF3 code as follow,
    /** @file HL_sys_main.c
    * @brief Application main file
    * @date 05-Oct-2016
    * @version 04.06.00
    *
    * This file contains an empty main function,
    * which can be used for the application.
    */

    /*
    * Copyright (C) 2009-2016 Texas Instruments Incorporated - www.ti.com
    *
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the
    * distribution.
    *
    * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    */


    /* USER CODE BEGIN (0) */
    /* USER CODE END */

    /* Include Files */

    #include "HL_sys_common.h"

    /* USER CODE BEGIN (1) */
    #include "HL_sys_core.h"
    #include "HL_sys_dma.h"
    #include "HL_sci.h"
    #include "HL_can.h"
    #include "stdio.h"
    /* USER CODE END */

    /** @fn void main(void)
    * @brief Application main function
    * @note This function is empty by default.
    *
    * This function is called after startup.
    * The user can use this function to implement the application.
    */

    /* USER CODE BEGIN (2) */
    #define D_SIZE 512


    uint8 TX_DATA1[D_SIZE]={0}; /* transmit buffer in sys ram */

    uint8 RX_DATA1[D_SIZE]= {0}; /* receive buffer in sys ram */


    uint32 DMA_Comp_Flag;
    g_dmaCTRL g_dmaCTRLPKT; /* dma control packet configuration stack */
    void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
    {
    DMA_Comp_Flag = 0x5555AAAA;
    }
    void canMessageNotification(canBASE_t *node, uint32 messageBox)
    {
    uint32 Received_ID = canREG1->IF3ARB & 0x1FFFFFFF;

    /* - setting the dma channel to trigger on h/w request */
    // dmaSetChEnable(DMA_CH0, DMA_HW);
    }
    void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint32 dsize);
    /* USER CODE END */

    int main(void)
    {
    /* USER CODE BEGIN (3) */
    uint32 bufnum = 0;

    //initialize the tx data
    for(bufnum=0; bufnum< (sizeof TX_DATA1) /*D_SIZE*/; bufnum++)
    {
    TX_DATA1[bufnum] = bufnum;
    }

    /* Enable IRQ interrupt in ARM CPSR register */
    _enable_interrupt_();

    /* Reset the Flag */
    DMA_Comp_Flag = 0xAAAA5555;

    /* initialize can 1 */
    canInit();

    // Enable DE3 bit in CTL register to trigger DMA when IF3 receives data
    canREG1->CTL |= (1U << 20U);

    /* At present HALCoGen does not support IF3 configuration,
    * hence doing it here
    */
    // Read ARB, DATA A & B - 8 bytes */
    //canREG1->IF3OBS = 0x1A;

    // Read DATA A & B - 8 bytes */
    canREG1->IF3OBS = 0x18;

    // Message box 2,4,6 configured for auto update
    canREG1->IF3UEy[0]= 0x0000000A;

    canEnableloopback(canREG1,Internal_Lbk);

    /* - DMA Configuration */
    /* Enable DMA */
    dmaEnable();

    /* Enable Interrupt after reception of data */
    dmaEnableInterrupt(DMA_CH0, FTC,DMA_INTA);

    /* - setting the dma channel to trigger on h/w request */
    dmaSetChEnable(DMA_CH0, DMA_HW); //Try this outside of the interrupt

    /* assigning dma request: channel-0 with request line - 16 ( DCAN1IF3) */
    /* Refer Datasheet DMA request Line connection Table */
    //-- Not nedded for a SW triggered DMA
    dmaReqAssign(DMA_CH0, DMA_REQ16);
    /* - Populate dma control packets structure */
    /* Source Address = IF3 Data register
    * Destination = Receive Buffer in Sys RAM
    * Length = 1 ( i.e., 64bits = 8 * 8 Bytes)
    */
    dmaConfigCtrlRxPacket((uint32)(&(canREG1->IF3DATx[0])),
    (uint32)(&RX_DATA1),
    1);

    /* - setting dma control packets for transmit */
    dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT);

    while(1)
    {
    for(bufnum=0; bufnum<(D_SIZE/8); bufnum++)
    {
    /* Reset the Flag */
    DMA_Comp_Flag = 0xAAAA5555;

    /* transmit on can1 */
    canTransmit(canREG1, canMESSAGE_BOX1, (uint8*) &TX_DATA1[(bufnum*8)]);

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

    while(1);
    }

    /* Disable Loopback */


    /* USER CODE END */

    return 0;
    }


    /* USER CODE BEGIN (4) */
    void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint32 dsize)
    {
    g_dmaCTRLPKT.SADD = sadd; /* source address */
    g_dmaCTRLPKT.DADD = dadd; /* destination address */
    g_dmaCTRLPKT.CHCTRL = 0; /* channel control */
    g_dmaCTRLPKT.FRCNT = (D_SIZE)/8; /* 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 = PORTB_READ_PORTA_WRITE; /* 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_INC1 ; /* address mode write */
    g_dmaCTRLPKT.AUTOINIT = AUTOINIT_OFF; /* autoinit */
    }
    /* USER CODE END */
  • Hi,
    I looked at your code and realized that the IF1/IF2 are not suitable for DMA operation. Perhaps some clarification is needed in the TRM to list the limitation for using DMA with the DCAN. If you go to DCAN IF1DATA and IF1DATB registers these registers are write-protected meaning that they can only be written in privileged mode. However, the DMA is designed to always operate in user mode. Therefore, the DMA can never write to these DCAN registers. When a write happens from the DMA, the DCAN will simply ignore these writes. There is no advantage of using DMA to transfer data to the IF1/2 register even if these registers are writeable in the user mode. First, the payload is only 8 bytes. You could have written a store-multiple (STM) instruction to the IF1DATA/IF1DATB register fairly quickly instead of using the DMA where you need to set up the channels and wait for the the DMA to interrupt the CPU when the transfer is complete. Second, the DMA does not know when it is allowed to write to the registers. Before you can write to the IFx registers you will need to poll the busy bit to know whether a transfer between IFx and the message RAM is in progress. The DMA has no such capability. Only CPU does. If you really want to use the DMA with the DCAN you should use the IF3 register instead and it is only made for reading the message objects not writing to the message objects.
  • Hi,
    Is your question answered? if your question is answered can you please click the 'Verify Answer' to close the thread? Thanks.