gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > DMA overlapping concerns...

#19518 - TaleriaKNT - Wed Apr 21, 2004 7:40 am

Do I need to worry about trying to do another DMA transfer before the previous one has finished? If so, what would the exact effects be of doing that? Also, if so, how would I make sure not to do it?

#19520 - NoMis - Wed Apr 21, 2004 9:50 am

The DMA copy process starts not emidiatly after you set the REG_DMAxCNT to Enable. You have to wait 2 cycles i think thill the process starts. So you must not access the Source and Target registers in this time. I figured it out once, when i was doing more than 1 DMA copy in a row and just the last one was working.
If you have other things in you programm which have to be done put them between the DMA Copys. You can also use a fake loop wich does nothing or using Interrupts. There is an interrupt which is fired when an DMA copy has finished.

NoMis

#19528 - poslundc - Wed Apr 21, 2004 2:56 pm

In my experience, it works out cycle-wise if you assign 0 to REG_DMAXCNT before attempting to set up the next DMA transfer.

The incremental timing issues notwithstanding, the DMA halts the CPU, so you won't return to your program until after the DMA is finished. But yes, be careful if you are performing multiple DMA transfers in a row that you make sure to turn off the DMA before setting up the next transfer.

Dan.

#19546 - TaleriaKNT - Wed Apr 21, 2004 6:32 pm

poslundc wrote:
assign 0 to REG_DMAXCNT before attempting to set up the next DMA transfer.

Wouldn't this have the adverse affect of canceling the transfer?

poslundc wrote:
the DMA halts the CPU, so you won't return to your program until after the DMA is finished...make sure to turn off the DMA before setting up the next transfer.

Halt it for the entirety of the transfer? Doesn't that defeat the purpose of DMA, or am I missing something? And again, wouldn't turning it off stop the previous transfer and leave you with a half copied chunk of data?

#19548 - sajiimori - Wed Apr 21, 2004 7:31 pm

It halts the CPU. DMA is fast because the CPU doesn't have to keep fetching and executing load, store, compare, and branch instructions.

#19552 - TaleriaKNT - Wed Apr 21, 2004 9:07 pm

So then, just to make sure I'm clear on this...

It would be safe to:
1) Start a DMA transfer.
2) Set the appropriate DMA count(EDIT: Oops, I meant control...) register to 0 as the next command in order to make sure there's not a problem starting another.
3) Immediately initiate another transfer.

Sound right?


Last edited by TaleriaKNT on Thu Apr 22, 2004 12:06 am; edited 1 time in total

#19555 - Gopher - Wed Apr 21, 2004 10:31 pm

I've done consecutive DMA copies (one followed immediately by another, with no instructions inbetween) and yes, this is how it works. I didn't even set the count to 0 inbetween, since the count will be 0 when the previous DMA is done anyway.
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein

#19563 - tepples - Thu Apr 22, 2004 12:24 am

If you want to waste two cycles after starting a DMA, then just loading the source address from your constant pool will do that.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#19564 - Gopher - Thu Apr 22, 2004 12:26 am

yeah, I was unaware of the need for the 2-cycle delay, so this must be why mine hasn't broken, heh
hmmm... I just realised this might be why an old project of mine wasn't working right, that was doing some odd hblank tricks... <runs to look>
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein

#19593 - White Owl - Thu Apr 22, 2004 3:37 pm

so, the code like that should work?
Code:

REG_DMA3SAD = (u32)source1;
REG_DMA3DAD = (u32)dest1;
REG_DMA3CNT =  count1 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE |DMA_32;
REG_DMA3CNT = 0;
REG_DMA3SAD = (u32)source2;
REG_DMA3DAD = (u32)dest2;
REG_DMA3CNT = count2 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE |DMA_32;
REG_DMA3CNT = 0;

#19603 - TaleriaKNT - Thu Apr 22, 2004 7:12 pm

tepples, are you saying to copy the source address a second time once you've set everything up, like...
Code:
REG_DMA3SAD = (u32)source;
REG_DMA3DAD = (u32)dest;
REG_DMA3CNT = count | DMA_ENABLE | DMA_TIMEING_IMMEDIATE |DMA_32;
REG_DMA3SAD = (u32)source;

If your source is from a variable instead of a constant, would it be better to do the set to zero thing?

#19606 - poslundc - Thu Apr 22, 2004 7:29 pm

I think that part of the problem is that with an optimizing compiler you can't be assured of what order it is doing things. Even with the registers declared volatile (which will make the statements execute in the proper order) it could be loading in the values to store earlier on, and therefore not wasting the necessary cycles in between DMA uses.

Setting REG_DMAXCNT to 0 in between consecutive or tightly-looped DMA sequences is something that I've found will eliminate just about any errors that can occur due to timing and control issues with the DMA. You don't need to bother if you're just using the DMA in an isolated situation, but if you're either tightly looping or running a bunch of DMA transfers in a row, you can get errors on hardware if you don't do something like this.

Dan.