/*********************************************************************
 *                  Flowcode CAL ADC File
 *
 * File: PIC16BIT_CAL_ADC.c
 *
 * (c) 2011 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, and is protected under applicable
 * copyright laws. All rights are reserved. Any use in violation
 * of the foregoing restrictions may subject the user to criminal
 * sanctions under applicable laws, as well as to civil liability
 * for the breach of the terms and conditions of this licence.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 060911 | BR | Created
 * 200911 | BR | Updated to include all ADC type files
 * 020312 | BR | Updated to v5.1 CAL Schema
 * 170812 | BR | Fixed a bug with the RAW ADC functions where the SAMP bit was being left clear
 * 170812 | BR | Added some minor mods to allow the FCD to correctly determine ADC conv speed
 * 180912 | BR | Added an extra ADC type for 24FxxKA devices
 * 191112 | BR | Added ADC type 10 for newer EP devices
 * 171212 | BR | Moved the code to begin the sample to allow for more optimised ADC readings
 * 030713 | LM | Standard API calls
 * 240414 | LM | Additions to support Touch via ADC
 * 180914 | LM | ADC based Touch implemented on a couple of types
 */


//ADC Function Prototypes
void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge);
MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode);
void FC_CAL_ADC_Disable ();
#ifdef MX_ADC_TOUCH
	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel);
#endif

//ADC Global Variables
MX_UINT16 old_tris, tris_mask;
MX_STRING tris_reg;					//TRIS register pointer


