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
}
}