/*********************************************************************
 *
 *                  SPI Library definitions
 *
 *********************************************************************
 * FileName:        Spi.h
 * Dependencies:
 * Processor:       PIC32
 *
 * Complier:        MPLAB C32
 *                  MPLAB IDE
 * Company:         Microchip Technology Inc..
 *
 * Software License Agreement
 *
 * The software supplied herewith by Microchip Technology Incorporated
 * (the Company) for its PIC Microcontroller is intended
 * and supplied to you, the Companys customer, for use solely and
 * exclusively on Microchip PIC Microcontroller products.
 * The software is owned by the Company and/or its supplier, 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
 * license.
 *
 * 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.
 *
 *
 * $Id: Spi.h,v 1.3 2006/11/11 00:11:04 C12878 Exp $
 * $Name:  $
 *
 ********************************************************************/

#ifndef _SPI_H_
#define _SPI_H_



#include <p32xxxx.h>




/* Detect the number of supported SPI channels.
 * The number of supported SPI channels is variant specific and it's
 * defined in the specific processor header file.
*/


#undef	_SPI_DEF_CHN_		// symbol used for SPI channel detection/definition

#if defined(_SPI1)
	#define	_SPI_DEF_CHN_		1	
#elif defined(_SPI2)
	#define	_SPI_DEF_CHN_		2
#endif	// getting a valid SPI channel definition



#ifdef _SPI_DEF_CHN_

// SPI channels definition
// this enumerated value can be used in any function that requires
// an SPI channel as an input parameter


typedef enum
{
	SPI_CHANNELS	= 0, 	// number of current available channels
#if defined(_SPI1)
	SPI_CHANNEL1	= 1,
	SPI_CHANNELS	= SPI_CHANNELS+1,
#endif	// _SPI1

#if defined(_SPI2)
	SPI_CHANNEL2	= 2,
	SPI_CHANNELS	= SPI_CHANNELS+1,
#endif	// _SPI2
	

}SpiChannel;


// macros to translate internal SPI register definition to more user friendly interface definitions
#define _SPI_CON_MASK_(x, m)		_SPI ## x ## CON_ ## m
#define X_SPI_CON_MASK_(x, m)		_SPI_CON_MASK_(x, m)			// concatenation macro
#define _SPIxCON_MASK_(m)		X_SPI_CON_MASK_(_SPI_DEF_CHN_, m)


/********************
 * Channel functions.
 * Defined only if there's at least one valid SPI channel
 * *********************************/




// open flags
typedef enum
{
	// master opening mode
	SPI_OPEN_MSTEN = 		_SPIxCON_MASK_(MSTEN_MASK),	// set the Master mode
	SPI_OPEN_SMP_END =	 	_SPIxCON_MASK_(SMP_MASK),	// Master Sample Phase for the input bit at the end of the data out time. Otherwise data is sampled in the middle.

	// slave opening mode
	SPI_OPEN_SLVEN =		0,				// set the Slave mode
	SPI_OPEN_SSEN = 		_SPIxCON_MASK_(SSEN_MASK),	// enable the SS (Slave Select) input pin. 
	
	// clocking opening mode
	SPI_OPEN_CKP_HIGH = 		_SPIxCON_MASK_(CKP_MASK),	// set the clock polarity to (idle-high, active-low). Otherwise is (idle-low, active-high).
	SPI_OPEN_CKE_REV =	 	_SPIxCON_MASK_(CKE_MASK),	// set the Clock Edge reversed: transmit from active to idle. Otherwise transmit when clock goes from idle to active

	// data characters opening mode
	SPI_OPEN_MODE8 =		0,				// set 8 bits/char
	SPI_OPEN_MODE16 = 		_SPIxCON_MASK_(MODE16_MASK),	// set 16 bits/char
	SPI_OPEN_MODE32 = 		_SPIxCON_MASK_(MODE32_MASK),	// set 32 bits/char
	
	// framed mode opening mode
	SPI_OPEN_FRMEN = 		_SPIxCON_MASK_(FRMEN_MASK),	// Enable the Framed SPI support. Otherwise the Framed SPI is disabled.
	SPI_OPEN_FSP_IN =		_SPIxCON_MASK_(FRMSYNC_MASK),	// Frame Sync Pulse (FSP) direction set to input (Frame Slave).
       									// Otherwise the FSP is output and the SPI channel operates as a Frame Master.
	SPI_OPEN_FSP_HIGH = 		_SPIxCON_MASK_(FRMPOL_MASK),	// FSP polarity set active high. Otherwise the FSP is active low.
	SPI_OPEN_FSP_CLK1 = 		_SPIxCON_MASK_(SPIFE_MASK),	// Set the Frame Sync Pulse (FSP) to coincide with the 1st bit clock.
       								// Otherwise the FSP precedes the 1st bit clock 

	// general opening mode
	SPI_OPEN_DISSDO = 		_SPIxCON_MASK_(DISSDO_MASK),	// disable the usage of the SDO pin by the SPI
	SPI_OPEN_SIDL = 		_SPIxCON_MASK_(SIDL_MASK),	// enable the Halt in the CPU Idle mode. Otherwise the SPI will be still active when the CPU is in Idle mode. 
	SPI_OPEN_FRZ = 			_SPIxCON_MASK_(FRZ_MASK),	// Debug mode only: enable the Freeze operation while in Debug. Otherwise continue to operate.
	SPI_OPEN_ON = 			_SPIxCON_MASK_(ON_MASK),	// turn ON the SPI (not used in SpiChnOpen)
}SpiOpenFlags;	// open flags that can be used with SpiChnOpen. Defined in the processor header file.



