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.

DS development > M3 Real, Touch and drawing: Emu Yes, DS No?

#151441 - nczempin - Tue Feb 26, 2008 12:58 pm

Hi,

I'm an experienced Software Developer, and recently I've started playing around with DS Homebrew.

I have an M3 Real (also have a Simply), got devkitPro and got it running (even under Vista), and can get most of the examples to work. However, it seems that something is wrong regarding the Stylus/touch recognition.

I have successfully built the libnds TouchTest. Now I want to actually do something with the Stylus (a Swiss colleague asked whether there was a Nine Men's Morris for the DS, I said "sure" and I guess I was wrong, so now I have to code it ;-).

Taking the TouchTest code and combining it with some drawing to VRAM directly, I tried to printf the touch coordinates on the top screen and draw pixels on the bottom.

It seems I must have got the combination wrong somehow.

Sorry not to be more specific; I'll post the code later (don't have it on this machine), but here's the problem:

The code works as designed on the No$GBA 2.6. However, after uploading to the M3 Real it seems as if only either the touch or the drawing works, but not both.

I think I need to learn more about all those graphics modes, but perhaps you can already spot something in the combination I'm using that would point to an easy solution.

I also had touch problems with nearly all the PAlib examples (which is why I tried to stick to libnds for now).

I haven't yet tried it on the M3 Simply (in case the Real is part of the problem) or another, perhaps more accurate, emulator.

Thank you for considering my request.

#151444 - nczempin - Tue Feb 26, 2008 2:31 pm

I will provide the code that is causing the problem below.

Please excuse the untidiness, this is work-in-progress code experimenting with libnds.

It would be great if you could help with the following:

