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
}
Solved! Go to Solution.
It hasn't taken the slightest bit of notice, has it?
In previous email I said:
> Read through "19.6.3 DMA Arbitration Mode Considerations" and play with the arbitration
> bits. Set them back to the Reset values (you're forcing them all to zero, might cause problems).
I see in your example you're still forcing them all to zero AND you're not using "Round Robin". Turn Round Robin on or use the Reset Default of 0x0000E400. Of course you may have tried this and it made no difference, but...
I'm guessing all of your other peripheral drivers are working? You can send and receive Ethernet packets, the serial port works and so on.
It really looks like it isn't getting a clock or it is disabled. But you've been through that.
This chip is more complex than the MCF52 or MCF53 ones. The more stuff in there, the more to go wrong. Not a patch on the i.MX53. That damn thing has 110 separate clock-enable controls for a start!
The MCF54xxx has an MMU. Could that be getting in the way? It shouldn't as it is between the CPU and the peripheral buses.
This chip has two Peripheral Controllers. One is at 0xExxxxxxx and the other is at 0xFxxxxxxx. Is it possible the DMAC is on one controller and all the other peripherals you're using are on the other controller ... and you forgot to disable the Cache over that other range? We;; that was a nice idea while it lasted. The EDMAC registers are at 0xFC044000 with other peripherals you have to be using on either side.
Still I'd try to write "illegal" values to some of the Reserved bits (like the upper ones in EDMA_CR) and make sure they don't set.
I'd suggest going right back to basics (if you're not there already).
When I said "a working example" I didn't mean just a sample DMA driver. I meant the whole system with all the CPU, peripheral, clock and memory initialisation. Something in this "platform initialisation" must be missing. Go to different hardware if possible.
Is it your only hardware example? You might have missed one or more VDD or VSS connections, or that board may have a bad joint on one of the power supplies. Very unlikely, but worth checking.
Do you have the Freescale Development Board for this chip? I'd try running your code on that chip, then I'd recommend running whatever came with the board (with its default "platform initialisation"). Maybe try to get MQX or something running on it and try to get the EDMA running under that.
Depending on how much this time-wasting is costing you, it might be worth buying a full development board if you don't have one. If the Freescale sample code works on that you might be able to compare all the peripheral registers to see what's different.
Tom
To summarize the problem:
The EDMA_CR register must not be set to zero. Specifically, the Priority settings (GRP3PRI, GRP2PRI, GRP1PRI, GRP0PRI) must NOT be set equal to one another. According to Tom's reading of the manual, setting the "Round Robin" bit might also work around this bug.
To fix the problems I was having, I used a value of 0x0000E400 (the reset value) for EDMA_CR.
Tom suggested that I should start with the example in 16.6.4.1 of Rev 3 of the CPU manual. Here's the code:
{ pipbuf *pBuf1, *pBuf2; int i; pBuf1 = PIPbuffers + 0; pBuf2 = PIPbuffers + 1; for( i = 0; i < 32; i++) pBuf1->Data[i] = i + 1; iprintf( "Loaded Buffer 1:\n"); hexdump( pBuf1->Data, 8); iprintf( "Buffer 2 is empty:\n"); memset( pBuf2->Data, 0, 32); hexdump( pBuf2->Data, 8); // Emulating example in section 19.6.4.1, p 19-41: MCF_eDMA_TCD1_NBYTES = 16; // MCF_eDMA_TCD1_CITER = 1; // MCF_eDMA_TCD1_BITER = 1; // MCF_eDMA_TCD1_SADDR = pBuf1->Data; MCF_eDMA_TCD1_SOFF = 1; // MCF_eDMA_TCD1_ATTR = 0x0002; // SSIZE = 0; DSIZE = 2 MCF_eDMA_TCD1_SLAST = -16; MCF_eDMA_TCD1_DADDR = pBuf2->Data; MCF_eDMA_TCD1_DOFF = 4; MCF_eDMA_TCD1_DLAST_SGA = -16; MCF_eDMA_TCD1_CSR = 2; // INT_MAJOR = 1` DumpDMAChannel( 1); DumpDMA(); MCF_eDMA_EDMA_SSRT = 1; // Set Start bit for Ch 1 Wait(10); // milliseconds iprintf( "Buffer 2 after DMA:\n"); hexdump( pBuf2->Data, 8); DumpDMAChannel( 1); DumpDMA();
while( TRUE) Relinquish( FALSE); }
And the result:
[1:3.144] PIP_Init exit
[1:3.146] Loaded Buffer 1:
[1:3.149] +------+-[88000482]----------------[ 8]-+
[1:3.152] | 0000 | 01 02 03 04 05 06 07 08 | ........ |
[1:3.154] +------+------------------------------------+
[1:3.156] Buffer 2 is empty:
[1:3.159] +------+-[880006A4]----------------[ 8]-+
[1:3.162] | 0000 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.164] +------+------------------------------------+
[1:3.167] Channel 1 DMA:
[1:3.169] TCD1_SADDR 88000482
[1:3.172] TCD1_ATTR 2
[1:3.174] TCD1_SOFF 1
[1:3.176] TCD1_NBYTES 10
[1:3.179] TCD1_SLAST FFFFFFF0
[1:3.181] TCD1_DADDR 880006A4
[1:3.183] TCD1_CITER 1
[1:3.186] TCD1_DOFF 4
[1:3.188] TCD1_DLAST_SGA FFFFFFF0
[1:3.190] TCD1_BITER 1
[1:3.193] TCD1_CSR 2
[1:3.195] eDMA_CR = 00000000
[1:3.198] eDMA_ES = 00000000
[1:3.200] eDMA_ERQL = 00003000
[1:3.203] eDMA_EEIL = 00000000
[1:3.205] eDMA_HRSL = 00000000
[1:3.208] eDMA_INTL = 00000000
[1:3.210] eDMA_ERRL = 00000000
{Delay happens here}
[1:3.245] Buffer 2 after DMA:[1:3.248] +------+-[880006A4]----------------[ 8]-+
[1:3.251] | 0000 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.253] +------+------------------------------------+
[1:3.255] Channel 1 DMA:
[1:3.258] TCD1_SADDR 88000482
[1:3.260] TCD1_ATTR 2
[1:3.262] TCD1_SOFF 1
[1:3.265] TCD1_NBYTES 10
[1:3.267] TCD1_SLAST FFFFFFF0
[1:3.270] TCD1_DADDR 880006A4
[1:3.272] TCD1_CITER 1
[1:3.274] TCD1_DOFF 4
[1:3.277] TCD1_DLAST_SGA FFFFFFF0
[1:3.279] TCD1_BITER 1
[1:3.281] TCD1_CSR 3
[1:3.284] eDMA_CR = 00000000
[1:3.286] eDMA_ES = 00000000
[1:3.289] eDMA_ERQL = 00003000
[1:3.291] eDMA_EEIL = 00000000
[1:3.294] eDMA_HRSL = 00000000
[1:3.296] eDMA_INTL = 00000000
[1:3.299] eDMA_ERRL = 00000000
It hasn't taken the slightest bit of notice, has it?
In previous email I said:
> Read through "19.6.3 DMA Arbitration Mode Considerations" and play with the arbitration
> bits. Set them back to the Reset values (you're forcing them all to zero, might cause problems).
I see in your example you're still forcing them all to zero AND you're not using "Round Robin". Turn Round Robin on or use the Reset Default of 0x0000E400. Of course you may have tried this and it made no difference, but...
I'm guessing all of your other peripheral drivers are working? You can send and receive Ethernet packets, the serial port works and so on.
It really looks like it isn't getting a clock or it is disabled. But you've been through that.
This chip is more complex than the MCF52 or MCF53 ones. The more stuff in there, the more to go wrong. Not a patch on the i.MX53. That damn thing has 110 separate clock-enable controls for a start!
The MCF54xxx has an MMU. Could that be getting in the way? It shouldn't as it is between the CPU and the peripheral buses.
This chip has two Peripheral Controllers. One is at 0xExxxxxxx and the other is at 0xFxxxxxxx. Is it possible the DMAC is on one controller and all the other peripherals you're using are on the other controller ... and you forgot to disable the Cache over that other range? We;; that was a nice idea while it lasted. The EDMAC registers are at 0xFC044000 with other peripherals you have to be using on either side.
Still I'd try to write "illegal" values to some of the Reserved bits (like the upper ones in EDMA_CR) and make sure they don't set.
I'd suggest going right back to basics (if you're not there already).
When I said "a working example" I didn't mean just a sample DMA driver. I meant the whole system with all the CPU, peripheral, clock and memory initialisation. Something in this "platform initialisation" must be missing. Go to different hardware if possible.
Is it your only hardware example? You might have missed one or more VDD or VSS connections, or that board may have a bad joint on one of the power supplies. Very unlikely, but worth checking.
Do you have the Freescale Development Board for this chip? I'd try running your code on that chip, then I'd recommend running whatever came with the board (with its default "platform initialisation"). Maybe try to get MQX or something running on it and try to get the EDMA running under that.
Depending on how much this time-wasting is costing you, it might be worth buying a full development board if you don't have one. If the Freescale sample code works on that you might be able to compare all the peripheral registers to see what's different.
Tom
> Read through "19.6.3 DMA Arbitration Mode Considerations" and play with the arbitration
> bits. Set them back to the Reset values (you're forcing them all to zero, might cause problems).
I see in your example you're still forcing them all to zero AND you're not using "Round Robin". Turn Round Robin on or use the Reset Default of 0x0000E400. Of course you may have tried this and it made no difference, but...
Tom... You mentioned this more than once and it somehow evaded my tests. And, as is often the case, you hit the nail on the head! This output is from one of my attempts of causing errors (to see ANY response from the peripheral):
[1:3.135] Loaded Buffer 1:
[1:3.138] +------+-[00000000]----------------[ 4]-+
[1:3.141] | 0000 | 88 01 00 00 | .... |
[1:3.143] +------+------------------------------------+
[1:3.146] Buffer 2 is empty:
[1:3.148] +------+-[40FF9F44]----------------[ 4]-+
[1:3.152] | 0000 | 00 00 00 20 | ... |
[1:3.154] +------+------------------------------------+
[1:3.156] Channel 1 DMA:
[1:3.158] TCD1_SADDR 1
[1:3.161] TCD1_ATTR 2
[1:3.163] TCD1_SOFF 1
[1:3.165] TCD1_NBYTES 10
[1:3.168] TCD1_SLAST FFFFFFF0
[1:3.170] TCD1_DADDR 11
[1:3.172] TCD1_CITER 1
[1:3.174] TCD1_DOFF 3
[1:3.177] TCD1_DLAST_SGA FFFFFFF0
[1:3.179] TCD1_BITER 1
[1:3.181] TCD1_CSR 2
[1:3.184] eDMA_CR = 0000E400
[1:3.186] eDMA_ES = 00000000
[1:3.189] eDMA_ERQL = 00003000
[1:3.191] eDMA_EEIL = 00000000
[1:3.193] eDMA_HRSL = 00000000
[1:3.196] eDMA_INTL = 00000000
[1:3.198] eDMA_ERRL = 00000000
[1:3.210] Buffer 2 after DMA:
[1:3.213] +------+-[40FF9F44]----------------[ 4]-+
[1:3.216] | 0000 | 00 00 00 20 | ... |
[1:3.219] +------+------------------------------------+
[1:3.221] Channel 1 DMA:
[1:3.223] TCD1_SADDR 1
[1:3.226] TCD1_ATTR 2
[1:3.228] TCD1_SOFF 1
[1:3.230] TCD1_NBYTES 10
[1:3.232] TCD1_SLAST FFFFFFF0
[1:3.235] TCD1_DADDR 11
[1:3.237] TCD1_CITER 1
[1:3.239] TCD1_DOFF 3
[1:3.241] TCD1_DLAST_SGA FFFFFFF0
[1:3.244] TCD1_BITER 1
[1:3.246] TCD1_CSR 2
[1:3.248] eDMA_CR = 0000E400
[1:3.251] eDMA_ES = 80000130
[1:3.253] eDMA_ERQL = 00003000
[1:3.256] eDMA_EEIL = 00000000
[1:3.258] eDMA_HRSL = 00000000
[1:3.261] eDMA_INTL = 00000000
[1:3.263] eDMA_ERRL = 00000002
Errors! Huzzah! Plenty of work to do from this point forward, but this gives me something to work with.
Tom, I owe you more than one beer now. If you're ever in Joplin...
--Adam
> I have to say, this is by far the worst user manual for a CPU that I have ever been subjected to.
If you have the latest version of the manual then you have the one where they broke the eDMA chapter. Search the forum for other people having eDMA problems, then read Version 3 of the manual:
https://community.freescale.com/message/307125#307125
Have you searched for any other working code using the eDMA?
Tom
One thing I did find in the Rev3 version of the user manual is the EDMA_HRSL register (it was never mentioned in the Rev 4 manual, I think).
Testing it, while SPI is active and not using DMA, shows a value of 0x3000 (channels 12 and 13 calling for service).
At the same time EDMA_ERQL has a value of 0x3000 (indicating, I believe, that it's configured to honor the above hardware requests).
Also, at the same time EDMA_ES has a value of zero (indicating, I believe, that there are no problems with the DMA's configuration).
To me, these do not add up.
Here's someone who has got the EDMA working, together with a reference to a block entry (on another problem they had) which might get you a contact/email address to ask them for their code:
https://community.freescale.com/thread/304877
I thought uTasker might have working code for this peripheral, but it looks like they only supported MCF522xx:
http://www.utasker.com/docs/documentation.html
> I took [part of] your advice, and configured a DMA channel to move data from RAM to RAM... Same thing: Nothing happens.
That's still the first thing to get working. You should also attempt moving from SRAM to SRAM in case there's something wrong with your main memory system and EDMA. Enable the SRAM, set up RAMBAR, put it on the right bus, enable BDE and make sure you have the Address Space Masks set properly.
Have you got the Crossbar set up properly? What Address Space ID does the EDMA use? Check the RAMBAR description if you don't know about M68k Address Space IDs.
I wrote:
>> I also suggest looking through the following, although Linux drivers don't normally get beyond the "just working" stage to be optimised with things like DMA unless someone really cares.
>> http://lxr.free-electrons.com/source/arch/m68k/coldfire/
Google found exactly this searching for "EDMA_CR". Have you looked at any of these?
Linux/drivers/dma/fsl-edma.c - Linux Cross Reference - Free Electrons
The above should show a difference with what you're doing.
> MCF_PMM_PPMCR0 = 17; // Enable eDMA controller (p. 9-7)
I'd suggest "MCF_PMM_PPMCR0 = 0x40;" to enable absolutely everything. You may have something disabled that is "in the way".
Tom
Here is one of several tests I ran to try to move data from SRAM to SRAM:
{ pipbuf *pBuf1, *pBuf2; int i; pBuf1 = PIPbuffers + 0; pBuf2 = PIPbuffers + 1; for( i = 0; i < 32; i++) pBuf1->Data[i] = i + 1; iprintf( "Loaded Buffer 1:\n"); hexdump( pBuf1->Data, 32); iprintf( "Buffer 2 is empty:\n"); memset( pBuf2->Data, 0, 32); hexdump( pBuf2->Data, 32); MCF_eDMA_TCD1_SADDR = pBuf1->Data; MCF_eDMA_TCD1_ATTR = 0; // 8-bit source, 8-bit dest; No modulo MCF_eDMA_TCD1_SOFF = 1; // Offset for source (will stay zero) MCF_eDMA_TCD1_NBYTES = 1; // 1 byte per request MCF_eDMA_TCD1_SLAST = 0; // Last Source Adjustment MCF_eDMA_TCD1_DADDR = pBuf2->Data; MCF_eDMA_TCD1_CITER = 64; // Will be the byte count (I think), written when enabled. MCF_eDMA_TCD1_DOFF = 1; // Increment Destination by 1 each write MCF_eDMA_TCD1_DLAST_SGA = 0; // Last Dest adjustment MCF_eDMA_TCD1_BITER = 64; // Will be set equal to CITER when enabled (I think) MCF_eDMA_TCD1_CSR = 0; // No Interrupt. p.19-26 // MCF_eDMA_TCD1_SADDR -= 0x08000000; // Point to SRAM "back door" // MCF_eDMA_TCD1_DADDR -= 0x08000000; DumpDMAChannel( 1); DumpDMA(); MCF_eDMA_EDMA_SSRT = 1; // Set Start bit for Ch 1 // MCF_eDMA_TCD1_CSR = 1; // No Interrupt. p.19-26 Wait(10); // milliseconds iprintf( "Buffer 2 after DMA:\n"); hexdump( pBuf2->Data, 32); DumpDMAChannel( 1); DumpDMA();
while( TRUE) Relinquish( FALSE); }
Which yielded the following debug output:
[1:3.103] Loaded Buffer 1:
[1:3.105] +------+-[88000482]----------------[ 32]-+
[1:3.108] | 0000 | 01 02 03 04 05 06 07 08 | ........ |
[1:3.112] | 0008 | 09 0A 0B 0C 0D 0E 0F 10 | ........ |
[1:3.115] | 0010 | 11 12 13 14 15 16 17 18 | ........ |
[1:3.118] | 0018 | 19 1A 1B 1C 1D 1E 1F 20 | ....... |
[1:3.120] +------+------------------------------------+
[1:3.122] Buffer 2 is empty:
[1:3.125] +------+-[880006A4]----------------[ 32]-+
[1:3.128] | 0000 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.131] | 0008 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.134] | 0010 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.137] | 0018 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.140] +------+------------------------------------+
[1:3.142] Channel 1 DMA:
[1:3.144] TCD1_SADDR 88000482
[1:3.147] TCD1_ATTR 0
[1:3.149] TCD1_SOFF 1
[1:3.151] TCD1_NBYTES 1
[1:3.154] TCD1_SLAST 0
[1:3.156] TCD1_DADDR 880006A4
[1:3.158] TCD1_CITER 40
[1:3.161] TCD1_DOFF 1
[1:3.163] TCD1_DLAST_SGA 0
[1:3.165] TCD1_BITER 40
[1:3.168] TCD1_CSR 0
[1:3.170] eDMA_CR = 00000000
[1:3.173] eDMA_ES = 00000000
[1:3.175] eDMA_ERQL = 00003000
[1:3.178] eDMA_EEIL = 00000000
[1:3.180] eDMA_HRSL = 00000000
[1:3.183] eDMA_INTL = 00000000
[1:3.185] eDMA_ERRL = 00000000
[1:3.220] Buffer 2 after DMA:
[1:3.222] +------+-[880006A4]----------------[ 32]-+
[1:3.225] | 0000 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.229] | 0008 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.232] | 0010 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.235] | 0018 | 00 00 00 00 00 00 00 00 | ........ |
[1:3.237] +------+------------------------------------+
[1:3.239] Channel 1 DMA:
[1:3.242] TCD1_SADDR 88000482
[1:3.244] TCD1_ATTR 0
[1:3.247] TCD1_SOFF 1
[1:3.249] TCD1_NBYTES 1
[1:3.251] TCD1_SLAST 0
[1:3.253] TCD1_DADDR 880006A4
[1:3.256] TCD1_CITER 40
[1:3.258] TCD1_DOFF 1
[1:3.261] TCD1_DLAST_SGA 0
[1:3.263] TCD1_BITER 40
[1:3.265] TCD1_CSR 1
[1:3.268] eDMA_CR = 00000000
[1:3.270] eDMA_ES = 00000000
[1:3.273] eDMA_ERQL = 00003000
[1:3.275] eDMA_EEIL = 00000000
[1:3.278] eDMA_HRSL = 00000000
[1:3.280] eDMA_INTL = 00000000
[1:3.283] eDMA_ERRL = 00000000
I have tried this with the DMA pointing to the SRAM's "backdoor" and its "regular" mapping location. Both give same result.
What a difficult thing this Forum post editor is. Spent 15 minutes trying to get my code pasted into this message.
> What a difficult thing this Forum post editor is.
That's because the forum software isn't meant for technical forums. It is a "Facebook Wannabee". That means you're obviously meant to post a VIDEO of your code, as you can do that with one click.
Spent 15 minutes trying to get my code pasted into this message.
And it ended up looking terrible anyway. At least cut-and-paste works mostly now. BTW it works better with IE than Firefox. That combination is destructive.
For future postings (or please use this to edit your last one so others can read your code), click on the very unhelpful ">>" thin, select "C++" or "Plain Text" and then paste the code into the thing that pops up then. Otherwise you can always format the code text as "Courier New" to get Monospace (what I had to do when the ">>" thing wouldn't work).
More details here:
https://community.freescale.com/thread/301959
Back to the code... I've probably typed much of this before.
I can't see anything obviously wrong on a quick inspection, but you're meant to move data in the INNER loop and not the outer one. You've got 0x40 "major loops" and 0x01 "inner loops". I'd swap them for a start. Refer to "Table 19-34. Example of Multiple Loop Iterations".
Copy the example in "19.6.4.1 Single Request". Make sure you have Versoin 3 of the Reference Manual.
I'd also dump every single register before you attempt the DMA Start and then every register after as well.
From the condition of TD1_CSR the DMA hasn't even started. It hasn't been triggered. It hasn't started.
Read through "19.6.3 DMA Arbitration Mode Considerations" and play with the arbitration bits. Set them back to the Reset values (you're forcing them all to zero, might cause problems).
Check the Crossbar again. Try to use the DMA Controller in External RAM. Try to transfer between some peripheral registers. Try to set it up with a deliberate error to see if it gets far enough to give you an error.
You need a working example to start from.
Tom
I looked at the section on the Crossbar again, and confirmed that--at least according to the manual--its configuration should be fine. From section 14.6 (of Rev3): "No initialization is required by or for the crossbar switch. Hardware reset ensures all the register bits used by the crossbar switch are properly initialized to a valid state."
Looks like I could futz with its registers and change priorities, but its configuration out of reset shouldn't prevent DMA from working...
For future postings (or please use this to edit your last one so others can read your code), click on the very unhelpful ">>" thin, select "C++" or "Plain Text" and then paste the code into the thing that pops up then. Otherwise you can always format the code text as "Courier New" to get Monospace (what I had to do when the ">>" thing wouldn't work).
Apparently, the hard tabs in my code completely freak out the code formatter. I had to select "Quote" from that menu.
I'd also dump every single register before you attempt the DMA Start and then every register after as well.
From the condition of TD1_CSR the DMA hasn't even started. It hasn't been triggered. It hasn't started.
Well; I did. If you look further down the debug output, you can see the CSR is 0 before the DMA "starts" and is 1 afterward. However, none of the other signs of "starting" are there, such as "Active" or "Done"
Thanks for your other suggestions. I'll have a quick go at the example 19.6.4.1, and put its results in this post.
> Apparently, the hard tabs in my code completely freak out the code formatter.
That might be a problem with Firefox. This site works better with Internet Explorer. From my link above complaining about cut-and-paste, one problem is the "Paste completion signal that runs Javascript to do paste cleanup". If you disable that in Firefox (using the "about:config" in the Address Bar hack) it gets better behaved.
I get multiple spaces and/or tabs triggering some sort of "That's a Spreadsheet, I'm making a Table" evil wizard.
Tom
Tom,
As always, I appreciate your time and effort.
I was unable to find any method to contact the author of that thread (with eDMA working).
I did read up on Address Space IDs; I reached the conclusion that because I have not enabled the MMU, the Address Space IDs are not going to affect this operation.
I did add the "enable absolutely everything" in the Power Management Module config (both of them). That didn't help (or hurt) anything so I've left it in place for the time being.
Yesterday, while searching the forum, I did run across a link to the Rev 3 manual, and re-printed the DMA chapter. I have yet to find any breakthroughs in there (but, it appears MUCH better than the "newer" Rev manual). But, this was not the only chapter I've had issues with...
I can't say I've searched for other working code using eDMA. Back in the olden days, the user's manual would have some examples, and others would have been found in Application Notes.
Do you have any recommendations for searching for example code? I assume sample code from another CPU may be irrelevant.
> Back in the olden days, the user's manual would have some examples, and others would have been found in Application Notes.
When Freescale was Motorola. Back in the 68000 days. That time is long gone. Freescale's newer products have manuals, but they have other problems, one of which being that they don't appear to be written by native speakers of English. Freescale do't seem to have heard of "Spelling Checking" either:
https://community.freescale.com/thread/328744
From the above:
My favourites are "CSU manges system sucurity alarms", "writting, wrotten, wrutten", "regitsers, regitsters, regsier, regsiter, regsiters", "cannnot" and most ironically, "accruate".
> Do you have any recommendations for searching for example code?
Google for unique register names. That often finds something.
I also suggest looking through the following, although Linux drivers don't normally get beyond the "just working" stage to be optimised with things like DMA unless someone really cares.
http://lxr.free-electrons.com/source/arch/m68k/coldfire/
Does your SPI driver work with interrupts? I'm guessing that all works OK.
Are there any "hidden module enable" bits anywhere that are stopping the clocks to the eDMA or keeping it powered down somehow? That happens a lot. Can you test the eDMA on its own to copy memory or with another peripheral, or from the ADC or DMA Timer perhaps?
Tom
I'm guessing that there must be some "hidden module enable" bits SOMEwhere.
I took [part of] your advice, and configured a DMA channel to move data from RAM to RAM... Same thing: Nothing happens. The "Active" bit does not set... Nothing changes.
Tried enabling the interrupts for the module (even though I don't plan to use them) wondering if there was a bug in the microcode. No dice.
Wasted a week banging my head against this DMA issue. Fortunately, I'm able to switch back and forth with a #define and am back to working on communications. For now. Before production units ship, I must work this out.
Once again, longing for the "good old days" where manuals had WORKING EXAMPLES... That will be one of the criteria when we select our next CPU supplier.
Thanks for your pointers.