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.

RM48L952: Using DMA transfer on SPI2 & SPI4

Part Number: RM48L952

Hi TI

I have looked at several examples for the Hercules DMA SPI transfer, but there is a missing link.

First of all, I'm not sure that SPI2 & SPI4 supports DMA transfer, because some of the examples uses some resisters only existing for the mibSPI1&3&5.

But looking in the reference manual DMA Request Sources are defined for SPI2 and SPI4.

The example from here, seems to miss the start trigger for the transfer.

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/856961/tms570lc4357-how-to-configure-spi-with-dma

The turturial from here uses some features only available for the mibSPI's.

https://training.ti.com/jp/hercules-tutorial-mibspi-and-dma-overview

In my working example (wich is for SPI3, but I need it to work on SPI2 as well) I have reached following, but the code is not compleate, the trivialities regarding the data is omitted:

void N2HET2_1_IRQHandler ( void ) /* Turn on */
{
  dmaConfigCtrlPacketUpdate(&g_dmaCTRLPKT_TX, tx_buffer, &spiREG3->DAT1, spi_words);
  dmaConfigCtrlPacketUpdate(&g_dmaCTRLPKT_RX, &spiREG3->BUF, rx_buffer, spi_words);
  
  dma_start_transfer(); /* FIXME Not defined yet */

  idle_led_off (); /* Switch 'Idle' LED off TODO */

}


void dmaConfigCtrlPacket(g_dmaCTRL *g_dmaCTRLPKT, 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	   = 1;                 /* frame count                */
  g_dmaCTRLPKT->ELCNT     = dsize;             /* element count              */
  g_dmaCTRLPKT->ELDOFFSET = 4;                 /* element destination offset */
  g_dmaCTRLPKT->ELSOFFSET = 0;		          /* element destination offset */
  g_dmaCTRLPKT->FRDOFFSET = 0;		          /* frame destination offset   */
  g_dmaCTRLPKT->FRSOFFSET = 0;                 /* frame destination offset   */
  g_dmaCTRLPKT->PORTASGN  = 4;                 /* port b                     */
  g_dmaCTRLPKT->RDSIZE    = ACCESS_16_BIT;	  /* read size                  */
  g_dmaCTRLPKT->WRSIZE    = ACCESS_16_BIT; 	  /* write size                 */
  g_dmaCTRLPKT->TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
  g_dmaCTRLPKT->ADDMODERD = ADDR_INC1;         /* address mode read          */
  g_dmaCTRLPKT->ADDMODEWR = ADDR_OFFSET;       /* address mode write         */
  g_dmaCTRLPKT->AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */
}             

void dmaConfigCtrlPacketUpdate(g_dmaCTRL *g_dmaCTRLPKT, volatile void *sadd, volatile void *dadd, uint32 dsize)
{
  g_dmaCTRLPKT->SADD      = (uint32_t)sadd;			  /* source address             */
  g_dmaCTRLPKT->DADD      = (uint32_t)dadd;			  /* destination  address       */
  g_dmaCTRLPKT->ELCNT     = dsize;      /* element count              */
}

void init_spi_dma(void)
{
  /* - assigning dma request: channel-0 with request line - 1 */
  dmaReqAssign(0, DMA_REQ_LINE_SPI3_TX );
  dmaReqAssign(1, DMA_REQ_LINE_SPI3_RX );

   /* - configuring dma control packets   */
  dmaConfigCtrlPacket(&g_dmaCTRLPKT_TX, 0,0,0);
  dmaConfigCtrlPacket(&g_dmaCTRLPKT_RX, 0,0,0);

  /* - setting dma control packets */
  dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT_TX);
  dmaSetCtrlPacket(DMA_CH1,g_dmaCTRLPKT_RX);

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

  /* - enabling dma module */
  dmaEnable();
}

