/* 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.
 */
/******************************************************************************
 * @version: V1.0.0 demo
 ******************************************************************************/

/*!
* @file spi.c
*
* @brief This file contains the user spi function..
*
*/

/* ===========================================  Includes  =========================================== */
#include "gpio.h"
#include "spi.h"
#include "ac780x_spi.h"
#include "spi_w25x16.h"
#include "ac780x_timer.h"
/* ============================================  Define  ============================================ */
#define SPI_DATA_LEN    8u /* In the full-duplex mode of SPI, the data length of TX and RX must be the same */
#define W25X16_DIS   /* Disable the macro of W25x16, if there is W25x16 on the development board, the macro can be blocked */


/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
uint8_t rxBuff[SPI_DATA_LEN] = {0};    /* SPI1 receive array */
uint8_t txBuff[SPI_DATA_LEN] = {0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55};  /* SPI1 send array */

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */

/**
* @brief   Test w25x16 read function
*
* @param[in] void
* @return   void
*
*/
void W25X16_ReadDataTest(void)
{
    /* Ready to time */
    g_flashWrRdRdy  = 1;
    g_flashWrRdTime = 0;
    
    /* read data */
    memset(g_flshTstDataBuf, 0x00, W25X16_TEST_DAT_LEN);
    W25X16_ReadBytes(W25X16_WRRD_DAT_ADDR, g_flshTstDataBuf, W25X16_TEST_DAT_LEN);
    
    /* Stop the timer */
    g_flashWrRdRdy  = 0;
    /* Print read data and time. */
    for (uint16_t ii = 0; ii < W25X16_TEST_DAT_LEN; ii++)
    {
        printf("%d ", g_flshTstDataBuf[ii]);
    }
    printf("\r\n");
    printf("Read W25X16 1K bytes time is: %d ms", g_flashWrRdTime);
    printf("\r\n");
}
/**
* @brief   Test w25x16 write function
*
* @param[in] void
* @return   void
*
*/
void W25X16_WriteDataTest(void)
{
    /* erase data */
    W25X16_ErsSector(W25X16_WRRD_DAT_ADDR, 1);/* Erase 1 sector 4KB */
    
    /* prepare data */
    for (uint16_t ii = 0; ii < W25X16_TEST_DAT_LEN; ii++)
    {
        g_flshTstDataBuf[ii] = ii;
        printf("%d ", g_flshTstDataBuf[ii]);
    }
    printf("\r\n");
    
    /* Ready to time */
    g_flashWrRdRdy  = 1;
    g_flashWrRdTime = 0;
    
    /* write data */
    W25X16_WriteBytes(W25X16_WRRD_DAT_ADDR, g_flshTstDataBuf, W25X16_TEST_DAT_LEN);
    
    /* Stop the timer */
    g_flashWrRdRdy  = 0;
    /* Print time. */
    printf("Write W25X16 1K bytes time is: %d ms", g_flashWrRdTime);
    printf("\r\n");
}

/*!
* @brief  Communication test of W25x16
*
* @param[in] none
* @return none
*/
void W25X16_Test(void)
{
    W25X16_ReadDataTest();
    mdelay(100);
    W25X16_WriteDataTest();
    mdelay(100);
}

/*!
* @brief  spi master polling test
*
* @param[in] none
* @return none
*/
void Spi1_Test(void)
{
    ERROR_Type ret = ERROR;
    
    txBuff[0]++;
    
    /* Polling send and receive functions for SPI */
    ret = SPI_TransmitReceivePoll(SPI1, rxBuff, txBuff, SPI_DATA_LEN); 
    if(ret == ERROR)
    {
        printf("ERROR\r\n");
    }
    else
    {
        LED1_TOGGLE;
        printf("SUCCESS rxBuff is 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\r\n", \
        rxBuff[0],rxBuff[1],rxBuff[2],rxBuff[3],rxBuff[4],rxBuff[5],rxBuff[6],rxBuff[7]);
    }
    mdelay(200);
}

