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 > Background woe

#134902 - ShannonB - Wed Jul 18, 2007 4:16 am

First off, all of this code is shamelessly ripped off from Jonathan Harbour's book on GBA programming. I'm just trying to figure out how it works before I write my own. The theory all makes sense in my head, it should work, it even compiles with no errors, except nothing appears on the screen. Nada. Big black nothingness.

I made my own tilemap, palette and tile data. I don't think they are the problem. I've even dumped them into the main.cpp file (after converting to a c++ array) just to simplify stuff. Still compiles. Personally I have a feeling the problem is with the DMAfastcopy function.

I ran the code in the VBA emulator and when opened the palette and map in VBA there was nothing there. Somehow I think the data just isn't being copied into the correct memory location.

I'll try to keep this as short as possible and as organized as possible:

Code:

const unsigned short test_Palette[256] = {
0x7fff, 0x25f5, 0x2658, 0x2637, 0x2636, 0x2615,........yadda yadda, this goes on for a while, not going to paste an entire 256 element array here...};

const unsigned char test_Tiles[28416] = {
0xf6, 0xed, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2...erm, as above...};

const unsigned short test_Map[1024] = {
0x0000, 0x0001, 0x0001, 0x0002, 0x0000, 0x0001, 0x0001, 0x0003,
0x0004, 0x0001, 0x0001...one last time for the tilemap...};


Next my header code. No, it's not in a separate file. I'm trying to keep this simple until I can figure out what the problem is.

Code:


//defines needed by DMAFastCopy
#define REG_DMA3SAD * (volatile unsigned int*) 0x40000D4
#define REG_DMA3DAD * (volatile unsigned int*) 0x40000DC
#define REG_DMA3CNT *(volatile unsigned int*)0x40000DC
#define DMA_ENABLE 0x80000000
#define DMA_TIMING_IMMEDIATE 0x00000000
#define DMA_16 0x00000000
#define DMA_32 0x04000000
#define DMA_32NOW (DMA_ENABLE | DMA_TIMING_IMMEDIATE | DMA_32)
#define DMA_16NOW (DMA_ENABLE | DMA_TIMING_IMMEDIATE | DMA_16)

//scrolling registers for background 0
#define REG_BG0HOFS *(volatile unsigned short*)0x4000010
#define REG_BG0VOFS *(volatile unsigned short*)0x4000012

//background setup registers and data
#define REG_BG0CNT *(volatile unsigned short*)0x4000008
#define REG_BG1CNT *(volatile unsigned short*)0x400000A
#define REG_BG2CNT *(volatile unsigned short*)0x400000C
#define REG_BG3CNT *(volatile unsigned short*)0x400000E
#define BG_COLOR256 0x80
#define CHAR_SHIFT 2
#define SCREEN_SHIFT 8
#define WRAPAROUND 0x1

//background tile bitmap sizes
#define TEXTBG_SIZE_256x256 0x0
#define TEXTBG_SIZE_256x512 0x8000
#define TEXTBG_SIZE_512x256 0x4000
#define TEXTBG_SIZE_512x512 0xC000

//background memory offset macros
#define CharBaseBlock(n) (((n)*0x4000)+0x6000000)
#define ScreenBaseBlock(n) (((n)*0x800)+0x6000000)

//background mode identifiers
#define BG0_ENABLE 0x100
#define BG1_ENABLE 0x200
#define BG2_ENABLE 0x400
#define BG3_ENABLE 0x800

//video identifiers
#define REG_DISPCNT *(unsigned int*)0x4000000
#define BGPaletteMem ((unsigned short*)0x5000000)
#define SetMode(mode) REG_DISPCNT = (mode)

//vertical refresh register
#define REG_DISPSTAT *(volatile unsigned short*)0x4000004

//button identifiers
#define BUTTON_RIGHT 16
#define BUTTON_LEFT 32
#define BUTTON_UP 64
#define BUTTON_DOWN 128
#define BUTTONS (*(volatile unsigned int*)0x04000130)

//function prototype
void DMAFastCopy (void*, void*, unsigned int, unsigned int);

//wait for vertical refresh
void WaitVBlank(void)
{
while((REG_DISPSTAT & 1));
}



Lastly the main() and game loop.

Code:

