Edit - I've figured out how to get this to work:
volatile int DmaTxIntFlag; // flag used in interrupts, signal that DMA transfer ended
volatile int DmaRxIntFlag; // flag used in interrupts, signal that DMA transfer ended
volatile int DMAINTCOUNT=0;
/*-----------------------------------------------------------------------*/
/* Start a DMA Sector Transfer between host to card */
/*-----------------------------------------------------------------------*/
BYTE sectorsendDMA(const BYTE *buff)
{
unsigned char resp;
int evFlags;
int done=0;
//clear SPI TX empty int
INTClearFlag(INT_SOURCE_SPI(_SPI3A_TX_IRQ));
DmaChnOpen(DMA_CHANNEL1, DMA_CHN_PRI3, DMA_OPEN_DEFAULT); // Tx
DmaChnSetEventControl(DMA_CHANNEL1, DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI3A_TX_IRQ));
DmaChnSetTxfer(DMA_CHANNEL1,(unsigned char*)buff, (void*)&SPI3ABUF, 512, 1, 1);
DmaChnSetEvEnableFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE);
INTSetVectorPriority(INT_VECTOR_DMA(DMA_CHANNEL1), INT_PRIORITY_LEVEL_5); // set INT controller priority
INTSetVectorSubPriority(INT_VECTOR_DMA(DMA_CHANNEL1), INT_SUB_PRIORITY_LEVEL_3); // set INT controller sub-priority
INTEnable(INT_SOURCE_DMA(DMA_CHANNEL1), INT_ENABLED); // enable the chn interrupt in the INT controller
DmaTxIntFlag=0; // clear the interrupt flag we're waiting on
//clear SPI TX empty int
//DmaChnEnable(DMA_CHANNEL1);
DmaChnStartTxfer(DMA_CHANNEL1, DMA_WAIT_NOT, 0);
while(!DmaTxIntFlag) {}
//DmaChnDisable(DMA_CHANNEL1);
//disable spi interrupt
INTEnable(INT_SOURCE_DMA(DMA_CHANNEL1), INT_DISABLED);
while(SPI3ASTATbits.SPIBUSY==1){}
volatile unsigned char discard=SPI3ABUF;
}
// handler for the DMA channel 1 interrupt
void __ISR(_DMA1_VECTOR, ipl5) DmaHandler1(void)
{
int evFlags; // event flags when getting the interrupt
SPI3ASTATbits.SPIROV=0;
volatile unsigned char discard=SPI3ABUF;
INTClearFlag(INT_SOURCE_DMA(DMA_CHANNEL1)); // acknowledge the INT controller, we're servicing int
evFlags=DmaChnGetEvFlags(DMA_CHANNEL1); // get the event flags
if(evFlags&DMA_EV_BLOCK_DONE)
{ // just a sanity check. we enabled just the DMA_EV_BLOCK_DONE transfer done interrupt
DmaTxIntFlag=1;
DmaChnClrEvFlags(DMA_CHANNEL1, DMA_EV_BLOCK_DONE);
}
DMAINTCOUNT++;
}
The DMAINTCOUNT variable was just me making sure that the interrupt was only called once per 512 byte block transfer. The reason it wasn't working was that I had forgotten to account for the fact that the interrupt is called when the DMA finishes sending its last byte to the SPI module - we have to wait for it to finish sending before reading the last byte out of the module. Interestingly, the overflow of the spi receive buffer doesn't appear to bother it when it's working in DMA mode like this - reception is unecessary, though I do clear the overflow bit once at the end of the 511th transaction/start of the 512th.
post edited by Aiden.Morrison - 2011/04/15 23:40:11