[TMS570 MibSPI mode with DMA ] How to clear tg transfer suspend interrupt flag in TGINTFLAG

Hi,  we are using TMS570LS20216 to develop our products. 

And, here come  MibSPI with DMA problems.

After writing source code according to the TRM and refer example code from e2e forum, I almost can run the our demo MibSPI with DMA program.

some details go here:

we want use DMA module to transfer 16-bit size datas from data RAM to buffers of SPI TX RAM.  the number of 16-bit datas now is 8.

and the number of buffers of SPI TX RAM used is 1.  It is an example program, so we do not want to make this example sophisticated.

After data is copied into TX RAM, use MibSPI TG to send it out to the peer.

bufmode in TX RAM buffer register, is  101, suspend to wait until TXFULL is set    in  MibSPI master ,

 

Some questions :

1.  how does SPI module DMAxCTRL register coordinate with DMA module to complete transmission from data ram to TX RAM buffers.

     what does  the SPI Module DMAxCTRL register do?

2.  interrupt handling,      It is not CLEAR to us.

     Do you have more details in DMA module FTC, LFS, BTC, HBC interrupt handling?  what are needed to be done in these interrupt handlers?  are there more infos?

     when SPI TG complete and TG suspend interrupt happen,  what should be done in MibSPI interrupt handler ?

      the critical quesiton now is  that we can not clear TGINTFLAG, whatever we do cannot clear TG interrupt Flag in TGINTFLAG register, that is TG suspend interrupt flag.

      Do you have suggestions?

3.  to avoid CPU burden, correspond hardware signal rapidly,  how to make use of MibSPI with DMA,  especially,  how to write the DMA module and SPI module interrupt handlers code ?

 

DMA module source code of our own are as follows:

void dma_cfg(void)
{
    // configure hardware channal enable
    // dmaRegBase->HWCHENA = 0xFFFF;
    // configure software channel enable
   // dmaRegBase->SWCHENA = 0xFFFF;

   dmaRegBase->GCHIE = 0xFFFF;

   // port assignment registers
   dmaRegBase->U_PAR0.PAR0_F.CH0PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH1PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH2PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH3PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH4PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH5PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH6PA = 4;
   dmaRegBase->U_PAR0.PAR0_F.CH7PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH8PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH9PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH10PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH11PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH12PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH13PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH14PA = 4;
   dmaRegBase->U_PAR1.PAR1_F.CH15PA = 4;

   // FTC LFS HBC BTC int enable
   dmaRegBase->FTCINTENA = 0xFFFF;
   dmaRegBase->LFSINTENA = 0xFFFF;
   dmaRegBase->HBCINTENA = 0xFFFF;
   dmaRegBase->BTCINTENA = 0xFFFF;

   // DMA module enable
   dmaRegBase->DMA_EN = 1;
}

void dma_setup_ctrl_pkt(unsigned dma_chan, unsigned short addr[], unsigned dst_addr)
{
     // channel check
     if (dma_chan > 15)
     {
          return ;
     }

    // initial source address
    dmaRamBase->prictrlpkt[dma_chan].ISADDR = (unsigned)addr;
    // initial destination address
    dmaRamBase->prictrlpkt[dma_chan].IDADDR = 0xFF0E0002;   // spi channel 1 TX RAM base
    
    //  initial transfer count
    dmaRamBase->prictrlpkt[dma_chan].U_ITCOUNT.ITCOUNT_F.IFTCOUNT = 8;
    dmaRamBase->prictrlpkt[dma_chan].U_ITCOUNT.ITCOUNT_F.IETCOUNT = 1;

    // chan control
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.NEXT_CHAN = 0;
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.RES = 1;   // 16-bit
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.WES = 1;    // 16-bit
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.TTYPE = 0;  // frame transfer
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.ADDMR = 1;  // post-incremented
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.ADDMW = 0;   // constant
    dmaRamBase->prictrlpkt[dma_chan].U_CHCTRL.CHCTRL_F.AIM = 1;       // auto-initiation
    dmaRamBase->prictrlpkt[dma_chan].U_EIOFFSET.EIOFFSET_F.EIDXD = 0;
    dmaRamBase->prictrlpkt[dma_chan].U_EIOFFSET.EIOFFSET_F.EIDXS = 2;
    dmaRamBase->prictrlpkt[dma_chan].U_FIOFFSET.FIOFFSET_F.FIDXD = 0;
    dmaRamBase->prictrlpkt[dma_chan].U_FIOFFSET.FIOFFSET_F.FIDXS = 1;  
}

