CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

DSPIC33: SPI AND DMA

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

DSPIC33: SPI AND DMA
PostPosted: Thu May 19, 2022 5:05 am     Reply with quote

Hi,

I would like to read data from flash using SPI and DMA.

I understand that i will need 2 dma channels, 1 to read and 1 to write while I read (dummy).

I can't seem to make it work.

Code:

#BANK_DMA
int8 dma0_buffer[256] = {0}; // dummy send

#BANK_DMA
int8 dma1_buffer[256]; // receive



....



#INT_DMA0
void dma0_isr(void)
{

 dma_0_done_flag = 1;
}

#INT_DMA1
void dma1_isr(void)
{
dma_1_done_flag = 1;
}



void main() // Main function
{
int8 rc = restart_cause(); // debug
initialize();

setup_dma(0, DMA_OUT_SPI2, DMA_BYTE);
setup_dma(1, DMA_IN_SPI2, DMA_BYTE);

enable_interrupts(int_dma0);
enable_interrupts(int_dma1);

..... code

// ask the flash for data



output_low(FLASH_CS); // select flash
spi_read2(FLASH_FREAD); // execute read command
spi_read2(make8(addr, 2)); // address MSB
spi_read2(make8(addr, 1)); //
spi_read2(make8(addr, 0)); // address LSB
spi_read2(0); // dummy data - for clocks
// enable dma spi input
dma_start(1, DMA_ONE_SHOT|DMA_FORCE_NOW, &dma1_buffer[0],256);
// enable spi send (dummy_send)
dma_start(0, DMA_ONE_SHOT|DMA_FORCE_NOW, &dma0_buffer[0],256);
output_high(FLASH_CS);

When i read the input buffer, its 0xFF.

But when i don't use the dma, and just regular spi_read, the data is ok.

Could you please help me?
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Thu May 19, 2022 5:58 am     Reply with quote

My own setup for doing SPI receive on SPI2, is:

setup_dma(0, DMA_TRIGGER_SPI2RX, DMA_BYTE | DMA_RELOAD_ADDRESS);

Then the DMA start is:

dma_start(0, DMA_SOURCE_ADDR_UNCHANGED | DMA_INC_DEST_ADDR | DMA_REPEATED, DMA_ADC_RX, getenv("SFR:SPI2BUFL"), 256);

I trigger by sending the setup sequence using DMA1. The chip's reply is
then what starts the receive.
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Thu May 19, 2022 6:08 am     Reply with quote

Ttelmah wrote:
My own setup for doing SPI receive on SPI2, is:

setup_dma(0, DMA_TRIGGER_SPI2RX, DMA_BYTE | DMA_RELOAD_ADDRESS);

Then the DMA start is:

dma_start(0, DMA_SOURCE_ADDR_UNCHANGED | DMA_INC_DEST_ADDR | DMA_REPEATED, DMA_ADC_RX, getenv("SFR:SPI2BUFL"), 256);

I trigger by sending the setup sequence using DMA1. The chip's reply is
then what starts the receive.


Thanks.

Those are not valid options in my chip.
I am using dspic33ep512gm306....
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Thu May 19, 2022 6:18 am     Reply with quote

The key thing you are missing is the difference between DMA_CONTINUOUS
and DMA_ONE_SHOT.
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Thu May 19, 2022 6:24 am     Reply with quote

OK, could you please elaborate?
because i think I tried some variation with continues,
but as I see it,
there is a point in my program, in which i would like to get data from the FLASH. It's a spesific moment, let's say it's a user pressing a button.
So, for me, it sounds like a one-shot...
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Thu May 19, 2022 6:47 am     Reply with quote

No.
The transfer stops after a block either way, but with 'continuous' the
address counter goes back to the start of the buffer. With one shot it
doesn't. If you don't select this, unless you do another 'setup', it goes
on up the memory.
It goes 'continuous', if you select ping_pong & continuous. Otherwise
it still stops.

Try this:
dma_start(1, DMA_CONTINUOUS|DMA_FORCE_NOW|DMA_PERIF_ADDR, dma1_buffer,256);

I must admit I've never tried sending the setup without DMA. I send the
setup as a defined block with the target address using the other DMA
channel, and the completion of this triggers the receive.
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Thu May 19, 2022 7:13 am     Reply with quote

Regarding the last part of your message, i also tried sending the commands as part of the dma0

int8 dma0_buffer[256] = {RD_OP, ADDR_2,ADDR_1,ADDR_0,DUMMY};

I looked at the signals going out on the MOSI line, they look ok.

regarding the main part of your message, i tried it, i get 0's back.

so my line of code now looks like this:
output_low(FLASH_CS);
dma_start(1, DMA_CONTINUES|DMA_FORCE_NOW|DMA_PERIF_ADDR, &dma1_buffer[0],256);
dma_start(2, DMA_ONE_SHOT|DMA_FORCE_NOW, &dma0_buffer[0],256);
output_high(FLASH_CS);

tried also continues with dma0 did not make a difference

so if MISO lines are OK
There is a problem with the recieve DMA
because when i use standalone SPI it all works fine, MISO MOSI , data is valid.


on a side note, when using continies, i noticed the lines of CLK and MOSI are always active, the dont stop...

Thanks for the help
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Thu May 19, 2022 8:46 am     Reply with quote

OK.
The problem you have is that nothing is starting the clocking.
Think about it without clocks, the bytes can't read, and nothing is
saying to the SPI 'start clocking'.
I started the transaction by sending a null byte. This then makes the
receive buffer load, and the SPI starts receiving, and the DMA reads
this.
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Thu May 19, 2022 9:51 am     Reply with quote

Ttelmah wrote:
OK.
The problem you have is that nothing is starting the clocking.
Think about it without clocks, the bytes can't read, and nothing is
saying to the SPI 'start clocking'.
I started the transaction by sending a null byte. This then makes the
receive buffer load, and the SPI starts receiving, and the DMA reads
this.


Yeah, but as i see it, i am sending 256- 5 = 252 null bytes.
The clock should be there (scratching my head...)
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Thu May 19, 2022 1:03 pm     Reply with quote

No, you are asking it to receive. You are reading the RX buffer, not
writing. That is the point. To send, you have to write, then the read
will occur.
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Thu May 19, 2022 1:45 pm     Reply with quote

I will not be at the lab for the next couple of days, but i can't let go Smile

So you are suggesting that on the dma channel i am writing, i will keep the buffer to a size of 5 which is the size of the instruction i am required to send in order to read.
And then execute, when i get a flag that it has ended, the start of the read dma which is let's say 256 or whatever amount of bytes i want to read?
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Sun May 22, 2022 4:08 am     Reply with quote

So... I am gonna need a little more help here.
I am now using DMA0 just to send the data in order to enable the read: OPCODE ADDRESSX3 and DUMMY bytes required by datasheet => 5 bytes.
EDIT:
I seem to be able to do one read of 256 bytes from the flash, but i cannot re-generate the operation, to read multiple pages (chunks).

Here is my current code:
Code:
#BANK_DMA
int8 dma0_buffer[5] = {RD_OP, ADDR_2,ADDR_1,ADDR_0,DUMMY};

#BANK_DMA
int8 dma1_buffer[256]; // receive

....


#INT_DMA0
void dma0_isr(void)
{
  dma_start(1, DMA_FORCE_NOW, &dma1_buffer[0],255); // once the data send is over, call for receive dma of 256 bytes
  dma_0_done_flag = 1;
}

#INT_DMA1
void dma1_isr(void)
{
dma_1_done_flag = 1;
}



void main() // Main function
{
int8 rc = restart_cause(); // debug
initialize();

setup_dma(0, DMA_OUT_SPI2, DMA_BYTE);
setup_dma(1, DMA_IN_SPI2, DMA_BYTE|DMA_WRITE_NULL);

enable_interrupts(INT_DMA0);
enable_interrupts(INT_DMA1);

//..... code

// ask the flash for data

for(page_num=0;page_num<4 ; page_num++)
{
addr = addr + page_num*256;
dma0_buffer[1] = make8(addr,2);
dma0_buffer[2] = make8(addr,1);
dma0_buffer[3] = make8(addr,0);

output_low(FLASH_CS); // select flash
dma_start(1, DMA_ONE_SHOT, &dma1_buffer[0],4); // prepare to dummy read, no use of the incoming data caused from upcoming write (next_line)
dma_start(0, DMA_ONE_SHOT|DMA_FORCE_NOW, &dma0_buffer[0],4); // write the sequence needed in order to start false read

while(!dma_1_done_flag ){}; // as long as the receiving dma did not flag its done, stay here
output_high(FLASH_CS);

// code to read from dma_1 buffer and send via uart
// ...
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Tue May 24, 2022 3:03 am     Reply with quote

The reading device can start the transfer. You don't need to use the write
device:

Code:

dma_start(1, DMA_ONE_SHOT|DMA_FORCE_NOW,, &dma1_buffer[0],256);


This will write 256 nulls, and read the replies. If you have WRITE_NULL
selected this will do your read transaction.

However you must not call the setup_dma, until after you have done
the memory chip initialisation with SPI. You are not allowed to write to the
SPI buffer register except with DMA once the DMA transaction is setup.

To do another transfer just call another dma_start.
dman232323



Joined: 19 May 2022
Posts: 8

View user's profile Send private message

PostPosted: Tue May 24, 2022 5:04 am     Reply with quote

Thanks!
Got it to work.
its functioning well now.

Thanks Ttelmah for the help
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group