/* Build in speaker 
   Last updated 29.10.00
 */

/* I/O ports 

   Each I/O port has a data direction register ( DDR ) that selects 
   input ( 0 ) or output ( 1 ), and a data register ( DR ) that 
   stores output data. The data direction register is write only. 
   A copy of the data direction register is maintained by the ROM
   based run time environment. When operating on the data direction
   register the copy should be used as follows

         P6DDR_ROM |= bit5; P6DDR = P6DDR_ROM;

  to select pin 5 as output and maintain the mode of the other pins of
  port 6.
 */ 

/* Port 6, Section 7, page 106. */
#define P6DR       *((volatile byte *) 0xffbb)
#define P6DDR      *((volatile byte *) 0xffb9)
#define P6DDR_ROM  *((volatile byte *) 0xfd85)

/* A simple busy loop that delays the caller for a number of miliseconds. */ 

void BusyPauseMS( uint16 ms ) 
{
  uint16 i;

  while( ms > 0 ){
     for (i=0; i < 660/8; i++) ;
     ms--;
  }
}


/* The build in speaker can be controlled via the I/O port 6, bit4.
   Waveforms of zeroes and ones written to this bit can produce sounds.
   Before the speaker can be used, the Data Direction Register should be
   set to output ( bit4 of P6DDR and P6DDR_ROM ).
 */
#define bit4          (1 << 4) 
#define SpeakerHigh   P6DR |=  bit4    
#define SpeakerLow    P6DR &= ~bit4 

void SpeakerInit( void )
{
  P6DDR_ROM |= bit4; P6DDR = P6DDR_ROM;
}

/* A very crude way of playing a tone on the speaker:
   HalfPeriod are given in msec, Duration as the number of
   periods to be played.
 */
void SpeakerPlay( int16 HalfPeriod, int16 Duration )
{
  int16 i;
  
  SpeakerInit();

  for ( i=1; i < Duration ; i++){
    SpeakerHigh;
    BusyPauseMS(HalfPeriod);
    SpeakerLow;
    BusyPauseMS(HalfPeriod);
  }
}

