SPI DMA problems

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI DMA problems

Jump to solution
8,026 Views
ecrampt
Contributor I

I am currently using the TWR-K60F120 and I am having a bit of trouble getting the DMA to work with the DSPI.  I am writing a simple driver at the moment to test the DMA.  I am not using an IDE (IAR or Codewarrior) or the MQX OS for this and would just like a simple stripped down driver to get this running.  I have successfully used the DSPI with interrupts and am now moving to get it working with DMA.  I believe my problem is in the setting up of the TCD registers.  When I enable the DSPI to begin transmitting the DSPI gives me a source bus error for that dma channel and it seems to keep looping even after the CITER loop as completed.  I have looked at some examples, but so far they haven't really helped.

 

I have attached a file with my functions for initializing/setting up the SPI and DMA and my write function.  Currently I am just trying to get the TX to work, but I also need to get the RX side of things working as well.  If someone can point me to a simple test SPI and DMA that works or could point out a flaw in my set up I would appreciate it.

 

Thanks

Original Attachment has been moved to: SpiController.txt.zip

Labels (1)
Tags (3)
0 Kudos
1 Solution
2,566 Views
LuisCasado
NXP Employee
NXP Employee

Hi,

Try to use this example as reference. It is for K40.

Best Regards,

Luis

View solution in original post

0 Kudos
11 Replies
2,567 Views
LuisCasado
NXP Employee
NXP Employee

Hi,

Try to use this example as reference. It is for K40.

Best Regards,

Luis

0 Kudos
2,566 Views
DustyStew
Contributor V

I had a look at the code provided by Luis, and it is quite helpful. I have one burning question, and I cannot seem to find the answer in the reference manual, for the K20 I am using.

In order to enable DMA, a bit is set that changes the interrupt request into a DMA request. And if the DMA has been properly  configured, it will read words from the SPI receive FIFO (single address), and write to sequential addresses in RAM (which presumably have been set to my array). Lovely. All makes perfect sense.

Now, if I am using the SPI in the normal mode, I need to write a byte in order to have the clocks generated so I can read a byte. Right? My burning question is, with the DMA, do I not have to also generate the SPI clock pulses by writing to the SPI?

If so, then what is the best way to do this? Setting the clock generation to continuous looks dangerous, because it would be difficult or impossible to control the exact number of pulses generated. Manually writing to the SPI defeats the purpose of using DMA. The logical answer is to use another DMA channel to block transfer 0xffff's to the SPI transmitter. But the code that Luis has provided does not seem to do this. Is there some hidden magic with DMA/SPI rx, that generates the clocks?

One other question. I cannot find in the reference manual where it says what DMA channel connects to the SPI rx/tx. I gather this is in the DMA mux, but have not found it yet.

thanks.

Tom

0 Kudos
2,566 Views
egoodii
Senior Contributor III

You might get some benefit from my code in:

Re: DMA with SPI to read SD Card?

Granted, this is a case of 'sending', not 'receiving', but the concepts are similar, and in any case as you mention you must send something for every receive chunk.

0 Kudos
2,566 Views
gordonjess
Contributor I

Thanks for the link.  Unfortunately your code wasn't much help as I am also using the KL25, like Steve Marmer.  His comments have prompted me to look into the DMAMUX stuff as I see he configures it in his solution, but I still can't grasp the concept of writing "garbage" to the SPI data register before reading it.  Surely this would result in the DMA just transferring garbage to my destination?

0 Kudos
2,566 Views
egoodii
Senior Contributor III

This is a 'K' thread.

In any case, it is the very definition of all SPI transactions to do a simultaneous read and write.  You don't supply any details about your slave, but I assure you it has a mechanism to deal with 'one sided' transactions in the inherently 'two way' communication link of SPI.

0 Kudos
2,566 Views
gordonjess
Contributor I

Sorry, my bad.

What I'm trying to do is configure the SPI in master mode to receive data from the output of a comparator circuit.  I can post my code too if you want.

I think I understand this simultaneous read/write now, please correct me if I'm wrong.  Once I manually write a byte into the data register, that byte is immediately transferred into the shift register and at the same time the data from my circuit (connected to the MISO pin) is clocked in and immediately transferred to the receive buffer where my DMA controller will read it .  So, the byte that I manually write to begin a transfer can be any value as it is essentially discarded.

0 Kudos
2,566 Views
DustyStew
Contributor V

SPI by nature has a loopback. The data shift register is like a standard 7400 shift register, which has a bit in, a bit out, and 8 bits parallel out, in, or both. MOSI is the serial data output pin, and MISO is the serial data input pin, of that shift register. The shift registers of the MCU and the peripheral part are wired as a loop. Theoretically you shouldn't have to put data into the shift register to get data back, you just need to generate the 8 clock pulses. But the MCUs apparently are design such that when you write a byte, it generates the 8 clock pulses. There is no other way to generate the 8 clock pulses, at least with the DSPI.

Now if what I just wrote is complete nonsense, then please correct me. That is my understanding of it.

It appears the answer to my original question is that it takes 2 DMA channels in order to receive data with DMA. One is constantly transmitting bytes, the other receiving a byte for every one sent. This then begs the question, can I block transfer from a single memory location, ie the increment is 0. Because I would sooner send a load of FF's than some random data out of memory.

Also there is the question of this 32 bit PUSH register, which has control bits, and those control bits presumably change depending on whether you are starting, continuing, or ending a block transfer. That would make sense, though I haven't looked at the docs for months and don't remember the particulars. I frankly did not understand it in the first place. Now I can gripe about imprecise documentation that only makes sense once you know the answers. But no point in that. Bottom line is, if the bytes stuffed into the PUSH register will change in any way through the transmission, that creates a new problem. It seems like the logical answer is, the start and stop are done "manually" (by the MCU code), while the middle part of the transfer is done by the DMA.

I find it ridiculous that a question like this could be left hanging for so long, without input from Freescale. Once you get to know the parts, and have your MCU-dependent code written, its all fine, the parts are great. But getting there?  Unbelievable. In the old days, you could phone an FAE in Austin TX, and that guy would know EVERYTHING. What is happening today is ...well...I can't say that word. You get the picture.

0 Kudos
2,566 Views
DustyStew
Contributor V

Sorry am I griping? Freescale's saving grace is that ST and TI are just as bad or worse.

0 Kudos
2,566 Views
egoodii
Senior Contributor III

It seems that anymore all peripherals are complicated.  Even a UART is now a plethora of connections and options.

Whether DSPI needs to 'alter' the control bits during a 'block' of send depends mostly on whether you are looking for a 'continuous CS' thru the block, or one that toggles at each 8thru16-bit transaction.  If it toggles for every byte, then 'SPI_PUSHR_CONT_MASK" won't ever be needed, and everything else would (in a normal sequence) not need changing.  You will know when your 'block' is received when the RX DMA is 'happy', so EOQF isn't needed either.  So your 'constant word' could just be (for example, match your CS):

(0xFFFF | SPI_PUSHR_PCS(0x10) | SPI_PUSHR_CTAS(0));

0 Kudos
2,566 Views
gordonjess
Contributor I

I am having similar issues Tom, did you ever find the answer?

Thanks

0 Kudos
2,566 Views
ecrampt
Contributor I

The only thing I seemed to be missing was setting the DMA_CSR_DREQ_MASK bit.  I already had the DMA_CSR_INTMAJOR_MASK bit set with the thinking that it would interrupt at the end of a loop, but the interrupt never fired.  I must have misunderstood because after setting both bits together the DMA end of loop interrupt was able to fire like I expected.

Thanks

0 Kudos