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.

RL57x CAN with DMA -- NO DMA Copy happens

Other Parts Discussed in Thread: HALCOGEN, TMS570LS3137

I've been working for a few days now to get code working that reads from CAN via DMA.  I've not been successful getting DMA to read from the IF3 register.  5305.HercCANDMA.zip

I've attached the full CCS project for my last attempt.  I have gotten a working version that uses CAN1 in loopback mode and reads the transmitted data using the IF3 data.  But I wasn't able to make the leap to getting DMA working. Here's the details in case someone can see the error.  When I run this, it doesn't appear that anything is copied via DMA.

void main(void) {
	/* USER CODE BEGIN (3) */
	initData();

	/* enable irq interrupt in */
	_enable_IRQ_interrupt_();

	/* - configuring dma control packets   */
	g_dmaCTRLPKT1.SADD = (uint32) &(canREG1->IF3DATx[0]); /* source address             */
	g_dmaCTRLPKT1.DADD = (uint32) rx_data; /* destination  address       */
	g_dmaCTRLPKT1.CHCTRL = 0; /* channel control            */
	g_dmaCTRLPKT1.FRCNT = 1; /* frame count                */
	g_dmaCTRLPKT1.ELCNT = 1; /* element count              */
	g_dmaCTRLPKT1.ELDOFFSET = 0; /* element destination offset */
	g_dmaCTRLPKT1.ELSOFFSET = 0; /* element source offset */
	g_dmaCTRLPKT1.FRDOFFSET = 0; /* frame destination offset   */
	g_dmaCTRLPKT1.FRSOFFSET = 0; /* frame source offset   */
	g_dmaCTRLPKT1.PORTASGN = PORTB_READ_PORTA_WRITE;
	g_dmaCTRLPKT1.RDSIZE = ACCESS_64_BIT; /* read size                  */
	g_dmaCTRLPKT1.WRSIZE = ACCESS_64_BIT; /* write size                 */
	g_dmaCTRLPKT1.TTYPE = FRAME_TRANSFER; /* transfer type              */
	g_dmaCTRLPKT1.ADDMODERD = ADDR_FIXED; /* address mode read          */
	g_dmaCTRLPKT1.ADDMODEWR = ADDR_FIXED; /* address mode write         */
	g_dmaCTRLPKT1.AUTOINIT = AUTOINIT_OFF; /* autoinit                   */

	canInit();
	canEnableloopback(canREG1, Internal_Lbk);

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

	// Message box 2 configured for auto update
	canREG1->IF3UEy[0] = 0x00000002;

	// Enable DMA REquest line for IF3
	canREG1->CTL |= 0x100000U;

	/* - DMA Configuration */

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

	// Assign CAN1 IF3
	dmaReqAssign(DMA_CH0, DMA_REQ16);

	/* - setting dma control packets */
	dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT1);

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

	/* Enable DMA */
    dmaEnable();

	for (int i = 0; i < D_COUNT; i += 8)
	{
		canTransmit(canREG1, canMESSAGE_BOX1, (const uint8 *) &tx_data[i]);
		timingLoop(1e4);
	}

	while (1) {}
	/* USER CODE END */
}

  • Alan,

    A colleague put this example together for demonstrating DCAN triggering a DMA request. It was designed to work on the TMS570LS3137 MCU. You can make the required changes (the HALCoGen setup files are also included) to your project and make it run on the RM57.

    6114.CAN+DMA.zip

    Regards,

    Sunil

  • Alan,

     You might want to check if your MPU setting for the CPU RAM. Is it configured as write-back or write-through cache scheme? If it is write-back, then change it to write-through no-write-allocate.  I suspect that you have write-back cache configured. When DMA transfers data to the CPU RAM, the CPU does not know the external memory becomes incoherent with its cache image. This incoherency occurs when you have write-back cache. One way to quickly check is to use the DAP to view the memory content. If you use the DAP to view the buffer that is supposed to contain the data transferred by the DMA then you should see the data. The DAP does not have cache like the CPU. If you still don't see the data using DAP then it is not the cache scheme problem.

  • Charles,

    You were correct about the cache settings, but unfortunately that doesn't seem to be the whole story. I tried changing the cache scheme and there was no difference.

    There is another clue that this isn't the problem as well. I've got it configured to read from the CAN IF3 register. When all of the data gets read from IF3 then it is allowed to pick up the next set of values when the next CAN messages comes in. In my case it appears that DMA never reads the registers. The values never update to the next set set of values when the next CAN message was sent. They would, if the register had been read. This was confirmed by using an interrupt based approach to read from the IF3 registers. When I do that everything works. This helped me eliminate the (most of) the CAN configuration.

    I have hooked the FTC and LFS interrupts from DMA and so I can confirm that the DMA request is firing (well, once). But it would appear that DMA isn't actually reading from the CAN ->IF3 registers. Is there some bit of obviously missing configuration?

    Thanks,
    Alan
  • Thanks, this is exactly the example code that I had previously found. Unfortunately, I've been unable to replicate your colleague's success with it. There are some minor changes that need to be made to move it to the RM57 and I believe I've found all of those. But that didn't seem to be enough to get it working.

    Do you know of any examples specific to the RM57 that are known to work? I think there is some subtlety that I must be missing.
  • /* - configuring dma control packets */
    g_dmaCTRLPKT1.SADD = (uint32) canREG2->IF3DATx; /* source address */
    g_dmaCTRLPKT1.DADD = (uint32) rx_data; /* destination address */
    g_dmaCTRLPKT1.CHCTRL = 0; /* channel control */
    g_dmaCTRLPKT1.FRCNT = 1; /* frame count */
    g_dmaCTRLPKT1.ELCNT = 4; /* element count */
    g_dmaCTRLPKT1.ELDOFFSET = 2; /* element destination offset */
    g_dmaCTRLPKT1.ELSOFFSET = 2; /* element source offset */
    g_dmaCTRLPKT1.FRDOFFSET = 0; /* frame destination offset */
    g_dmaCTRLPKT1.FRSOFFSET = 0; /* frame source offset */
    g_dmaCTRLPKT1.PORTASGN = PORTB_READ_PORTA_WRITE;
    g_dmaCTRLPKT1.RDSIZE = ACCESS_16_BIT; /* read size */
    g_dmaCTRLPKT1.WRSIZE = ACCESS_16_BIT; /* write size */
    g_dmaCTRLPKT1.TTYPE = FRAME_TRANSFER; /* transfer type */
    g_dmaCTRLPKT1.ADDMODERD = ADDR_OFFSET; /* address mode read */
    g_dmaCTRLPKT1.ADDMODEWR = ADDR_OFFSET; /* address mode write */
    g_dmaCTRLPKT1.AUTOINIT = AUTOINIT_ON; /* autoinit */

    I think we got it working. The trouble was in the control packet. In particuar the SIZE and ADDMODE were of particular importance. There is a note on page 1213 of the Technical manual 26.17.27 (IF3 Observation Register) that mentions

    "Any access order of single bytes or half-words is supported. "

    Changing our read scheme to honor this note seems to have been the key.