• ### Announcements

#### Archived

This topic is now archived and is closed to further replies.

# GBA- Waiting for DMA

## 12 posts in this topic

I am officially stumped. What''s the best way to wait for a DMA transfer to finish? I know you can adjust when it starts, but let''s say I''m telling it to start immediately. Now, what seems to be happening is it''s going further into the program without waiting for DMA to finish. I figure I could probably fix this with a simple while loop or something, but for the life of me I can''t find any way to tell when DMA is finished. Is there any way to track how much it''s copied, or when it''s finished...? -Arek the Absolute
0

##### Share on other sites
Can anyone at least tell me if my theory is reasonable? If I use DMA to fill the screen buffer, for instance, the fill color overlaps some of the lines I draw afterward. If I don''t fill the screen, there''s no problem. Is this DMA taking time after I set its registers? And is there anything I can do about it?

-Arek the Absolute
0

##### Share on other sites
To be honest I am not sure what exactly you are trying to do. If you are trying to do this in 3D be careful and test it on Boycott Advance since it is the only legal emulator because you could crash just unlikly

Anyway try this link and see if it help but I am still unsure what you are trying to accomplish.

http://www.doc.ic.ac.uk/~mac/manuals/hpux-manual-pages/hpux/usr/man/man7/framebuf.7.html

Good Luck and I will keep an eye on the thread because I would like to know if I am wrong or not.
0

##### Share on other sites
My code specifically:

  #include "smlib.h" /* include basic libraries, functions, etc. All taken from StaringMonkey''s examples, with DMA.h taken from Dovoto''s tutorials*/#define BUTTON(key) (!(*KEYS & key)) // macro for key inputu16* videoBuffer = (u16*)0x6000000;  // for writing to screenvoid DMA_FillScreen(void* color);    /* prototype for clear screen function*/int x = 0; int y = 0; // upper left corner of squareint main(void){	SetMode(MODE_3 | BG2_ENABLE); /* set to mode 3, enable BG2*/        // main game loop	while(1){                /* fill the screen in white, the function is defined below */                u16 color[] = {0xFFFF};                DMA_FillScreen((void*)color);                // adjust position according to key input		if (BUTTON(KEY_UP)){y--;}		if (BUTTON(KEY_DOWN)){y++;}		if (BUTTON(KEY_LEFT)){x--;}		if (BUTTON(KEY_RIGHT)){x++;}                /* draw the edges of the square using a simple Brasenham line algorithm */		Line(x,y,x,y+30,0x0FFF);		Line(x,y,x+30,y,0x0FFF);		Line(x+30,y,x+30,y+30,0x0FFF);		Line(x,y+30,x+30,y+30,0x0FFF);                // wait for the screen to finish drawing		while(REG_VCOUNT < 160){}	}}void DMA_FillScreen(void* color){	REG_DMA3SAD = (u32)color;	REG_DMA3DAD = (u32)VideoBuffer;	REG_DMA3CNT = 240*160 | DMA_ENABLE | DMA_TIMEING_IMMEDIATE | DMA_16 | DMA_SOURCE_FIXED | DMA_DEST_RELOAD;}

Now, if you compile it and run it, you don''t see anything other than a white screen. You can move the square down, however, and it begins to appear. It''s pretty obvious that either something is overlapping the square, or that the line functions aren''t working. However, if you comment out the DMA_FillScreen, the problem doesn''t happen! That means clearly something is overlapping the square. The only thing that accesses the screen other than the calls to Line is DMA_FillScreen. The only way I can see this is happening is if DMA still finishes filling the screen AFTER the lines are drawn. How can that be prevented?

All those functions, constants, etc can all be found on http://www.thepernproject.com either in StaringMonkey''s demos, or in Dovoto''s. (And I''m pretty sure I only used DMA.h from him)

-Arek the Absolute
0

##### Share on other sites
I always thought DMA halted the CPU, so your program stalls until it is completed... But in your situation that doesn''t appear to be the case. Are you testing on real hardware or emulator?
Is the VCOUNT register declared as volatile? Else GCC might optimize out the while loop that waits for vblank, causing your screen to tear...
Maybe it''s got something to do with the line drawing algorithm you use. Maybe you could try plotting some pixels yourself, see if the same is happening there.
As a final soluting (but only if nothing else helps, because it''s more of a hack) you could use an interrupt. They signal when a DMA transfer finishes. But that''s not the optimal solution.
Well, if all else fails you can always try the gbadev.org mailing list. That''s where the pros are. Good luck,

Jasper
0

##### Share on other sites
I''m not sure if this is right, but your using the flag DMA_DEST_RELOAD in the DMA register. Wouldn''t this cause the destination (in this case the video buffer) to revert to its original value after the DMA transfew is finished? So, shouldn''t you be using the flag DMA_DEST_INCREMENT instead?
0

