Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20803 Discussions

URGENT: Peripheral to Memory DMA Transaction

Altera_Forum
Honored Contributor II
5,820 Views

Hello, may I know how to transfer data from peripheral to memory using DMA? It is quite confusing from memory-to-memory transfer. please help! thanks!

0 Kudos
111 Replies
Altera_Forum
Honored Contributor II
762 Views

Do you wait for the transfer to finish?  

 

Also, 0x199 does not seem correct. I thought you data is 32bit wide?
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

Oh... yeah 32bit... how to wait for transfer to finish?

0 Kudos
Altera_Forum
Honored Contributor II
762 Views

while (IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE) & 1)==0); ? 

but I'd suggest using usleep until you confirm the DMA working.
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

i tried but still cant... can you pls provide me a fragment of code of how it run, like i am just using FIFO as peripherals? data is 0-9

0 Kudos
Altera_Forum
Honored Contributor II
762 Views

Your SOPC connections are ok?

0 Kudos
Altera_Forum
Honored Contributor II
762 Views

In the attachment is my SOPC connection. I connect both DMA write and read to the peripheral.

0 Kudos
Altera_Forum
Honored Contributor II
762 Views

Looks ok to me. 

Try reading back the DMA registers, if the correct values are really set.
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

currently, this is my code: 

 

--- Quote Start ---  

# include "io.h"# include <stdio.h># include <unistd.h># include <sys/alt_dma.h># include "altera_avalon_dma_regs.h"# include "altera_avalon_pio_regs.h"# include "alt_types.h"# include "system.h" 

//#include "sys/alt_timestamp.h" 

 

int main() 

int i; 

unsigned int dst = SDRAM_BASE + 0x200000; 

for(i=0; i<128; i++) 

IOWR_32DIRECT(PERIPHERAL_0_BASE, 0, i); 

//printf("%d\n", IORD_32DIRECT(PERIPHERAL_0_BASE, 0)); 

 

IOWR_ALTERA_AVALON_DMA_STATUS(DMA_BASE, 0x00); 

printf("%d\n", IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE)); 

IOWR_32DIRECT(PERIPHERAL_0_BASE, 0, i); 

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, PERIPHERAL_0_BASE); 

IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE,dst); 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_BASE,100); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE,0x19C); 

usleep(200000); 

 

for(i=0; i<128; i++) 

printf("%d\n", IORD_32DIRECT(dst, i)); 

 

return 0; 

}  

 

--- Quote End ---  

i dont know if the arrangement of my code is correct.  

 

update: i just manage to get the result for this: printf("%d\n", IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE)); which is 0
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

That's strange, because either done or busy should be set. 

What values do you read from the other registers? 

Try setting the control register first to 0x194, then read it back, and at last 0x19c to add the Run bit. 

I'm not certain the DMA will start if the control reg is set to run from Zero. 

 

Are you sure, you want to enable the interrupt? 

 

Maybe it's neccessary to first issue a softreset. 

 

Edit: 

Now I see you read the status right after you reset it. 

Try reading it later on, to see what happened to the DMA....
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

I think now my DMA is working... But it seems like it cannot write into the memory.. my code: 

 

 

--- Quote Start ---  

#include "io.h"# include <stdio.h># include <unistd.h># include <sys/alt_dma.h># include "altera_avalon_dma_regs.h"# include "altera_avalon_pio_regs.h"# include "alt_types.h"# include "system.h" 

 

int main() 

int i; 

 

for(i=0; i<100; i++) 

{  

IOWR(PERIPHERAL_0_BASE, 0, i); 

IOWR_ALTERA_AVALON_DMA_STATUS(DMA_BASE, 0x00); 

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, PERIPHERAL_0_BASE); 

IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE, EXT_SRAM_BASE); 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_BASE, 200); 

 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x1102); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x10A); 

 

printf("done\n"); 

 

for(i=0; i<100; i++) 

