Using MCF5441x CPU, I have been working on code to manage an SPI link to another CPU. I was able to configure the DSPI module to operate with the peer processor (we're the slave in the link), but when I attempt to get DMA to feed its data, nothing happens. It's as if DMA is not triggered at all.
I have to say, this is by far the worst user manual for a CPU that I have ever been subjected to. I am certainly thankful that this is not my FIRST Coldfire, else I might have thrown in the towel by now. In the section on DMA, it only acknowledges DMA channels over #15 in a few places (though it's implied that there are 64).
In any case, it seems as if this should not be so difficult as it's turning out to be.
I have made sure to configure my DMA completely before starting the SPI. At this point, I expect the Tx DMA to start IMMEDIATELY, but it does not.
I think all the relevant code is listed below. There *are* interrupt routines, but since this won't *start*, they do not execute.
Thanks in advance for any advice/info you can provide.
--Adam
This code is called on startup:
void PIP_ConfigHdwe( void) // Set up SPI interface
{ // Now configure the SPI interface between the PIP and ourselves:
// Enable internal clock to DSPI Module:
MCF_PMM_PPMCR0 = 23; // Enable DSPI0 (p. 9-7)
MCF_PMM_PPMCR0 = 17; // Enable eDMA controller (p. 9-7)
// Configure DSPI (chapter 40)
// DSPI is interrupt 31 (on INTC0)
MCF_DSPI0_MCR = MCF_DSPI_MCR_HALT +
MCF_DSPI_MCR_SMPL_PT_0CLK + // No modification to sample point
MCF_DSPI_MCR_CLR_RXF + // Okay; clear the FIFOs just this once.
MCF_DSPI_MCR_CLR_TXF +
// MCF_DSPI_MCR_DIS_RXF + // Disable neither FIFO. We like FIFO.
// MCF_DSPI_MCR_DIS_TXF +
// MCF_DSPI_MCR_MDIS + // Enable clocks
MCF_DSPI_MCR_PCSIS0 + // Mandatory config for Slave operation
// MCF_DSPI_MCR_ROOE + Overflow bad either way. We'll just avoid that
// MCF_DSPI_MCR_MTFE +
// MCF_DSPI_MCR_FRZ + // Do not halt serial transfers on DEBUG
MCF_DSPI_MCR_DCONF(0) + // Only valid config
// MCF_DSPI_MCR_CONT_SCKE + Disable continuous clock
// MCF_DSPI_MCR_MSTR + We're a slave
0;
// Max Frequency is Fsys / 8 ( Coldfire AC timing specs, per Rocky. )
// Fsys is 250MHz so 31.25MHz s/b our max.
MCF_DSPI0_CTAR0 = // Omitting a bunch of Master mode settings, all set to zero.
MCF_DSPI_CTAR_LSBFE + // LSB first. Not sure, but p. 64 of PIP book *suggests* LSB first
MCF_DSPI_CTAR_CPHA + // p. 40-11. 1 = sample on falling edge
// MCF_DSPI_CTAR_CPOL + // p. 40-11. 1 = inactive state is high
// Partner board CLK rests low and changes on rising edge
MCF_DSPI_CTAR_FMSZ(7) + // 8 bits per frame (PIP p. 64)
// MCF_DSPI_CTAR_DBR +
0;
MCF_DSPI0_RSER = 0 +
// MCF_DSPI_RSER_RFDF_DIRS + // For FIRST byte, we want an Interrupt!
MCF_DSPI_RSER_RFDF_RE + // Enable Interrupt/DMA for Rx
// MCF_DSPI_RSER_RFOF_RE + // Don't want overflow Interrupt.
MCF_DSPI_RSER_TFFF_DIRS + // DMA for Tx
MCF_DSPI_RSER_TFFF_RE + // Enable Interrupt/DMA for Tx
// MCF_DSPI_RSER_TFUF_RE + // No Int for Underflow
MCF_DSPI_RSER_EOQF_RE + // No End Of Queue interrupt
MCF_DSPI_RSER_TCF_RE + // Yes, Interrupt on Transmision Complete!
0;
// eDMA Config Chapter 19
// Channel 12 = DSPI0_SR[RFDF] (Receive)
// Channel 13 = DSPI0_SR[TFFF] (Transmit)
MCF_eDMA_EDMA_CR = 0; // Fixed priority. Continue to operate in DEBUG mode.
// Clear flags in eDMA engine:
MCF_eDMA_EDMA_CDNE = MCF_eDMA_EDMA_CDNE_CADN; // Clear DONE status bits register
MCF_eDMA_EDMA_CERQ = MCF_eDMA_EDMA_CERQ_CAER; // Clear Enable Requests
MCF_eDMA_EDMA_CEEI = MCF_eDMA_EDMA_CEEI_CAEE; // Clear Error Interrupt Enables
// Configure DMA for Rx:
MCF_eDMA_TCD12_SADDR = (&MCF_DSPI0_POPR); // 32-bit register
MCF_eDMA_TCD12_ATTR = 0x0200; // 32-bit source, 8-bit dest; No modulo
MCF_eDMA_TCD12_SOFF = 0; // Offset for source (will stay zero)
MCF_eDMA_TCD12_NBYTES = 1; // 1 byte per request
MCF_eDMA_TCD12_SLAST = 0; // Last Source Adjustment
MCF_eDMA_TCD12_DADDR = 0; // Will be filled in when initialized with address of buffer.
MCF_eDMA_TCD12_CITER = 0; // Will be the byte count (I think), written when enabled.
MCF_eDMA_TCD12_DOFF = 1; // Increment Destination by 1 each write
MCF_eDMA_TCD12_DLAST_SGA = 0; // Last Dest adjustment
MCF_eDMA_TCD12_BITER = 0; // Will be set equal to CITER when enabled (I think)
MCF_eDMA_TCD12_CSR = 0; // No Interrupt. p.19-26
// Configure DMA for Tx:
MCF_eDMA_TCD13_SADDR = 0; // Will be set with address from Tx Buffer.
MCF_eDMA_TCD13_ATTR = 0x0002; // 8-bit source, 32-bit dest; no modulo.
MCF_eDMA_TCD13_SOFF = 1; // Source address will increment by 1 each read
MCF_eDMA_TCD13_NBYTES = 1; // 1 byte per request
MCF_eDMA_TCD13_SLAST = 0; // No last Source adjustment
MCF_eDMA_TCD13_DADDR = (&MCF_DSPI0_PUSHR); // 32-bit register
MCF_eDMA_TCD13_CITER = 0; // Byte count (I think) will be set later.
MCF_eDMA_TCD13_DOFF = 0; // Desination register will NOT change
MCF_eDMA_TCD13_DLAST_SGA = 0; // Last Dest adjustment
MCF_eDMA_TCD13_BITER = 0; // Equal to CITER when enabled
MCF_eDMA_TCD13_CSR = 0; // Rx DMA will provide interrupt.
// DSPI0 is Interrupt source 31 in INTC0 p.17-13. */
MCF_INTC0_ICR31 = MCF_INTC_ICR_LEVEL(7); // Level 6 IRQ
MCF_INTC0_IMRL &= ~ MCF_INTC_IMRL_INT_MASK31; // Unmask this interrupt
MCF_eDMA_EDMA_SERQ = 12; // Enable Channel 12 (DSPI Rx)
MCF_eDMA_EDMA_SERQ = 13; // Enable Channel 13 (Tx)
}
Then the function SPI_Send does the rest:
void SPI_Send( pipbuf * pTxBuf, int Mode )
{ // Prepare SPI Interface for a transaction. Mode is one of PIP_SPI_TX or _RX
pipbuf *pRxBuf;
int ByteCount;
ByteCount = pTxBuf->Length;
if( ByteCount < 16 || ByteCount > PIP_MAXFRAME + 16 ) {
#ifdef DEBUG
iprintf( "Invalid byte count (%d)\n", ByteCount);
#endif
if( pTxBuf) {
freePIPbuffer( pTxBuf);
}
return;
}
switch( PIPInfo.SPIState ) {
case PIP_SPI_IDLE :
case PIP_SPI_TXDONE :
case PIP_SPI_RXDONE :
break;
case PIP_SPI_TX :
case PIP_SPI_RX :
#ifdef DEBUG
iprintf( "SPI_Send: Error: Attempt to send while SPIState is %d\n", PIPInfo.SPIState );
#endif
return;
}
pRxBuf = getPIPbuffer();
if( pRxBuf == NULL ) {
#ifdef DEBUG
iprintf( "SPI_Send failed to get a buffer for Rx\n");
#endif
freePIPbuffer( pTxBuf);
}
PIPInfo.TxBuf = pTxBuf;
PIPInfo.TxBuf->pCursor = & PIPInfo.TxBuf->Header.MsgType;
PIPInfo.TxBuf->Count = ByteCount;
PIPInfo.RxBuf = pRxBuf;
PIPInfo.RxBuf->pCursor = & PIPInfo.RxBuf->Header.MsgType;
PIPInfo.RxBuf->Length = 0;
PIPInfo.RxBuf->Count = ByteCount;
PIPInfo.SPIState = Mode;
// Configure DMA for Rx:
MCF_eDMA_TCD12_SADDR = (&MCF_DSPI0_POPR); // 32-bit register
MCF_eDMA_TCD12_DADDR = &(PIPInfo.RxBuf->Header.MsgType); // Point to first byte of frame
MCF_eDMA_TCD12_CITER = ByteCount;
MCF_eDMA_TCD12_BITER = ByteCount;
// Configure DMA for Tx:
MCF_eDMA_TCD13_SADDR = &(PIPInfo.TxBuf->Header.MsgType); // First byte of Tx Frame
MCF_eDMA_TCD13_DADDR = (&MCF_DSPI0_PUSHR); // 32-bit register
MCF_eDMA_TCD13_CITER = ByteCount;
MCF_eDMA_TCD13_BITER = ByteCount;
MCF_DSPI0_RSER = 0 +
MCF_DSPI_RSER_RFDF_DIRS + // DMA all the way
MCF_DSPI_RSER_RFDF_RE + // Enable Interrupt/DMA for Rx
// MCF_DSPI_RSER_RFOF_RE + // Don't want overflow Interrupt.
MCF_DSPI_RSER_TFFF_DIRS + // DMA for Tx
MCF_DSPI_RSER_TFFF_RE + // Enable Interrupt/DMA for Tx
// MCF_DSPI_RSER_TFUF_RE + // No Int for Underflow
MCF_DSPI_RSER_EOQF_RE + // No End Of Queue interrupt
MCF_DSPI_RSER_TCF_RE + // Yes, Interrupt on Transmision Complete!
0;
MCF_DSPI0_MCR &= ~(MCF_DSPI_MCR_HALT); // Clear the HALT bit, allow SPI to start.
PIP_Ready( TRUE); // Handshake to peer that we're ready
}