View previous topic :: View next topic |
Author |
Message |
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
dspic SPI DMA |
Posted: Sat Jul 28, 2018 10:47 am |
|
|
Hello again,
I am using a dspic33fj64gp804 to send out SPI data to neopixel LEDs.
Anyway, I already got it working and now I want to do it with DMA to save some cpu cycles because each transfer is 240 bytes.
Code: |
#BANK_DMA
unsigned char SPI2Buff[240];
setup_dma(6,DMA_OUT_SPI2,DMA_BYTE);
void DMATest(){
int p=0;
for(p=0;p<240;++p) SPI2Buff[p]=0b11010001; //fill the buffer with known data
while(1){
dma_start(6, DMA_ONE_SHOT | DMA_FORCE_NOW, &SPI2Buff[0],239);
delay_ms(10);
}
}
|
The problem is that in my oscilloscope I see only the 1st byte repeating.
Nothing more.
Any ideas??
[img]https://ibb.co/eW9wR8[/img] _________________ George.
Last edited by georpo on Sat Jul 28, 2018 11:17 am; edited 1 time in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9242 Location: Greensville,Ontario
|
|
Posted: Sat Jul 28, 2018 11:01 am |
|
|
hmm.. the way I see your code is that every byte of the buffer contains the same data ??
Quote: | for(p=0;p<240;++p) SPI2Buff[p]=0b11010001; //fill the buffer with known data |
so everything you see is the same.
Jay |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Sat Jul 28, 2018 11:06 am |
|
|
Yes of course they are the same.
This is just to send some known values that I can recognize in the oscilloscope.
The problem is that I see only 1 byte of data.
I should see a stream of 240 bytes with the same value of course. _________________ George. |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Sat Jul 28, 2018 12:07 pm |
|
|
From a search in Microchip forum other people have this problem also.
It has to do with the SPI receiver that accepts data as you transmit but no one handles this data so the spi module overruns.
In my case I have enabled only the SDO. No clock, NO SDI.
So my module does not receive data... _________________ George. |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Sat Jul 28, 2018 12:25 pm |
|
|
Definitely has to do with SPI receiver.
I am tracking bit SPIROV (Receive Overflow Flag bit) and it is SET which proves my assumption.
I set up interrupt #INT_SPI2 to read the buffer and now my DMA transmit works.
Code: |
#INT_SPI2
void SPI2ISR(){
char aa=0;
aa=SPI2BUF;
}
|
The point is that it is useless because I want to use DMA. Not interrupt. It is a waste of time.
So, now I have to set another DMA channel to SPI receive.
Any help here? _________________ George. |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Sat Jul 28, 2018 12:56 pm |
|
|
Finally solved. I use channel 7 to receive from SPI:
Code: |
setup_dma(7, DMA_IN_SPI2, DMA_BYTE); //use DMA channel 7 for SPI2 DATA IN (dummy)
dma_start(7, DMA_CONTINOUS ,&SPI2InBuff[0],239); //setup dummy receive to avoid SPI2 overrun
|
It is really strange though because no data is being shifted in to the SDI.
I am only using the SDO.
Where does this data come from??
Anyway problem solved. _________________ George. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Sat Jul 28, 2018 1:32 pm |
|
|
SPI is always bi-directional. If the pin is not defined it'll just be random....
You also need to set the DMA to increment the source address. Otherwise it is just going to keep sending the first byte....
Look at the defines for your chip (the syntax varies according to the nature of the DMA unit, and I'm not on a computer with CCS installed at the moment, so can't check what it is for this chip).
Have just checked, and for this chip the increment is automatic. Unlike many of the chips which have separate controls for increment source or destination this only has two modes, designed for 'peripheral to RAM' or 'RAM to peripheral', and in each case the RAM address always increments.
The receive buffer to prevent the SPI hang, can be tiny. Four bytes is ideal. No need to have the same size buffer as your TX. Using continuous, it'll loop and re-use the buffer. |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Sun Jul 29, 2018 8:35 am |
|
|
Yes, I got it.
Thanks for the support guys!!!
I set the receive buffer to 4 bytes. It is all good.
BTW. What happens if I omit the last parameter: the 239 in the example below:
Code: |
dma_start(7, DMA_CONTINOUS ,&SPI2InBuff[0],239);
|
Will it wait for 240 bytes? _________________ George. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Sun Jul 29, 2018 11:07 am |
|
|
If you are using a four byte buffer, it needs to be 4 (or possibly 3 - see below).
Using 'continuous' it'll repeat using the same buffer, whenever data arrives.
Every four bytes (when the buffer is filled), it'll issue a DMA interrupt (so if you wanted the data you could do something with it), but you simply ignore this.
The count tells the controller when to reset the index count in the buffer (and interrupt unless half count interrupting is enabled).
Get the manual 70182C.pdf (from MicroChip). This is vital reading for anyone using DMA. Look at 22.6.8. The number in this setup, is DMACMT.
You need to check whether your chip has type1 or type2 DMA. On Type1, this needs to be one less than the count to transfer (so 3). On Type2, the count required....
Just checked and this chip is type1, so needs 1 less than the count (3). |
|
|
georpo
Joined: 18 Nov 2008 Posts: 281 Location: Athens, Greece.
|
|
Posted: Sun Jul 29, 2018 10:59 pm |
|
|
Yes, It is already setup for 4 bytes buffer and with 3 in count.
Thank you very much for the responses! _________________ George. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19538
|
|
Posted: Mon Jul 30, 2018 12:52 am |
|
|
On your 'omitting the last value', you can't do this.
Except you can....
The DMA count register _must_ be initialised. If you look at the DMA data sheet, it says:
Quote: |
Initializing DMA transfer count must be initialized (see 22.5.4 “DMA Transfer Count Set
Up”)
|
The count value must be specified.
The point about the function version without this setting, is that the register retains what it was last set to. So for example, you can start the DMA once with a count, and then on subsequent starts, omit the count. So if using 'one shot' mode, send the the repeated commands to do a transfer, just with the peripheral address and the buffer address, but no count.
What you must not do it trigger the first DMA on a particular channel without a count.... |
|
|
|