printf("%d\n", IORD(EXT_SRAM_BASE, i)); 

}  

 

 

return 0; 

}  

--- Quote End ---  

i disable the interrupt and add in the softreset initially... 

 

update: result is: 

 

done 

-1 

-1 

-1 

-1 then all are -1....
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

i'm not sure if it is ok to configure the DMA when issuing a reset. 

Doesn't the DMA reset the registers then? 

Resetting the DMA should be the very first thing to do....
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

is it reset the DMA first only then write 0x00 into the dma status? result i got: 

result is: 

 

done 

-1 

-1 

-1 

-1 then all are -1....
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

 

--- Quote Start ---  

#include "io.h"# include <stdio.h># include <unistd.h># include <sys/alt_dma.h># include "altera_avalon_dma_regs.h"# include "altera_avalon_pio_regs.h"# include "alt_types.h"# include "system.h" 

 

int main() 

int i; 

 

for(i=0; i<100; i++) 

{  

IOWR(PERIPHERAL_0_BASE, 0, i); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x1000); 

IOWR_ALTERA_AVALON_DMA_STATUS(DMA_BASE, 0x00); 

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, PERIPHERAL_0_BASE); 

IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE, EXT_SRAM_BASE); 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_BASE, 200); 

 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x102); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x10A); 

 

printf("done\n"); 

 

for(i=0; i<100; i++) 

printf("%d\n", IORD(EXT_SRAM_BASE, i)); 

}  

 

 

return 0; 

}  

--- Quote End ---  

 

 

result: 

 

--- Quote Start ---  

done 

131072 

393220 

655368 

917516 

1179664 

1441812 

1703960....  

--- Quote End ---  

until finish, all are random numbers
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

maybe is it because i dont disable the dma in BSP setting? because i cant find it in Nios II IDE 9.0

0 Kudos
Altera_Forum
Honored Contributor II
762 Views

That might be a reason. The NIOS manual is clear in this case: 

 

--- Quote Start ---  

If ... the HAL driver is active for the same device, your driver will conflict and fail to operate. 

--- Quote End ---  

 

 

As I already said, check the DMA register contents, whether the HAl driver interferes with your settings. Do it at least before issuing the run bit.
0 Kudos
Altera_Forum
Honored Contributor II
762 Views

Yes, I just read all the registers and the values are all correct. before i print out the result, the DONE is already '1' and status is '10001' in binary, suppose finish running. But still, in the dst, cant get the result. my new code is as below, DMA transfer data from SDRAM to peripheral, then second DMA_0 transfer from peripheral to EXT_SRAM.  

 

 

--- Quote Start ---  

# include "io.h"# include <stdio.h># include <unistd.h># include <sys/alt_dma.h># include "altera_avalon_dma_regs.h"# include "altera_avalon_pio_regs.h"# include "alt_types.h"# include "system.h" 

 

int main() 

int i; 

 

unsigned int src = SDRAM_BASE + 0x200000; 

unsigned int dst = EXT_SRAM_BASE; 

 

for(i=0; i<100; i++) 

IOWR(src, i, 1); 

printf("initial: %d\n", IORD(src, i)); 

}  

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x1000); 

printf("ctrl1: %d\n", IORD_ALTERA_AVALON_DMA_CONTROL(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE, 0x1000); 

printf("ctrl2: %d\n", IORD_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE)); 

IOWR_ALTERA_AVALON_DMA_STATUS(DMA_BASE, 0x00); 

printf("stat1: %d\n", IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE, 0x00); 

printf("stat2: %d\n", IORD_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE)); 

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE, src); 

printf("rdadd1: %d\n", IORD_ALTERA_AVALON_DMA_RADDRESS(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE, PERIPHERAL_0_BASE); 

printf("wradd1: %d\n", IORD_ALTERA_AVALON_DMA_WADDRESS(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_0_BASE, PERIPHERAL_0_BASE); 

printf("rdadd2: %d\n", IORD_ALTERA_AVALON_DMA_RADDRESS(DMA_0_BASE)); 

IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_0_BASE, dst); 

printf("wradd2: %d\n", IORD_ALTERA_AVALON_DMA_WADDRESS(DMA_0_BASE)); 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_BASE, 200); 

