//-----------------------------------------------------------------------------
//  FILE:   Master_I2C.c
//-----------------------------------------------------------------------------
//  Copyright 2020 SONiX Technology Corp. All rights reserved. 
//
//  AUTHOR:     SONiX
//  DATE:       2020/09/30
//
//  The program is an example of Master I2C to implement it.
//    
//  I2C decription:
//      1. User need to external pull-high at SDA and SCL pin
//      2. Mast Send data (0x55¡X0xBB¡X0xCC) to slave
//      
//  The system clock frequency is IHRC 32MHz
//
//  Device:     SN8F5928 
//  Tool chain: KEIL C51 V9.50a
//

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <string.h>
#include <SN8F5928.h>
#include "GenericTypeDefs.h"
#include <intrins.h>
//-----------------------------------------------------------------------------
// Global Constants 
//-----------------------------------------------------------------------------
#define EN_STO      I2CCON |= 0x10
#define MAXDATALEN  10

//-----------------------------------------------------------------------------
// Global Variables 
//-----------------------------------------------------------------------------
UINT8 u8I2CFlag = 0;
UINT8 u8I2CData[MAXDATALEN] = {0};
UINT8 u8I2CAddr = 0;
UINT8 u8I2CLen = 0;
UINT8 u8I2CCnt = 0;

//UINT8 u8I2CStatLog[20] = {0};
unsigned char u8I2CStatLog[20] = {0};

UINT8 u8StatLogCnt = 0;
//-----------------------------------------------------------------------------
// Function Prototypes 
//-----------------------------------------------------------------------------
void I2C_Init(void);
void I2C_ISR(void); 

UINT8 I2C_Master_Write_One_Byte(UINT8 u8Addr, UINT8 u8data);
UINT8 I2C_Master_Write_N_Byte(UINT8 u8Addr, UINT8 *u8data, UINT8 u8size);
UINT8 I2C_Master_Read_N_Byte(UINT8 u8Addr, UINT8 *u8data, UINT8 u8size);

//-----------------------------------------------------------------------------
// Main loop
//-----------------------------------------------------------------------------
void main(void) 
{
    UINT8 u8TxData[3] = {0x55, 0xBB, 0xCC};     // for test
    UINT8 u8RxData[5] = {0};
		
		UINT8 u8SlaveAddr = 0x70;                   // set addr -- for Mast tx
//		UINT8 u8SlaveAddr = 0x70;                   // set addr -- for Mast tx	FOR	DS
//  UINT8 u8SlaveAddr = 0x2D;                   // set addr -- for Mast rx
		/*
				CLKSEL  = 0x07;
        CLKCMD = 0x69;             	// clock switch start
        

	      CKCON &= 0x11; 
		*/
    WDTR = 0x5A;            // clear watchdog if watchdog enable

    I2C_Init();    
/*
    // Write one data to slave
    I2C_Master_Write_One_Byte(u8SlaveAddr, u8TxData[0]);
    I2C_Master_Write_One_Byte(u8SlaveAddr, u8TxData[1]);
    I2C_Master_Write_One_Byte(u8SlaveAddr, u8TxData[2]);

    // Write multi data to slave
    I2C_Master_Write_N_Byte(u8SlaveAddr, u8TxData, sizeof(u8TxData));

    // read multi data form slave
    I2C_Master_Read_N_Byte(u8SlaveAddr, u8RxData, 2);
    I2C_Master_Read_N_Byte(u8SlaveAddr, u8RxData, sizeof(u8RxData));
*/
    while (1) {
        WDTR = 0x5A;        // clear watchdog if watchdog enable

        // To Do...
			   I2C_Master_Write_N_Byte(u8SlaveAddr, u8TxData, sizeof(u8TxData));//for Mast tx
				//I2C_Master_Read_N_Byte(u8SlaveAddr, u8RxData, sizeof(u8RxData));//for Mast rx
    }
}

//-----------------------------------------------------------------------------
//  Function:   void I2C_Init(void)
//  Description:
//          SCL and SDA need to external pull high
//-----------------------------------------------------------------------------
void I2C_Init(void)
{
		CLKSEL = 0x06;								// set Fcpu = Fhosc/2		(16M Hz)		
		CLKCMD = 0x69;								// Apply CLKSEL¡¦s setting

    P02 = 0;
    P03 = 0;
    P0M |= 0x00;                    // P02 & P03 as input

    I2CCON |= 0x40;                 // I2C enable (ENS1)

    // select clk rate
    //I2CCON |= 0x03;               // Clock rate bit : 011b ; 100KHz at 16MHz
    //I2CCON |= 0x81;      	        // Clock rate bit : 101b ; 133.3KHz at 16MHz
    I2CCON |= 0x82;                 // Clock rate bit : 110b ; 226.7KHz at 16MHz
	
		
    EI2C = 1;                       // I2C interrupt enable
    EAL = 1;                        // Interrupt enable
}

