GBA- Waiting for DMA

Started by
11 comments, last by Arek the Absolute 22 years ago
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
-Arek the Absolute"The full quartet is pirates, ninjas, zombies, and robots. Create a game which involves all four, and you risk being blinded by the sheer level of coolness involved." - Superpig
Advertisement
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
-Arek the Absolute"The full quartet is pirates, ninjas, zombies, and robots. Create a game which involves all four, and you risk being blinded by the sheer level of coolness involved." - Superpig
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.
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
-Arek the Absolute"The full quartet is pirates, ninjas, zombies, and robots. Create a game which involves all four, and you risk being blinded by the sheer level of coolness involved." - Superpig
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
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?
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
-Arek the Absolute"The full quartet is pirates, ninjas, zombies, and robots. Create a game which involves all four, and you risk being blinded by the sheer level of coolness involved." - Superpig
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
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
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
-Arek the Absolute"The full quartet is pirates, ninjas, zombies, and robots. Create a game which involves all four, and you risk being blinded by the sheer level of coolness involved." - Superpig

This topic is closed to new replies.

Advertisement