printf("len1: %d\n", IORD_ALTERA_AVALON_DMA_LENGTH(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_0_BASE, 200); 

printf("len2: %d\n", IORD_ALTERA_AVALON_DMA_LENGTH(DMA_0_BASE)); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x282); 

printf("crtl1: %d\n", IORD_ALTERA_AVALON_DMA_CONTROL(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE, 0x182); 

printf("ctrl2: %d\n", IORD_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE)); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_BASE, 0x28A); 

printf("run1: %d\n", IORD_ALTERA_AVALON_DMA_CONTROL(DMA_BASE)); 

IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE, 0x18A); 

printf("run2: %d\n", IORD_ALTERA_AVALON_DMA_CONTROL(DMA_0_BASE)); 

printf("status: %d\t%d\n", IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE), IORD_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE)); 

for(i=0;i<100;i++) 

printf("waiting\n"); 

printf("status: %d\t%d\n", IORD_ALTERA_AVALON_DMA_STATUS(DMA_BASE), IORD_ALTERA_AVALON_DMA_STATUS(DMA_0_BASE)); 

printf("done\n"); 

 

for(i=0; i<100; i++) 

printf("end: %d\n", IORD(dst, i)); 

}  

 

 

return 0; 

}  

 

--- Quote End ---  

 

 

pls help me to check the flow of my code. i am not sure if i arrange the calling function in such way is correct or not. i am afraid, maybe sometimes the data hasnt arrive and DMA also start fetching the data. pls help me to check. thanks!
0 Kudos
Altera_Forum
Honored Contributor II
763 Views

my registers: all in decimals 

 

 

--- Quote Start ---  

 

ctrl1: 4096 

ctrl2: 4096 

stat1: 0 

stat2: 0 

rdadd1: 10485760 

wradd1: 17838208 

rdradd2: 17838208 

wradd2: 17301504 

len1: 200 

len2: 200 

crtl1: 642 

ctrl2: 386 

run1: 650 

run2: 394 

status: 17 17 

 

--- Quote End ---  

0 Kudos
Altera_Forum
Honored Contributor II
763 Views

So the DMA seems to work. 

Why are you setting every register double time? 

Why are you setting it to different values? 

e.g the control register is first set to constant write address, then to constant read address. 

When you start the transaction, you set it again to constant write address, then start it again with constant read address. If the DMA was not finished at that time, your code might confuse it during operation... 

 

You can read these register as often as you like, but you should only need to write them only once. The values should not change until the DMA is really started, even afterwards most of them should still read the same values.
0 Kudos
Altera_Forum
Honored Contributor II
763 Views

I am quite confuse with the register as well. But I am using two different DMA in the system. One is for memory to peripheral and another is for peripheral to memory. Do you mind suggest me a solution? thanks!

0 Kudos
Altera_Forum
Honored Contributor II
763 Views

oh, i didn't see there's 2 base addresses DMA_BASE and DMA_0_BASE. 

So then it should be ok....
0 Kudos
Altera_Forum
Honored Contributor II
763 Views

Haha, I think I got it... 

your "random" numbers don't seem so random to me.... 

 

131072 = 0x20000 

393220 = 0x60004 

655368 = 0xA0008 

917516 = 0xE000C 

and so on... 

 

Is either of your RAM or your periphereal 16bit wide? 

 

Instead of doing a IORD(dst,i) try doing a IORD_16DIRECT(), that shoud do the trick... 

 

Edit: 

Maybe you must do IORD_16DIRECT(dst, i*2), because it might use a byte offset. 

IORD() itself already converted the offset to bus width, which it thought being 32bit.
0 Kudos
Reply