/******************** (C) COPYRIGHT 2023 SONiX *******************************
* COMPANY:		SONiX
* DATE:				2023/12
* AUTHOR:			SA1
* IC:					SN32F240C
*____________________________________________________________________________
*	REVISION	Date				User		Description
*	1.0				2023/12/11	SA1			1. First version released
*																2. Compatible to CMSIS DFP Architecture in Keil MDK v5.X (http://www.keil.com/dd2/pack/)
*																3. Run HexConvert to generate bin file and show checksum after building.
*
*____________________________________________________________________________
* 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 <SN32F240C.h>
#include <SN32F200_Def.h>
#include "Interface\I2C\I2C.h"

/*_____ D E C L A R A T I O N S ____________________________________________*/
void PFPA_Init(void);
void NotPinOut_GPIO_init(void);
void I2C_TestFun(void); 

uint32_t wI2C_TestCase = 0;
uint8_t bI2C_MasEndFlag = 0;
uint8_t bI2C_SlaEndFlag = 0;
uint8_t bI2C_MasCheckFIFO[30];
uint8_t bI2C_SlaCheckFIFO[30];

/*_____ D E F I N I T I O N S ______________________________________________*/
#ifndef	SN32F248C					//Do NOT Remove or Modify!!!
	#error Please install SONiX.SN32F2_DFP.1.3.6.pack or version >= 1.2.9
#endif
#define	PKG		SN32F248C		//User SHALL modify the package on demand (SN32F248C, SN32F247C, SN32F246C, SN32F2451C) 

//I2C Master use
#define	I2C_SEND_4BYTE			4				//Set the Number of sending Data
#define	I2C_SEND_9BYTE			9				//Set the Number of sending Data

#define	I2C_NO_REPEAT				0				//No use repeat
#define	I2C_REPEAT_START		1				//Next transfer with a Repated Start condition
#define	I2C_NEXT_START			2				//Work next transfer

#define	I2C_MAS_ACK_1BYTE		0				//Send (wReTxNum + 1) Data when wRepeatTX is 1.
#define	I2C_MAS_ACK_2BYTE		1
#define	I2C_MAS_ACK_3BYTE		2
#define	I2C_MAS_ACK_4BYTE		3
#define	I2C_MAS_ACK_5BYTE		4

#define	I2C_MAS_TX_ADDR			0x07		//Master Tx addr

//I2C Slave use
#define	I2C_4BYTE_NACK			4				//Return NACK when getting the number of data

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

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

/*****************************************************************************
* Function		: main
* Description	: Demo code of I2C
* Input			: None
* Output		: None
* Return		: None
* Note			: Connect I2C0 and I2C1 
*****************************************************************************/
int	main(void)
{
	//User can configure System Clock with Configuration Wizard in system_SN32F240C.c
	SystemInit();
	SystemCoreClockUpdate();				//Must call for SN32F240C, Please do NOT remove!!!

	//Note: User can refer to ClockSwitch sample code to switch various HCLK if needed.

	PFPA_Init();										//User shall set PFPA if used, do NOT remove!!!

	//1. User SHALL define PKG on demand.
	//2. User SHALL set the status of the GPIO which are NOT pin-out to input pull-up.
	NotPinOut_GPIO_init();

	//--------------------------------------------------------------------------
	//User Code starts HERE!!!

	//System Interface Init
	I2C0_Init();	//I2C0 is master mode
	I2C1_Init();	//I2C1 is slave mode
	
	//Set the address sent by Master
	hwI2C_Device_Addr_I2C0 = I2C_MAS_TX_ADDR;

	//I2C data
	bI2C_MasTxData[0] = 0x055;
	bI2C_MasTxData[1] = 0x0A5;
	bI2C_MasTxData[2] = 0x077;
	bI2C_MasTxData[3] = 0x0FF;
	bI2C_MasTxData[4] = 0x001;

	bI2C_MasTxData[5] = 0x099;
	bI2C_MasTxData[6] = 0x011;
	bI2C_MasTxData[7] = 0x0B0;
	bI2C_MasTxData[8] = 0x00F;
	bI2C_MasTxData[9] = 0x0E3;  

	I2C_TestFun();

	//All Pass
	while (1);		
}

