
/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors,  any
 * reproduction,  modification,  use or disclosure of AutoChips Software,  and
 * information contained herein,  in whole or in part,  shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE,  RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES,  EXPRESS OR IMPLIED,  INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN,  OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE,  AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE,  AT AUTOCHIPS'S OPTION,  TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE,  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */

/*************<start>******************/


/*************<include>****************/
#include "string.h"
#include "gpio.h"
#include "i2c_at24c02.h"

/*************<macro>******************/
#define AT24C02_MAX_SIZE        (256)

#define AT24C02_WR_TST_ADDR     (0x00)
#define AT24C02_TST_BUF_LEN     (256)


/*************<enum>*******************/


/*************<union>******************/


/*************<struct>*****************/


/*************<variable>***************/
uint8_t     g_eepromTstDataBuf[AT24C02_TST_BUF_LEN];        /*EEPROM Reading and writing data arrays*/
uint8_t     g_eepromWrRdRdy;                                /*EEPROM Reading and writing timing start flag*/
uint8_t     g_eepromWrRdTime;                               /*EEPROM Read Write Timing*/
uint8_t     g_DMA_startTransmit;                            /*DMA transmission start*/
uint8_t     g_DMA_startReceive;                             /*DMA reception start*/


/*************<prototype>**************/
void DMA_TX_Callback(void *device, uint32_t wpara, uint32_t lpara);
void DMA_RX_Callback(void *device, uint32_t wpara, uint32_t lpara);

/**
* @prototype I2C_ParaInit(void)
*
* @param[in] void
* @return    void
*
* @brief     ³υΚΌ»―I2C.
*/
void I2C_ParaInit(void)
{
    I2C_ConfigType i2cConfig;

    /*Initialize pin function to I2C.*/
    GPIO_SetFunc(I2C0_SCL_PORT, I2C0_SCL_PIN, GPIO_FUN3);
    GPIO_SetFunc(I2C0_SDA_PORT, I2C0_SDA_PIN, GPIO_FUN3);

    /*Zeroing structural variables.*/
    memset(&i2cConfig, 0x00, sizeof(i2cConfig));

    /*Parameters that need to be configured for both host and slave modes.*/
    i2cConfig.mode              = I2C_MASTER;   /*Set Master Slave Mode.*/
    i2cConfig.extAddrEn         = DISABLE;      /*10bit Extended address disable.*/
    i2cConfig.dmaRxEn           = ENABLE;       /*Set DMA reception data.*/
    i2cConfig.dmaTxEn           = ENABLE;       /*Set DMA to send data.*/
    i2cConfig.interruptEn       = ENABLE;       /*I2C interrupt,BND/SAMF/ARBLOST.*/
    i2cConfig.nackInterruptEn   = DISABLE;      /*NACK interrupt.*/
    i2cConfig.ssInterruptEn     = DISABLE;      /*bus start or stopinterrupt.*/
    i2cConfig.i2cEn             = ENABLE;       /*Enabling module.*/
    i2cConfig.callBack          = NULL;         /*Interrupt callback function.*/

    /*The parameters that need to be configured in the host mode can be ignored when configured in the slave mode.*/
    i2cConfig.masterConfig.sampleCnt = 9;       /*Set the baud rate to 100Kbps,bandrate=(32M/(10*16*2))=100Kbps.*/
    i2cConfig.masterConfig.stepCnt   = 15;
    i2cConfig.masterConfig.ARBEn     = ENABLE;  /*Set host arbitration function.*/
    i2cConfig.masterConfig.SYNCEn    = ENABLE;  /*Set host SCL synchronization function.*/

    /*The parameters that need to be configured in slave mode can be ignored when configured in master mode.*/
    i2cConfig.slaveConfig.slaveAddr      = AT24C02_DEV_ADDR;/*Slave address.*/
    i2cConfig.slaveConfig.slaveRangeAddr = 0;               /*Slave range address.*/
    i2cConfig.slaveConfig.glitchFilterCnt = 0;              /*Burr filtration.*/
    i2cConfig.slaveConfig.stretchEn      = DISABLE;         /*Slave SCL extension function.*/
    i2cConfig.slaveConfig.rangeAddrEn    = DISABLE;         /*Prohibited range address.*/
    i2cConfig.slaveConfig.monitorEn      = DISABLE;         /*Disable slave monitoring function.*/
    i2cConfig.slaveConfig.generalCallEn  = DISABLE;         /*Slave SCL broadcast address.*/
    i2cConfig.slaveConfig.wakeupEn       = DISABLE;         /*Wake up function, only effective during slave mode.*/
    i2cConfig.slaveConfig.rxOFInterruptEn   = DISABLE;      /*Receive cache overflow interrupt.*/
    i2cConfig.slaveConfig.txUFInterruptEn   = DISABLE;      /*Send cache overflow interrupt.*/

    I2C_Init(I2C0, &i2cConfig);
}