/*********************************************************************
 * Function:        void SpiChnOpen(SpiChannel chn, SpiOpenFlags oFlags, unsigned int srcClkDiv)
 *
 * PreCondition:    srcClkDiv  - valid value between 2 and 1024
 *                  chn        - a valid SPI channel number
 *
 * Input:           chn    - the channel to set
 *                  oFlags - any of the values from SpiOpenFlags:
 *                             master slave opening mode: SPI_OPEN_MSTEN, SPI_OPEN_SLVEN, SPI_OPEN_SSEN
 *                             clocking and character opening mode: SPI_OPEN_CKP, SPI_OPEN_CKE, SPI_OPEN_SMP, SPI_OPEN_MODE8, SPI_OPEN_MODE16, SPI_OPEN_MODE32
 *                             framed mode opening mode: SPI_OPEN_SPIFE, SPI_OPEN_FRMPOL, SPI_OPEN_FRMSYNC, SPI_OPEN_FRMEN
 *                             general opening mode: SPI_OPEN_DISSDO, SPI_OPEN_SIDL, SPI_OPEN_FRZ, SPI_OPEN_ON
 *                  srcClkDiv - Source Clock divisor to extract the bitrate=srcClk/srcClkDiv.
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function opens the SPI channel: turns the channel on and initializes it according to the oFlags input parameter.
 *                  After that the channel is enabled.
 *                  It also sets the brg register.
 *                  The SPI bitrate is given by: bitrate=srcClk/(2*(SPIBRG+1))
 *                  The input parametes srcClkDiv specifies the srcClk divisor term (2*(SPIBRG+1)),
 *                  so the BRG is calculated as SPIBRG=srcClkDiv/2-1.
 *
 * Note:            - The channel is turned off, the pending interrupts are cleared, interrupts are disabled. After that it is configured
 *                  - The bitrate is always obtained by dividing the srcClk by srcClkDiv, an even number
 *                  between 2 and 1024.
 *                  - For a specific SPI bitrate, the srcClkDiv that has to be passed is:
 *                  srcClkDiv=srcClk/bitrate;
 *                  - When selecting the number of bits per character, SPI_OPEN_MODE32 has the highest priority.
 *                  If SPI_OPEN_MODE32 is not set, then SPI_OPEN_MODE16 selects the character width.
 *                  - The function properly sets the SPI pins as digital i/o pins.
 *                  - The SS pin is set as a digital pin only if in frame mnode or if the SPI_OPEN_SSEN is set.
 *                  Even in master mode the library will properly se the SS pin as an digital output
 *                  if the SPI_OPEN_SSEN is set.
 *                  - The SPI channel is turned ON after it is configured. The use of SPI_OPEN_ON is not needed.
 *                  - For PIC32MX the srcClk is the peripheral bus clock.
 *
 * Example:        int srcClk=GetPBusFrequency(); SpiChnOpen(SPI_CHANNEL1, SPI_OPEN_MSTEN|SPI_OPEN_SMP|SPI_OPEN_MODE32, srcClk/20000000);
 *                 will open the SPI1 and set the bit rate to 20MHz.
 ********************************************************************/