/*****************************************************************************
* Function		: I2C_TestFun
* Description	:
*				  I2C0 is Master.
*					I2C1 is Slave.
*
*				  Case 1(wI2C_TestCase = 0): Master sends 4 data
*				  Case 2(wI2C_TestCase = 1): Master sends 4 data ,and then works Repeat Start to send 4 data
*				  Case 3(wI2C_TestCase = 2): Master sends 4 data over ,and then sends another 4 data.
*				  Case 4(wI2C_TestCase = 3): Master gets 9 data.		
*				  Case 5(wI2C_TestCase = 4): Master gets 4 data ,and then works Repeat Start to get 5 data
*				  Case 6(wI2C_TestCase = 5): Master gets 4 data over ,and then gets another 5 data.
*
*				  When transmission is over , Check that the data of Master and Slave is right.
*
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void I2C_TestFun(void)
{
	uint32_t i = 0;
	uint32_t wcheckDataPinter = 0;
	uint32_t wcheckDataPinter1 = 0;

	for (wI2C_TestCase = 0; wI2C_TestCase < 6; wI2C_TestCase++)
	{
		SN_I2C0->CTRL |= (0x01 << 5);	//Start

		while (bI2C_MasEndFlag == 0);
		bI2C_MasEndFlag = 0;
		while (bI2C_SlaEndFlag == 0);
		bI2C_SlaEndFlag = 0;
		bI2C_SlaRxPointer = 0;
		bI2C_SlaTxPointer = 0;

		if (wI2C_TotalError != 0x00)
		{
			while (1);					//Happen Error
		}

		if (wI2C_TestCase >= 0x03)
		{
			for (i = 0; i < 9; i++)
			{
				bI2C_MasCheckFIFO[wcheckDataPinter] = bI2C_MasRxData[i];
				wcheckDataPinter=wcheckDataPinter + 1;
			}
		}
		else if (wI2C_TestCase == 0x00)
		{
			for (i = 0; i < 4; i++)
			{
				bI2C_SlaCheckFIFO[wcheckDataPinter1] = bI2C_SlaRxData[i];
				wcheckDataPinter1=wcheckDataPinter1 + 1;
			}
		}
		else	
		{
			//wI2C_TestCase = 1 & 2
			for (i = 0; i < 8; i++)
			{
				bI2C_SlaCheckFIFO[wcheckDataPinter1] = bI2C_SlaRxData[i];
				wcheckDataPinter1=wcheckDataPinter1 + 1;
			}
		}

		//Dealy 	
		for (i = 0; i < 1000; i++);
	}

	//Check I2C0 Master Getting Data
	wI2C_TestCase = 0;
	for (i = 0; i < 27; i++)
	{
		if (bI2C_MasCheckFIFO[i] != bI2C_MasTxData[wI2C_TestCase++])
		{
			while (1);
		}

		if (wI2C_TestCase == 9)
		{
			wI2C_TestCase = 0;
		}
	}

	//check I2C1 Slave Getting Data
	wI2C_TestCase = 0;
	for (i = 0; i < 4; i++)
	{
		if (bI2C_SlaCheckFIFO[i] != bI2C_MasTxData[wI2C_TestCase++])
		{
			while (1);
		}
	}

	wI2C_TestCase = 0;
	for (i = 4; i < 20; i++)
	{
		if (bI2C_SlaCheckFIFO[i] != bI2C_MasTxData[wI2C_TestCase++])
		{
			while (1);
		}

		if (wI2C_TestCase == 8)
		{
			wI2C_TestCase = 0;
		}
	}
}

/*****************************************************************************
* Function		: I2C0_IRQHandler
* Description	: ISR of I2C0 interrupt
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
__irq void I2C0_IRQHandler(void)
{
	if (wI2C_TestCase == 0)
	{
		I2C0_Master_Tx(&bI2C_MasTxData[bI2C_MasTxPointer], &bI2C_MasTxPointer, &bI2C_MasEndFlag, hwI2C_Device_Addr_I2C0, I2C_SEND_4BYTE, I2C_NO_REPEAT, I2C_MAS_ACK_1BYTE);
	}
	else if (wI2C_TestCase == 1)
	{
	 	I2C0_Master_Tx(&bI2C_MasTxData[bI2C_MasTxPointer], &bI2C_MasTxPointer, &bI2C_MasEndFlag, hwI2C_Device_Addr_I2C0, I2C_SEND_4BYTE, I2C_REPEAT_START, I2C_MAS_ACK_4BYTE);
	}
	else if (wI2C_TestCase == 2)
	{
		I2C0_Master_Tx(&bI2C_MasTxData[bI2C_MasTxPointer], &bI2C_MasTxPointer, &bI2C_MasEndFlag, hwI2C_Device_Addr_I2C0, I2C_SEND_4BYTE, I2C_NEXT_START, I2C_MAS_ACK_4BYTE);
	}
	else if (wI2C_TestCase == 3)
	{
		I2C0_Master_Rx(&bI2C_MasRxData[bI2C_MasRxPointer], &bI2C_MasRxPointer, &bI2C_MasEndFlag, hwI2C_Device_Addr_I2C0, I2C_SEND_9BYTE, I2C_NO_REPEAT, I2C_MAS_ACK_1BYTE);		
	}
	else if (wI2C_TestCase == 4)
	{
		I2C0_Master_Rx(&bI2C_MasRxData[bI2C_MasRxPointer], &bI2C_MasRxPointer, &bI2C_MasEndFlag, hwI2C_Device_Addr_I2C0, I2C_SEND_4BYTE, I2C_REPEAT_START, I2C_MAS_ACK_5BYTE);
	}
	else if (wI2C_TestCase == 5)
	{
		I2C0_Master_Rx(&bI2C_MasRxData[bI2C_MasRxPointer], &bI2C_MasRxPointer, &bI2C_MasEndFlag, hwI2C_Device_Addr_I2C0, I2C_SEND_4BYTE, I2C_NEXT_START, I2C_MAS_ACK_5BYTE);
	}
}

/*****************************************************************************
* Function		: I2C1_IRQHandler
* Description	: ISR of I2C1 interrupt
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
__irq void I2C1_IRQHandler(void)
{
	if ((wI2C_TestCase == 0) || (wI2C_TestCase == 1) || (wI2C_TestCase == 2))
	{
		I2C1_Slave_Rx(&bI2C_SlaRxData[bI2C_SlaRxPointer], &bI2C_SlaRxPointer, &bI2C_SlaEndFlag, I2C_4BYTE_NACK);
	}
	else if ((wI2C_TestCase == 3) || (wI2C_TestCase == 4) || (wI2C_TestCase == 5))
	{
		I2C1_Slave_Tx(&bI2C_MasTxData[bI2C_SlaTxPointer], &bI2C_SlaTxPointer, &bI2C_SlaEndFlag);
	}
}

/*****************************************************************************
* Function		: NotPinOut_GPIO_init
* Description	: Set the status of the GPIO which are NOT pin-out to input pull-up. 
* Input				: None
* Output			: None
* Return			: None
* Note				: 1. User SHALL define PKG on demand.
*****************************************************************************/
void NotPinOut_GPIO_init(void)
{
	//(SN32F248C, SN32F247C, SN32F246C, SN32F2451C) 
#if (PKG == SN32F248C)
	//set P3.2~P3.4 to input pull-up
	SN_GPIO3->CFG = 0x00AAA80A;
#elif (PKG == SN32F247C)	
	//set P0.8~P0.9, P0.12~P0.15 to input pull-up
	SN_GPIO0->CFG = 0x00A0AAAA;
	//set P1.0~P1.2, P1.14~P1.15 to input pull-up
	SN_GPIO1->CFG = 0x0AAAAA80;
	//set P2.12~P2.14 to input pull-up
	SN_GPIO2->CFG = 0x80AAAAAA;
	//set P3.0~P3.4 to input pull-up
	SN_GPIO3->CFG = 0x00AAA800;
#elif (PKG == SN32F246C)
	//set P0.8~P0.9, P0.12~P0.15 to input pull-up
	SN_GPIO0->CFG = 0x00A0AAAA;
	//set P1.0~P1.2, P1.14~P1.15 to input pull-up
	SN_GPIO1->CFG = 0x0AAAAA80;
	//set P2.10~P2.14 to input pull-up
	SN_GPIO2->CFG = 0x800AAAAA;
	//set P3.0~P3.4 to input pull-up
	SN_GPIO3->CFG = 0x00AAA800;
#elif (PKG == SN32F2451C)
	//set P0.0~P0.1, P0.8~P0.15 to input pull-up
	SN_GPIO0->CFG = 0x0000AAA0;
	//set P1.0~P1.4, P1.12~P1.15 to input pull-up
	SN_GPIO1->CFG = 0x00AAA800;
	//set P2.6~P2.15 to input pull-up
	SN_GPIO2->CFG = 0x00000AAA;
	//set P3.0~P3.4, P3.10~P3.11 to input pull-up
	SN_GPIO3->CFG = 0x000AA800;
#endif
}

/*****************************************************************************
* Function		: HardFault_Handler
* Description	: ISR of Hard fault interrupt
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
__irq void HardFault_Handler(void)
{
	NVIC_SystemReset();
}
