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.

Coding > DMA trouble

#5756 - Daikath - Thu May 08, 2003 4:42 am

For some mysterious reason I can't seem to use DMA's, the data is as fine as it gets as it works fine with a for loop but I just want to know how to use DMA.

Code:

REG_DMA3SAD = (u32)tilesPalette;
REG_DMA3DAD = (u32)BGPaletteMem;
REG_DMA3CNT_L = 256;
REG_DMA3CNT_H = DMA_16NOW;

REG_DMA3SAD = (u32)tilesData;
REG_DMA3DAD = (u32)BGMem;
REG_DMA3CNT_L = 128*128/2;
REG_DMA3CNT_H = DMA_16NOW;
   
REG_DMA3SAD = (u32)New;
REG_DMA3DAD = (u32)FrontBuffer;
REG_DMA3CNT_L = 32*32;
REG_DMA3CNT_H = DMA_16NOW;


With these defines
Code:

#define DMA_ENABLE 0x80000000
#define DMA_TIMEING_IMMEDIATE 0x00000000
#define DMA_16NOW DMA_ENABLE | DMA_TIMEING_IMMEDIATE| DMA_16

_________________
?There are no stupid questions but there are a LOT of inquisitive idiots.?

#5757 - niltsair - Thu May 08, 2003 4:49 am

Those 2 :
REG_DMA3CNT_L
REG_DMA3CNT_H

Are 16 bits pointers. And you try to give them 32bits values :
#define DMA_ENABLE 0x80000000
#define DMA_TIMEING_IMMEDIATE 0x00000000
#define DMA_16NOW DMA_ENABLE | DMA_TIMEING_IMMEDIATE| DMA_16

So, either transform those defines to 16bits, or use them as they should, by adressing the register in 1 shot, in 32bits :
REG_DMA3SAD = (u32)tilesPalette;
REG_DMA3DAD = (u32)BGPaletteMem;
REG_DMA3CNT = DMA_16NOW | 256;

I did the exact same thing at first ;-)

#5758 - Daikath - Thu May 08, 2003 4:57 am

Sorry for some weird reason I only see a all black palette when I check it in Visual Boy Advance.
_________________
?There are no stupid questions but there are a LOT of inquisitive idiots.?

#5760 - niltsair - Thu May 08, 2003 5:42 am

You changed yours REG_DMA3CNT_L, REG_DMA3CNT_H for 1 REG_DMA3CNT ?

Here's what i use and that work perfectly fine :

#define DMA_ENABLE 0x80000000
#define DMA_TIMEING_IMMEDIATE 0x00000000
#define DMA_16 0x00000000
#define DMA_16NOW (DMA_ENABLE | DMA_TIMEING_IMMEDIATE |DMA_16)

REG_DMA3SAD = (u32)pic;
REG_DMA3DAD = (u32)VideoBuffer;
REG_DMA3CNT = 160*240 | DMA_16NOW;

Which is also what you basicly do. So the problem must be elsewhere. Are tilesPalette; and the other variable, pointers on 16bits data? Because that's the only thing that could be wrong, non 16bits aligned data. Else, beside wrong pointers, i really don't see what might be wrong.

#5762 - Daikath - Thu May 08, 2003 6:11 am

Lol, just my luck. I was also stuck 3 months getting a sprite to animate or move at all because REG_VCOUNT wasnt defined as a volatile. Am I just cursed to take the hardest way or what? ;)

Anyways I uploaded my entire source file, hopefully this'll help because I just can't seem to fix it.

http://212.187.35.37/jordi/tegelachtergronden.zip
_________________
?There are no stupid questions but there are a LOT of inquisitive idiots.?

#5776 - niltsair - Thu May 08, 2003 2:22 pm

I'll have a quick look at it tonight (in ~9 hours :-) )

#5796 - jenswa - Thu May 08, 2003 6:57 pm

What you're trying to do is loading background stuff,
like tiles and maps.

I also tried that, but couldn't get it to work,
although you're palettes must work, since i load my palettes
the same way and they work fine, also loading sprite graphics
is going fine, just the background stuff isn't.

I'd love to hear a solution.
_________________
It seems this wasn't lost after all.