void	SpiChnOpen(SpiChannel chn, SpiOpenFlags oFlags, unsigned int srcClkDiv);



/*********************************************************************
 * Function:        void SpiChnClose(SpiChannel chn)
 *
 * PreCondition:    chn	- a valid SPI channel number
 *
 * Input:			chn		- the channel to close
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function closes the SPI channel. Some previous error conditions are cleared.
 * 					Channel interrupts are disabled.
 *
 * Note:		- The I/O pins used by the SPI module are returned to their reset configuration.
 * 			- The SPI_OPEN_SSEN is used to decide if the SS pin has to be returned to the reset state.
 *
 * Example:			SpiChnClose(SPI_CHANNEL2);
 ********************************************************************/
void	SpiChnClose(SpiChannel chn);


/*********************************************************************
 * Function:        void SpiChnChangeMode(SpiChannel chn, int isMaster, int isFrmMaster, int waitBusy)
 *
 * PreCondition:    None
 *
 * Input:           chn         - the channel to set
 *                  isMaster    - master/slave mode
 *                  isFrmMaster - frame master/slave mode
 *                  waitBusy    - boolean to wait/no wait for the current transfer to finish
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function changes the SPI channel mode on the fly.
 *
 * Note:            - If waitBusy is TRUE, the function blocks until the current transfer, if any, is completed.
 *                    Due to a bug in the PIC32_3XX_4xx and PIC32_5XX_6xx_7xx SPI implementation, the BUSY/SRMT flag is set one spi_clk earlier.
 *                    What it means is that the data is not available in the SPIRxBUFF/SPIRxFIFO at the moment that BUSY is cleared.
 *                    The function will wait for the BUSY to be cleared.
 *                    For high SPIxBRG and PBDIV values note that the number of CPU clock cycles that have to be spent in this function could be significant.
 *                  - If waitBusy is FALSE, the function performs the mode switching immediately. It assumes that no transfer is currently on.
 *                    The caller must make sure that the current transfer, if any, is completed. 
 *                  - isFrmMaster is relevant only if the SPI channel is operating in frame mode
 *                  - The SCK is properly configured as an digital I/O pin
 *                  - The SS is configured as a digital pin only if in frame mode or if the SSEN configuration bit is set.
 *
 * Example:         SpiChnChangeMode(SPI_CHANNEL2A, TRUE, TRUE, TRUE);
 ********************************************************************/
void	SpiChnChangeMode(SpiChannel chn, int isMaster, int isFrmMaster, int waitBusy);



/*********************************************************************
 * Function:        int SpiChnDataRdy(SpiChannel chn)
 *
 * PreCondition:    None
 *
 * Input:			chn			- the channel to check
 *
 * Output:          TRUE		- if data available
 * 					FALSE		otherwise
 *
 * Side Effects:    None
 *
 * Overview:        This function reads the SPI channel data ready condition.
 *
 * Note:            None
 *
 * Example:         int isDataAvlbl=SpiChnDataRdy(SPI_CHANNEL1);
 ********************************************************************/
int		SpiChnDataRdy(SpiChannel chn);


/*********************************************************************
 * Function:        unsigned int SpiChnReadC(SpiChannel chn)
 *
 * PreCondition:    None
 *
 * Input:           chn - the channel to use
 *
 * Output:          data available in the SPI rx buffer
 *
 * Side Effects:    None
 *
 * Overview:        This function returns immediately the data from the SPI buffer.
 *                  It does not check if there's any new data available.
 *
 * Note:            When a new data word has been shifted into shift register SPIxSR and:
 *                  - in standard mode: the previous contents of receive register SPIxRXB have not been read
 *                  - in FIFO mode: the FIFO is full
 *                  then the Rx Overflow (SPIROV) bit will be set.
 *                  The module will not transfer the received data from SPIxSR to the SPIxRXB (FIFO)
 *                  Further data reception is disabled until the SPIROV bit is cleared. 
 *                  The SPIROV bit is not cleared automatically by the module and must be 
 *                  cleared by the user software.
 *
 * Example:         unsigned int newData=SpiChnReadC(SPI_CHANNEL2);
 ********************************************************************/