/* ADC Type 1 Supported Devices ************************************************************
PIC24FJ128GA Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_1
	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		tris_reg = (MX_UINT8 *) &TRISB;
		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<Channel);

		clear_bit(AD1PCFG, Channel);							//Setup ADC Channel
		AD1CHS = (Channel & 0x0F);

		if (Vref == 0)											//Setup Vref+ functionality
			AD1CON2bits.VCFG0 = 0;
		else
			AD1CON2bits.VCFG0 = 1;

		AD1CON3 = 0;
		if (Conv_Speed & 0x40)									//Assign conversion speed
			AD1CON3bits.ADRC = 1;								//Internal RC Clock
		else
			AD1CON3 = (Conv_Speed & 0x3F);						//Based on system clock

		AD1CON1bits.ADON = 1;									//Turn on ADC
		AD1CON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		AD1CON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

		while (!AD1CON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADC1BUF0;									//10-bit ADC
		}
		else
			iRetVal = (ADC1BUF0 >> 2);							//8-bit ADC

		AD1CON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		AD1CON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;
		AD1PCFG = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 2 Supported Devices ************************************************************
PIC33FJ128GP Family
PIC33FJ64GP Family
PIC33FJ32GP Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_2
	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		if (Channel <= 2)
		{
			tris_reg = (MX_UINT8 *) &TRISA;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | (1<<Channel);
		}

		clear_bit(AD1PCFGL, Channel);							//Setup ADC Channel
		AD1CHS0 = (Channel & 0x0F);

		if (Vref == 0)											//Setup Vref+ functionality
			AD1CON2bits.VCFG0 = 0;
		else
			AD1CON2bits.VCFG0 = 1;

		AD1CON3 = 0;
		if (Conv_Speed & 0x40)									//Assign conversion speed
			AD1CON3bits.ADRC = 1;								//Internal RC Clock
		else
			AD1CON3 = (Conv_Speed & 0x3F);						//Based on system clock

		AD1CON1bits.ADON = 1;									//Turn on ADC
		AD1CON1bits.AD12B = 1;
		AD1CON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		AD1CON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;


		while (!AD1CON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADC1BUF0;									//12-bit ADC
		}
		else
			iRetVal = (ADC1BUF0 >> 4);							//8-bit ADC

		AD1CON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		AD1CON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;
		AD1PCFGL = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 3 Supported Devices ************************************************************
dsPIC30 Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_3
	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		tris_reg = (MX_UINT8 *) &TRISB;
		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<Channel);

		ADCON1 = 0x0000;
		ADCON2 = 0x0000;
		ADCON3 = 0x0000;
		ADCHS = 0x0000;

		clear_bit(ADPCFG, Channel);								//Setup ADC Channel
		ADCHS = (Channel & 0x000F);

		if (Vref == 0)											//Setup Vref+ functionality
			ADCON2 = ADCON2 & 0x1FFF;
		else
			ADCON2 = ADCON2 | 0x2000;

		ADCON3 = 0;
		if (Conv_Speed & 0x40)									//Assign conversion speed
			ADCON3bits.ADRC = 1;								//Internal RC Clock
		else
			ADCON3 = (Conv_Speed & 0x3F);						//Based on system clock

		//ADCON3 |= 0x0100;										//Dont think this is needed 17/08/12 BR

		ADCON1bits.ADON = 1;									//Turn on ADC
		ADCON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		ADCON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

		while (!ADCON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADCBUF0;									//10-bit ADC
		}
		else
			iRetVal = (ADCBUF0 >> 2);							//8-bit ADC

		ADCON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		ADCON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;
		ADPCFG = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 4 Supported Devices ************************************************************
dsPIC33FJx6GSx0x Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_4

	MX_UINT8 MX_Current_Channel;

	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		if (Channel <= 2)
		{
			tris_reg = (MX_UINT8 *) &TRISA;
			old_tris = *tris_reg;								//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | (1<<Channel);
		}
		else
		{
			tris_reg = (MX_UINT8 *) &TRISB;
			old_tris = *tris_reg;								//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | (1<<(Channel-2));
		}

		ADCON = 0x0000;
		clear_bit(ADPCFG, Channel);								//Setup ADC Channel
		ADCON = (Conv_Speed & 0x07);							//Assign conversion speed
		ADCONbits.ADON = 1;										//Turn on ADC
		delay_us(T_Charge);										//wait the acquisition time

		MX_Current_Channel = Channel;
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

	  #if (defined MX_ADC_CHANNEL_0 || defined MX_ADC_CHANNEL_1)
		if(MX_Current_Channel <= 1)								//begin next conversion
		{
			ADCPC0 = 0x0001;
			ADCPC0bits.SWTRG0 = 1;
			while (!ADCPC0bits.SWTRG0);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_2 || defined MX_ADC_CHANNEL_3)
		if(MX_Current_Channel >= 2 && MX_Current_Channel <= 3)
		{
			ADCPC0 = 0x0100;
			ADCPC0bits.SWTRG1 = 1;
			while (!ADCPC0bits.SWTRG1);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_4 || defined MX_ADC_CHANNEL_5)
		if(MX_Current_Channel >= 4 && MX_Current_Channel <= 5)
		{
			ADCPC1 = 0x0001;
			ADCPC1bits.SWTRG2 = 1;
			while (!ADCPC1bits.SWTRG2);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_6 || defined MX_ADC_CHANNEL_7)
		if(MX_Current_Channel >= 6 && MX_Current_Channel <= 7)
		{
			ADCPC1 = 0x0100;
			ADCPC1bits.SWTRG3 = 1;
			while (!ADCPC1bits.SWTRG3);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_8 || defined MX_ADC_CHANNEL_9)
		if(MX_Current_Channel >= 8 && MX_Current_Channel <= 9)
		{
			ADCPC2 = 0x0001;
			ADCPC2bits.SWTRG4 = 1;
			while (!ADCPC2bits.SWTRG4);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_10 || defined MX_ADC_CHANNEL_11)
		if(MX_Current_Channel >= 10 && MX_Current_Channel <= 11)
		{
			ADCPC2 = 0x0100;
			ADCPC2bits.SWTRG5 = 1;
			while (!ADCPC2bits.SWTRG5);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_12 || defined MX_ADC_CHANNEL_13)
		if(MX_Current_Channel >= 12 && MX_Current_Channel <= 13)
		{
			ADCPC3 = 0x0001;
			ADCPC3bits.SWTRG6 = 1;
			while (!ADCPC3bits.SWTRG6);
		}
	  #endif

		if (Sample_Mode)
		{
			iRetVal = ADCBUF0;									//10-bit ADC
		}
		else
			iRetVal = (ADCBUF0 >> 2);							//8-bit ADC

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		ADCONbits.ADON = 0;
		ADPCFG = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 5 Supported Devices ************************************************************
dsPIC33FJx6GSx0x Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_5

	MX_UINT8 MX_Current_Channel;

	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{

		if(Channel < 16)
		{
			tris_reg = (MX_UINT8 *) &TRISB;
			tris_mask = Channel;
			clear_bit(ADPCFG, Channel);
		}
	  #ifdef MX_ADC_CHANNEL_16
		if(Channel == 16)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			tris_mask = 1;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_17
		if(Channel == 17)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			tris_mask = 2;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_18
		if(Channel == 18)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			tris_mask = 3;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_19
		if(Channel == 19)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			tris_mask = 4;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_20
		if(Channel == 20)
		{
			tris_reg = (MX_UINT8 *) &TRISE;
			tris_mask = 8;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_21
		if(Channel == 21)
		{
			tris_reg = (MX_UINT8 *) &TRISE;
			tris_mask = 9;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_22
		if(Channel == 22)
		{
			tris_reg = (MX_UINT8 *) &TRISA;
			tris_mask = 6;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_23
		if(Channel == 23)
		{
			tris_reg = (MX_UINT8 *) &TRISA;
			tris_mask = 7;
			clear_bit(ADPCFG2, (Channel - 16));
		}
	  #endif

		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<tris_mask);

		ADCON = 0x0000;
		ADCON = (Conv_Speed & 0x07);							//Assign conversion speed
		ADCONbits.ADON = 1;										//Turn on ADC
		delay_us(T_Charge);										//wait the acquisition time

		MX_Current_Channel = Channel;
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

	  #if (defined MX_ADC_CHANNEL_0 || defined MX_ADC_CHANNEL_1)
		if(MX_Current_Channel <= 1)								//begin next conversion
		{
			ADCPC0 = 0x0001;
			ADCPC0bits.SWTRG0 = 1;
			while (!ADCPC0bits.SWTRG0);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_2 || defined MX_ADC_CHANNEL_3)
		if(MX_Current_Channel >= 2 && MX_Current_Channel <= 3)
		{
			ADCPC0 = 0x0100;
			ADCPC0bits.SWTRG1 = 1;
			while (!ADCPC0bits.SWTRG1);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_4 || defined MX_ADC_CHANNEL_5)
		if(MX_Current_Channel >= 4 && MX_Current_Channel <= 5)
		{
			ADCPC1 = 0x0001;
			ADCPC1bits.SWTRG2 = 1;
			while (!ADCPC1bits.SWTRG2);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_6 || defined MX_ADC_CHANNEL_7)
		if(MX_Current_Channel >= 6 && MX_Current_Channel <= 7)
		{
			ADCPC1 = 0x0100;
			ADCPC1bits.SWTRG3 = 1;
			while (!ADCPC1bits.SWTRG3);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_8 || defined MX_ADC_CHANNEL_9)
		if(MX_Current_Channel >= 8 && MX_Current_Channel <= 9)
		{
			ADCPC2 = 0x0001;
			ADCPC2bits.SWTRG4 = 1;
			while (!ADCPC2bits.SWTRG4);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_10 || defined MX_ADC_CHANNEL_11)
		if(MX_Current_Channel >= 10 && MX_Current_Channel <= 11)
		{
			ADCPC2 = 0x0100;
			ADCPC2bits.SWTRG5 = 1;
			while (!ADCPC2bits.SWTRG5);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_12 || defined MX_ADC_CHANNEL_13)
		if(MX_Current_Channel >= 12 && MX_Current_Channel <= 13)
		{
			ADCPC3 = 0x0001;
			ADCPC3bits.SWTRG6 = 1;
			while (!ADCPC3bits.SWTRG6);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_14 || defined MX_ADC_CHANNEL_15)
		if(MX_Current_Channel >= 14 && MX_Current_Channel <= 15)
		{
			ADCPC3 = 0x0100;
			ADCPC3bits.SWTRG7 = 1;
			while (!ADCPC3bits.SWTRG7);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_16 || defined MX_ADC_CHANNEL_17)
		if(MX_Current_Channel >= 16 && MX_Current_Channel <= 17)
		{
			ADCPC4 = 0x0001;
			ADCPC4bits.SWTRG8 = 1;
			while (!ADCPC4bits.SWTRG8);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_18 || defined MX_ADC_CHANNEL_19)
		if(MX_Current_Channel >= 18 && MX_Current_Channel <= 19)
		{
			ADCPC4 = 0x0100;
			ADCPC4bits.SWTRG9 = 1;
			while (!ADCPC4bits.SWTRG9);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_20 || defined MX_ADC_CHANNEL_21)
		if(MX_Current_Channel >= 20 && MX_Current_Channel <= 21)
		{
			ADCPC5 = 0x0001;
			ADCPC5bits.SWTRG10 = 1;
			while (!ADCPC5bits.SWTRG10);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_22 || defined MX_ADC_CHANNEL_23)
		if(MX_Current_Channel >= 22 && MX_Current_Channel <= 23)
		{
			ADCPC5 = 0x0100;
			ADCPC5bits.SWTRG11 = 1;
			while (!ADCPC5bits.SWTRG11);
		}
	  #endif
	  #if (defined MX_ADC_CHANNEL_24 || defined MX_ADC_CHANNEL_25)
		if(MX_Current_Channel >= 24 && MX_Current_Channel <= 25)
		{
			ADCPC6 = 0x0001;
			ADCPC6bits.SWTRG12 = 1;
			while (!ADCPC6bits.SWTRG12);
		}
	  #endif

		if (Sample_Mode)
		{
			iRetVal = ADCBUF0;									//10-bit ADC
		}
		else
			iRetVal = (ADCBUF0 >> 2);							//8-bit ADC

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		ADCONbits.ADON = 0;
		ADPCFG = 0xFFFF;

	  #ifdef ADPCFG2
		if(MX_Current_Channel >= 16)
			ADPCFG2 = 0xFFFF;
	  #endif
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 6 Supported Devices ************************************************************
dsPIC30 Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_6
	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		tris_reg = (MX_UINT8 *) &TRISB;
		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<Channel);

		ADCON1 = 0x0000;
		ADCON2 = 0x0000;
		ADCON3 = 0x0000;
		ADCHS = 0x0000;

		clear_bit(ADPCFG, Channel);								//Setup ADC Channel
		ADCHS = (Channel & 0x000F);

		if (Vref == 0)											//Setup Vref+ functionality
			ADCON2 = ADCON2 & 0x1FFF;
		else
			ADCON2 = ADCON2 | 0x2000;

		ADCON3 = 0;
		if (Conv_Speed & 0x40)									//Assign conversion speed
			ADCON3bits.ADRC = 1;								//Internal RC Clock
		else
			ADCON3 = (Conv_Speed & 0x3F);						//Based on system clock

		//ADCON3 |= 0x0100;										//Dont think this is needed 17/08/12 BR

		ADCON1bits.ADON = 1;									//Turn on ADC
		ADCON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		ADCON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

		while (!ADCON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADCBUF0;									//12-bit ADC
		}
		else
			iRetVal = (ADCBUF0 >> 4);							//8-bit ADC

		ADCON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		ADCON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		ADCON1bits.ADON = 0;
		ADPCFG = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#define ADC_TOUCH_CONV_SPEED_VAL	0x0101
	#define ADC_TOUCH_LOOP_VAL			8
	#define ADC_TOUCH_PORT				LATB
	#define ADC_TOUCH_DDR				TRISB

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		MX_UINT16 ADC_Value = 0;
		MX_UINT8 loop = ADC_TOUCH_LOOP_VAL;
		MX_UINT16 dummy;

		// Initial setup
		ADCON2 = 0x0000;
		ADCON3 = ADC_TOUCH_CONV_SPEED_VAL;
		ADCON1 = 0x8000;		// ADON = 1 = A/D converter module is operating
		ADCHS = (Channel & 0x000F);

		while (loop--)
		{
			// output Vdd to pin, mux to read Vss
			ADPCFG  |= (1 << Channel);				// pin as digital
			ADC_TOUCH_PORT |= (1 << Channel);		// output high to pin
			ADC_TOUCH_DDR  &= ~(1 << Channel);		// pin as an output
			ADC_TOUCH_DDR  |= (1 << Channel);		// pin as an input
			// dummy read of the Vss sample
			ADCON1bits.SAMP = 1;					// take a sample
			delay_us(100);
			ADCON1bits.SAMP = 0;					// begin conversion
			while (!ADCON1bits.DONE);
			dummy = ADCBUF0;
			// change the mux and sample the pin
			ADPCFG  &= ~(1 << Channel);				// pin as an analogue input
			ADCON1bits.SAMP = 1;					// take a sample
			delay_us(100);
			ADCON1bits.SAMP = 0;					// begin conversion
			while (!ADCON1bits.DONE);
			ADC_Value += ADCBUF0;
		}

		// Shutdown
		ADCON1 = 0x0000;
		ADPCFG  |= (1 << Channel);					// pin as digital
		return ADC_Value / ADC_TOUCH_LOOP_VAL;
	}

	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 7 Supported Devices ************************************************************
dsPIC33/PIC24EPxxGP/MCx0x Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_7

	MX_UINT8 MX_Current_Channel;

	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		#ifdef MX_ADC_CHANNEL_0
			if (Channel == 0)
			{
				tris_reg = (MX_UINT8 *) &TRISA;
				tris_mask = 0;
				ANSELA = 0x0001;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_1
			if (Channel == 1)
			{
				tris_reg = (MX_UINT8 *) &TRISA;
				tris_mask = 1;
				ANSELA = 0x0002;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_2
			if (Channel == 2)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 0;
				ANSELB = 0x0001;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_3
			if (Channel == 3)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 1;
				ANSELB = 0x0002;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_4
			if (Channel == 4)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 2;
				ANSELB = 0x0004;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_5
			if (Channel == 5)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 3;
				ANSELB = 0x0008;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_6
			if (Channel == 6)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 0;
				ANSELC = 0x0001;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_7
			if (Channel == 7)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 1;
				ANSELC = 0x0002;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_8
			if (Channel == 8)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 2;
				ANSELC = 0x0004;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_9
			if (Channel == 9)
			{
				tris_reg = (MX_UINT8 *) &TRISA;
				tris_mask = 11;
				ANSELA = 0x0800;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_10
			if (Channel == 10)
			{
				tris_reg = (MX_UINT8 *) &TRISA;
				tris_mask = 12;
				ANSELA = 0x1000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_11
			if (Channel == 11)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 11;
				ANSELC = 0x0800;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_12
			if (Channel == 12)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 12;
				ANSELC = 0x1000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_13
			if (Channel == 13)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 13;
				ANSELE = 0x2000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_14
			if (Channel == 14)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 14;
				ANSELE = 0x4000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_15
			if (Channel == 15)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 15;
				ANSELE = 0x8000;
			}
		#endif

		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<tris_mask);

		AD1CHS0 = (Channel & 0x1F);

		AD1CON2bits.VCFG1 = 0;
		AD1CON2bits.VCFG2 = 0;

		if (Vref == 0)											//Setup Vref+ functionality
			AD1CON2bits.VCFG0 = 0;
		else
			AD1CON2bits.VCFG0 = 1;

		if (Conv_Speed == 64)									//Assign conversion speed
		{
			AD1CON3bits.ADRC = 1;
		}
		else
		{
			AD1CON3bits.ADRC = 0;
			AD1CON3 = (Conv_Speed & 0xFF);
		}

		AD1CON1bits.AD12B = 1;									//12bit sampling
		AD1CON1bits.ADON = 1;									//Turn on ADC
		AD1CON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		AD1CON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

		while (!AD1CON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADC1BUF0;									//12-bit ADC
		}
		else
			iRetVal = (ADC1BUF0 >> 4);							//8-bit ADC

		AD1CON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		AD1CON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;

		#ifdef ANSELA
			ANSELA = 0x00;
		#endif
		#ifdef ANSELB
			ANSELB = 0x00;
		#endif
		#ifdef ANSELC
			ANSELC = 0x00;
		#endif
		#ifdef ANSELE
			ANSELE = 0x00;
		#endif
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif


/* ADC Type 8 Supported Devices ************************************************************
PIC33FJxxxMCx06A / x08A / x10A Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_8
	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		if (Channel < 16)
		{
			tris_reg = (MX_UINT8 *) &TRISB;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | (1<<Channel);
			clear_bit(AD1PCFGL, Channel);							//Setup ADC Channel
		}

	  #ifdef MX_ADC_CHANNEL_16
		if (Channel == 16)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x02;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_17
		if (Channel == 17)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x04;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_18
		if (Channel == 18)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x08;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_19
		if (Channel == 19)
		{
			tris_reg = (MX_UINT8 *) &TRISC;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x10;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_20
		if (Channel == 20)
		{
			tris_reg = (MX_UINT8 *) &TRISE;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x0100;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_21
		if (Channel == 21)
		{
			tris_reg = (MX_UINT8 *) &TRISE;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x0200;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_22
		if (Channel == 22)
		{
			tris_reg = (MX_UINT8 *) &TRISA;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x40;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif
	  #ifdef MX_ADC_CHANNEL_23
		if (Channel == 23)
		{
			tris_reg = (MX_UINT8 *) &TRISA;
			old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
			*tris_reg = old_tris | 0x80;
			clear_bit(AD1PCFGH, (Channel - 16));					//Setup ADC Channel
		}
	  #endif

		AD1CHS0 = (Channel & 0x1F);

		if (Vref == 0)											//Setup Vref+ functionality
			AD1CON2bits.VCFG0 = 0;
		else
			AD1CON2bits.VCFG0 = 1;

		AD1CON3 = 0;
		if (Conv_Speed & 0x40)									//Assign conversion speed
			AD1CON3bits.ADRC = 1;								//Internal RC Clock
		else
			AD1CON3 = (Conv_Speed & 0x3F);						//Based on system clock

		AD1CON1bits.ADON = 1;									//Turn on ADC
		AD1CON1bits.AD12B = 1;
		AD1CON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		AD1CON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;

		while (!AD1CON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADC1BUF0;									//12-bit ADC
		}
		else
			iRetVal = (ADC1BUF0 >> 4);							//8-bit ADC

		AD1CON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		AD1CON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;
		AD1PCFGL = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif



/* ADC Type 9 Supported Devices ************************************************************
PIC24FxxKAxxx Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_9
	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		tris_reg = (MX_UINT8 *) &TRISB;
		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<Channel);

		//clear_bit(AD1PCFG, Channel);							//Setup ADC Channel
		AD1CHS = (Channel & 0x0F);

		if (Vref == 0)											//Setup Vref+ functionality
			AD1CON2bits.VCFG0 = 0;
		else
			AD1CON2bits.VCFG0 = 1;

		AD1CON3 = 0;
		if (Conv_Speed & 0x40)									//Assign conversion speed
			AD1CON3bits.ADRC = 1;								//Internal RC Clock
		else
			AD1CON3 = (Conv_Speed & 0x3F);						//Based on system clock

		AD1CON1bits.ADON = 1;									//Turn on ADC
		AD1CON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		AD1CON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;


		while (!AD1CON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADC1BUF0;									//12-bit ADC
		}
		else
			iRetVal = (ADC1BUF0 >> 2);							//8-bit ADC

		AD1CON1bits.SAMP = 1;
		delay_us(1);											//Required or processor locks up using Raw functions
		AD1CON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;
		//AD1PCFG = 0xFFFF;
	}

	#ifdef MX_ADC_TOUCH

	#warning "ADC Touch not yet supported on this device"

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		return 0;
	}
	#endif // MX_ADC_TOUCH

#endif



/* ADC Type 10 Supported Devices ************************************************************
dsPIC33/PIC24EPxxGU Family
*******************************************************************************************/