[after you press R, a Nine Men's Morris board should appear. Irrespective of that, the text showing the xy coordinates of the touch should be displayed, just like in TouchTest]

1. If you have an M3 Real, can you get it to work?
2. Does it work on any other Homebrew solution?
3. What am I doing wrong (aside from unused variables, functions, etc. :-)?
4. If it works on the No$GBA but not with the M3Real, is the No$GBA the problem or the M3Real? Note that I've had virtually no other problems with the M3Real.

I'm using the latest devkitPro, everything that comes with the 1.4.4 updater, and I'm on Vista Home Premium.

Again, TouchTest by itself works.

Code:
#include <nds.h>
#include <registers_alt.h>

static int shape_width = 15;
static int shape_height = 15;
static int old_x = 0;
static int old_y = 0;
static int shape_x = 0;
static int shape_y = 0;
   static uint16 line_color = RGB15(31,31,31);
   static uint16 COLOR_A = RGB15(31,0,0);
   static uint16 COLOR_B = RGB15(0,0,31);

static int MID_X=SCREEN_WIDTH /2;
static int MID_Y=SCREEN_HEIGHT/2;
static int direction = 1;


   int min_x  = 4096 , min_y  = 4096, max_x  = 0, max_y   = 0;
   int min_px = 4096 , min_py = 4096, max_px = 0 , max_py = 0;
   touchPosition touch;
volatile int frame = 0;

enum { CONTINUOUS, SINGLE } TouchType = CONTINUOUS;


void draw_shape(int x, int y, uint16* buffer, uint16 color)
{
  buffer += y * SCREEN_WIDTH + x;
  int i;
  for(i = 0; i < shape_height; ++i) {
    uint16* line = buffer + (SCREEN_WIDTH * i);
    int j;
    for(j = 0; j < shape_width; ++j) {
      *line++ = color;
    }
  }
}
void draw_shape_b(int x, int y, uint16* buffer, uint16 color){
   draw_shape(x-shape_width/2,y-shape_width/2,buffer, color);
}   
void draw_line_horiz(int x, int y,int deltax,uint16* buffer, uint16 color)
{
  buffer += y * SCREEN_WIDTH + x;
  int i=0;
  //for(i = 0; i < shape_height; ++i) {
    uint16* line = buffer + (SCREEN_WIDTH * i);
    int j;
    for(j = 0; j < deltax; ++j) {
      *line++ = color;
    }
 // }
}
void draw_line_vert(int x, int y,int deltax,const uint16* buf, uint16 color)
{
  uint16* buffer = buf +y * SCREEN_WIDTH + x;
    uint16* line = buffer;// + (SCREEN_WIDTH * i);
    int j;
    for(j = 0; j < deltax; ++j) {
      *line = color;
      line += SCREEN_WIDTH;
    }
 }

void draw_rect(int ulx1,int uly1,int w1){
   draw_line_horiz(ulx1,uly1,w1,VRAM_A,line_color);
   draw_line_horiz(ulx1,SCREEN_HEIGHT-uly1,w1,VRAM_A,line_color);
   draw_line_vert(ulx1,uly1,w1,VRAM_A,line_color);
   draw_line_vert(SCREEN_WIDTH-ulx1,uly1,w1,VRAM_A,line_color);
}
void draw_board(){
       int w1=(SCREEN_HEIGHT*90)/100;
    int ulx1 =MID_X - w1/2;
    int uly1 = MID_Y-w1/2;
   int w2=(SCREEN_HEIGHT*60)/100;
    int ulx2 =MID_X - w2/2;
    int uly2 = MID_Y-w2/2;
   int w3=(SCREEN_HEIGHT*30)/100;
    int ulx3 =MID_X - w3/2;
    int uly3 = MID_Y-w3/2;
    //int w1=(SCREEN_HEIGHT*90)/100;
    //int h1 = 20;
    draw_rect(ulx1,uly1,w1);
   draw_rect(ulx2,uly2,w2);
   draw_rect(ulx3,uly3,w3);
   draw_line_horiz(ulx1,MID_Y,ulx3-ulx1,VRAM_A,line_color);
   draw_line_horiz(SCREEN_WIDTH-ulx3,MID_Y,ulx3-ulx1,VRAM_A,line_color);
   draw_line_vert(MID_X,uly1,ulx3-ulx1,VRAM_A,line_color);
   draw_line_vert(MID_X,SCREEN_HEIGHT-uly3,ulx3-ulx1,VRAM_A,line_color);
   
   int board[7][7];
   int i,j;
for (i=0;i<7;i++){
   for (j=0;j<7;j++){
      board[i][j]=0;
   }
}
            
   board[0][0] = 1;
   board[0][3] = 1;
   board[0][6] = 1;
   board[6][0] = 2;
   board[2][2] = 2;
   board[6][3] = 2;
   
   
//   board[0][0] = 1;
//   board[0][0] = 1;
//   board[0][0] = 1;
   int m = (SCREEN_WIDTH*30/2)/100;
   int n = (SCREEN_HEIGHT*30/2)/100+1;
   for (i=0;i<7;++i){
      for (j=0;j<7;++j){
    //     int xx = ulx1+(i*SCREEN_WIDTH*30)/100;
         int xx = ulx1+i*n;//30;//SCREEN_WIDTH*30)/100;
         int yy = uly1+n*j;
         if (board[i][j]==1){
             draw_shape_b(xx,yy,VRAM_A,COLOR_A);
        }else if (board[i][j]==2){
            
            draw_shape_b(xx,yy,VRAM_A,COLOR_B);
         }
      }                     
   }
         
   //draw_shape_b(SCREEN_WIDTH-ulx1,uly1,VRAM_A,RGB15(0,0,31));
}
void on_irq()
{   
  if(REG_IF & IRQ_VBLANK) {
//    draw_shape(old_x, old_y, VRAM_A, RGB15(0, 0, 0));
//    draw_shape(shape_x, shape_y, VRAM_A, RGB15(31, 0, 0));
    // Tell the DS we handled the VBLANK interrupt
    VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK;
    REG_IF |= IRQ_VBLANK;
  }
  else {
    // Ignore all other interrupts
    REG_IF = REG_IF;
  }
}

void InitInterruptHandler()
{
  REG_IME = 0;
  IRQ_HANDLER = on_irq;
  REG_IE = IRQ_VBLANK;
  REG_IF = ~0;
  DISP_SR = DISP_VBLANK_IRQ;
  REG_IME = 1;
}
void Vblank() {
//---------------------------------------------------------------------------------
   //frame++;
}

int main(int argc, char ** argv)
{
   int min_x  = 4096 , min_y  = 4096, max_x  = 0, max_y   = 0;
   int min_px = 4096 , min_py = 4096, max_px = 0 , max_py = 0;
   touchPosition touch;

   powerON(POWER_ALL_2D);

   // put the main screen on the bottom lcd
   lcdMainOnBottom();

   // Initialise the interrupt system
   irqInit();
   // install our simple vblank handler
   irqSet(IRQ_VBLANK, Vblank);
   // enable the interrupt
   irqEnable(IRQ_VBLANK);
   //initOAM();
    //enable vram and map it to the right places
    vramSetMainBanks(   VRAM_A_MAIN_SPRITE,        //A and B maped consecutivly as sprite memory
                        VRAM_B_MAIN_SPRITE,        //this gives us 256KB which is the max
                        VRAM_C_MAIN_BG_0x06000000,  //map C to background memory
                        VRAM_D_LCD                 //not using D
                        );
   
   //set the video mode
    videoSetMode(  MODE_0_2D |
                   DISPLAY_SPR_ACTIVE |      //turn on sprites
                   DISPLAY_BG0_ACTIVE |      //turn on background 0
                   DISPLAY_SPR_1D         //this is used when in tile mode
                    );

   int i;
   

   // black backdrop
   BG_PALETTE[0]=RGB15(0,0,0);

   BG0_CR = BG_MAP_BASE(31);//use bg0 for the text
   
   BG_PALETTE[255] = RGB15(31,31,31);//by default font rendered with color 255
   
   //consoleInit() is a lot more flexible but this gets you up and running quick
   //consoleInitDefault((u16*)SCREEN_BASE_BLOCK(31), (u16*)CHAR_BASE_BLOCK(0), 16);
   videoSetMode(MODE_FB0);
 vramSetBankA(VRAM_A_LCD);
   irqInit();
// install our simple vblank handler
   irqSet(IRQ_VBLANK, Vblank);
   // enable the interrupt
   irqEnable(IRQ_VBLANK);
   //videoSetMode(0);
  videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
  vramSetBankC(VRAM_C_SUB_BG);
  SUB_BG0_CR = BG_MAP_BASE(31);

  // Set the colour of the font to White.
  BG_PALETTE_SUB[255] = RGB15(31,31,31);

 consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);   
printf("\n\n\tNine Men's Morris\n");

//lcdSwap();

 
   iprintf("\x1b[4;8HTouch Screen Test");
   iprintf("\x1b[15;4HRight Shoulder toggles");
 
  while(1) {
        //swiWaitForVBlank();
 scanKeys();
  touchPosition touchXY;
  touchXY.px = 0;
  touchXY.py = 0;
 int pressed = keysDown();   // buttons pressed this loop

 
  uint32 kh = keysHeld();
  if (kh&KEY_TOUCH){
     touchXY = touchReadXY();
}
    printf("\x1b[10;0H");
    printf("Touch x = %d   \n", touchXY.px);
    printf("Touch y = %d   \n", touchXY.py);
 
      // read the button states
   //   scanKeys();

      // read the touchscreen coordinates
      touch=touchReadXY();
      
   //   int pressed = keysDown();   // buttons pressed this loop
      int held = keysHeld();      // buttons currently held

      // Right Shoulder button toggles the mode
      if ( pressed & KEY_R) TouchType ^= SINGLE;

      iprintf("\x1b[14;4HTouch mode: %s",TouchType==CONTINUOUS?"CONTINUOUS ":"SINGLE SHOT");

      iprintf("\x1b[6;5HTouch x = %04X, %04X\n", touch.x, touch.px);
      iprintf("\x1b[7;5HTouch y = %04X, %04X\n", touch.y, touch.py);      

      iprintf("\x1b[0;18Hkeys: %08X\n", keysHeld());
      iprintf("\x1b[9;10HFrame %d\n", frame);

      if ( TouchType == SINGLE && !(pressed & KEY_TOUCH) ) continue;

      if ( !(held & KEY_TOUCH) || touch.x == 0 || touch.y == 0) continue;
      
      iprintf("\x1b[12;12H(%d,%d)      ",touch.px,touch.py);

      if ( touch.x > max_x)      max_x = touch.x;
      if ( touch.y > max_y)      max_y = touch.y;
      if ( touch.px > max_px)   max_px = touch.px;
      if ( touch.py > max_py)   max_py = touch.py;

      if ( touch.x < min_x)      min_x = touch.x;
      if ( touch.y < min_y)      min_y = touch.y;
      if ( touch.px < min_px)   min_px = touch.px;
      if ( touch.py < min_py)   min_py = touch.py;

      iprintf("\x1b[0;0H(%d,%d)      ",min_px,min_py);
      iprintf("\x1b[1;0H(%d,%d)      ",min_x,min_y);
      iprintf("\x1b[22;21H(%d,%d)",max_x,max_y);
      iprintf("\x1b[23;23H(%d,%d)",max_px,max_py);
      if (TouchType==SINGLE){
draw_board();
}
 
  }   return 0;
} // End of main()