#5797 - niltsair - Thu May 08, 2003 7:03 pm

Just a thought, are you waiting for VSync before sending your datas? I know they can get sheared, but i think(am i'm really not positive on this) that you can't update certain area unless your scanline is below 160.

#5801 - Daikath - Thu May 08, 2003 9:19 pm

I use WaitforVsync after copying the data.
_________________
?There are no stupid questions but there are a LOT of inquisitive idiots.?

#5805 - niltsair - Thu May 08, 2003 9:42 pm

should be done before copying the data. The point is to wait for VSync to have completed refreshing the screen, then you can change things to the display, before it start displaying again.

#5814 - niltsair - Fri May 09, 2003 12:04 am

Ehehehehehehe, you'l love this one.

I checked your code, stripped everything without getting it to work. Was really swamped as to why it wouldn't work....

Remember that older thing you got stuck on? ;-)
Code:

#define REG_DMA3SAD    *(volatile u32*)0x40000D4      /* DMA3 Source Address */
#define REG_DMA3SAD_L  *(volatile u16*)0x40000D4      /* DMA3 Source Address Low Value */
#define REG_DMA3SAD_H  *(volatile u16*)0x40000D6      /* DMA3 Source Address High Value */
#define REG_DMA3DAD    *(volatile u32*)0x40000D8      /* DMA3 Destination Address */
#define REG_DMA3DAD_L  *(volatile u16*)0x40000D8      /* DMA3 Destination Address Low Value */
#define REG_DMA3DAD_H  *(volatile u16*)0x40000DA      /* DMA3 Destination Address High Value */
#define REG_DMA3CNT    *(volatile u32*)0x40000DC      /* DMA3 Control (Amount) */
#define REG_DMA3CNT_L  *(volatile u16*)0x40000DC      /* DMA3 Control Low Value */
#define REG_DMA3CNT_H  *(volatile u16*)0x40000DE      /* DMA3 Control High Value */


:-) Just declare all your register's variable as volatile. And Voil?.
The most esthetic way to do this is :
#define vu8 volatile unsigned char
#define vu16 volatile unsigned short...

#5815 - Daikath - Fri May 09, 2003 12:16 am

Could you send me the entire source document you made? Because even with those registers registered as a volatile it doesnt do anything different here.
_________________
?There are no stupid questions but there are a LOT of inquisitive idiots.?

#5816 - niltsair - Fri May 09, 2003 12:50 am

Put every register to volatile, especially :

#define REG_VCOUNT *(volatile u16*)0x4000006 /* Vertical Control (Sync) */

#5820 - niltsair - Fri May 09, 2003 2:04 am

Here's the solution:
---Removed---

Just do a seach on //SF to find where i changed things.

But really, the only problems were :
1. Needed to declare every register pointer, as volatile
2. When you were passing your array address, you didn't need to do '&Array', only 'Array' since an array is a pointer, you were passing the pointer address and not the data address.


Last edited by niltsair on Sat May 10, 2003 12:34 am; edited 1 time in total

#5822 - Daikath - Fri May 09, 2003 3:20 am

*kisses niltsair on the lips*

thank you! heil niltsair!
_________________
?There are no stupid questions but there are a LOT of inquisitive idiots.?

#5823 - niltsair - Fri May 09, 2003 4:46 am

Errrr, if you're a guy, no needs for that really. And if you're a girl, well i'm not sure my girlfriend would approve :-) A small 20$ would be enough ;-)

#6982 - hzx - Thu Jun 05, 2003 7:20 pm

hello

I totally stucked with a code, and it seems to be a DMA problem, maybe similar with the aforementioned one. It wants to be a mode3 double buffer, in which you always draw into the background buffer and then copy it to VideoBuffer on VBlank. Here it is:

u16 *DrawBuffer = (u16 *)0x02000000;

// Backbuffer in EWRAM, because it is bigger than 32K

void Wkey() {
while ((*KEYS) & 1) {
};
}

// just for debugging purposes

void CopyDrawBuffer() {

REG_DMA3SAD = (u32)DrawBuffer;
REG_DMA3DAD = 0x06000000;
REG_DMA3CNT = 38400 | DMA_ENABLE;

}