##### Share on other sites
Aprosenf:
Thanks for pointing that out, and it is a good point. Unfortunately, I''ve tried it on all the possible settings, and that just happened to be the last one that I had it on when I posted the code. Thanks tho, I''d forgotten about that.
JasperW:
Man, I wish DMA did halt the CPU, but it seems I have no such luck. I''ve now tested it personally on VisualBoy Advance, BoyCott Advance, and on a real-life GBA, with the same results all around.
REG_VCOUNT is declared as volatile, but thanks anyway. And same with plotting pixels myself. They don''t show up in certain regions (top third or more of the screen) And even if that were the case, I have no idea what I''d be able to change. As I said earlier, the problem doesn''t happen if I don''t fill the screen using DMA. I''ll think about that interrupt, but as you say, that''s a last resort. I think I''ll take your advice on that mailing list.

Thanks a lot anyway, all around! Speak up if you think of anything! (At least I don''t feel stupid for not being able to figure it out anymore. )

-Arek the Absolute
0

##### Share on other sites
Hey,
I don''t know a solution to your problem, but from everything I''ve heard/read, DMA does halt the CPU and doesn''t release it until the copy is finished. Perhaps your code error is somewhere else?

--Nairb
0

##### Share on other sites
I was thinking about it some more when I realized that DMA transfer is taking up one hell of a lot of CPU cycles. You''re transferring 240 x 160 = 38400 16 bits values. I don''t know how long the transfer takes, but since you are using DMA16 at least 2 cycles per 16 bits and possibly more because of the wait states of the VRAM (I don''t know if the source address is in IWRAM or EWRAM, but if it''s in EWRAM it also adds 2 cycles per 16 bits).
This means you''re doing at least 38400 * 2 cycles = 76800 cycles (and probably more) per vblank while you''ve only 83776 cycles. So the internal clock might get messed up.
Try filling only one third of the screen or switch to 32 bits DMA (twice as fast). Let me know what your findings are. Good luck,

Jasper
0

##### Share on other sites
I think you may be on to something, JasperW. If I only fill one third of the screen, there''s no overlapping problem. Just a lot of old data in the bottom two thirds of the screen. If I switch to 32 bits, it draws every other pixel as black... Which means if I tell it to copy (240*160/3) pixels, it fills two thirds of the screen, but every other pixel is black instead of white. If I try to fill 240*160 pixels in 32 bit pieces, the overlapping problem still occurs. It would seem then, that the problem doesn''t occur in smaller DMA transfers. Unfortunately, I don''t really know how to solve that. If I use for loops, it takes way too long. And DMA''s doing this... Anyone have any ideas on ways around this mess?

-Arek the Absolute
0

##### Share on other sites
The black/white pixel problem can probably be solved by making color an u32 instead of an u16 and assigning it the value 0xFFFFFFFF (two pixels at a time). Or did you already do that? I thought 32 bits DMA to VRAM is possible but I''m no expert

Then on to the problem of the duration of the DMA. It seems nearly impossible to solve. One 32 bits transfer takes at a standard of 2 cycles plus the wait states of the memory you''re reading from and writing to.

You should make sure the color variable is in IWRAM (zero wait states) rather than EWRAM (2 cycles) but GCC might already do that (if not I don''t know how to do it). Make sure it isn''t defined as a constant and residing in ROM (lots of wait states). The wait states to video memory are variable so I don''t really know how much time they take but I''ll assume it''s about 2 cycles (same as EWRAM).

So the optimal 32 bit transfer takes standard + read + write = 2 + 0 + 2 = 4 cycles. You''ll need 240 * 160 / 2 = 19200 transfers, which mean 76800 cycles to fill the whole screen. Seeing that you have 83776 you should be able to make it in theory (!= practice). It does how leave you with very little time to do anything else...

You might want to consider switching to mode 4 or 5 where you have a backbuffer so you don''t have to worry too much about filling the screen in time. Or create a backbuffer for mode 3 in EWRAM, but that''s a lot of pain and effort. Other than that I really don''t know what to do. Well, that''s about it from me. Good luck,

Jasper
0

##### Share on other sites
Thanks for your help! I don''t know if I''ll ever be able to deal with Mode 3, but thanks for helping me with that. At least I know what''s going wrong, if not any way to solve it. I guess, however, if I ever figure things out I''m honor bound to write a tutorial, right? Don''t get your hopes up. I''ll probably be going to Mode 4 soon enough. Heh. Thanks, and BTW, I did get the u32 color[] = {0xFFFFFFFF}; thing, and copying does now work properly. Thanks!

-Arek the Absolute
0

##### Share on other sites
There was some stuff about this on the GBADev mailing list (www.gbadev.org) a while ago. If I remember correctly it was eventually decided it wasn''t possible to DMA an entire 15bpp screen in the vblank period. You could however transfer the new in image line by line in the hblank period (at the end of each line) much in the same way as the GBC worked with the camera.
0