I know that this topic (DMA and SPI) has already been discussed in numerous threads on the microchip forum, in fact I read all 15 pages as a result of the search with the keyword "dma" and read all the topics about dma and sleep.
And I still stick to my problem. Hope someone can help me.
Here is the problem.
My chip is the PIC32MX775F512H. I am trying to receive (only receive) data using SPI via DMA. Since you cannot "simply" receive in SPI and that the SPI core starts switching the SPI clock only if you write in SPIBUF (SPI1ABUF for me), I try to get my data using 2 DMA channels. DMA_CHANNEL1 for the transmitting part. DMA_CHANNEL2 for the receiving part.
Copy the code from http://www.microchip.com/forums/tm.aspx?tree=true&high=&m=562453&mpage=1#
And tried to get it to work without luck. It receives only a few bytes (5 or 6).
I set the event-enabled flags to DMA_EV_BLOCK_DONE for both dma channels, no interruptions occur.
Do you have any ideas?
Here is the code I'm using:
int Spi_recv_via_DMA(SPI_simple_master_class* SPI_Port, int8u *in_bytes, int16u num_bytes2)
{
DmaChannel dmaTxChn=DMA_CHANNEL1;
DmaChannel dmaRxChn=DMA_CHANNEL2;
SpiChannel spiTxChn=SPI_Port->channel;
int8u dummy_input;
DmaChnOpen(dmaTxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT);
DmaChnOpen(dmaRxChn, DMA_CHN_PRI3, DMA_OPEN_DEFAULT);
DmaChnSetEventControl(dmaTxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ));
DmaChnSetEventControl(dmaRxChn, DMA_EV_START_IRQ_EN | DMA_EV_START_IRQ(_SPI1A_RX_IRQ));
DmaChnClrEvFlags(dmaTxChn, DMA_EV_ALL_EVNTS);
DmaChnClrEvFlags(dmaRxChn, DMA_EV_ALL_EVNTS);
DmaChnSetEvEnableFlags(dmaRxChn, DMA_EV_BLOCK_DONE);
DmaChnSetEvEnableFlags(dmaTxChn, DMA_EV_BLOCK_DONE);
//SpiChnClrTxIntFlag(spiTxChn);
//SpiChnClrRxIntFlag(spiTxChn);
DmaChnSetTxfer(dmaTxChn, tx_dummy_buffer, (void *)&SPI1ABUF, num_bytes2, 1, 1);
DmaChnSetTxfer(dmaRxChn, (void *)&SPI1ABUF, in_bytes, 1, num_bytes2, 1);
while ( (SPI1ASTAT & SPIRBE) == 0)
dummy_input = SPI1ABUF;
SPI1ASTAT &= ~SPIROV;
DmaRxIntFlag = 0;
DmaChnEnable(dmaRxChn);
DmaChnStartTxfer(dmaTxChn, DMA_WAIT_NOT, 0);
while(!DmaRxIntFlag);
return 1;
}
with these two interrupt handlers:
void __ISR(_DMA1_VECTOR, ipl5) DmaHandler1(void)
{
int evFlags;
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL1));
evFlags=DmaChnGetEvFlags(DMA_CHANNEL1);
if(evFlags&DMA_EV_BLOCK_DONE)
{
DmaTxIntFlag = 1;
DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE);
}
}
void __ISR(_DMA2_VECTOR, ipl5) DmaHandler2(void)
{
int evFlags;
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL2));
evFlags=DmaChnGetEvFlags(DMA_CHANNEL2);
if(evFlags&DMA_EV_BLOCK_DONE)
{
DmaRxIntFlag = 1;
DmaChnClrEvFlags(DMA_CHANNEL2, DMA_EV_BLOCK_DONE);
}
}
So, I'm always on the line waiting: while (! DmaRxIntFlag);
I set breakpoints in interrupt vectors, they are never called.
This is the state of several registers during long wait:
DMACON 0x0000C800
DMASTAT 0x00000001
I use port SPI1A, so SPI1ABUF and _SPI1A_RX_IRQ
DCH1SPTR 0x5
DCH1SSIZ 0x2B
DCH2DPTR 0x6
DCH2DSIZ 0x2B
DCH2CON 0x00008083
DCH2ECON 0x1B10
DCH2INT 0x00800C4
DCH2SSA 0x1F805820
DCH2DSA 0x00000620
1
2