unsigned int		SpiChnReadC(SpiChannel chn);


/*********************************************************************
 * Function:        unsigned int SpiChnGetC(SpiChannel chn)
 *
 * PreCondition:    None
 *
 * Input:			chn			- the channel to check
 *
 * Output:          data available in the SPI rx buffer
 *
 * Side Effects:    None
 *
 * Overview:        This function waits for data to be available and returns it.
 *
 * Note:            When a new data word has been shifted into shift register SPIxSR and 
 *                  the previous contents of receive register SPIxRXB have not been read
 *                  by the user software, then SPIROV bit (SPIxSTAT<6>) will be set.The 
 *                  module will not transfer the received data from SPIxSR to the SPIxRXB. 
 *                  Further data reception is disabled until the SPIROV bit is cleared. 
 *                  The SPIROV bit is not cleared automatically by the module and must be 
 *                  cleared by the user software.
 *
 * Example:			int newData=SpiChnGetC(SPI_CHANNEL2);
 ********************************************************************/
unsigned int		SpiChnGetC(SpiChannel chn);


/*********************************************************************
 * Function:        void SpiChnGetS(SpiChannel chn, unsigned int *pBuff, unsigned int nChars)
 *
 * PreCondition:    pBuff has to be a valid pointer to a buffer large enough to store all the received characters
 *
 * Input:			chn				- the SPI channel
 * 			        pBuff			- address of buffer to store data
 * 					nChars			- number of characters expected
 *
 * Output:          None

 * Side Effects:    None
 *
 * Overview:        This routine reads a buffer of characters from the corresponding SPI channel receive buffer.
 * 					The number of byte/hword/word to be read is determined by parameter nChars.
 * 					Waits for RX data available for each character.
 *
 * Note:            - pBuff is considered to be 8/16/32 bits data pointer, according to the
 * 					current SPI mode!
 * 					- The function blocks waiting for the whole buffer to be received.
 *                  
 *                  When a new data word has been shifted into shift register SPIxSR and 
 *                  the previous contents of receive register SPIxRXB have not been read
 *                  by the user software, then SPIROV bit (SPIxSTAT<6>) will be set.The 
 *                  module will not transfer the received data from SPIxSR to the SPIxRXB. 
 *                  Further data reception is disabled until the SPIROV bit is cleared. 
 *                  The SPIROV bit is not cleared automatically by the module and must be 
 *                  cleared by the user software.
 *
 * Example:			unsigned short myBuff[100]; SpiChnGetS(SPI_CHANNEL2, myBuff, sizeof(myBuff)/sizeof(*myBuff));	// receive 16 bit characters
 ********************************************************************/
void	SpiChnGetS(SpiChannel chn, unsigned int *pBuff, unsigned int nChars);




/*********************************************************************
 * Function:        int SpiChnTxBuffEmpty(SpiChannel chn)
 *
 * PreCondition:    None
 *
 * Input:			chn			- the channel to check
 *
 * Output:          TRUE		- if transmit buffer empty
 * 					FALSE		otherwise
 *
 * Side Effects:    None
 *
 * Overview:        This function reads the SPI channel transmit buffer empty condition.
 *
 * Note:            None
 *
 * Example:			int canTransmit=SpiChnTxBuffEmpty(SPI_CHANNEL1);
 ********************************************************************/
int		SpiChnTxBuffEmpty(SpiChannel chn);


/*********************************************************************
 * Function:        void SpiChnWriteC(SpiChannel chn, unsigned int data)
 *
 * PreCondition:    None
 *
 * Input:           chn  - the channel to use
 *                  data - the data to be written to the port
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This routine writes inmmediately a character (byte/half word/word) to the SPI buffer register.
 *
 * Note:            byte/hword/word accesses will perform correctly.
 *
 * Example:         SpiChnWriteC(SPI_CHANNEL1, 0x1b);		// send an ESC character
 ********************************************************************/