/*!
* @brief  TIM1 module interrupt handler.
*
* @param[in] none
* @return none
*/
void TIM1_IRQnCallBack(void *device, uint32_t wpara, uint32_t lpara)
{
    if (g_flashWrRdRdy)
    {
        g_flashWrRdTime++;
    }
}

/*!
* @brief  Initalize TIM1 module.
*
* @param[in] none
* @return none
*/
void TIMER_InitHardwr(void)
{
    TIMER_ConfigType timerConfig;
    
    memset((void *)&timerConfig, 0, (uint32_t)sizeof(TIMER_ConfigType));   
    
    timerConfig.timeMode = TIMER_WORKMODE_TIMER;   
    timerConfig.prescaler = TIMER_PRESCALE_16_GLITCHFILTER_7;
    timerConfig.periodValue = 2000;
    timerConfig.callback = TIM1_IRQnCallBack;
    timerConfig.interruptEn = ENABLE;
    timerConfig.bypEn = DISABLE;
    
    TIMER_Init(TIMER_CLKSR_APB);        
    TIMER_InitChannel(TIMER_CHANNEL1, &timerConfig);        /* Enable TIMER_CHANNEL1, 1ms generates an interrupt */
}

/*!
* @brief  Init spi0 pin
*
* @param[in] none
* @return none
*/
void Spi0_Gpio_Init(void)
{
    GPIO_SetFunc(GPIOB, GPIO_PIN5, GPIO_FUN3);     /* SCK */
    GPIO_SetFunc(GPIOB, GPIO_PIN4, GPIO_FUN3);     /* MOSI */
    GPIO_SetFunc(GPIOA, GPIO_PIN8, GPIO_FUN3);     /* CS */
    GPIO_SetFunc(GPIOA, GPIO_PIN7, GPIO_FUN3);     /* MISO */
}

/*!
* @brief  Init spi
*
* @param[in] none
* @return none
*/
void Spi0_Init(void)
{
    SPI_ConfigType spi_config_t;

    memset(&spi_config_t, 0x00, sizeof(spi_config_t));
    
    /* The baud rate of SPI is 2Mhz */
    spi_config_t.csSetup = 5;   /* Chip Select Setup Time  = (CS_SETUP + 1) * CLK_PERIOD. */
    spi_config_t.csHold  = 5;   /* Chip Select Hold Time = (CS_HOLD + 1) * CLK_PERIOD. */
    spi_config_t.sckHigh = 7;   /* SCK clock high time= (SCK_HIGH + 1) * CLK_PERIOD. */
    spi_config_t.sckLow  = 7;   /* SCK clock low time = (SCK_LOW + 1) * CLK_PERIOD. */
    spi_config_t.csIdle  = 5;   /* CS free time = (CS_IDLE + 1) * CLK_PERIOD. */
    spi_config_t.mode      = SPI_MASTER;        /* set master */
    spi_config_t.cpha      = SPI_CPHA_2EDGE;    /* second edge sampling */
    spi_config_t.cpol      = SPI_CPOL_HIGH;     /* SCK active high */
    spi_config_t.frmSize   = SPI_FRAME_SIZE_8BITS;  /* transfer byte width 8bits */
    spi_config_t.rxMsbFirstEn      = ENABLE;    /* RX MSB */
    spi_config_t.txMsbFirstEn      = ENABLE;    /* TX MSB */
    spi_config_t.csOutputEn        = ENABLE;    /* CS is hardware control */
    spi_config_t.continuousCSEn    = ENABLE;    /* CS is continuous mode */
    spi_config_t.dmaRxEn       = DISABLE;   /* RX DMA disable */
    spi_config_t.dmaTxEn       = DISABLE;   /* TX DMA disable */
    spi_config_t.modeFaultEn   = DISABLE;   /* Fault detection mode disable*/
    spi_config_t.wakeUpEn      = DISABLE;   /* wake up disable */
    spi_config_t.spiEn         = ENABLE;    /* Spi enable */
    spi_config_t.callBack      = NULL;      /* call back fun null */
    spi_config_t.interruptEn   = DISABLE;   /* interrupt disable */
    spi_config_t.txUFInterruptEn       = DISABLE;   /* TX buffer underflow interrupt disabled */
    spi_config_t.rxOFInterruptEn       = DISABLE;   /* RX buffer overflow interrupt disable */
    spi_config_t.modeFaultInterruptEn = DISABLE;    /* Mode Fault Interrupt disable*/
    
    SPI_Init(SPI0, &spi_config_t);  /* spi initialization */
    Spi0_Gpio_Init();               /* spi Pin initialization */
}
/*!
* @brief  Init spi1 pin
*
* @param[in] none
* @return none
*/
void Spi1_Gpio_Init(void)
{
    GPIO_SetFunc(GPIOB, GPIO_PIN12, GPIO_FUN3);     /* SCK */
    GPIO_SetFunc(GPIOB, GPIO_PIN11, GPIO_FUN3);     /* MOSI */
    GPIO_SetFunc(GPIOC, GPIO_PIN1, GPIO_FUN3);      /* CS */
    GPIO_SetFunc(GPIOC, GPIO_PIN0, GPIO_FUN3);      /* MISO */
}