//-----------------------------------------------------------------------------
//  Function:   UINT8 I2C_Master_Write_One_Byte(UINT8 u8Addr, UINT8 u8Data)
//  Description:
//
//-----------------------------------------------------------------------------
UINT8 I2C_Master_Write_One_Byte(UINT8 u8Addr, UINT8 u8Data)
{
    if (!u8I2CFlag) {
        u8I2CFlag = 1;              // get Use Right            
        u8I2CLen = 1;               // set length
        u8I2CCnt = 0;               // clear tx count
        u8I2CData[0] = u8Data;
        u8I2CAddr = u8Addr | 0x00;  // write mode                
        I2CCON |= 0x20;             // START (STA) = 1

        while(u8I2CFlag);           // wait Trasmit end

        return TRUE;
    }
    else
        return FALSE;
}

//-----------------------------------------------------------------------------
//  Function:   UINT8 I2C_Master_Write_N_Byte(UINT8 u8Addr, UINT8 *u8data, UINT8 u8size)
//  Description:
//
//-----------------------------------------------------------------------------
UINT8 I2C_Master_Write_N_Byte(UINT8 u8Addr, UINT8 *u8data, UINT8 u8size)
{
    if (u8size >= MAXDATALEN)    
        return FALSE;               // over buf size
    
    if (u8size == 0)    
        return FALSE;               // error size
    
    if (!u8I2CFlag) {
        u8I2CFlag = 1;              // get Use Right
        u8I2CLen = u8size;          // set length
        u8I2CCnt = 0;               // clear tx count
        u8I2CAddr = u8Addr | 0x00;  // write mode            
        memcpy(u8I2CData, u8data, u8size);
        I2CCON |= 0x20;             // START (STA) = 1

        while(u8I2CFlag);           // wait Trasmit end

        return TRUE;
    }
    else
        return FALSE;
}

//-----------------------------------------------------------------------------
//  Function:   UINT8 I2C_Master_Read_N_Byte(UINT8 u8Addr, UINT8 *u8data, UINT8 u8size)
//  Description:
//
//-----------------------------------------------------------------------------
UINT8 I2C_Master_Read_N_Byte(UINT8 u8Addr, UINT8 *u8data, UINT8 u8size)
{
    if (u8size >= MAXDATALEN)    
        return FALSE;               // over buf size
    if (u8size == 0)    
        return FALSE;               // error size
    if (!u8I2CFlag) {
        u8I2CFlag = 1;              // get Use Right
        u8I2CLen = u8size;          // set length
        u8I2CCnt = 0;
        u8I2CAddr = u8Addr | 0x01;  // read mode
        I2CCON |= 0x20;             // START (STA) = 1
    
        while(u8I2CFlag);           // wait recevier end
    
        memcpy(u8data, u8I2CData, u8size);
    
        return TRUE;
    }
    else
        return FALSE;
}

//-----------------------------------------------------------------------------
//  Function:   I2C interrupt
//  Description:      
//
//-----------------------------------------------------------------------------
void I2C_ISR(void) interrupt ISRI2c     // Vector @  0xAB
{  
  //u8I2CStatLog[u8StatLogCnt++] = I2CSTA;
    switch (I2CSTA)
    {
        // tx mode
        case 0x08:
            I2CCON &= 0xDF;             // START (STA) = 0
            I2CDAT = u8I2CAddr;         // Tx/Rx addr             
            break;
				
        case 0x18:  

						I2CDAT = u8I2CData[u8I2CCnt++];	
	          u8I2CLen--; 				
            break;
				
        case 0x28:  
            if (u8I2CLen == 0) {        // chk length if empty
                I2CCON |= 0x10;         // STOP (STO)
                u8I2CFlag = 0;
                u8I2CCnt = 0;	
            }
            else {
                I2CDAT = u8I2CData[u8I2CCnt++];
                u8I2CLen--;
            }
							

            break;
						
        case 0x30:                      // Arbitration lost  
            I2CCON |= 0x10;             // STOP (STO)
            u8I2CFlag = 0;
            break;
            
        //    rx mode    
        case 0x40:                      // get slave addr
						if((u8I2CCnt+1) == u8I2CLen){
								I2CCON &= 0xFB;         // AA = 0		(last byte,not ACK will be returned)							
						}	
						else{
								I2CCON |= 0x04;         // AA = 1 	(not last byte,ACK will be returned)	
						}		
            break;
        case 0x50:                      // read n byte
            u8I2CData[u8I2CCnt++] = I2CDAT; 					
						if((u8I2CCnt+1) == u8I2CLen){
								I2CCON &= 0xFB;         // AA = 0		(last byte,not ACK will be returned)							
						}	
						else{
								I2CCON |= 0x04;         // AA = 1 	(not last byte,ACK will be returned)	
						}	
            break;
        case 0x58:                      // read last byte & stop
            u8I2CData[u8I2CCnt] = I2CDAT; 
            I2CCON |= 0x10;             // STOP (STO)
            u8I2CFlag = 0;
            break;
        default:
            I2CCON |= 0x10;             // STOP (STO)
            u8I2CFlag = 0;
    }

    I2CCON &= 0xF7;                     // Clear I2C flag (SI)        
}
