//-----------------------------------------------------------------------------
// init.c
//-----------------------------------------------------------------------------
// Copyright 2004 UK SolarCar Team.
//
// AUTH: Saravana Kannan
// DATE: 14 May 04
//
// This program is used to initialize the various devices in the
// microcontroller
//
// Target: C8051F31x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <c8051f310.h>		// SFR declarations
#include "init.h"

//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for 'F31x
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK      24500000	// SYSCLK frequency in Hz
#define BAUDRATE     9600	// Baud rate of UART in bps

//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// This routine initializes the system clock to use the internal oscillator
// at its maximum frequency.
// Also enables the Missing Clock Detector.
//

void SYSCLK_Init (void)
{
    OSCICN |= 0x03;		// Configure internal oscillator for its maximum frequency
    RSTSRC = 0x04;		// Enable missing clock detector

}

//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports.
//
// P0.4 - UART TX
// P0.5 - UART RX
// P0.0 - CEX0
// P3.5 - ADC Input 1

void PORT_Init (void)
{
    // assignments

    XBR0 = 0x01;		// Enable UART on P0.4(RX) and P0.5(TX)                     
    XBR1 = 0x42;		// Enable crossbar and enable 
    // weak pull-ups and CEX0 & CEX1

    P3MDOUT |= 0x08;		// enable LED as a push-pull output

    P0MDOUT |= 0x11;		// enable UTX and CEX0 (pin 3) as push-pull output
    P2MDIN &= ~0x30;		// Set pin P2.5 & P2.4 for analog input
    P2SKIP |= 0x0C;		// Skip pin P2.5 in the crossbar

}

//-----------------------------------------------------------------------------
// Timer0_Init
//-----------------------------------------------------------------------------
//
// Configure Timer0 to 8-bit auto-reload and generate 4.9 MHz pulse.
//
void Timer0_Init ()
{
    CKCON |= 0x04;		// Timer0 clocked based on SYSCLK (24.5MHz)
    TMOD &= ~0x0f;		// Set Timer0 to 8-bit auto reload mode and
    TMOD |= 0x02;		/* set it's timebase to the clock defined by
				 * CKCON.3 and set GATE0 to 0 (so that Timer0
				 * is enabled when TR0=1). */
    TL0 = 0xFF;			// Set to reload immediately
    TH0 = 0xFB;			/* Set the auto reload value to 
				 * 0xFB = 0xFF - 0x5 = 24.5 MHz / 5 = 4.9 MHz.
				 */
    ET0 = 0;			// disable Timer0 interrupts
    TR0 = 1;			// start Timer0 (TR0 = TCON.4)   
}

//-----------------------------------------------------------------------------
// Timer2_Init
//-----------------------------------------------------------------------------
//
// Configure Timer2 to 16-bit auto-reload and set the time period as high as
// possible. Interrupt enabled for high-byte overflow.
//
void Timer2_Init ()
{
    T2SPLIT = 0;		// Set Timer2 to operate in 16bit mode
    T2XCLK = 0;			// Set Timer2 clk to SYSCLK/12
    TF2L = 0;
    TF2LEN = 0;			// Disable interrupt for low byte overflow
    TMR2RLL = 0;		// Set reload values
    TMR2RLH = 0;
    ET2 = 1;

    TR2 = 1;			// Enable Timer 2
}

//-----------------------------------------------------------------------------
// PCA_Init
//-----------------------------------------------------------------------------
// Configure the PCA Capture/Compare module to use Timer0 as it's
// timebase and set it to work in 8-bit PWM mode.
//
void PCA_Init (int count)
{
    PCA0MD = (PCA0MD & 0xF0) | 0x04;	/* Set time base to Timer0 overflow and enable PCA Interrupt */

    // Pulse Width Modulator
    PCA0CPM0 = 0x42;		// Set CCM0 to work in 8 bit PWM mode
    PCA0CPL0 = 0xFF;		/* Initial duty cycle. This must come before PCA0CPH0 always. */
    PCA0CPH0 = count & 0xFF;	// Determines the duty cycle
    PCA0H = 0x00;		// Set the PCA high byte to 0
    PCA0L = 0xFF;		// Set to reload immediately

    // Speed-o-meter
    EIE1 |= 0x10;		// Enable PCA interrupt
    PCA0CPM1 = 0x21;		/* Set CCM1 to work in +ve edge triggered mode and enable CCF1 interrupt */

    CR = 1;			//Enable the PCA counter.
}

//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//
void UART0_Init (void)
{
    SCON0 = 0x10;		// SCON0: 8-bit variable bit rate
    //        level of STOP bit is ignored
    //        RX enabled
    //        ninth bits are zeros
    //        clear RI0 and TI0 bits
    if (SYSCLK / BAUDRATE / 2 / 256 < 1)
    {
	TH1 = -(SYSCLK / BAUDRATE / 2);
	CKCON &= ~0x0B;		// T1M = 1; SCA1:0 = xx
	CKCON |= 0x08;
    }
    else if (SYSCLK / BAUDRATE / 2 / 256 < 4)
    {
	TH1 = -(SYSCLK / BAUDRATE / 2 / 4);
	CKCON &= ~0x0B;		// T1M = 0; SCA1:0 = 01                  
	CKCON |= 0x09;
    }
    else if (SYSCLK / BAUDRATE / 2 / 256 < 12)
    {				//This is the case that works for us
	TH1 = -(SYSCLK / BAUDRATE / 2 / 12);
	CKCON &= ~0x0B;		// T1M = 0; SCA1:0 = 00
    }
    else
    {
	TH1 = -(SYSCLK / BAUDRATE / 2 / 48);
	CKCON &= ~0x0B;		// T1M = 0; SCA1:0 = 10
	CKCON |= 0x02;
    }

    TL1 = TH1;			// init Timer1
    TMOD &= ~0xf0;		// TMOD: timer 1 in 8-bit autoreload
    TMOD |= 0x20;
    TR1 = 1;			// START Timer1
    TI0 = 1;			// Indicate TX0 ready

    //ES0 = 1;			// Enable UART0 timer, shouldn't be necessary in the final code
}


//-----------------------------------------------------------------------------
// ADC0_Init ADBUSY, LP tracking, no Interrupt, ADC disabled
//-----------------------------------------------------------------------------
//
// Configure ADC0 to use ADBUSY as conversion source, and to sense the output 
// of the temp sensor.  Disables ADC end of conversion interrupt. Leaves ADC 
// disabled.
//
void ADC0_Init (void)
{
    ADC0CN = 0x80;		// ADC0 enabled; Normal tracking
    // mode; ADC0 conversions are initiated 
    // on a write to ADBusy
    AMX0P = 0x0D;		// Set up pin 2.5 for input
    AMX0N = 0x1F;		// Single-ended mode

    ADC0CF = (SYSCLK / 3000000) << 3;	// ADC conversion clock <= 3MHz   

    ADC0CF &= ~0x04;		//makes bit 2 to 0  // Make ADC0 right-justified
    REF0CN = 0x0A;		// VREF = VDD, bias generator is on. Using 0x0A instead of 0x0E

    EIE1 &= ~0x08;		// Disable ADC0 EOC interrupt
}
