/******************** (C) COPYRIGHT 2020 SONiX *******************************
* COMPANY:			SONiX
* DATE:					2020/06
* AUTHOR:				SA1
* IC:						SN32F780/790
* DESCRIPTION:	I2S0 related functions.
*____________________________________________________________________________
* REVISION	Date				User		Description
* 0.1				2020/06/24	SA1			1. First release
*	
*____________________________________________________________________________
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS TIME TO MARKET.
* SONiX SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL 
* DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT OF SUCH SOFTWARE
* AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN 
* IN CONNECTION WITH THEIR PRODUCTS.
*****************************************************************************/

/*_____ I N C L U D E S ____________________________________________________*/
#include "I2S.h"
#include "..\..\Utility\Utility.h"

/*_____ D E C L A R A T I O N S ____________________________________________*/

/*_____ D E F I N I T I O N S ______________________________________________*/

/*_____ M A C R O S ________________________________________________________*/

/*_____ F U N C T I O N S __________________________________________________*/

/**************************************************************
* Function		: I2S0_Master_INIT
* Description	: Set I2S0 as master
* Input			: None
* Output		: None
* Return		: None
* Note			: None
****************************************************************/
void I2S0_Master_Init(void)
{
	__I2S0_ENABLE_I2SHCLK;														//Enable HCLK for I2S
	
	SN_I2S0->CTRL_b.I2SEN = I2S_I2SEN_EN;							//I2S enable bit	
	SN_I2S0->CTRL_b.CHLENGTH = I2S_CHLENGTH_32BITS;		//Single channel[4:0]
	SN_I2S0->CTRL_b.RXFIFOTH = I2S_RXFIFOTH_2;				//RX FIFO Threshold level
	SN_I2S0->CTRL_b.TXFIFOTH = I2S_TXFIFOTH_6;				//TX FIFO Threshold level

	SN_I2S0->CTRL_b.DL = I2S_DL_24BITS;								//I2S Data Length
	__I2S0_RESET_RXFIFO;															//Clear I2S RX FIFO
	__I2S0_RESET_TXFIFO;															//Clear I2S TX FIFO
	SN_I2S0->CTRL_b.RXEN = I2S_RXEN_EN;								//Receiver enable bit
	SN_I2S0->CTRL_b.TXEN = I2S_TXEN_EN;								//Transmit enable bit
	
	SN_I2S0->CTRL_b.FORMAT = I2S_FORMAT_STANDARD;			//I2S operation format
	SN_I2S0->CTRL_b.MS = I2S_MS_MASTER_MODE;					//Master selection bit			
	SN_I2S0->CTRL_b.MONO = I2S_MONO_STERO;						//Stereo selection bit
	SN_I2S0->CTRL_b.MUTE = I2S_MUTE_DIS;							//Mute enable bit
	
	//I2S clk
	SN_I2S0->CLK = mskI2S_CLKSEL_HCLK |								//I2S clock source selection
								mskI2S_BCLKDIV_DIV |								//MCLK/n, n = 2, 4, 6, 8, ...,512
								mskI2S_MCLKSEL_I2S_PCLK |						//MCLK source of master is from I2S_PCLK
								mskI2S_MCLKOEN_OUTPUT_DIS |					//MCLK output enable bit
								mskI2S_MCLKDIV_DIV3;								//MCLK = MCLK source / 6
}

/**************************************************************
* Function		: I2S0_Slave_Init
* Description	: Set I2S0 as slave
* Input			: None
* Output		: None
* Return		: None
* Note			: None
****************************************************************/
void I2S0_Slave_Init(void)
{
	__I2S0_ENABLE_I2SHCLK;														//Enable HCLK for I2S

	SN_I2S0->CTRL_b.I2SEN = I2S_I2SEN_EN ;						//I2S enable bit	
	SN_I2S0->CTRL_b.CHLENGTH = I2S_CHLENGTH_32BITS;		//Single channel[4:0]
	SN_I2S0->CTRL_b.RXFIFOTH = I2S_RXFIFOTH_2;				//RX FIFO Threshold level
	SN_I2S0->CTRL_b.TXFIFOTH = I2S_TXFIFOTH_6;	
	
	SN_I2S0->CTRL_b.DL = I2S_DL_24BITS;								//I2S Data Length
	__I2S0_RESET_RXFIFO;															//Clear I2S RX FIFO
	__I2S0_RESET_TXFIFO;															//Clear I2S TX FIFO
	SN_I2S0->CTRL_b.RXEN = I2S_RXEN_EN;								//Receiver enable bit
	SN_I2S0->CTRL_b.TXEN = I2S_TXEN_EN;	
	
	SN_I2S0->CTRL_b.FORMAT=I2S_FORMAT_STANDARD;				//I2S operation format
	SN_I2S0->CTRL_b.MS=I2S_MS_SLAVE_MODE;							//Master selection bit			
	SN_I2S0->CTRL_b.MONO=I2S_MONO_STERO;							//Stereo selection bit
	SN_I2S0->CTRL_b.MUTE=I2S_MUTE_DIS;	
}