/**
* @prototype AT24C0X_WriteDataTest(void)
*
* @param[in] void
* @return    void
*
* @brief     Write data to EEPROM for testing.
*/
void AT24C0X_WriteDataTest(void)
{
    /*Prepare data.*/
    for (uint16_t ii = 0; ii < AT24C02_TST_BUF_LEN; ii++)
    {
        g_eepromTstDataBuf[ii] = ii;
        printf("%d ", g_eepromTstDataBuf[ii]);
    }
    printf("\r\n");

    /*Prepare for timing.*/
    g_eepromWrRdRdy  = 1;
    g_eepromWrRdTime = 0;

    /*Write data.*/
    AT24C0X_WriteBytes(AT24C02_WR_TST_ADDR, g_eepromTstDataBuf, AT24C02_TST_BUF_LEN);

    /*Stop timing.*/
    g_eepromWrRdRdy  = 0;

    /*Printing time.*/
    printf("Write AT24C02 256 bytes time is: %d ms", g_eepromWrRdTime);
    printf("\r\n");
}

/**
* @prototype AT24C0X_ReadDataTest(void)
*
* @param[in] void
* @return    void
*
* @brief     Test reading data from EEPROM.
*/
void AT24C0X_ReadDataTest(void)
{
    /*Prepare for timing.*/
    g_eepromWrRdRdy  = 1;
    g_eepromWrRdTime = 0;

    /*Read data.*/
    memset(g_eepromTstDataBuf, 0x00, AT24C02_TST_BUF_LEN);
    AT24C0X_ReadBytes(AT24C02_WR_TST_ADDR, g_eepromTstDataBuf, AT24C02_TST_BUF_LEN);

    /*Stop timing.*/
    g_eepromWrRdRdy  = 0;

    /*Print data and time.*/
    for (uint16_t ii = 0; ii < AT24C02_TST_BUF_LEN; ii++)
    {
        printf("%d ", g_eepromTstDataBuf[ii]);
    }
    printf("\r\n");
    printf("Read AT24C02 256 bytes time is: %d ms", g_eepromWrRdTime);
    printf("\r\n");
}

/**
* @prototype AT24C0X_ReadBytes(uint8_t startAddr, uint8_t *pDataBuf, uint16_t dataLen)
*
* @param[in] startAddr:Read data starting address
* @param[in] pDataBuf: Read Data Cache
* @param[in] dataLen:  Read data length
* @return    void
*
* @brief     Reading data from EEPROM.
*/
void AT24C0X_ReadBytes(uint8_t startAddr, uint8_t *pDataBuf, uint16_t dataLen)
{
    uint8_t __align(4) tempRdBuf[AT24C02_MAX_SIZE + 1];/*DMA transmission requires 4-byte alignment*/

    tempRdBuf[0] = startAddr;

    g_DMA_startTransmit = TRUE;             /*Preparing to send data*/
    I2C_MasterTransmitDMA(I2C0, AT24C02_DEV_ADDR, DMA0_CHANNEL0, tempRdBuf, 1, DMA_TX_Callback);/*Send Read Address*/
    while (g_DMA_startTransmit == TRUE);    /*Waiting for sending to complete*/
    I2C_WaitOneByteFinished(I2C0);          /*Waiting for the last byte to be sent*/

    g_DMA_startReceive  = TRUE;             /*Preparing to receive data*/
    I2C_MasterReceiveDMA(I2C0, AT24C02_DEV_ADDR, DMA0_CHANNEL1, tempRdBuf, dataLen, DMA_RX_Callback); /*read data*/
    while (g_DMA_startReceive == TRUE);     /*Waiting for reading to complete*/
    I2C_Stop(I2C0);

    memcpy(pDataBuf, tempRdBuf, dataLen);   /*Place data in the specified cache area*/
}