#151468 - nczempin - Wed Feb 27, 2008 2:32 pm

Am I being impatient?

Is no-one able or willing to:

a) even write a single comment, no matter how disparaging?
b) Try the code on an emulator?
c) try the code on their M3 Real?
c) try the code on their non-M3-Real device?

Would it help if I provided a compiled .nds file?

Where could I upload it?

Would it help if I cut down the code to isolate the problem more? (I guess that's a rhetorical question, assuming there are experienced DS homebrew devs even reading my question)

#151469 - asiekierka - Wed Feb 27, 2008 2:51 pm

I'm not experienced, but the experienced ones are too busy working on Wii hacking and devkitPro r22. Give me the binary, i'll try it on NO$GBA, then on my EZ-V. Try to cut down the code a bit though.

#151470 - nczempin - Wed Feb 27, 2008 3:00 pm

asiekierka wrote:
I'm not experienced, but the experienced ones are too busy working on Wii hacking and devkitPro r22. Give me the binary, i'll try it on NO$GBA, then on my EZ-V. Try to cut down the code a bit though.


Well, I'll cut it down for analysis when I have some time (I've also downloaded the libnds source code to learn more about what's under the hood and perhaps pin it down). For now I can send you the actual binary by pm. Should be sufficient to at least learn something...

#151472 - eKid - Wed Feb 27, 2008 3:49 pm

Works for me, I push R and the board pops up, and the touch position is shown on the top screen. I'm testing using an old gba flashcart and WMB.

#151473 - nczempin - Wed Feb 27, 2008 4:11 pm

eKid wrote:
Works for me, I push R and the board pops up, and the touch position is shown on the top screen. I'm testing using an old gba flashcart and WMB.


Thank you for trying it.

So at least for now there is evidence to suggest that the code is correct, and there is a problem with my M3Real, M3Real in general, or the way I am using it.

It could also be that there is a problem with my devkit setup (default arm7), although I find it unlikely, since the Emu ran it like it should.


So I would like to extend my plea for help: Can any others who have an M3Real confirm that it doesn't work for them?

Are there any other known problems with the M3Real? Perhaps I am not using the correct firmware, or, or, or...

#151474 - eKid - Wed Feb 27, 2008 4:22 pm

Hmm.. I don't see anything terribly awful in the code, I'm not sure how running it on different devices could change the result. I think the problem is most likely in your devkit setup...

BTW, why did you comment out the swiWaitForVBlank :(

#151475 - nczempin - Wed Feb 27, 2008 5:11 pm

eKid wrote:
Hmm.. I don't see anything terribly awful in the code, I'm not sure how running it on different devices could change the result. I think the problem is most likely in your devkit setup...


So if the source is not the problem (we could confirm if someone sent me an .nds built from the code that I can try on my card), perhaps I should send out binaries. What is a good method of doing that; my own server has been offline for almost 6 months now... what methods does everybody else use to share temp files? Perhaps I can dig out my old myspace, or whatever. I am so out of touch with the latest in free webspace (because I had my own root server for so long) :-).


If the problem is in my devkit setup, that still doesn't explain why the same .nds works on no$gba but not on my machine...

Quote:

BTW, why did you comment out the swiWaitForVBlank :(


Because I don't have any animation, and I was desperately trying to isolate the problem, and I took out interrupts and put them back in, etc....

#151476 - JLsoft - Wed Feb 27, 2008 5:18 pm

You can try booting it from DSOrganize (3.2) set to use the Chishm booting method and see if that changes anything.

I've noticed recently that some things don't act properly on the M3 DS Real when they're loaded using the cart's firmware (tried 2.8/2.9/3.0) menu, and using DSO made them run correctly :/

#151477 - SiW - Wed Feb 27, 2008 5:29 pm

JLsoft wrote:
I've noticed recently that some things don't act properly on the M3 DS Real when they're loaded using the cart's firmware (tried 2.8/2.9/3.0) menu, and using DSO made them run correctly :/


Which would perhaps be explained by the firmware loader not clearing state properly.

#151479 - nczempin - Wed Feb 27, 2008 5:39 pm

JLsoft wrote:
You can try booting it from DSOrganize (3.2) set to use the Chishm booting method and see if that changes anything.

I've noticed recently that some things don't act properly on the M3 DS Real when they're loaded using the cart's firmware (tried 2.8/2.9/3.0) menu, and using DSO made them run correctly :/


Bingo! Now it works.

So what next?

Do I boot from DSO for eternity, or can we nag someone about the firmware (or even help out)?

Can I clear the state manually from my code? Presumably it has to do with the touch pad. I'll experiment myself (want to learn the nitty-gritty anyway), but if someone has a good idea already, I'd be willing to hear it ;-)

(just for the record, I have "2.9 X version")

#151484 - Cydrak - Wed Feb 27, 2008 6:57 pm

If you want better answers, then yes, please remove the extra code! In the process, you might find your own problem (yay). If not, it will help others out (yay^2). I know that sometimes it's not obvious what "extra" is, but in this case you have duplicate lines, and functions and variables that aren't even used. You know that, but impatient developers with bigger projects don't. ;)

Also it would be nice to know exactly *what* it does. "Either the touch or drawing works"? Does touch make the drawing disappear? Does it only work with one or the other commented out? Does it seem to crash entirely? If so, can you find out when and where? How about registers? Try setting BRIGHTNESS to zero, that can still affect framebuffer. I think you've got all the other important stuff, but it's hard to tell.

It works on my SC Lite. Sorry... I don't know what's up, though. This can be hard to work out without sitting in front of it. Last week had to debug a crash on M3CF over IMs... did I mention I <3 assert()? Very muchly. <3 <3 <3.

I noticed on_irq() is broken: REG_IF is *not* a variable, and saying REG_IF |= FOO will clear *all* the pending interrupts, not just FOO. This would cause you to "lose" IRQs. I assume you pasted from a tutorial, so just beware: some of them are good, some are rather dodgy. :/

Just use irqInit/irqSet/irqEnable, as you've correctly done--albeit, um, twice?--in main(). libnds will call the handlers for you. You just need to request IRQs from some things (timer, dma etc) when you start them up.

#151528 - nczempin - Thu Feb 28, 2008 11:43 am

Cydrak wrote:
If you want better answers, then yes, please remove the extra code! In the process, you might find your own problem (yay). If not, it will help others out (yay^2). I know that sometimes it's not obvious what "extra" is, but in this case you have duplicate lines, and functions and variables that aren't even used. You know that, but impatient developers with bigger projects don't. ;)

Also it would be nice to know exactly *what* it does. "Either the touch or drawing works"? Does touch make the drawing disappear? Does it only work with one or the other commented out? Does it seem to crash entirely? If so, can you find out when and where? How about registers? Try setting BRIGHTNESS to zero, that can still affect framebuffer. I think you've got all the other important stuff, but it's hard to tell.

It works on my SC Lite. Sorry... I don't know what's up, though. This can be hard to work out without sitting in front of it. Last week had to debug a crash on M3CF over IMs... did I mention I <3 assert()? Very muchly. <3 <3 <3.

I noticed on_irq() is broken: REG_IF is *not* a variable, and saying REG_IF |= FOO will clear *all* the pending interrupts, not just FOO. This would cause you to "lose" IRQs. I assume you pasted from a tutorial, so just beware: some of them are good, some are rather dodgy. :/

Just use irqInit/irqSet/irqEnable, as you've correctly done--albeit, um, twice?--in main(). libnds will call the handlers for you. You just need to request IRQs from some things (timer, dma etc) when you start them up.


Yep, the code is very much pasted, and stitched, and garbled (I did warn you about it, and yes, I wouldn't normally call the irq inits twice ;-), and if there is a way to present this apparent bug in the M3Real Firmware to their developers I will make sure to absolutely isolate it.

Not sure if you noticed from my last post that I'm pretty sure I've found the problem, as the DSOrganize workaround works.

The strange thing is that the basic TouchTest from which I copied half the code works, once I add the drawing code things start to go wrong.

But we have found out that aside from the generic brain-dead-ness of my code, it actually works, except on (at least) the M3 DS Real Firmware 2.8, 2.9 and 3.0.

#151610 - thegamefreak0134 - Sat Mar 01, 2008 10:08 am

From what I can tell from my experiments, you will want to un-comment the swiWaitForVSync(). I had very similar issues, although I was simply getting very inaccurate touch results, and it was a result of trying to poll the touch hardware too often, or some other issue associated. The touch code and the hardware appear to be designed to handle only one coordinate per frame, so try putting the VSyncs back in and see if it helps.

I wouldn't put it past the firmware on your card to leave garbage in memory, I know my SuperCard does exactly the same thing. Odd that it would respond in that particular way though. My best advice is, you have found a way to boot it using DSOrganize, and I tend to trust homebrew loaders rather than card firmware, so just use DSOrganize for it.

-thegamefreak
_________________
What if the hokey-pokey really is what it's all about?

[url=http:/www.darknovagames.com/index.php?action=recruit&clanid=1]Support Zeta on DarkNova![/url]

#151701 - nczempin - Mon Mar 03, 2008 6:03 pm

thegamefreak0134 wrote:
From what I can tell from my experiments, you will want to un-comment the swiWaitForVSync(). I had very similar issues, although I was simply getting very inaccurate touch results, and it was a result of trying to poll the touch hardware too often, or some other issue associated. The touch code and the hardware appear to be designed to handle only one coordinate per frame, so try putting the VSyncs back in and see if it helps.

I wouldn't put it past the firmware on your card to leave garbage in memory, I know my SuperCard does exactly the same thing. Odd that it would respond in that particular way though. My best advice is, you have found a way to boot it using DSOrganize, and I tend to trust homebrew loaders rather than card firmware, so just use DSOrganize for it.

-thegamefreak


well, the wait for sync was not the problem.

I've changed a few other things that did the trick, however. I haven't determined yet which of these was the culprit:

1. Cleaned up the code a little
2. removed any PALib dependencies
3. exchanged the palib makefile by one from the libnds examples

I think probably 3) was what did it; I had a lot of problems with PALib in my setup, especially none of the touch examples seem to work (sorry to be so vague ;-)