#ifdef MX_ADC_TYPE_10

	MX_UINT8 MX_Current_Channel;

	void FC_CAL_ADC_Enable (MX_UINT8 Channel, MX_UINT8 Conv_Speed, MX_UINT8 Vref, MX_UINT8 T_Charge)
	{
		#ifdef MX_ADC_CHANNEL_0
			if (Channel == 0)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 0;
				ANSELB = 0x0001;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_1
			if (Channel == 1)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 1;
				ANSELB = 0x0002;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_2
			if (Channel == 2)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 2;
				ANSELB = 0x0004;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_3
			if (Channel == 3)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 3;
				ANSELB = 0x0008;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_4
			if (Channel == 4)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 4;
				ANSELB = 0x0010;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_5
			if (Channel == 5)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 5;
				ANSELB = 0x0020;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_6
			if (Channel == 6)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 6;
				ANSELB = 0x0040;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_7
			if (Channel == 7)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 7;
				ANSELB = 0x0080;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_8
			if (Channel == 8)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 8;
				ANSELB = 0x0100;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_9
			if (Channel == 9)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 9;
				ANSELB = 0x0200;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_10
			if (Channel == 10)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 10;
				ANSELB = 0x0400;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_11
			if (Channel == 11)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 11;
				ANSELB = 0x0800;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_12
			if (Channel == 12)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 12;
				ANSELB = 0x1000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_13
			if (Channel == 13)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 13;
				ANSELB = 0x2000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_14
			if (Channel == 14)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 14;
				ANSELB = 0x4000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_15
			if (Channel == 15)
			{
				tris_reg = (MX_UINT8 *) &TRISB;
				tris_mask = 15;
				ANSELB = 0x8000;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_16
			if (Channel == 16)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 1;
				ANSELC = 0x0002;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_17
			if (Channel == 17)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 2;
				ANSELC = 0x0004;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_18
			if (Channel == 18)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 3;
				ANSELC = 0x0008;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_19
			if (Channel == 19)
			{
				tris_reg = (MX_UINT8 *) &TRISC;
				tris_mask = 4;
				ANSELC = 0x0010;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_20
			if (Channel == 20)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 8;
				ANSELE = 0x0100;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_21
			if (Channel == 21)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 9;
				ANSELE = 0x0200;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_22
			if (Channel == 22)
			{
				tris_reg = (MX_UINT8 *) &TRISA;
				tris_mask = 6;
				ANSELA = 0x0040;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_23
			if (Channel == 23)
			{
				tris_reg = (MX_UINT8 *) &TRISA;
				tris_mask = 7;
				ANSELA = 0x0080;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_24
			if (Channel == 24)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 0;
				ANSELE = 0x0001;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_25
			if (Channel == 25)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 1;
				ANSELE = 0x0002;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_26
			if (Channel == 26)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 2;
				ANSELE = 0x0004;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_27
			if (Channel == 27)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 3;
				ANSELE = 0x0008;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_28
			if (Channel == 28)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 4;
				ANSELE = 0x0010;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_29
			if (Channel == 29)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 5;
				ANSELE = 0x0020;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_30
			if (Channel == 30)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 6;
				ANSELE = 0x0040;
			}
		#endif
		#ifdef MX_ADC_CHANNEL_31
			if (Channel == 31)
			{
				tris_reg = (MX_UINT8 *) &TRISE;
				tris_mask = 7;
				ANSELE = 0x0080;
			}
		#endif

		old_tris = *tris_reg;									//store old tris value, and set the i/o pin as an input
		*tris_reg = old_tris | (1<<tris_mask);

		AD1CHS0 = (Channel & 0x1F);

		AD1CON2bits.VCFG1 = 0;
		AD1CON2bits.VCFG2 = 0;

		if (Vref == 0)											//Setup Vref+ functionality
			AD1CON2bits.VCFG0 = 0;
		else
			AD1CON2bits.VCFG0 = 1;

		if (Conv_Speed == 64)									//Assign conversion speed
		{
			AD1CON3bits.ADRC = 1;
		}
		else
		{
			AD1CON3bits.ADRC = 0;
			AD1CON3 = (Conv_Speed & 0xFF);
		}

		AD1CON1bits.AD12B = 1;									//12bit sampling
		AD1CON1bits.ADON = 1;									//Turn on ADC
		AD1CON1bits.SAMP = 1;

		delay_us(T_Charge);										//wait the acquisition time

		AD1CON1bits.SAMP = 0;									//begin next conversion
	}

	MX_UINT16 FC_CAL_ADC_Sample (MX_UINT8 Sample_Mode)
	{
		MX_UINT16 iRetVal;
		MX_UINT16 counter = 0;

		while (!AD1CON1bits.DONE);

		if (Sample_Mode)
		{
			iRetVal = ADC1BUF0;									//12-bit ADC
		}
		else
			iRetVal = (ADC1BUF0 >> 4);							//8-bit ADC

		AD1CON1bits.SAMP = 1;
		delay_us(1);											//wait the acquisition time											//Required or processor locks up using Raw functions
		AD1CON1bits.SAMP = 0;									//begin next conversion

		return (iRetVal);
	}

	void FC_CAL_ADC_Disable ()
	{
		*tris_reg = old_tris;									//restore old tris value, and reset adc registers
		AD1CON1bits.ADON = 0;

		#ifdef ANSELA
			ANSELA = 0x00;
		#endif
		#ifdef ANSELB
			ANSELB = 0x00;
		#endif
		#ifdef ANSELC
			ANSELC = 0x00;
		#endif
		#ifdef ANSELE
			ANSELE = 0x00;
		#endif
	}

	#ifdef MX_ADC_TOUCH

	#define ADC_TOUCH_CONV_SPEED_VAL	1
	#define ADC_TOUCH_LOOP_VAL			16
	#define ADC_TOUCH_VREF_VAL			0
	#define ADC_TOUCH_CHARGE_VAL		50

	MX_UINT16 FC_CAL_ADC_Touch (MX_UINT8 Channel)
	{
		MX_UINT16 ADC_Value = 0;
		MX_UINT8 loop = ADC_TOUCH_LOOP_VAL;
		MX_UINT16* latx;
		MX_UINT16* trisx;

		// use FC_CAL_ADC_Enable to setup the globals
		FC_CAL_ADC_Enable(Channel, ADC_TOUCH_CONV_SPEED_VAL, ADC_TOUCH_VREF_VAL, ADC_TOUCH_CHARGE_VAL);
		// wait until the conversion it kicks off has completed
		while (!AD1CON1bits.DONE);
		// get the LAT register from the configured TRIS register
		trisx = (MX_UINT16*)tris_reg;
		latx = trisx + 4;

		while (loop--)
		{
			// output Vdd to pin
			*trisx &= ~(1 << tris_mask);		// pin as output
			*latx |= (1 << tris_mask);			// set pin high
			delay_us(ADC_TOUCH_CHARGE_VAL);		// wait a while
			*trisx |= (1 << tris_mask);			// pin as input
			// sample the pin
			AD1CON1bits.SAMP = 1;				// take a sample
			delay_us(ADC_TOUCH_CHARGE_VAL);		// wait a while
			AD1CON1bits.SAMP = 0;				// begin conversion
			while (!AD1CON1bits.DONE);			// wait until it completes
			ADC_Value += ADC1BUF0;
		}

		FC_CAL_ADC_Disable();
		return ADC_Value / ADC_TOUCH_LOOP_VAL;
	}

	#endif // MX_ADC_TOUCH

#endif

