
#include <C8051F120.H>

void config (void)
{
   int n = 0;

   WDTCN = 0x07;	// Watchdog Timer Control Register
   WDTCN = 0xDE;   // Disable WDT
   WDTCN = 0xAD;
	
   SFRPAGE = 0x0F;
   XBR0 = 0x04;	// XBAR0: Initial Reset Value
   XBR1 = 0x00;	// XBAR1: Initial Reset Value
   XBR2 = 0x44;	// XBAR2: Initial Reset Value added on 11 July 2004 for Com2

   SFRPAGE = 0x0F;
   P0MDOUT = 0x05; // Output configuration for P0 
   P1MDOUT = 0x40; //  P1^6 to push pull mode
 
   P1MDIN = 0xFF;  // Input configuration for P1

// Oscillator Configuration	

    SFRPAGE = 0x00;
    FLSCL = 0x10;   // FLASH Memory Control

    SFRPAGE = 0x0F;
    OSCXCN = 0x00;	// EXTERNAL Oscillator Control Register
    OSCICN = 0xC3;	// 83 ALSO SAME Internal Oscillator Control Register

    PLL0CN = 0;

    PLL0DIV = 0x01; // PLL pre-divide Register 
    PLL0FLT = 0x31; // PLL Filter Register
    PLL0MUL = 0x02; // PLL Clock scaler Register
    PLL0CN = 0x01;  // PLL Control Register

    for(n = 0; n < 500; n++);               // wait at least 5us
    PLL0CN |= 0x02;                         // enable PLL
    while ( (PLL0CN & 0x10) == 0 );        // wait for PLL to lock

    CLKSEL = 0x02;  // Oscillator Clock Selector	

// UART0 Configuration

    SFRPAGE = 0x00;
    SADEN0 = 0x00;      // Serial 0 Slave Address Enable
    SADDR0 = 0x00;      // Serial 0 Slave Address Register
    SSTA0 = 0x1A;       // UART0 Status and Clock Selection Register

// UART0 Mode 1 8bit auto variable baud rate

    SCON0 = 0x50;       // Serial Port Control Register
    SCON0 &= 0xFC; 	   //clear interrupt pending flags

    PCON = 0x00;        // Power Control Register

    SFRPAGE = 0x00;
	 // Timer 1 uses SYSCLK as time base
	 // timer0/1 prescales = SYSCLK / 4
    CKCON = 0x01;   // Clock Control Register

// timer 1 generates UART1 baud rate
// TIMER 1 USES CLK PRESCALER. TIME BASE IS SYSCLK / 4

    TL0 = 0x00;     // Timer 0 Low Byte
    TH0 = 0xee;     // Timer 0 High Byte 
    TL1 = 0x00;     // Timer 1 Low Byte
    TH1 = 0x61;     // Timer 1 High Byte 
    TMOD = 0x22;    // Timer Mode Register 8bit auto reload
    TCON = 0x50;    // Timer Control Register 

// Timer 3 for UART0 BAUD GENERATOR		
// Time Base is SYSCLK @ 49MHZ
// Baud Rate 38765  = FFB1
// Baud Rate 117788 = FFE6

    SFRPAGE = 0x01;
    TMR3CF = 0x08;  // 0 Timer 3 Configuration
    RCAP3L = 0xB1;  // Timer 3 Reload Register Low Byte
    RCAP3H = 0xFF;  // Timer 3 Reload Register High Byte
    TMR3H = 0x00;   // Timer 3 High Byte
    TMR3L = 0x00;   // Timer 3 Low Byte
    TMR3CN = 0x04;  // Timer 3 Control Register

    SFRPAGE = 0x00;
    RSTSRC = 0x00;	// Reset Source Register 

    IP = 0x00;          //Interrupt Priority
    SFRPGCN = 0x01;

}   //End of config

#define TBUF_SIZE   128 
#define RBUF_SIZE   128 

static xdata unsigned char tbuf [TBUF_SIZE];
static xdata unsigned char rbuf [RBUF_SIZE];
static xdata unsigned char t_in = 0;
static xdata unsigned char t_out = 0;
static xdata unsigned char r_in = 0;
static xdata unsigned char r_out = 0;

xdata unsigned char rcount;
xdata unsigned char tcount;

static bit ti_restart = 0;  
static unsigned char oldsfrPage = 0;

sbit LED = P1^6;

void Serial_ISR (void) interrupt 4
{
   oldsfrPage = SFRPAGE;

   SFRPAGE = 0;

   if(RI0 != 0) //Received data interrupt.
   {
      RI0 = 0;
      rbuf [r_in] = SBUF0;
      r_in++;
      if(r_in >= RBUF_SIZE)
         r_in = 0;
      rcount++;
   }	

   if(TI0 != 0) 
   {
      TI0 = 0;
      if(tcount)
         tcount--;

      if(t_in != t_out)
      {
         SBUF0 = tbuf[t_out];
         t_out++;

         if(t_out >= TBUF_SIZE)
            t_out = 0;

         ti_restart = 0;
      }
      else
      {
         ti_restart = 1;
      }
   }

   LED = !LED;

   SFRPAGE = oldsfrPage;
}

unsigned char getc()
{
   while(!rcount);

   if(r_out >= RBUF_SIZE)
      r_out = 0;

   rcount--;
   return(rbuf[r_out++]);
}

void main()
{
   unsigned int k;

   config();

   SFRPAGE = 0; 

   RI0 = 0;
   TI0 = 0;

   t_in = 0;     // transmit buffer
   t_out = 0;
   r_in = 0;     // receive buffer
   r_out = 0;
   ti_restart = 1;   // to send first character
   rcount = 0;
   tcount = 0;

   PS = 1;   // serial interrupt to high priority
   IE = 0x90;

   while(1)
   {
      SFRPAGE = 0;

      if(t_in < TBUF_SIZE)
      {
      	tbuf [t_in] = getc();  // t_in;
   	   t_in++;       // if serial interrupt it transmits character 'A'
         tcount++;

         if(t_in >= TBUF_SIZE)
            t_in = 0;

      	if(ti_restart)
         {
            ti_restart = 0;
            TI0 = 1;  /* generate transmit interrupt */
         }
      }
//      for(k=0;k<5000;k++); // delay
   }
}