void		SpiChnWriteC(SpiChannel chn, unsigned int data);

/*********************************************************************
 * Function:        void SpiChnPutC(SpiChannel chn, unsigned int data)
 *
 * PreCondition:    None
 *
 * Input:			chn			- the channel to check
 * 					data	- the data to be written to the port
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This routine writes a single byte/half word/word to the SPI bus.
 * 					It waits for TX buffer empty, so that it doesn't overwrite the previous untransmitted data.
 *
 * Note:            byte/hword/word accesses will perform correctly.
 *
 * Example:			SpiChnPutC(SPI_CHANNEL1, 0x1b);		// send an ESC character
 ********************************************************************/
void		SpiChnPutC(SpiChannel chn, unsigned int data);

/*********************************************************************
 * Function:        void SpiChnPutS(SpiChannel chn, unsigned int* pBuff, unsigned int nChars)
 *
 * PreCondition:    None
 *
 * Input:           chn		- the SPI channel
 * 					pBuff	- address of buffer storing the data to be transmitted.
 * 					nChars	- number of characters to be transmitted

 * Output:          None

 * Side Effects:    None

 * Overview:        This function writes the specified number of 8/16/32 bit characters
 * 					from the specified buffer.
 *					It waits for Tx buffer empty so the characters are not overwritten.

 * Note:            pBuff is considered to be 8/16/32 bits data pointer, according to the
 * 					current SPI mode!
 *
 * Example:			SpiChnPutS(SPI_CHANNEL1, myBuff, 100);
 ********************************************************************/
void		SpiChnPutS(SpiChannel chn, unsigned int* pBuff, unsigned int nChars);

/*********************************************************************
 * Function:        int SpiChnGetRov(SpiChannel chn, int clear)
 *
 * PreCondition:    None
 *
 * Input:			chn			- the channel to check
 *					clear		- if TRUE, the overflow condition has to be cleared, if present
 *
 * Output:          TRUE		- if overflow
 * 					FALSE		otherwise
 *
 * Side Effects:    None
 *
 * Overview:        This function reads the SPI channel overflow condition and clears it, if required.
 *
 * Note:            None
 *
 * Example:			int isOvfl=SpiChnGetRov(SPI_CHANNEL1, FALSE);
 ********************************************************************/
int		SpiChnGetRov(SpiChannel chn, int clear);

/********************************************************************
 * Low Level SPI functions
 * Direct configuration and Clock/bitrate helpers.
 ********************************************************************/