void dma_transfer_start(unsigned chan, unsigned ttype)
{
      // configure hardware channal enable
     (0 == ttype) ? (dmaRegBase->HWCHENA = (1 << chan) ) : (dmaRegBase->SWCHENA = (1 << chan) ); 
}

void dma_rst(void)

{
     /*dma reset*/
     dmaRegBase->DMA_RST = 1;


    while(dmaRegBase->DMA_RST)
    {
     ;  // wait dma reset finishes
    }
}

-------------------------------------------------------------------------------------------

and part of SPI sourc code is :

/** @fn void spiGroupNotification(spiBASE_t *spi, unsigned group)
*   @brief Transfer complete notification callback
*   @param[in] spi   - Spi module base address
*   @param[in] group - Transfer group
*
* This is a callback function provided by the application.  It is call when
* a transfer is complete.  The paramter is the transfer group that triggered
* the interrupt.
*/
void spiGroupNotification(spiBASE_t *spi, unsigned group)
{
           // TODO
          unsigned i = 0, j = 0, k = 0, l = 0;

           i = spi->INTVECT0;
           i = *(volatile unsigned *)(0xFFF7F400 + 0x60);
           j = spi->INTVECT1;
           j = *(volatile unsigned *)(0xFFF7F400 + 0x64);
          spi->INTFLGRDY = 1;   // clear TG complete flag
          spi->INTFLGSUS = 1;   // clear TG suspend flag
          *(volatile unsigned *)(0xFFF7F400 + 0x84) = 0xffffffff;
          j++;
}

/* it is normal interrupts or error interrupts */
#define INT_VEC_ERROR  0x21   //0b100001

#define INT_VEC_ERROR_MASK  0x3E

#define INT_VEC_TRANSERROR_VAL   0x22

#define INT_VEC_RECVBUF_OVRN_VAL   0x26 
// 

/** @fn void spi1HighLevelInterrupt(void)
*   @brief Level0 Interrupt for SPI1
*/
#pragma INTERRUPT(spi1HighLevelInterrupt, IRQ)

void spi1HighLevelInterrupt(void)
{
    unsigned vec = spiREG1->INTVECT0;

//    if (vec > 0x100001U)
    if (vec > INT_VEC_ERROR)
    {
         if (INT_VEC_TRANSERROR_VAL == (vec & INT_VEC_ERROR_MASK))
         {
                // transfer error interrupt    
               unsigned flags = spiREG1->FLG & (~spiREG1->LVL & 0x035F);
               spiREG1->FLG = flags;
        
               // added by baixueyuan
                spiREG1->FLG |= 0x5F;
        
                spiNotification(spiREG1, flags);     // null, do nothing
        }
       else
       if (INT_VEC_RECVBUF_OVRN_VAL == (vec & INT_VEC_ERROR_MASK))
        {
             // receiver buffer overrun interrupt    
             // TODO
            unsigned short arr[16];
            spiGetData(spiREG1, 0, arr);  // read 
    
           // added by baixueyuan, clear overrun interrupt
           spiREG1->FLG |= 0x40;    
        
       }
    }
    else
    {      
           if (spiREG1->FLG & 0x100)
           {
                 // deal with receiver full interrupt
    
                // TODO
                unsigned short test[16];
                spiGetData(spiREG1, 0, test);
    
               // Clear receiver full interrupt
               spiREG1->FLG |= 0x100;
         }

        spiGroupNotification(spiREG1, ((vec & 0x3FU) >> 1U) - 1U);
        
    }
}

-------------------------------------------------------------------------------------------


and main  function goes below:

void main(void)

