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.

TMS570: reset DMA with DMA BTC interrupt

Other Parts Discussed in Thread: TMS570LS3137

Hello,

I'm using a TMS570LS3137 and SafeRTOS to receive and transmit datagrams via SCI and RS485 with aid of DMA. I use DMA block transfer complete interrupts when receiving or transmitting datagrams to switch the state machine of my SCI driver in order to synchronize a bidirectional communication via half-duplex RS485.

Therefore, I need to reset the DMA from time to time. So, I'd like to let the DMA start receiving one datagram from the beginning if certain conditions are given. This means already received bytes are to get discarded and the DMA is reset within the DMA BTC interrupt service routine. I've tried to reset the DMA using the DMA RES bit in GCTRL. But this doesn't work at all and nothing is received or transmitted any more, see the attached source code. Is there a safe and working way to reset DMA transfer in the DMA interrupt service routine?


Thank you in advance

Andre

 

void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
   /* datagram transmission completed */
   if((channel == (uint32)DMA_CH0) && (inttype == (dmaInterrupt_t)BTC))
   {
      /* reset DMA if necessary */
      if(...)
      {
         /* DMA software reset: discard already received bytes */
         dmaREG->GCTRL &= 0xfffffffe;
         dmaREG->GCTRL |= 0x00000001;
      }
      ...
      /* reveive new datagram */
      dmaSetChEnable((uint32)DMA_CH1, (uint32)DMA_HW);
   }
   ...
}

  • Hi Andre,

    I have forwarded your answer to one of our experts who developed a sample project for SCI using DMA. He will come back to you soon.

    Regards,
    QJ
  • Andre, I work with 1227 and I think the DMA module is similar. A note in TRM says " Changing the contents of a channel control packet will clear the corresponding pending bit (PEND) if the channel has a pending status. If the control packet of an active channel (as indicated in DMASTAT) is changed, then the channel will stop immediately at an arbitration boundary. When the same channel is triggered again, it will begin with the new control packet information." So try changing a field in the control packet (frame transfer count for example) to restart DMA channels working registers. Good luck, Joe
  • Joe,

    Thank you for your answer. Unfortunately, your proposed approach hasn't worked. The DMA stops working and nothing is transmitted or received any more. I changed the frame count and tried a simple and an elaborate version. Please find attached both versions of resetDMA().

    void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
    {
      /* datagram transmission completed */
      if((channel == (uint32)DMA_CH0) && (inttype == (dmaInterrupt_t)BTC))
      {
         /* reset DMA if necessary */
         if(...)
         {
            /* DMA software reset: discard already received bytes */
            resetDMA();
         }
         ...
         /* reveive new datagram */
         dmaSetChEnable((uint32)DMA_CH1, (uint32)DMA_HW);
      }
      ...
    }
    
    /* simple version */
    void resetDMA()
    {
      /* simply change frame count and set it back to proper value again */
      dmaRAMREG->PCP[DMA_CH0].ITCOUNT = (8U << 16U) | 1U;
      dmaRAMREG->PCP[DMA_CH0].ITCOUNT = (9U << 16U) | 1U;
    }
    
    /* elaborate version */
    void resetDMA()
    {
      /* reconfigure DMA to make it reset using dmaSetCtrlPacket() */
      g_dmaCTRL dma_control_TX;
      dma_control_TX.SADD = (uint32) &g_datagramToSend; /* initial source address */
      dma_control_TX.DADD = ((uint32)&(sciREG->TD)) + 3U; /* initial destination address (big endian!) */
      dma_control_TX.CHCTRL = 0U; /* is overwritten by some of the next commands */
      dma_control_TX.FRCNT = 8U; /* frame count (ITCOUNT): wrong value */
      dma_control_TX.ELCNT = 1U; /* element count (ITCOUNT) */
      dma_control_TX.ELDOFFSET = 0U; /* element destination offset */
      dma_control_TX.ELSOFFSET = 0U; /* element source offset */
      dma_control_TX.FRDOFFSET = 0U; /* frame destination offset */
      dma_control_TX.FRSOFFSET = 0U; /* frame source offset */
      dma_control_TX.PORTASGN = 4U; /* channel 0 assigned to port B (PAR0) */
      dma_control_TX.RDSIZE = ACCESS_8_BIT; /* read element size */
      dma_control_TX.WRSIZE = ACCESS_8_BIT; /* write element size */
      dma_control_TX.TTYPE = FRAME_TRANSFER; /* trigger type - frame/block */
      dma_control_TX.ADDMODERD = ADDR_INC1; /* addressing mode for source */
      dma_control_TX.ADDMODEWR = ADDR_FIXED; /* addressing mode for destination */
      dma_control_TX.AUTOINIT = AUTOINIT_OFF; /* auto-init mode */
      dmaSetCtrlPacket((uint32)DMA_CH0, dma_control_TX);
      /* set frame count back to proper value */
      dma_control_TX.FRCNT = 9U; /* frame count (ITCOUNT) */
      dmaSetCtrlPacket((uint32)DMA_CH0, dma_control_TX);
    }