/*  TT8 specific includes  */
#include        <TT8.h>                 /* Tattletale Model 8 Definitions */
#include        <tat332.h>              /* 68332 Tattletale (7,8) Hardware Definitions */
#include        <sim332.h>              /* 68332 System Integration Module Definitions */
#include        <qsm332.h>              /* 68332 Queued Serial Module Definitions */
#include        <dio332.h>              /* 68332 Digital I/O Port Pin Definitions */
#include        <tt8lib.h>              /* definitions and prototypes for Model 8 library */

/*  general C includes  */
#include        <stdio.h>
#include        <stdlib.h>
#include        <userio.h>

//  our includes
#include		"ASSERT.h"
#include		"MAX186.h"

//  subroutine not for external use
void MAX186_SPI_rupt_handler (void);

//  used in setting the SP registers
#define		MAX186_BAUD		0x04
#define		MAX186_DSCKL	15
#define		MAX186_DTL		0

short int MAX186_SPI_finished;


//  MAX186_power_on_init (void)
//
//  Completes all initialization to put the 186 in a low power mode
//
void MAX186_power_on_init (void)  {
	MAX186_shutdown (-1);
	MAX186_power_up ();
	MAX186_power_down ();
	MAX186_shutdown (0);
}




//  MAX186_shutdown (int state)
//
//  Sets the MAX186 shutdown pin to the requested state.
//  The MAX186 is is controlled by pin 7 of PORT F.  It may
//  be set to 0 to shut down, set to 1 to turn on with internal
//  compensation, or left floating to turn on with external
//  compensation.
//
void MAX186_shutdown (int state)  {
	ASSERT ((state == 0) || (state == 1) || (state == -1));
	
	switch (state)  {
		case 0:
			PConfOutp (F, 7);
			PClear (F, 7);
			return;
			
		case 1:
			PConfOutp (F, 7);
			PSet (F, 7);
			return;
			
		case -1:
			PConfInp (F, 7);
			return;
			
		default:
			ASSERT (0);
			return;	
	}
	ASSERT (0);
}

		

//  MAX186_power_down (void)
//
//	Implements a full software power down of the MAX186.
//
//  SPI assignments:
//		QPDR-7 = TxD (used by SCI)
//		QPDR-6 = PCS3 (user by TT8's on-board MAXIM A/D converter)
//		QPDR-5 = PCS2 (connected to AD7716 RESET - active high)
//		QPDR-4 = PCS1 (connected to AD7716 TFS)
//		QPDR-3 = PCS0 (connected to AD7716 RFS)
//		QPDR-2 = SCK (SPI clock)
//		QPDR-1 = MOSI (master out, slave in)
//		QPDR-0 = MISO (master in, slave out)
//
void MAX186_power_down (void)  {
	//  set all the SPI registers for access to the MAX 186
	MAX186_init_SPI ();

	//  MAX186 command implements full power down mode
	SPIXMT[0] = 0x80;

	//  68332 QSPI command controls PCS and various parameters
	SPICMD[0] =     0x3                     //  Set PCS3 low, RESET low, TFS, RFS high
			|       M_CONT  &       SET     //  1=keep CS active between cmds
			|       M_BITSE &       CLR     //  0=8 bits, 1=use SPCR0
			|       M_DT    &       SET     //  0=no delay after, 1=use SPCR1
			|       M_DSCK  &       SET     //  0=1/2SCK, 1=use SPCR1
			;
			
	//	Control register specifies one command and interrupt when complete
	*SPCR2 =        0x0						//  NEWQP
			|       (0x0 << 8)				//  ENDQP
			|       M_SPIFIE &      SET		//  SPI finished rupt enable = 1
			|       M_WREN   &      CLR		//  wraparound enabled if = 1
			|       M_WRTO   &      CLR		//  wrap to enabled if = 1
	;
			
	MAX186_SPI_finished = 0;
	_SPSR->SPIF = 0;                        //  clear any old results (intrpt flag)
	_SPCR1->SPE = 1;                        //  start QSPI
	while (MAX186_SPI_finished == 0)
		{;}
	return;
}





//  MAX186_power_up (void)
//
//	Implements the power up sequence.    The system will require
//	20 mSec to recover before it can accurately convert again.
//  This is the time required to charge the reference capacitor
//
void MAX186_power_up (void)  {
	int result;
//	result = MAX186_read_channel (0);
//	printf ("Value %d = 0x%04X\n", result, result);
//	return;

	//  set all the SPI registers for access to the MAX 186
	MAX186_init_SPI ();

	//  MAX186 command implements fast power down mode, which seems
	//  to mean it powers up the reference.  The user who calls this
	//  routine must wait an appropriate number of time constants for
	//  the RC network on the reference output to stabilize.  Typical
	//  time constant would require a 2 mS wait.
	SPIXMT[0] = 0x81;

	//  68332 QSPI command controls PCS and various parameters
	SPICMD[0] =     0x3                     //  Set PCS3 low, RESET low, TFS, RFS high
			|       M_CONT  &       SET     //  1=keep CS active between cmds
			|       M_BITSE &       SET     //  0=8 bits, 1=use SPCR0
			|       M_DT    &       SET     //  0=no delay after, 1=use SPCR1
			|       M_DSCK  &       SET     //  0=1/2SCK, 1=use SPCR1
			;
			
	//	Control register specifies one command and interrupt when complete
	*SPCR2 =        0x0						//  NEWQP
			|       (0x0 << 8)				//  ENDQP
			|       M_SPIFIE &      SET		//  SPI finished rupt enable = 1
			|       M_WREN   &      CLR		//  wraparound enabled if = 1
			|       M_WRTO   &      CLR		//  wrap to enabled if = 1
	;
			
	MAX186_SPI_finished = 0;
	_SPSR->SPIF = 0;                        //  clear any old results (intrpt flag)
	_SPCR1->SPE = 1;                        //  start QSPI
	while (MAX186_SPI_finished == 0)
		{;}
	return;
}