// configuration flags
typedef enum
{
	// master configuration
	SPI_CONFIG_MSTEN = 		_SPIxCON_MASK_(MSTEN_MASK),	// set the Master mode
	SPI_CONFIG_SMP_END =	 	_SPIxCON_MASK_(SMP_MASK),	// Master Sample Phase for the input bit at the end of the data out time. Otherwise data is sampled in the middle.

	// slave configuration
	SPI_CONFIG_SLVEN =		0,				// set the Slave mode
	SPI_CONFIG_SSEN = 		_SPIxCON_MASK_(SSEN_MASK),	// enable the SS (Slave Select) input pin. 
	
	// clocking configuration
	SPI_CONFIG_CKP_HIGH = 		_SPIxCON_MASK_(CKP_MASK),	// set the clock polarity to (idle-high, active-low). Otherwise is (idle-low, active-high).
	SPI_CONFIG_CKE_REV =	 	_SPIxCON_MASK_(CKE_MASK),	// set the Clock Edge reversed: transmit from active to idle. Otherwise transmit when clock goes from idle to active

	// data characters configuration
	SPI_CONFIG_MODE8 =		0,				// set 8 bits/char
	SPI_CONFIG_MODE16 = 		_SPIxCON_MASK_(MODE16_MASK),	// set 16 bits/char
	SPI_CONFIG_MODE32 = 		_SPIxCON_MASK_(MODE32_MASK),	// set 32 bits/char
	
	// framed mode configuration
	SPI_CONFIG_FRMEN = 		_SPIxCON_MASK_(FRMEN_MASK),	// Enable the Framed SPI support. Otherwise the Framed SPI is disabled.
	SPI_CONFIG_FSP_IN =		_SPIxCON_MASK_(FRMSYNC_MASK),	// Frame Sync Pulse (FSP) direction set to input (Frame Slave).
       									// Otherwise the FSP is output and the SPI channel operates as a Frame Master.
	SPI_CONFIG_FSP_HIGH = 		_SPIxCON_MASK_(FRMPOL_MASK),	// FSP polarity set active high. Otherwise the FSP is active low.
	SPI_CONFIG_FSP_CLK1 = 		_SPIxCON_MASK_(SPIFE_MASK),	// Set the Frame Sync Pulse (FSP) to coincide with the 1st bit clock.
       								// Otherwise the FSP precedes the 1st bit clock 

	// general configuration
	SPI_CONFIG_DISSDO = 		_SPIxCON_MASK_(DISSDO_MASK),	// disable the usage of the SDO pin by the SPI
	SPI_CONFIG_SIDL = 		_SPIxCON_MASK_(SIDL_MASK),	// enable the Halt in the CPU Idle mode. Otherwise the SPI will be still active when the CPU is in Idle mode. 
	SPI_CONFIG_FRZ = 		_SPIxCON_MASK_(FRZ_MASK),	// Debug mode only: enable the Freeze operation while in Debug. Otherwise continue to operate.
	SPI_CONFIG_ON = 		_SPIxCON_MASK_(ON_MASK),	// turn ON the SPI (not used in SpiChnOpen)
}SpiConfigFlags;	// configuration flags that can be used with SpiChnConfigure. Defined in the processor header file.

/*********************************************************************
 * Function:        void SpiChnConfigure(SpiChannel chn, SpiConfigFlags config)
 *
 * PreCondition:    chn        - a valid SPI channel number
 *
 * Input:           chn    - the channel to set
 *                  config - any of the values from SpiConfigFlags:
 *                             master slave configure: SPI_CONFIG_MSTEN, SPI_CONFIG_SLVEN, SPI_CONFIG_SSEN
 *                             clocking and character configuration: SPI_CONFIG_CKP, SPI_CONFIG_CKE, SPI_CONFIG_SMP, SPI_CONFIG_MODE8, SPI_CONFIG_MODE16, SPI_CONFIG_MODE32
 *                             framed mode configuration: SPI_CONFIG_SPIFE, SPI_CONFIG_FRMPOL, SPI_CONFIG_FRMSYNC, SPI_CONFIG_FRMEN
 *                             general configuration: SPI_CONFIG_DISSDO, SPI_CONFIG_SIDL, SPI_CONFIG_FRZ, SPI_CONFIG_ON
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function is an alternative to SpiChnOpen. The application can first configure and then turn ON the channel.
 *                  The function performs the configuration of the SPI channel according to the config input parameter.
 *
 * Note:            - The channel is NOT turned off by this function; It should be turned off before calling this function.
 *                  - The pending interrupts are NOT cleared or disabled.
 *                  - The function does NOT set the SPI pins as digital i/o pins.
 *                  - The SPI channel is configured but NOT turned ON. Use SpiChnEnable(1) to turn ON the channel.
 *                  - When selecting the number of bits per character, SPI_CONFIG_MODE32 has the highest priority.
 *                  If SPI_CONFIG_MODE32 is not set, then SPI_CONFIG_MODE16 selects the character width.
 *
 * Example:        SpiChnEnable(SPI_CHANNEL1, 0);
 *                 SpiChnConfigure(SPI_CHANNEL1, SPI_CONFIG_MSTEN|SPI_CONFIG_SMP|SPI_CONFIG_MODE32);
 *                 SpiChnEnable(SPI_CHANNEL1, 1);
 *                 will configure and then enable the SPI1.
 ********************************************************************/
void	SpiChnConfigure(SpiChannel chn, SpiConfigFlags config);