/**
* @prototype AT24C0X_WriteBytes(uint8_t startAddr, uint8_t *pDataBuf, uint16_t dataLen)
*
* @param[in] startAddr:Write data start address
* @param[in] pDataBuf: Write data buffer
* @param[in] dataLen:  Write data length
* @return    void
*
* @brief     Write data to EEPROM.
*/
void AT24C0X_WriteBytes(uint8_t startAddr, uint8_t *pDataBuf, uint16_t dataLen)
{
    uint8_t ii, restLen, wrTimes;
    uint8_t __align(4) tempWrBuf[AT24C02_PAGE_SIZ + 1];/*DMA transmission requires 4-byte alignment*/

    if ((startAddr + (dataLen - 1)) > AT24C02_ADDR_MAX) {return;} /* Address out of range exit */

    restLen = (dataLen % 8);
    wrTimes = (dataLen / 8);

    for (ii = 0; ii < wrTimes; ii++)
    {
        tempWrBuf[0] = startAddr;
        memcpy(&tempWrBuf[1], &pDataBuf[ii * AT24C02_PAGE_SIZ], AT24C02_PAGE_SIZ);/*Single page write 8 bytes*/

        g_DMA_startTransmit = TRUE;             /*Preparing to send data*/
        I2C_MasterTransmitDMA(I2C0, AT24C02_DEV_ADDR, DMA0_CHANNEL0, tempWrBuf, (AT24C02_PAGE_SIZ + 1), DMA_TX_Callback);
        startAddr   += AT24C02_PAGE_SIZ;
        while (g_DMA_startTransmit == TRUE);    /*Waiting for sending to complete*/
        I2C_WaitOneByteFinished(I2C0);          /*Waiting for the last byte to be sent*/
        I2C_Stop(I2C0);

        mdelay(5);                              /*Need to wait for 5ms to send the next write command*/
    }

    if (restLen > 0)                            /*Not full page, requires single byte write*/
    {
        for (ii = 0; ii < restLen; ii++)
        {
            tempWrBuf[0] = startAddr++;
            memcpy(&tempWrBuf[1], &pDataBuf[wrTimes * AT24C02_PAGE_SIZ + ii], 1);

            g_DMA_startTransmit = TRUE;         /*Preparing to send data*/
            I2C_MasterTransmitDMA(I2C0, AT24C02_DEV_ADDR, DMA0_CHANNEL0, tempWrBuf, 1, DMA_TX_Callback);/*Write 1 byte at a time*/
            while (g_DMA_startTransmit == TRUE); /*Waiting for sending to complete*/
            I2C_WaitOneByteFinished(I2C0);      /*Waiting for the last byte to be sent*/
            I2C_Stop(I2C0);

            mdelay(5);                          /*Need to wait for 5ms to send the next write command*/
        }
    }
}


/**
* @prototype DMA_TX_Callback(void *device, uint32_t wpara, uint32_t lpara)
*
* @param[in] ...
* @return    void
*
* @brief     DMA TX Interrupt callback function.
*/
void DMA_TX_Callback(void *device, uint32_t wpara, uint32_t lpara)
{
    if (wpara & DMA_CHANNEL_STATUS_FINISH_Msk)
    {
        g_DMA_startTransmit = FALSE;
    }
}

/**
* @prototype DMA_TX_Callback(void *device, uint32_t wpara, uint32_t lpara)
*
* @param[in] ...
* @return    void
*
* @brief     DMA RX Interrupt callback function.
*/
void DMA_RX_Callback(void *device, uint32_t wpara, uint32_t lpara)
{
    if (wpara & DMA_CHANNEL_STATUS_FINISH_Msk)
    {
        g_DMA_startReceive = FALSE;
    }
}

/*************<end>********************/
