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.

Audio > DMA Make a little noise when returns...

#4817 - rome - Thu Apr 10, 2003 8:00 pm

i?m currently coding a GBA Sound engine and i?m having a problem: i used DMA and a sound buffer to fill with sounds. DMA is always reading data from sound buffer. But when dma must be restarted to read again the sound buffer, a noise garbage is audible.
there is a problem when restart DMA in timer 1 interrupt?

when sound is filled into the buffer, the noise is louder

here is my code:


Code:

///////////////Interrupts/////////////////////////////
#define INT_TIMER0 0x0008
#define INT_TIMER1 0x0010

// Sound Buffer Size
#define SOUND_BUFFER_SIZE  1024

// prototype
void InterruptProcess(void)  __attribute__ ((section (".iwram"), long_call));

// struct to initialize sound parameters
typedef struct stSountCntH
{
   int Ch1to4OutputRatio          : 2;
   int DSndAOutRatio              : 1;
   int DSndBOutRatio              : 1;
   int unused                     : 4;

   int EnableDSndAToRightSpeaker  : 1;
   int EnableDSndAToLeftSpeaker   : 1;
   int DSndASampleRateTimer       : 1;
   int DSndAFIFOReset             : 1;

   int EnableDSndBToRightSpeaker  : 1;
   int EnableDSndBToLeftSpeaker   : 1;
   int DSndBSampleRateTimer       : 1;
   int DSndBFIFOReset             : 1;
}SountCntH;


// gbasound device class
class  WGBASoundDevice
{
public:
  s8 SoundBuffer[SOUND_BUFFER_SIZE];  // Sound Buffer   
  volatile u32 BufferPos;  // buffer Pos

  int Initialize();  // init sound device 
};


// Sound Device Global variable
WGBASoundDevice SndDev __attribute__ ((section (".ewram")));


//----------------------------------------------------------------------------
// Name: Interrupt Handler
// Desc:
// Pams:
//----------------------------------------------------------------------------
void InterruptProcess()
{
  if(REG_IF & INT_TIMER1) // end of buffer
  {
   // disable DMA
   REG_DM1CNT_H &= 0x7FFF;
   // reset DMA Source
   // HERE MUST BE THE PROBLEM!!!
   REG_DM1SAD   = (unsigned long)SndDev.SoundBuffer;
      
   // enable DMA
   REG_DM1CNT_H |= 0x8000;
   // reset sound buffer pos
   SndDev.BufferPos = 0;
   }
   else
    if(REG_IF & INT_TIMER0) // enter here at 16Khz
    {
     // inc sound buffer pos
     SndDev.BufferPos++;
    }

 REG_IF |= REG_IF;
}

//----------------------------------------------------------------------------
// Name: Initialize()
// Desc: Initialize GBASound (timers, etc...)
// Pams:
//----------------------------------------------------------------------------
int WGBASoundDevice::Initialize()
{
  SountCntH snd_ctrl;

   snd_ctrl.Ch1to4OutputRatio          = 0;
   snd_ctrl.DSndAOutRatio              = 1;   // 100%
   snd_ctrl.DSndBOutRatio              = 0;   
   snd_ctrl.unused                     = 0;

   snd_ctrl.EnableDSndAToRightSpeaker  = 1;
   snd_ctrl.EnableDSndAToLeftSpeaker   = 1;
   snd_ctrl.DSndASampleRateTimer       = 0;   //Timer 0
   snd_ctrl.DSndAFIFOReset             = 1;

   snd_ctrl.EnableDSndBToRightSpeaker  = 0;
   snd_ctrl.EnableDSndBToLeftSpeaker   = 0;
   snd_ctrl.DSndBSampleRateTimer       = 0;   // Timer 0
   snd_ctrl.DSndBFIFOReset             = 0;


   // reset sound buffer pos
   BufferPos = 0;
   
   REG_SGCNT0_H = *(u16*) &snd_ctrl;   // init sound parameters
   REG_SGCNT1   = 0x80;                       //turn sound chip on

   // Initialize DMA channel
   REG_DM1CNT_L = 0;
   REG_DM1SAD = (unsigned long)SoundBuffer;
   REG_DM1DAD = 0x040000a0;  // set dest in FIFO A
   REG_DM1CNT_H = 0xB640;    // init DMA: repeat, 32 bit, Enable

   // will be triggered when buffer reaches the end
   REG_TM1D   = 0xFFFF - SOUND_BUFFER_SIZE;
   // Enable timer 1 + IRQ + cascade from timer 0;
   REG_TM1CNT = 0xC4;  // Generete IRQ when buffer reaches the end
   
   
   // Enable IRQ for timer 0 and 1
   REG_IE |= 0x18;   
   // Enable Master IRQ
   REG_IME=1;

   
   //enable timer at CPU freq/1024 +irq =16384Khz sample rate
   REG_TM0D   = 0xFFFF;
   REG_TM0CNT = 0x00C3;
 
 return 1;
}

// main routine
int main(void)

  REG_INTERUPT = (u32)InterruptProcess;
 
  // fill buffer with any data to increase NOISE
  // problem on Return of DMA to Read Buffer (22 is a stupid data)
  memset(SndDev.SoundBuffer,22,sizeof(char)*SOUND_BUFFER_SIZE);

  // initialize sound (timers and DMA)
  SndDev.Initialize();
   
   while(1)
   {
   }

  return 0;
}


this code is very simple, and can be compiled to test.
the code fill buffer with data 22 and make dma to play it forever.
when timer 1 is triggered, DMA restart to original source position and begins. then noise can be hearded.

thanks so much!!!