// use DMA to copy the backbuffer to VideoBuffer

void DMAClearDrawBuffer() {

REG_DMA3SAD = 0x05000000;
REG_DMA3DAD = (u32)DrawBuffer;
REG_DMA3CNT = 38400 | DMA_ENABLE | DMA_SOURCE_FIXED;
}

// this one clears the backbuffer. Takes the zero value from the Palette[0]

void StupidClear() {

int i;
for (i = 0; i < 38400; i++) {
DrawBuffer[i] = 0;
}
}

// a debug clearscreen, filling background buffer with zeros

int main() {

int i;

SetMode(MODE_3 | BG2_ENABLE);

i = 1000; // for a little demonstration

while(1) {
DrawBuffer[i] = RGB16(31,31,31);
WaitForVSync();
CopyDrawBuffer();
Wkey();
i++;
DMAClearDrawBuffer();
// StupidClear();
}

So, when i run the code, the screen remains blank until the first keypress, which is strange, because the CopyDrawBuffer should display the white pixel in the 1000th position of VideoBuffer. After the first keypress, the code works as it is expected, BUT! only with the stupid clear routine - the DMA version clears the screen though, the program doesnt work at all. Maybe i am missing some oblivious, but i cannot see it. Somebody can help me? As the last thing, i suspected the compiler, but i am not smart enough to write an asm code to setup DMA regs yet.
_________________
.hzx

#6983 - jenswa - Thu Jun 05, 2003 7:33 pm

The gba draws two pixels at a time,
so not one like your trying.

If you want one white pixel and you need to draw two pixels,
what will you do? There is more than one way.

Just write a white pixel where you want it, followed by tranparent.
That should work.
_________________
It seems this wasn't lost after all.

#6989 - niltsair - Thu Jun 05, 2003 8:11 pm

Jenswa: No, this part is ok. The 2 pixels writing only apply in 256colors mode, (and 4pixels for 16colors mode). In mode 3, a pixel takes 16bits, so you write one at a time.

#6999 - hzx - Thu Jun 05, 2003 9:56 pm

jenswa wrote:
The gba draws two pixels at a time,
so not one like your trying.

If you want one white pixel and you need to draw two pixels,
what will you do? There is more than one way.

Just write a white pixel where you want it, followed by tranparent.
That should work.


Jenswa, I'm afraid you missed the point in my case. In mode3 you write one pixel with a 16 bit transfer, and there are no "transparent" pixels IMHO. The strange thing is that this code works if you use the SillyClear function, and does not, if you use the DMA for clearing the backbuffer. If you set Palette[0] to an other color (RGB16(31,0,0) for example), you can see that it actually clears the backbuffer, and thus the VideoBuffer, just halts the running of the program somehow.
_________________
.hzx

#7034 - hzx - Fri Jun 06, 2003 3:18 pm

Damn, I figured it out! This code won't work if you compile it with the -O2 optimizing option. But goes perfectly, if compile without.
_________________
.hzx

#7040 - niltsair - Fri Jun 06, 2003 5:12 pm

Ah, the typical error ;-)

Declare all your register's pointers as 'volatile'. Should work fine with -O2 afterward.

#7043 - tepples - Fri Jun 06, 2003 5:31 pm

Also, make sure to set DMA3CNT to 0 before setting up the copy. If DMA3CNT is not 0, then the DMA3 registers may be write-protected.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#7059 - Lupin - Sat Jun 07, 2003 2:42 pm

I played around with loading up tile maps, and I used this code to load an 512p(32t) x 512p(32t) map

Could I do it with less DMA copies?

u16 y;
for(y = 0; y < 64; y++) {
if(y<32) {
DMACopyCH3((void*)planets_MapData+y*128, (void*)pMapData+y*64, 16, DMA_32NOW);
DMACopyCH3((void*)planets_MapData+64+y*128, (void*)pMapData+y*64+2048, 16, DMA_32NOW);
}else{
DMACopyCH3((void*)planets_MapData+y*128, (void*)pMapData+(y-32)*64+4096, 16, DMA_32NOW);
DMACopyCH3((void*)planets_MapData+64+y*128, (void*)pMapData+(y-32)*64+6144, 16, DMA_32NOW);
}
}