|
|
View previous topic :: View next topic |
Author |
Message |
dman232323
Joined: 19 May 2022 Posts: 8
|
DSPIC33: SPI AND DMA |
Posted: Thu May 19, 2022 5:05 am |
|
|
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
|
|
Posted: Thu May 19, 2022 5:58 am |
|
|
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
|
|
Posted: Thu May 19, 2022 6:08 am |
|
|
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
|
|
Posted: Thu May 19, 2022 6:18 am |
|
|
The key thing you are missing is the difference between DMA_CONTINUOUS
and DMA_ONE_SHOT. |
|
|
dman232323
Joined: 19 May 2022 Posts: 8
|
|
Posted: Thu May 19, 2022 6:24 am |
|
|
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
|
|
Posted: Thu May 19, 2022 6:47 am |
|
|
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
|
|
Posted: Thu May 19, 2022 7:13 am |
|
|
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
|
|
Posted: Thu May 19, 2022 8:46 am |
|
|
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
|
|
Posted: Thu May 19, 2022 9:51 am |
|
|
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
|
|
Posted: Thu May 19, 2022 1:03 pm |
|
|
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
|
|
Posted: Thu May 19, 2022 1:45 pm |
|
|
I will not be at the lab for the next couple of days, but i can't let go
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
|
|
Posted: Sun May 22, 2022 4:08 am |
|
|
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
|
|
Posted: Tue May 24, 2022 3:03 am |
|
|
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
|
|
Posted: Tue May 24, 2022 5:04 am |
|
|
Thanks!
Got it to work.
its functioning well now.
Thanks Ttelmah for the help |
|
|
|
|
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
|