int main(void)
{
int x = 0, y = 0;
int n;

//create a pointer to background 0 tilemap buffer
unsigned short* bg0map =(unsigned short*)ScreenBaseBlock(31);

//set up background 0
REG_BG0CNT = BG_COLOR256 | TEXTBG_SIZE_256x256 | (31 << SCREEN_SHIFT) | WRAPAROUND;

//set video mode 0 with background 0
SetMode(0 | BG0_ENABLE);

//copy the palette into the background palette memory
DMAFastCopy((void*)test_Palette, (void*)BGPaletteMem, 256, DMA_16NOW);

//copy the tile images into the tile memory
 //DMAFastCopy((void*)test_Tiles, (void*)CharBaseBlock(0), 57984/4, DMA_32NOW);
DMAFastCopy((void*)test_Tiles, (void*)CharBaseBlock(0), 28416/4, DMA_32NOW);


//copy the tile map into background 0
DMAFastCopy((void*)test_Map, (void*)bg0map, 1024, DMA_32NOW);

   //main game loop
   while(1)
   {
   
   //wait for vertical refresh
   WaitVBlank();

   //D-pad moves background
   if(!(BUTTONS & BUTTON_LEFT)) x--;
   if(!(BUTTONS & BUTTON_RIGHT)) x++;
   if(!(BUTTONS & BUTTON_UP)) y--;
   if(!(BUTTONS & BUTTON_DOWN)) y++;

   //use hardware background scrolling
   REG_BG0VOFS = y ;
   REG_BG0HOFS = x ;

   //wait for vertical refresh
   WaitVBlank();
   for(n = 0; n < 4000; n++);
   }
   
return 0;

}


And here we have the suspect DMA copy function:

Code:

void DMAFastCopy(void* source, void* dest, unsigned int count,
unsigned int mode)
{
if (mode == DMA_16NOW || mode == DMA_32NOW)
{
REG_DMA3SAD = (unsigned int)source;
REG_DMA3DAD = (unsigned int)dest;
REG_DMA3CNT = count | mode;
}
}


That's it. Thanks muchly in advance to anyone that can figure this out. I've spent more than a week on this. Read as much as I could and I just can't find what the problem is. Not trying to insult Mr Harbour's coding. I'm sure his stuff all works. Likely I've simply done something stupid, I just can't for the life of me figure out what it is.
_________________
"Do you know what the chain of command is? It's the chain I get and beat you with until you understand who's in rutting command here!" -Jayne Cobb

#134917 - Cearn - Wed Jul 18, 2007 9:46 am

ShannonB wrote:
Code:
#define REG_DMA3SAD * (volatile unsigned int*) 0x40000D4
#define REG_DMA3DAD * (volatile unsigned int*) 0x40000DC
#define REG_DMA3CNT *(volatile unsigned int*)0x40000DC

REG_DMA3DAD is at 0x40000D8, not 0x40000DC.

ShannonB wrote:
Not trying to insult Mr Harbour's coding. I'm sure his stuff all works.
Actually, no, a good deal of the book doesn't work. REG_DMA3DAD is correct in the book, but, for example, all of the four WaitForVBlank variations in the book are incorrect (the one you have here actually waits for the VBlank to be over, rather than when it begins). Those silly empty wait-loops ( "for(n=0;n<4000;n+) ;", etc ) are attempts to work around those incorrect VBlankWait routines. Just use the correct one once per game-loop and remove those kinds of loops. Other incorrect #defines here are WRAPAROUND, which should be 0x2000, and BUTTONS, which is a 16-bit register, not 32-bit.

Be careful what you take from the book. The code style is inconsistent and the code itself often inefficient and at times even wrong. These things don't help when you're learning :\

#134918 - ShannonB - Wed Jul 18, 2007 9:56 am

Oh man, thanks so much. It would have taken me years to figure all of that out.

I've been going through the TONC tutorials. I really like them, but they're a lot less gentle than the Jharbour book. Something I like, but somedays I guess I just want to be molly-coddled :)

Thanks again.
_________________
"Do you know what the chain of command is? It's the chain I get and beat you with until you understand who's in rutting command here!" -Jayne Cobb

#136969 - elyk1212 - Mon Aug 06, 2007 10:49 pm

Cearn is right. I have had various difficulties with the reasoning in Harbors book. Although it was a good attempt, it confused me quite a bit in some areas. Also, as Cearn mentioned, looping for an arbitrary amount of time when an interrupt solution should be used, is silly and not portable (if you are going for this type of thing), nor optimal.

If he isn't going to do it, I should at least mention Cearn's tutorial:

http://www.coranac.com/tonc/


Sorry man, I had to SPAM your stuff :). But I think it is really worth reading.

Anyhow, read up on some of these folk's tutorials (referenced on this board). Keep in mind, the random ones you find online have some slop and inconsistencies, just like many of my engineering books (unfortunately).


EDIT: Ops, I should have read last post more carefully, you already found them.


Last edited by elyk1212 on Mon Aug 06, 2007 11:40 pm; edited 1 time in total

#136972 - keldon - Mon Aug 06, 2007 11:17 pm

Well what's your programming experience, maybe you're jumping too far into the deep end! You can in theory learn programming entirely using the Game Boy Advance, but there are no tutorials on earth that would put a beginner in that position - not because it's impossible or bad, but because it's difficult for the teacher.

There are many basic programming concepts you must know, most GBA tutorials are instructions to use the hardware, not to program - and the same can probably be said about just about every tutorials of that nature from Win32 programming to DirectX.