/*********************************************************************
 * Function:        void SpiChnEnable(SpiChannel chn, int enable)
 *
 * PreCondition:    chn        - a valid SPI channel number
 *
 * Input:           chn    - the channel to enable/disable
 *                  enable - boolean to enable/disable the channel
 *                  
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function enables or disables the SPI channel.
 * 
 * Note:            - Before enabling the channel, proper configuration should be done.
 *
 * Example:        SpiChnConfigure(SPI_CHANNEL1, SPI_CONFIG_MSTEN|SPI_CONFIG_SMP|SPI_CONFIG_MODE32);
 *                 SpiChnEnable(1);
 *                 will configure and enable the SPI1 channel.
 ********************************************************************/
void	SpiChnEnable(SpiChannel chn, int enable);


/*********************************************************************
 * Function:        unsigned int SpiChnSetBitRate(SpiChannel chn, unsigned int srcClk, unsigned int spiClk)
 *
 * PreCondition:    srcClk/1024 <= spiClk <= srcClk/2;
 *                  chn        - a valid SPI channel number
 *
 * Input:           chn    - the channel to set the bitrate for
 *                  srcClk - the SPI module Source Clock, Hz
 *                  spiClk - the desired SPI bitrate frequency, Hz
 *
 * Output:          the actual selected bitrate, Hz
 *
 * Side Effects:    None
 *
 * Overview:        This function configures the SPI channel with a desired bitrate.
 *                  The SPI bitrate is given by: spiClk=srcClk/(2*(SPIBRG+1))
 *                  The proper SPIBRG value is calculated as SPIBRG=(srcClk/spiClk)/2-1.
 *
 * Note:            - The channel has to be first configured with a valid bitrate and then enabled.
 *                  The bitrate can be changed dynamically, when no transaction is in progress.
 *                  - The bitrate is irrelevant for the Slave operation mode since the clock is provided externally, by the Master.
 *                  - For PIC32MX the srcClk is the peripheral bus clock.
 *
 * Example:        SpiChnEnable(0);
 *                 SpiChnConfigure(SPI_CHANNEL1, SPI_CONFIG_MSTEN|SPI_CONFIG_SMP|SPI_CONFIG_MODE32); 
 *                 SpiChnSetBitRate(SPI_CHANNEL1, GetPBusFrequency(), 20000000);
 *                 SpiChnEnable(1);
 *                 will configure the SPI1, set the bitrate to 20MHz.
 ********************************************************************/
unsigned int	SpiChnSetBitRate(SpiChannel chn, unsigned int srcClk, unsigned int spiClk);


/*********************************************************************
 * Function:        void SpiChnSetBrg(SpiChannel chn, unsigned int brg)
 *
 * PreCondition:    None
 *
 * Input:			chn		- the channel to set
 *					brg		- value for the brg register
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        This function updates the values for the SPI channel brg/prescalers.
 *
 * Note:            None
 *
 * Example:         SpiChnSetBrg(SPI_CHANNEL1, 0x12);
 ********************************************************************/
void	SpiChnSetBrg(SpiChannel chn, unsigned int brg);


/******************************************************************************
 * Function:        unsigned int SpiBrgVal(unsigned int srcClk, unsigned int spiClk)
 *
 * Description:     Calculates the BRG values needed for the SPI configuration
 *
 * PreCondition:    srcClk/1024 <= spiClk <= srcClk/2;
 *
 * Inputs:          srcClk:   - the source clock to the SPI module, Hz
 *                  spiClk:   - the desired SPI clock frequency, Hz
 *
 * Output:          The proper BRG value.
 *                  For PIC32MX the srcClk is the Peripheral bus clock value.
 *
 * Example:         SpiChnSetBrg(SPI_CHANNEL1, SpiBrgVal(72000000, 9000000));
 *
 *****************************************************************************/
extern __inline__ unsigned int __attribute__((always_inline))	SpiBrgVal(unsigned int srcClk, unsigned int spiClk)
{
	return (srcClk / (2 * spiClk)) - 1;
}





/********************************************************************
 * Include legacy SPI functions
 * New projects should not use them!
 * Note that interrupt functions are no longer provided.
 * The functions in the int.h should be used instead.
 ********************************************************************/
#ifndef _PLIB_DISABLE_LEGACY
	#include <peripheral/legacy/spi_legacy.h>
#endif


#endif		// _SPI_DEF_CHN_ 

#endif /*_SPI_H_*/