/*****************************************************************************
* Function		: I2S0_Enable
* Description	: I2S0 enable
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void I2S0_Enable(void)
{
	__I2S0_ENABLE_I2SHCLK;														//Enable HCLK for I2S
	
	SN_I2S0->CTRL_b.I2SEN = I2S_I2SEN_EN ;						//I2S enable bit	
	__I2S0_RESET_TXFIFO;
	__I2S0_RESET_RXFIFO;
}

/*****************************************************************************
* Function		: I2S0_Disable
* Description	: I2S0 disable
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void I2S0_Disable(void)
{
	SN_I2S0->CTRL_b.I2SEN   = I2S_I2SEN_DIS;    			//I2S disable bit
		
	__I2S0_DISABLE_I2SHCLK;														//Disable HCLK for I2S
}

/**********************************
* Function		: I2S0_Interrupt_Enable
* Description	: I2S0 interrupt enable
* Input			: None
* Output		: None
* Return		: None
* Note			: None
**********************************/
void I2S0_Interrupt_Enable(void)
{
	SN_I2S0->IC = mskI2S_RXFIFOTHIC |									//Clear RXFIFOTHIF bit
							 mskI2S_TXFIFOTHIC |									//Clear TXFIFOTHIF bit
							 mskI2S_RXFIFOUDIC |									//Clear RXFIFOOUDIF bit
							 mskI2S_TXFIFOOVIC;										//Clear TXFIFOOVIF bit
	
	SN_I2S0->IE = mskI2S_TXFIFOOVFIEN_EN |						//TX FIFO overflow interrupt enable bit
							 mskI2S_RXFIFOUDFIEN_EN |							//RX FIFO underflow interrupt enable bit
							 mskI2S_TXFIFOTHIEN_EN |							//TX FIFO threshold interrupt enable bit
							 mskI2S_RXFIFOTHIEN_EN;								//RX FIFO threshold interrupt enable bit
}

/**************************************************************
* Function		: I2S0_IRQHandler
* Description	: I2S0 as interrupt handler
* Input			: None
* Output		: None
* Return		: None
* Note			: None
****************************************************************/
__irq void I2S0_IRQHandler(void)
{
	I2S0_Master_Irq();
	//I2S0_Slave_Irq();
}

/*****************************************************************************
* Function		: I2S0_Master_Irq
* Description	: I2S0 master irq
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void I2S0_Master_Irq(void)
{
	uint32_t wI2S_Read_Data;
	uint32_t wI2S_Loop_Cnt = 0;
	
	if (SN_I2S0->RIS & mskI2S_TXFIFOOVIF)					//Tx overflow
	{												
		SN_I2S0->IC = mskI2S_TXFIFOOVIC;		
		while (1);
	}
	else if (SN_I2S0->RIS & mskI2S_TXFIFOTHIF)		//Tx threshold
	{									
		while (!(SN_I2S0->STATUS & mskI2S_TXFIFOFULL))
		{
			SN_I2S0->TXFIFO = (wI2S0_Tx_Data++);
			if (wI2S0_Tx_Data >= 0x00FFFFFF )		
			wI2S0_Tx_Data = 0x00A00000;
		}	
		SN_I2S0->IC = mskI2S_TXFIFOTHIC;		
	}
	else if (SN_I2S0->RIS & mskI2S_RXFIFOUDIF)		//Rx underflow
	{									
		SN_I2S0->IC = mskI2S_RXFIFOUDIC;
		while (1);
	}
	else if (SN_I2S0->RIS & mskI2S_RXFIFOTHIF)		//Rx THreshold		
	{
		while (!(SN_I2S0->STATUS & mskI2S_RXFIFOEMPTY))
		{
			wI2S_Read_Data = SN_I2S0->RXFIFO;
 			if (wI2S_Read_Data != wI2S0_Rx_Check)
			{
   			while (1);															//data compare error
			}
			wI2S0_Rx_Check++;
			if (wI2S0_Rx_Check >= 0x00FFFFFF)
			{
				wI2S_Loop_Cnt++;
				wI2S0_Rx_Check = 0x00A00000;
			}
		}
		SN_I2S0->IC = mskI2S_RXFIFOTHIC;
	}
}

/*****************************************************************************
* Function		: I2S0_Slave_Irq
* Description	: I2S0 slave irq
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void I2S0_Slave_Irq(void)
{
	uint32_t wI2S_Read_Data;
	uint32_t wI2S_Loop_Cnt = 0;
	
	if(SN_I2S0->RIS & mskI2S_TXFIFOOVIF)					//Tx overflow	
	{											
		SN_I2S0->IC = mskI2S_TXFIFOOVIC;
		while (1);
	}
	else if (SN_I2S0->RIS & mskI2S_TXFIFOTHIF)		//Tx threshold
	{								
		while (!(SN_I2S0->STATUS & mskI2S_TXFIFOFULL))
		{
			SN_I2S0->TXFIFO = (wI2S0_Tx_Data++);
			if (wI2S0_Tx_Data >= 0x00FFFFFF)
			{
				wI2S0_Tx_Data=0x00A00000;
			}
		}
		SN_I2S0->IC = mskI2S_TXFIFOTHIC;		
	}
	else if (SN_I2S0->RIS & mskI2S_RXFIFOUDIF)		//Rx underflow
	{								
		SN_I2S0->IC = mskI2S_RXFIFOUDIC;
		while (1);
	}
	else if (SN_I2S0->RIS & mskI2S_RXFIFOTHIF)		//Rx THreshold
	{							
		while (!(SN_I2S0->STATUS & mskI2S_RXFIFOEMPTY))
		{
			wI2S_Read_Data = SN_I2S0->RXFIFO;
			if (wI2S_Read_Data != wI2S0_Rx_Check)
			{
				while (1);															//data compare error
			}
			wI2S0_Rx_Check++;
			if (wI2S0_Rx_Check >= 0x00FFFFFF)
			{
				wI2S_Loop_Cnt++;
				wI2S0_Rx_Check = 0x00A00000;
			}
		}
		SN_I2S0->IC = mskI2S_RXFIFOTHIC;
	}
}