{

spiInit(1);   // use dma

/* dma module reset and enable */
dma_rst();

// dma module configuration register set
dma_cfg();

// dma control packet set up
dma_setup_ctrl_pkt(0, arr1, 0);

// enable dma channel 0 software triggered DMA requests
dma_transfer_start(0, 1);     <<------------------------- when running to this point,   first 16-bit data has been moved to first buffer of TX RAM?  corrent ?

//  configure spi DMA registers
spi_dma_cfg(spiREG1, 0/*chan*/, 0/*rx_enable*/, 1/*tx_enable*/, 0/*bufid*/, 1/*count*/);

//  enable  TG
spiTransfer(spiREG3, 0);

// enable  TG
spiTransfer(spiREG1, 0);

 

    while(1)

    {

          ;  // dead loop

    }

}

 

  • 1.  the reason why tg suspend interrupt flag cannot be cleared maybe goes like this:

       because suspend interrupt will not happen when TXFULL flag in buffers of SPI RAM is set . And every time entering SPI interrupt handler, reading INTVECTx register will clear suspend interrupt flag as TRM says, but there is no data written into TX RAM after suspend interrupt flag is cleared, so suspend interrupt happens again, and the suspend interrupt flag is set.

       if what is said above is corrent,  how do we deal with interoperation between datas' transmission from data ram to TX RAM and suspend interrupt which happens when there is no new data written into TX RAM after the content of buffer is sent. 

       Or, I must be confused with SPI with DMA.  Please corrent me.

     

    2.  in DMA module,  there are hardware triggered DMA requests and software triggered DMA request, 

         how do we use there two kinds of DMA request's triggered modes, or  what are their differences ?

    3.  when MibSPI is used with DMA,  it seems that even if there is no configuration on SPI DMAxCTRL register, the MibSPI with DMA goes well with data transmitting and receiving.

     

    Thanks.

    Shawn

  • In reply to shawn bai:

    Shawn,

    I am working on your questions and will post a suggestion for using the DMA along with the MibSPI shortly.

    Regards,

    Sunil

  • In reply to Sunil Oak:

    Thanks in advance,  Sunil.

    Also, 

    In our application, we wanna use MibSPI to communicate for redundant datas.  There is the chance that slave sends more datas than master.

    Could we send more datas from slave to master than those from master to slave in the same transfer cycles ?

    It seems that it is impossible,  doesn't it?

    Do you or others have suggestions for our application? 

    Or, could something  be done in software design, even if making software more sophisticated, to achieve this goal ?

     

    Regards,

    Shawn

  • In reply to shawn bai:

    Hello Shawn,

    Sunil has had to start his holiday break early so it may be some time before he can respond to you.  In the meantime, I was wondering if you have looked at the example code that is provided with the latest HALCoGen release specifically showing SPI or MibSPI with DMA supported transfers?

    It would get installed on your machine at: ...\Texas Instruments\Hercules\HALCoGen\v2.11\examples\TMS570LS31x\example_mibspiDma

  • In reply to Brian Fortman:

    Hi, Brian,

         Thanks for the news.

         And,  the example source code you mentioned have been looked at, I am sure.

         Actually,  we are very focusing on how  the DMA interrupts and MibSPI  suspend to wait interrupts, also other MibSPI interrupts, are handled.

        'Cause in our application, the number of the datas  maybe are very large, maybe 1MB or 2MB, they are seperated to send in more than one DMA requests in order,  and the number of buffers allocated to a TG is possiblly  128 buffers.

        In your CCS Hercules example code, what is not very same with our application, and more importantly,  there is no corrsponding interrupt handling we focus on,

        Also, what I have mentioned in previous post is, even if DMAxCTRL register is not configured and not enabled, the DMA module could work well, that is the datas can be moved from data RAM to SPI RAM successfully.  According to this,  I don't  understand very much what is the intention that  DMAxCTRL register in MibSPI module is implemented.

        To make our application more clear,   in single TMS570 CPU,  MibSPI channel 1 works as the master, and channel 3 works as slave,  the SPI is in 4-pin mode.

       If more infos need to be suuplied,  please tell me.

       Because of the time pressure in our production development,  I don't know how long Sunil's holiday will delay us.

       Thanks.

    Shawn

  • In reply to shawn bai:

    Hello Shawn,

    I am trying to answer each one of your questions in this post. Please let me know if it answers all your queries.

    1.  how does SPI module DMAxCTRL register coordinate with DMA module to complete transmission from data ram to TX RAM buffers.

         what does  the SPI Module DMAxCTRL register do?

    >> The DMAxCTRL register in the MibSPI module allows the application to configure the generation of the hardware DMA requests for the transmit and receive operations. Each MibSPI module can generate up to 16 DMA requests. Of these, 8 are dedicated for transmit events and 8 for receive events. The datasheet has a table that shows the actual DMA request line connections. This microcontroller supports 32 DMA request lines. Requests 0 and 1 are connected to MibSPI1 module DMA requests 1 and 0, respectively. These two outputs from the MibSPI module can be configured using the DMA0CTRL register.

    2.  interrupt handling,      It is not CLEAR to us.

         Do you have more details in DMA module FTC, LFS, BTC, HBC interrupt handling?  what are needed to be done in these interrupt handlers?  are there more infos?

    >> The use of these interrupts is completely application dependent, and we cannot recommend any specific handler routines. The main idea behind these interrupts is to keep the DMA engine busy and not waiting for the application to configure the next set of data to be transferred.

         when SPI TG complete and TG suspend interrupt happen,  what should be done in MibSPI interrupt handler ?

    >> The TG complete interrupt is generated when all buffers selected for transmission in the particular transfer group have actually been transferred by the MibSPI module. This interrupt condition can be used by the application to configure the next set of data to be transmitted using this transfer group.

    >> The TG Suspend interrupt is generated when a buffer within a triggered transfer group is configured to have a BUFMODE such that it will stop servicing the transfer group until either new data is written to the TX DATA field of this buffer (BUFMODE = 0x5), or received data for this buffer is read out (BUFMODE = 0x6), or both (BUFMODE = 0x7). The interrupt handler in these cases should write new data in the TX DATA field, or read out the data from the RX DATA field, or both.

    3.  to avoid CPU burden, correspond hardware signal rapidly,  how to make use of MibSPI with DMA,  especially,  how to write the DMA module and SPI module interrupt handlers code ?

    >> This again depends on the application requirements. For example, if a SPI port is being used just to dump data out as fast as possible, then the 128 buffers can be divided up into 2 transfer groups. These transfer groups can then be sequentially triggered and the CPU or DMA can be updating one transfer group's data while the data from the other transfer group is being transmitted by the MibSPI.

    4.  in DMA module,  there are hardware triggered DMA requests and software triggered DMA request, 

         how do we use there two kinds of DMA request's triggered modes, or  what are their differences ?

    >> The transfers done by the DMA are defined using "control packets". There is one control packet for each DMA channel, and there are 16 DMA channels in total on this microcontroller. The control packets define the source address, destination address, and the amount of data to be transferred by that DMA channel. The DMA channel needs to be "triggered" in order for it to perform the transfers as defined by its control packet. This trigger can be generated in 2 ways:

    1) by the CPU setting the SWCHENAS bit of the corresponding channel number: this is considered to be a software triggered DMA request.

    2) by configuring the HWCHENAS bit of the corresponding channel number: this is considered to be a hardware triggered DMA request. The DMA module now waits for an actual DMA request to come from one of the defined sources as listed in the datasheet. Please note that the DMA channel needs to also be mapped to one of the DMA requests using the DMAREQASI (DMA request assignment) registers.

    5.  when MibSPI is used with DMA,  it seems that even if there is no configuration on SPI DMAxCTRL register, the MibSPI with DMA goes well with data transmitting and receiving.

    >> This is not the case when the MibSPI module is configured to be in multi-buffered mode (not the default).

  • In reply to Sunil Oak:

    Thanks, Sunil.

    Here are another 2 questions.

    In our application,  there are kinds of types of packets which go between master and slave.  In fact, length of these types of packets are different too.

    Could you give us suggestion that how we can specify the DMA control packets, and allocate the SPI TX/RX buffers?

    One more question, 

    is there a mechanism by which we can determine the end of a packet on the slave site?

    It may be something like timeout interrupt in UART from which it can be told that  the end of packet arrives.

  • In reply to shawn bai:

    Shawn,

    It seems like your application needs handshaking between the master and slave SPIs. You can implement this handshaking in software or in hardware using the chip select and / or the enable signals.

    When the chip select is defined as a SPI functional signal (versus a GIO signal), the master SPI drives the chip select low as soon as a transfer is requested. The master then either waits for the slave to drive the enable signal low (5-pin SPI mode), or waits for a programmable amount of time before it starts driving the CLK and SIMO (and captures SOMI). The module also supports a mode (CSHOLD = 1) in which the chip select can be held low for multiple accesses to the same slave. The slave can detect a high on the chip select line to determine that the master has stopped accessing it.

    Regards, Sunil