#152702 - krozen - Wed Mar 19, 2008 9:52 pm
Hi guys,
I'm messing about with DMA and interrupts, and using Toncs tutorial as a guide. In this tutorial, a DMA which copies one chunk is used to copy a colour from a palette into the first element of the palette. The source address is fixed, and the destination address moves. Also, this DMA transfer occurs every HBLANK.
I was trying to understand the basics behind this. If a DMA is set up in this way, does this mean the source address moves on by 1 on each HBLANK, even though they are two differents calls to the DMA transfer? Or, is it the same DMA transfer, that's just being put to sleep in between HBLANKs.
Cheers!
#152726 - eKid - Thu Mar 20, 2008 2:29 am
DMA has different settings that affect the behavior of the source/destination addresses after a transfer.
#152731 - wintermute - Thu Mar 20, 2008 3:25 am
Or, to answer the actual question :P ...
Yes, Hblank DMA is continuous and is put to sleep between hblanks.
I'd need to see the code you're talking about to comment further. If the source is fixed then it doesn't ever move so I'm not quite sure what you mean. It's also more common to have a fixed destination with a moving source for HDMA, handy for mode7 style effects & circular windows.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog
#152739 - HyperHacker - Thu Mar 20, 2008 9:01 am
Yeah, I figured he meant moving source, fixed destination, to automatically change a colour every scanline. The other way around doesn't make much sense unless you want to slowly clear the palette, maybe for some weird fade effect.
_________________
I'm a PSP hacker now, but I still <3 DS.
#152751 - krozen - Thu Mar 20, 2008 11:58 am
Hi guys,
Yes, HyperHacker, that's what I meant. Typo in my original post - sorry about that.
Cheers for your responses anyway. Just needed to confirm my original thoughts.
So, this can be used for circular window effects. Does this mean you have an array of window size values for each scanline. Then just have the destination as the window x and y extents, and the source as the array of window size values?
What other kind of nice HDMA effects can be achieved in this way?
Thanks again
#152850 - SiW - Fri Mar 21, 2008 5:45 pm
I'm having the damndest time getting this to work for a simple gradient effect. I tried a while ago and just ended up doing it in the hblank IRQ instead, but I want to get this to work.
What's wrong with this?
Code: |
u16 gradient[193];
BuildGradient( gradient, 192, RGB15(9,9,15), RGB15(27,27,31) );
gradient[192] = gradient[0];
while ( PlayingReallyAwesomeGame )
{
// ...
swiWaitForVBlank();
DMA_SRC(3) = (u32)(&gradient[1]);
DMA_DEST(3) = (u32)(&BG_PALETTE_SUB[0]);
DMA_CR(3) = DMA_ENABLE | DMA_16_BIT | DMA_REPEAT | DMA_START_HBL | DMA_SRC_INC | DMA_DST_FIX | ( (u32)1 >> 1 );
while ( DMA_CR(3) & DMA_BUSY );
};
|
#152865 - Cydrak - Fri Mar 21, 2008 10:57 pm
It'd be nice to know what it's doing, but I'll hazard a guess or two.
First, you're changing a single halfword each hblank, so you want a count of 1 (rather than 1>>1 = 0, which I think is max count). Also try removing the wait... it's a repeating transfer, after all. The timing is scheduled automatically, so you can go off and do more important things.
#152866 - SiW - Fri Mar 21, 2008 11:54 pm
Thanks for the input. Yes, I should have given some symptoms :)
For debugging purposes, I'm now filling my gradient buffer with yellow (RGB15(31,31,0)) and what was happening with the code as I posted it was that it would freeze ("it" being no$gba or hardware) as soon as my DMA call started.
Making the changes you suggested, the background flashes yellow about two thirds, the rest black, then switches to completely black and freezes. I've tried different DMA channels too, no change.
#152869 - Cydrak - Sat Mar 22, 2008 1:11 am
Sorry, couple things I should have mentioned. :-)
DMA doesn't know anything about TCM or cache. This becomes a problem as the stack is in DTCM, so transfer from a local array won't work. It needs to be somewhere in RAM or VRAM (such as by making it global or static). Further, if in RAM, you may need to flush changes out of cache.
Also, to make the new DMA_SRC / DMA_DEST settings "stick", DMA_ENABLE needs to be zero beforehand; it only responds when changed:
Code: |
DC_FlushRange(gradient, sizeof(gradient));
...
while( awesomeness )
{
swiWaitForVBlank();
...
DMA_CR(0) = 0;
DMA_SRC(0) = (u32)&gradient[1];
DMA_DEST(0) = (u32)&BG_PALETTE[0];
DMA_CR(0) = DMA_ENABLE | DMA_REPEAT | DMA_START_HBL | DMA_DST_RESET | 1;
...
} |
#152925 - SiW - Sat Mar 22, 2008 6:38 pm
Okay, thanks. With these pointers I was able to get a simple test working properly.
In my actual project however, it still wasn't working. I tracked it down to my usage of glCallList (I'm doing 3D on the other screen) and after looking at that code I understood why I was getting the freeze - it waits for all other DMA to finish, and as you pointed out, with HDMA being repeating it wasn't going to play nice.
My solution was to do my HDMA on channel 2 (3 interferes with some of my other code) and use my own version of glCallList, removing the busy check for channel 2. I will heed the comment warning that "FIFO DMA is touchy as hell" however if I run into any problems in the future.