/*!
* @brief  Init spi
*
* @param[in] none
* @return none
*/
void Spi1_Init(void)
{
    SPI_ConfigType spi_config_t;
    
    memset(&spi_config_t, 0x00, sizeof(spi_config_t));
    
    /* The baud rate of SPI is 1Mhz */
    spi_config_t.csSetup = 20;   /* Chip Select Setup Time  = (CS_SETUP + 1) * CLK_PERIOD. */
    spi_config_t.csHold  = 20;   /* Chip Select Hold Time = (CS_HOLD + 1) * CLK_PERIOD. */
    spi_config_t.sckHigh = 15;   /* SCK clock high time= (SCK_HIGH + 1) * CLK_PERIOD. */
    spi_config_t.sckLow  = 15;   /* SCK clock low time = (SCK_LOW + 1) * CLK_PERIOD. */
    spi_config_t.csIdle  = 20;   /* CS free time = (CS_IDLE + 1) * CLK_PERIOD. */
    spi_config_t.mode      = SPI_MASTER;        /* set master */
    spi_config_t.cpha      = SPI_CPHA_1EDGE;    /* second edge sampling */
    spi_config_t.cpol      = SPI_CPOL_LOW;     /* SCK active high */
    spi_config_t.frmSize   = SPI_FRAME_SIZE_8BITS;  /* transfer byte width 8bits */
    spi_config_t.rxMsbFirstEn      = ENABLE;    /* RX MSB */
    spi_config_t.txMsbFirstEn      = ENABLE;    /* TX MSB */
    spi_config_t.csOutputEn        = ENABLE;    /* CS is hardware control */
    spi_config_t.continuousCSEn    = ENABLE;    /* CS is continuous mode */
    spi_config_t.dmaRxEn       = DISABLE;   /* RX DMA disable */
    spi_config_t.dmaTxEn       = DISABLE;   /* TX DMA disable */
    spi_config_t.modeFaultEn   = DISABLE;   /* Fault detection mode disable*/
    spi_config_t.wakeUpEn      = DISABLE;   /* wake up disable */
    spi_config_t.spiEn         = ENABLE;    /* Spi enable */
    spi_config_t.callBack      = NULL;      /* call back fun null */
    spi_config_t.interruptEn   = DISABLE;   /* interrupt disable */
    spi_config_t.txUFInterruptEn       = DISABLE;   /* TX buffer underflow interrupt disabled */
    spi_config_t.rxOFInterruptEn       = DISABLE;   /* RX buffer overflow interrupt disable */
    spi_config_t.modeFaultInterruptEn = DISABLE;    /* Mode Fault Interrupt disable*/
    
    SPI_Init(SPI1, &spi_config_t);  /* spi initialization */
    Spi1_Gpio_Init();               /* spi Pin initialization */
    TIMER_InitHardwr();
}
/* =============================================  EOF  ============================================== */
