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 > FIFO Problem

#116157 - relpats_eht - Mon Jan 22, 2007 5:51 pm

I have been attempting to set up a FIFO sound system but have been running into a bit of trouble. As of now, the queue on the ARM9 side merely fills up, and is never received by the ARM7 (as far as I can tell). I have read through these forums looking for some form of answer, but I still haven't found one.
In any event, here is a condensed form of the code, perhaps someone could give me a few pointers.

ARM7:
Code:
void recvSoundCommand(NDS_SOUND_COMMAND* command){
   while((REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY));
   command->command = REG_IPC_FIFO_RX;

   while((REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY));
   command->voice = REG_IPC_FIFO_RX;

   while((REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY));
   command->value = REG_IPC_FIFO_RX;
}

void sendSoundCommand(NDS_SOUND_COMMAND command){
   while(!(REG_IPC_FIFO_CR & IPC_FIFO_SEND_EMPTY));

   while((REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL));
   REG_IPC_FIFO_TX = command.command;

   while((REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL));
   REG_IPC_FIFO_TX = command.voice;

   while((REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL));
   REG_IPC_FIFO_TX = command.value;
}

void fifoHandler(void){
   NDS_SOUND_COMMAND command;
   recvSoundCommand(&command);

   switch(command.command){
      // Handle command
   }

   u32 extra;
   while(!(REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY)){
      extra = REG_IPC_FIFO_RX;
   }
}


ARM9:
Code:
void nds_fifo_recv_sound_command(NDS_SOUND_COMMAND* command){
   while((REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY));
   command->command = REG_IPC_FIFO_RX;

   while((REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY));
   command->voice = REG_IPC_FIFO_RX;

   while((REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY));
   command->value = REG_IPC_FIFO_RX;
}

void nds_fifo_send_sound_command(NDS_SOUND_COMMAND command){
   while(!(REG_IPC_FIFO_CR & IPC_FIFO_SEND_EMPTY)); // Eventually, the code hangs here

   while((REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL));
   REG_IPC_FIFO_TX = command.command;

   while((REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL));
   REG_IPC_FIFO_TX = command.voice;

   while((REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL));
   REG_IPC_FIFO_TX = command.value;
}

void nds_fifo_handler(void){
   NDS_SOUND_COMMAND command;
   nds_fifo_recv_sound_command(&command);

   switch(command.command){
      // Handle Command
   }

   u32 extra;
   while(!(REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY)){
      extra = REG_IPC_FIFO_RX;
   }
}

_________________
- relpats_eht

#116161 - GrizzlyAdams - Mon Jan 22, 2007 6:37 pm

I would suggest only using the fifo to trigger commands, not to send data. that way every transfer is the same size and you can't have problems with missing data.
To send your data I'd suggest using the main ram or shared ram.

WinterMute sent along a chunk of code to me similar to what I have below. I've been using this in mythremote 0.2
Code:

enum {
   CMD_WAIT,
   WIFI_INIT
};
 
u32 fifo_status = CMD_WAIT;

void arm7_fifo() { // check incoming fifo messages
//---------------------------------------------------------------------------------
   while ( !(REG_IPC_FIFO_CR & (IPC_FIFO_RECV_EMPTY)) ) {
      u32 msg = REG_IPC_FIFO_RX;
      REG_IPC_FIFO_TX = msg;
 
      switch (fifo_status) {
         case WIFI_INIT:
            REG_IME = 1;   // allow other interrupts
            Wifi_Init(msg);
            Wifi_SetSyncHandler(arm7_synctoarm9); // allow wifi lib to notify arm9
            fifo_status = CMD_WAIT;
            break;

         case CMD_WAIT:
            switch(msg) {
               case IPC_WIFISYNC7:
                  Wifi_Sync();
                  break;

               case IPC_POWEROFF:
                  IPC_PowerOff();
                  break;

               case IPC_CARTRESET:
                  IPC_CartReset();
                  break;

// ... other IPCs were here

// this our only exception to the data shouldnt go in FIFO rule:
               case IPC_WIFIINIT:
                  fifo_status = WIFI_INIT;
                  break;
            }
            break;
      }
   }
}


on the arm7 I have this chunk being called from a tight loop at the end of the init sequence:
Code:

   for(;;) {
      arm7_fifo();
      swiWaitForVBlank();
   }


on the arm9 a similar handler is called from the fifo irq.

#116201 - relpats_eht - Tue Jan 23, 2007 3:01 am

I may end up doing that, but first, I would like to know why what I have isn't working, if only so I have a better understanding of FIFO. At present, I can put this loop
Code:
u32 extra;
while(!(REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY)){
   extra = REG_IPC_FIFO_RX;
}
in my v blank handler on the ARM7 and still have the code hang infinitely waiting for the queue to be empty on the ARM9, which as far as I can tell, which clearly isn't far enough, shouldn't happen.
_________________
- relpats_eht

#116237 - Puyo - Tue Jan 23, 2007 4:17 pm

Do you turn it on? Something like:
Code:
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR;

Because your code should work. And read Chris Double tutorials if you want to understand fifo.

#116239 - Mighty Max - Tue Jan 23, 2007 4:41 pm

If i understand it correctly, IF is not updated when a interrupt occures when IME is disabled.

This leads to the problem: If you are handling an IRQ on the target side, at the moment the source sends something, the IRQ gets not issued on the other side, as IME is set to 0 in the default interrupt Dispatcher.

Thus your fifo is never touched on the target side

See http://devkitpro.cvs.sourceforge.net/devkitpro/libnds/source/common/interruptDispatcher.s?revision=1.9&view=markup
Line 74 disables irqs, and line 144 enables it again. All code inbetween these points (including your irq handlers) is unable to receive or remember any irq request.

The I-Flag should instead be used, so the CPU won't jump to the new irq, while we are handling the last, but still remembers that an irq happened in the meanwhile.
_________________
GBAMP Multiboot

#116254 - relpats_eht - Tue Jan 23, 2007 6:25 pm

Puyo: Yes, I do turn FIFO on via code similar to the following on both processors.
Code:
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR | IPC_FIFO_RECV_IRQ;
irqSet(IRQ_FIFO_NOT_EMPTY, fifoHandler);
irqEnable(IRQ_FIFO_NOT_EMPTY);
Also, I have read Chris Double's tutorials on the subject.

Mighty Max: That may be true, but what are the odds of my IRQ being sent at that exact time thousands of times in sequence? In any case, what is the I-Flag and how would I use it?
_________________
- relpats_eht

#116255 - Mighty Max - Tue Jan 23, 2007 6:50 pm

The odds are not really bad, i.e. if you try to send something in the arm9 vblank, the arm7 might be in vblank too and vice versa.

The PSR bit is documented in the arm references. But i wouldnt recommend playing with it, if you don't knowit allready. There is an easier workaround available:

Enable the ipc sync irq on both sides and issue an sync irq on the other side everytime you have been waiting for some time and nothing happens. This ipc sync should cause you to check the fifo in the same way as the fifo not empty irq. This way you can "politly remember" the other side if he didnt "hear" the other irqs.
_________________
GBAMP Multiboot

#116262 - relpats_eht - Tue Jan 23, 2007 9:20 pm

Thank you, MightyMax, that fixed the problem.
_________________
- relpats_eht