Am I close? Is it possible?

  • And how do I control the Data Format and Chip Select? Should I use 32bit data transfer, and use the upper 16 bit for this just lige when transmitting manually?

  • Got it, This actually starts the transfer of the first frame.:

    spiREG3->GCR1 |= (0x1 << 24);
    spiREG3->INT0 |= (0x1 << 16);

    Testing . . . .
  • And how do I control the Data Format and Chip Select? Should I use 32bit data transfer, and use the upper 16 bit for this just lige when transmitting manually?

    You can program the upper 16 bits of SPIDAT1 without touching the TXDATA field. Writing to only the control fields (upper 16 bits) does not initiate any SPI transfer in master mode.

  • OK, Im using SPIDAT1 as in "manual mode", writing the control fields in every 32-bit data in the transmit buffer. Configuring the DMA to process a 4-byte word on every transfer.

    Now the first data word is transfered correctly (16 bits). But the next bytes are not followed up by the DMA controller.

    I'm not sure if I use the correctly DMA Request sources, as the table is rather confusing.

    I have tried 14/15 for SPI3-RX/TX, with no success.

    How does the DMA controller distinguish between different DMA request sources when there are multiple for each DMA request?

    Kasper

  • And please notice, that I am on using mibSPI, but standard SPI.

  • /* - configuring dma control packets */
    dmaConfigCtrlPacket(&g_dmaCTRLPKT_TX, 0,0,0);
    dmaConfigCtrlPacket(&g_dmaCTRLPKT_RX, 0,0,0);

    Don't you call dmaConfigCtrlPacketUpdate() in your code to update the addresses and element size?

  • It is dmaSetCtrlPacket() I need to call after updating the control packet. Works much better now. Thanks

    void N2HET2_1_IRQHandler ( void ) /* Turn on */
    {
      dmaConfigCtrlPacketUpdate(&g_dmaCTRLPKT_TX, tx_buffer, &spiREG3->DAT1, spi_words);
      dmaConfigCtrlPacketUpdate(&g_dmaCTRLPKT_RX, &spiREG3->BUF, rx_buffer, spi_words);
      dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT_TX);
      dmaSetCtrlPacket(DMA_CH1,g_dmaCTRLPKT_RX);
      dma_start_transfer(spiREG3, tx_buffer[0]);
    }
    
    void dma_start_transfer(spiBASE_t *spiREG, uint32_t data)
    {
      spiREG->GCR1 |= (0x1 << 24);
      spiREG->INT0 |= (0x1 << 16);
      spiREG->DAT1 = data;
    }

    It seems that the DMA is copying the wrong data, and monitoring the "Working Control Packet" confirms that there is something odd. And the values never changes. I have also verified the address for the CTCOUNT register:

      dmaRAMREG->WCP[DMA_CH0].CTCOUNT: 0xfbea9ffe
      dmaRAMREG->WCP[DMA_CH0].CSADDR : 0xfefd5e6e
      dmaRAMREG->WCP[DMA_CH1].CTCOUNT: 0x5cf077b1
      dmaRAMREG->WCP[DMA_CH1].CSADDR : 0xff6ed9fd  
    

    After omitting the SW trigger of DMA channel 1 (The SPI receive) the "Working Control Packet" now is correct for DMA channel 1. (But I believe that both the transmit and the receive channel should be triggered. Right?

      dmaRAMREG->WCP[DMA_CH0].CTCOUNT: 0xfbea9ffe
      dmaRAMREG->WCP[DMA_CH0].CSADDR : 0xfefd5e6e
      dmaRAMREG->WCP[DMA_CH1].CTCOUNT: 0x00010004
      dmaRAMREG->WCP[DMA_CH1].CSADDR : 0xfff7f840 

    And now some data is actually sent. But still odd. If I send one frame (16 bits) it is OK, two is also OK, but if I try to send three or for frames, only the first and the last is transmitted, i.e. 32 bits. Very odd. The data format configuration seems to be handled as it should. Nice.

    The result is that the transmitted data, ans the frame format is wrong, and only two elements are transmittet regardles of the element count parameter.

    By the way 2: I have tried to use address mode = ADDR_OFFSET instead of ADDR_INC1. Same result. Only two frames are sent.

    By the way 3: I cannot find a .SVD for RM48 for showing the special functions registers in the debugger (I am using Rowley CrossStudio for ARM). Does TI have this definition file? I have searched for it with no luck.

  • both the transmit and the receive channel should be triggered. Right?

    The SPI generates a DMA TX request when the TX data is copied to the TX shift register, and generates a DMA RX request each time the received data is copied to the SPIBUF. 

    One frame (16-bit data) is transferred per DMA request. 

    Can you try the following DMA settings to transfer 4 16-bit data:

    g_dmaCTRLPKT->FRCNT = 4; /* frame count */
    g_dmaCTRLPKT->ELCNT = 1; /* element count */

  • I have now tired different combinations of Frame count and Element count. If I change TTYPE to BLOCK transfer, I se no different behavior. Only the first and last frame is sent.

    In TTYPE = Frame transfer I have a similar behavior. I have change the data set to contain two frames of each three elements. And of cause, I trigger the DMA after the first frame is sent. First frame consists of element 0 and 2, second frame consists of element 3 and 5.

    Could it be a runaway on the DMA request? If e.g. all DME requests are spammed  within the transfer of the first element? and therefore only the first and last element is actually in place in the transmit buffer, when the SPI is ready to transmit it?

    I am using following request lines for SPI3 (standard mode):

    dmaReqAssign(DMA_CH0, 15);
    dmaReqAssign(DMA_CH1, 14);

    In table Table 16-2. in SPNU503C there is multiple request signals from (mib)SPI3. It is rather confusing, and what does the [x] refer to?

    for DMA request line 15 following signals can be mapped: MIBSPI3 / USB Device / MibADC2 / MIBSPI5. Could the latter 3 signals give a problem? I cannot find out hot to enable/disable the signal from each peripheral. I am not using DMA for USB/ADC2/MIBSPI5, but I am using the USB peripheral. should I disable something in the DMAxCTRL of the mibSPI2 peripheral even though that I do not use the mib-facilities?

  • One more observation:

    I have tired to uncomment the (intentional) DMA trigger:

    • "dmaSetChEnable(DMA_CH0, DMA_SW);"

    Resulting in no transfer at all. Conclusion: It is not other peripherals causing unintended triggering of my SPI DMA transfer.

  • Sorry, in one of my attempts I tried to change the trigger to a SW trigger:

    dmaSetChEnable(DMA_CH0, DMA_SW);
    dmaSetChEnable(DMA_CH1, DMA_SW);

    Which obviously is wrong. I have changed it back to DMA_HW, however, now the DMA is not triggered at all, which brings me bacj to the issue regarding DMA trigger source.

    I am trying to enable and trigger the DMA by the following code.

    spiREG3->GCR1 |= (1U << 24);
    spiREG3->INT0 |= (1U << 16);
    spiREG3->INT0 |= (1U << 9);

    With no luck.