//  array to match a channel number with the bit pattern that the
//  MAX186 uses
static short channel_pattern[] = {
	0x0,
	0x40,
	0x10,
	0x50,
	0x20,
	0x60,
	0x30,
	0x70
};




short MAX186_read_channel (int channel)  {
	short result;
	ASSERT ((channel >= 0) && (channel <= 7));
	//  set all the SPI registers for access to the MAX 186
	MAX186_init_SPI ();

	//  first command combines the channel pattern with the control
	//  bits.  the second and third are essentially no-ops, cause there
	//  is no 1 bit in the pattern
	SPIXMT[0] = channel_pattern[channel]  |
				0x80					  |
				0x0F;
	SPIXMT[1] = 0x0;

	//  68332 QSPI command controls PCS and various parameters;
	//  1st command xfers 8 bits to specify the channel converted
	//  2nd command xfers 16 bits to rcv the converted data
	SPICMD[0] =     0x3                     //  Set PCS3 low, RESET low, TFS, RFS high
			|       M_CONT  &       SET     //  1=keep CS active between cmds
			|       M_BITSE &       CLR     //  0=8 bits, 1=use SPCR0
			|       M_DT    &       CLR     //  0=no delay after, 1=use SPCR1
			|       M_DSCK  &       SET     //  0=1/2SCK, 1=use SPCR1
			;
	SPICMD[1] =     0x3                     //  Set PCS3 low, RESET low, TFS, RFS high
			|       M_CONT  &       SET     //  1=keep CS active between cmds
			|       M_BITSE &       SET     //  0=8 bits, 1=use SPCR0
			|       M_DT    &       CLR     //  0=no delay after, 1=use SPCR1
			|       M_DSCK  &       SET     //  0=1/2SCK, 1=use SPCR1
			;
			
	//	Control register specifies two commands and interrupt when complete
	*SPCR2 =        0x0						//  NEWQP
			|       (0x01 << 8)				//  ENDQP
			|       M_SPIFIE &      SET		//  SPI finished rupt enable = 1
			|       M_WREN   &      CLR		//  wraparound enabled if = 1
			|       M_WRTO   &      CLR		//  wrap to enabled if = 1
	;
			
	MAX186_SPI_finished = 0;
	_SPSR->SPIF = 0;                        //  clear any old results (intrpt flag)
	_SPCR1->SPE = 1;                        //  start QSPI
	while (MAX186_SPI_finished == 0)
		{;}
	return SPIRCV[1];
}



//  MAX186_init_SPI
//
//	Sets the SPI up for transfers to the MAX186.  A key to the proper
//  operation with this routine in cooporation with other routines is
//  that is only adjusts values of the PCS lines that it uses.  Other
//  lines will be unchanged from their current state.
//
//  The MAX186 uses PCS line 3 as a chip select.  It should idle high
//
void MAX186_init_SPI (void)  {
	static ExcCFrame MAX186_SPI_Frame;
	
	// install QSPI interrupt handler
	InstallHandler(MAX186_SPI_rupt_handler, QSPI_INT_VECTOR, &MAX186_SPI_Frame);

	//  PCS3 idles high
	_QPDR->PCS3 = 1;

	//  The SPI is assigned PCS3, MISO, and MOSI; SCK is automatic
	_QPAR->PCS3 = 1;
	_QPAR->MISO = 1;
	_QPAR->MOSI = 1;
	
	//  PCS3, MOSI, and SCK are outputs; MISO is an input
	_QDDR->PCS3 = 1;
	_QDDR->MOSI = 1;
	_QDDR->SCK = 1;
	_QDDR->MISO = 0;

	//  Now set up the control registers.  The baud rate is chosen assuming
	//  that we are running with a system clock of 16 MHz.  Bits per xfer
	//  is 16, and we override this using the SPICMD variable to get
	//  only eight for the first xfer of the control word
	*SPCR0 =        MAX186_BAUD             //  8 = 1 MHz;  baud rate (2 is max)
			|       (0x0 << 10)				//  bits per transfer (0 = 16)
			|       M_MSTR  &       SET     //  1 = Master, 0 = Slave
			|       M_WOMQ  &       CLR     //  1 = open drain, 0 = cmos
			|       M_CPOL  &       CLR     //  1 = inactive SCK high
			|       M_CPHA  &       CLR     //  1 = change on leading edge, capture on falling
	;

	*SPCR1 = MAX186_DTL           |			//  DTL delay after xfer
			 (MAX186_DSCKL << 8)  |			//  delay between PCS valid and start of xfer
			 M_SPE & CLR;					//  don't enable the SPI yet

	//  SPCR2 will be set up by the routine which runs a command through
	*SPCR3 =        M_LOOPQ &       CLR     //  QSPI loop mode, 1 = on
			|       M_HMIE  &       CLR     //  HALTA & MODF interrupt enable
			|       M_HALT  &       CLR     //  Halt
	;
	
	//  The SPCR2 register is set according to the specific commands which
	//  are being executed.  It is set by the routines which actually execute
	//  the commands
}




//  MAX186_SPI_rupt_handler (void)  {
//  Internal use only
//
//  Interrupt handler for SPI
//
void MAX186_SPI_rupt_handler (void)  {
    //  clear any old results (intrpt flag)
	_SPSR->SPIF = 0;
	MAX186_SPI_finished = 1;
}
	