
/******************************************************************************
*@file  : app.c
*@brief : application
******************************************************************************/

#include "app.h"
#include "IC_W25Qxx.h"

#define BUFFER_LENGTH    (256)

uint8_t TxBuffer[BUFFER_LENGTH];
uint8_t RxBuffer[BUFFER_LENGTH];

SPI_Handler_t    hspi;

void printf_buff_byte(uint8_t* buff, uint32_t length)
{
	uint32_t i;

	for(i = 0; i < length; i++)
	{
		printf("%.2x ",buff[i]);	
	}
	printf("\n");
}

void SPI1_GPIO_Init(void)
{
    GPIO_InitTypeDef gpio;
    __RCC_GPIOA_CLK_ENABLE();
    
    /*  PA4    CS        AF0 
        PA5    SCK       AF0       
        PA12   MOSI      AF0
        PA11   MISO      AF0
        PA7    IO2(WP)   AF3
        PA6    IO3(HOLD) AF3
    */
    
    gpio.Pin = GPIO_PIN_4 | GPIO_PIN_5;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pull = GPIO_PULLUP;
    gpio.Drive = GPIO_DRIVE_LEVEL3;
    gpio.Alternate = GPIO_FUNCTION_0;
    GPIO_Init(GPIOA, &gpio);
    
    gpio.Pin = GPIO_PIN_11 | GPIO_PIN_12 ;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pull = GPIO_PULLUP;
    gpio.Drive = GPIO_DRIVE_LEVEL3;
    gpio.Alternate = GPIO_FUNCTION_0;
    GPIO_Init(GPIOA, &gpio);
    
    printfS("SPI1 PINs selected:\r\n");
    printfS("SPI1 CS  :PA4\r\n");
    printfS("SPI1 SCK :PA5\r\n");
    printfS("SPI1 MOSI:PA12\r\n");
    printfS("SPI1 MISO:PA11\r\n");
    
    gpio.Pin = GPIO_PIN_6 | GPIO_PIN_7;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pull = GPIO_PULLUP;
    gpio.Drive = GPIO_DRIVE_LEVEL3;
    gpio.Alternate = GPIO_FUNCTION_3;
    
    GPIO_Init(GPIOC, &gpio);
    printfS("SPI1 WP  :PA7\r\n");
    printfS("SPI1 HOLD:PA6\r\n");    
}


void SPI3_GPIO_Init(void)
{
    GPIO_InitTypeDef gpio;
    
    __RCC_GPIOA_CLK_ENABLE();
    __RCC_GPIOC_CLK_ENABLE();

    /*  PA15   CS        AF4 
    PC10   SCK       AF2       
    PC12   MOSI      AF2
    PC11   MISO      AF2
    PC9    IO2(WP)   AF2
    PC8    IO3(HOLD) AF2
    */

    gpio.Pin = GPIO_PIN_15 ;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pull = GPIO_PULLUP;
    gpio.Drive = GPIO_DRIVE_LEVEL3;
    gpio.Alternate = GPIO_FUNCTION_4;
    GPIO_Init(GPIOA, &gpio);

    gpio.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 ;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pull = GPIO_PULLUP;
    gpio.Drive = GPIO_DRIVE_LEVEL3;
    gpio.Alternate = GPIO_FUNCTION_2;
    GPIO_Init(GPIOC, &gpio);

    printfS("SPI3 PINs selected:\r\n");
    printfS("SPI3 CS  :PA15\r\n");
    printfS("SPI3 SCK :PC10\r\n");
    printfS("SPI3 MOSI:PC12\r\n");
    printfS("SPI3 MISO:PC11\r\n");

    gpio.Pin = GPIO_PIN_8 | GPIO_PIN_9;
    gpio.Mode = GPIO_MODE_AF_PP;
    gpio.Pull = GPIO_PULLUP;
    gpio.Drive = GPIO_DRIVE_LEVEL3;
    gpio.Alternate = GPIO_FUNCTION_2;
    GPIO_Init(GPIOC, &gpio);
    printfS("SPI3 WP  :PC9\r\n");
    printfS("SPI3 HOLD:PC8\r\n");
}


void SPI1_Init(void)
{
    SPI_InitTypeDef SPI_InitStruct;
    
    __RCC_SPI1_CLK_ENABLE();
    
    SPI_InitStruct.SPI_Mode = SPI_MODE_MASTER;
                  
    SPI_InitStruct.SPI_Work_Mode = SPI_WORK_MODE_0;
                  
    SPI_InitStruct.X_Mode = SPI_1X_MODE;      
                  
    SPI_InitStruct.First_Bit = SPI_FIRSTBIT_MSB;
                  
    SPI_InitStruct.BaudRate_Prescaler = SPI_BAUDRATE_PRESCALER_8;    

    SPI_InitStruct.Master_SShift = SPI_MASTER_SSHIFT_NONE;
   
    SPI_Init(SPI1, &SPI_InitStruct);
    
    NVIC_ClearPendingIRQ(SPI1_IRQn);
    
    NVIC_EnableIRQ(SPI1_IRQn);
}

void SPI3_Init(void)
{
    SPI_InitTypeDef SPI_InitStruct;
    
    __RCC_SPI3_CLK_ENABLE();
    
    SPI_InitStruct.SPI_Mode = SPI_MODE_MASTER;
                  
    SPI_InitStruct.SPI_Work_Mode = SPI_WORK_MODE_0;
                  
    SPI_InitStruct.X_Mode = SPI_4X_MODE;      
                  
    SPI_InitStruct.First_Bit = SPI_FIRSTBIT_MSB;
                  
    SPI_InitStruct.BaudRate_Prescaler = SPI_BAUDRATE_PRESCALER_8;
                  
    SPI_InitStruct.Master_SShift = SPI_MASTER_SSHIFT_NONE;
   
    SPI_Init(SPI3, &SPI_InitStruct);
    
    NVIC_ClearPendingIRQ(SPI3_IRQn);
    
    NVIC_EnableIRQ(SPI3_IRQn);
}

/**
  * @brief  SPI_Master_Communicates with a SPI slave by loop mode
  * @param None
  * @retval None
  */
void SPI_Master_Comm_Loop(void)
{
    uint32_t i;
    
    uint32_t COM_OK  = 0;
    uint32_t COM_Err = 0;
    uint32_t DataLength = 50;

    printfS("SPI Master Comm Loop Demo.\r\n");

    SPI1_Init();
    
    SPI1_GPIO_Init();
    
//    printfS("Please press the USR_PB button to continue......\r\n\r\n");
//    
//    while(GPIO_PIN_SET == BSP_PB_GetState());
    
    do
    {        
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            TxBuffer[i] = i;
        }

        SPI_Master_Transmit(SPI1, TxBuffer, DataLength, 0);        
        DelayMs(300);
        SPI_Master_Receive(SPI1, RxBuffer, DataLength, 0);
        
        for (i = 0; i < DataLength; i++)
        {
            if (TxBuffer[i] != RxBuffer[i]) 
            {
                printfS("There is one mistake : TxBuffer[%d] != RxBuffer[%d] \r\n", i, i);
                
                COM_Err++;
            }
            else 
            {
                COM_OK++;
            }
        }
        
        printfS("SPI Master Test OK count %d times \r\n",  COM_OK);
        printfS("SPI Master Test Err count %d times \r\n", COM_Err);

        COM_OK = 0;
        COM_Err = 0;
        
        DelayMs(500);
    }while(1);
    
    printfS("SPI Master Test End!!! \r\n");
}

/**
  * @brief  SPI_Master_Communicates with a SPI slave by Interrupt mode
  * @param None
  * @retval None
  */
void SPI_Master_Comm_IT(void)
{
    uint32_t i;
    uint32_t COM_OK  = 0;
    uint32_t COM_Err = 0;
    uint32_t DataLength = 50;

    SPI1_Init();
    
    SPI1_GPIO_Init();

    printfS("SPI Master Comm IT Demo\r\n");

    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        TxBuffer[i] = i;
    }
    
//    printfS("Please press the USR_PB button to continue......\r\n\r\n");
//    
//    while(GPIO_PIN_SET == BSP_PB_GetState());
        
    while (1) 
    {
        
        SPI_Master_Transmit_IT(SPI1, &hspi, TxBuffer, DataLength);
        //while(SPI_GetTxState() != SPI_TX_STATE_IDLE);
        while (hspi.TxState == SPI_TX_STATE_SENDING);
        DelayMs(300);
        
        SPI_Master_Receive_IT(SPI1, &hspi, RxBuffer, sizeof(RxBuffer));
        //while(SPI_GetRxState() != SPI_RX_STATE_IDLE);
        while (hspi.RxState == SPI_TX_STATE_SENDING);

        
        
        for (i = 0; i < DataLength; i++)
        {
            if (TxBuffer[i] != RxBuffer[i]) 
            {
                printfS("There is one mistake : TxBuffer[%d] != RxBuffer[%d] \r\n", i, i);
                
                COM_Err++;
            }
            else 
            {
                COM_OK++;
            }
        }
        
        printfS("SPI Master Test OK count %d times \r\n",  COM_OK);
        printfS("SPI Master Test Err count %d times \r\n", COM_Err);

        COM_OK = 0;
        COM_Err = 0;
        
        DelayMs(500);
    }
}

bool flag_dma_tx = false;
bool flag_dma_rx = false;
/**
  * @brief  SPI_Master_Communicates with a SPI slave by DMA mode
  * @param None
  * @retval None
  */ 
void SPI_Master_Comm_DMA(void)
{
    uint32_t i;
    
    DMA_InitTypeDef InitData;

    uint32_t COM_OK  = 0;
    uint32_t COM_Err = 0;
    uint32_t DataLength = 50;

    printfS("SPI Master Comm DMA Demo\r\n");

    SPI1_Init();
    
    SPI1_GPIO_Init();    
    
    __RCC_DMA1_CLK_ENABLE();
    
    InitData.Mode        = DMA_MODE_NORMAL;
    InitData.DataFlow    = DMA_DATAFLOW_M2P;
    InitData.ReqID       = DMA1_REQ1_SPI1_SEND;
    InitData.SrcAddr     = 0;
    InitData.DestAddr    = 0;
    InitData.Size        = 0;
    InitData.RawInt      = DMA_RAWINT_ENABLE;
    InitData.SrcWidth    = DMA_SRCWIDTH_BYTE;
    InitData.DestWidth   = DMA_DESTWIDTH_BYTE;
    InitData.SrcInc      = DMA_SRCINC_ENABLE;
    InitData.DestInc     = DMA_DESTINC_DISABLE;
    InitData.SrcBurst    = DMA_SRCBURST_1;
    InitData.DestBurst   = DMA_DESTBURST_1;
       
    DMA_Init(DMA1_Channel0, &InitData);
    
    memset((void*)&InitData, 0, sizeof(InitData));
    
    InitData.Mode        = DMA_MODE_NORMAL;
    InitData.DataFlow    = DMA_DATAFLOW_P2M;
    InitData.ReqID       = DMA1_REQ2_SPI1_RECV;
    InitData.SrcAddr     = 0;
    InitData.DestAddr    = 0;
    InitData.Size        = 0;
    InitData.RawInt      = DMA_RAWINT_ENABLE;
    InitData.SrcWidth    = DMA_SRCWIDTH_BYTE;
    InitData.DestWidth   = DMA_DESTWIDTH_BYTE;
    InitData.SrcInc      = DMA_SRCINC_DISABLE;
    InitData.DestInc     = DMA_DESTINC_ENABLE;
    InitData.SrcBurst    = DMA_SRCBURST_1;
    InitData.DestBurst   = DMA_DESTBURST_1;
       
    DMA_Init(DMA1_Channel1, &InitData);

    SPI_DMA_RXFIFO_Level_Set(SPI1, SPI_RX_CTL_DMA_LEVEL_0);
    SPI_DMA_TXFIFO_Level_Set(SPI1, SPI_TX_CTL_DMA_LEVEL_0);
    DMA_ITConfig(DMA1_Channel1, DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE , ENABLE);
    DMA_ITConfig(DMA1_Channel0, DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE , ENABLE);

    NVIC_ClearPendingIRQ(DMA1_IRQn);
    NVIC_SetPriority(DMA1_IRQn, 5);
    NVIC_EnableIRQ(DMA1_IRQn); 
    
//    printfS("Please press the USR_PB button to continue......\r\n\r\n");
    
//    while(GPIO_PIN_SET == BSP_PB_GetState());
    
    do
    {           
        for (i = 0; i < DataLength; i++)
        {
            TxBuffer[i] = 1 + i;
        }
        
        SPI_ClearFlag(SPI1, SPI_STATUS_BATCH_DONE);
    
        SPI_ITConfig(SPI1, SPI_IE_TX_BATCH_DONE_EN, ENABLE);
        
        SPI_WriteBatch(SPI1, DataLength);
        
        SPI_ClearTxFifo(SPI1);

        SPI_TxCmd(SPI1, ENABLE);
        
        SPI_DMACmd(SPI1, SPI_DMAReq_TX, ENABLE);
                
        DMA_SrcAddrConfig(DMA1_Channel0, (uint32_t)TxBuffer);
        
        DMA_DestAddrConfig(DMA1_Channel0, (uint32_t)&SPI1->DAT);
        
        DMA_SetTransferSize(DMA1_Channel0, DataLength);

        DMA_Cmd(DMA1_Channel0, ENABLE);
        
        SPI_SSOutputCmd(SPI1, ENABLE);       
        
        while (!flag_dma_tx);
        flag_dma_tx = false;
        DelayMs(200);

        SPI_ClearFlag(SPI1, SPI_STATUS_BATCH_DONE);

        SPI_ITConfig(SPI1, SPI_IE_RX_BATCH_DONE_EN, ENABLE);

        SPI_WriteBatch(SPI1, DataLength);

        SPI_RxCmd(SPI1, ENABLE);
        
        SPI_ClearTxFifo(SPI1);
                
        SPI_DMACmd(SPI1, SPI_DMAReq_RX, ENABLE);    
                
        DMA_SrcAddrConfig(DMA1_Channel1, (uint32_t)&SPI1->DAT);
        
        DMA_DestAddrConfig(DMA1_Channel1, (uint32_t)RxBuffer);
        
        DMA_SetTransferSize(DMA1_Channel1, DataLength);

        DMA_Cmd(DMA1_Channel1, ENABLE);
        
        SPI_SSOutputCmd(SPI1, ENABLE);
                   
        while (!flag_dma_rx);
        flag_dma_rx = false;
        
        for (i = 0; i < DataLength; i++)
        {
            if (TxBuffer[i] != RxBuffer[i]) 
            {                
                COM_Err++;
                printfS("Error@ %x\n",i);
                goto end;
            }
            else 
            {
                COM_OK++;
            }
        }
        
        printfS("SPI Master DMA Test OK count %d times \r\n",  COM_OK);
        printfS("SPI Master DMA Test Err count %d times \r\n", COM_Err);
        
        COM_OK = 0;
        COM_Err = 0;

        DelayMs(100);

    }while(1);
end:
    printf_buff_byte(RxBuffer, DataLength);
    printfS("SPI Master DMA Test End!!! \r\n");
}

/**
  * @brief  SPI_Master_Communicates with a SPI slave by FullDuplex mode
  * @param None
  * @retval None
  */ 
void SPI_Master_FullDuplex_Test(void)
{
    uint32_t i;
    
    uint32_t COM_OK  = 0;
    uint32_t COM_Err = 0;
    uint32_t DataLength = 50;

    printfS("SPI Master Full Duplex Demo\r\n");

    SPI1_Init();
    
    SPI1_GPIO_Init();
    
//    printfS("Please press the USR_PB button to continue......\r\n\r\n");
//    
//    while(GPIO_PIN_SET == BSP_PB_GetState());
        
    do
    {
        for (i = 0; i < BUFFER_LENGTH; i++)
        {
            TxBuffer[i] = i;
        }
        
        SPI_Master_TransmitReceive(SPI1, TxBuffer, RxBuffer, DataLength, 0);
        
        for (i = 0; i < DataLength; i++)
        {
            if (TxBuffer[i] != (RxBuffer[i]-1)) 
            {
                printfS("There is one mistake : TxBuffer[%d]: 0x%02x != RxBuffer[%d]: 0x%02x \r\n", i,TxBuffer[i], i, RxBuffer[i]);
                
                COM_Err++;
            }
            else 
            {
                COM_OK++;
            }
        }
        
        printfS("SPI Master Full Duplex Test OK count %d times \r\n",  COM_OK);
        printfS("SPI Master Full Duplex Test Err count %d times \r\n", COM_Err);
        
        COM_OK = 0;
        COM_Err = 0;

        DelayMs(500);
    }while(1);
    
    printfS("SPI Master Full Duplex Test End!!! \r\n");
}

/**
  * @brief  SPI_Master NorFlash Read/Write Demo
  * @param None
  * @retval None
  */ 
void SPI_Nor_Flash_Test(void)
{
    uint32_t i;
    
    uint16_t Flash_ID;
    uint32_t ErrCount = 0;
    uint32_t TestMode = 0;
    
    GPIO_InitTypeDef GPIO_Handle; 
    
    #define TEST_1X_MODE    (0)
    #define TEST_2X_MODE    (2)
    #define TEST_4X_MODE    (3)

    SPI3_Init();
    
    SPI3_GPIO_Init();
    
    /* CS USE Software Control */
    /*   SPI CS PortA Pin15    */
    GPIO_Handle.Pin            = GPIO_PIN_15;
    GPIO_Handle.Mode           = GPIO_MODE_OUTPUT_PP;
    GPIO_Handle.Pull           = GPIO_PULLUP;
    GPIO_Handle.Drive          = GPIO_DRIVE_LEVEL3;
    GPIO_Handle.Alternate      = GPIO_FUNCTION_0;
    GPIO_Init(GPIOA, &GPIO_Handle);

    __SPI_SET_1X_MODE();
    
    /* First Set CS HIGH */
    __SPI_CS_Release(); 
    
    DelayMs(500);
    
    /* Please Select Test Mode */
    TestMode = TEST_4X_MODE;

    /*************************************** Test Prepare ***************************************/
    if (TestMode == TEST_1X_MODE) 
        printfS("SPI TEST_1X_MODE is Start!!! \r\n");
    else if (TestMode == TEST_2X_MODE) 
        printfS("SPI TEST_2X_MODE is Start!!! \r\n");
    else if (TestMode == TEST_4X_MODE) 
        printfS("SPI TEST_4X_MODE is Start!!! \r\n");

    /* Read Read Manufacture ID and Device ID */
    Flash_ID = IC_W25Qxx_Read_ID();

    printfS("Get Manufacture ID and Device ID : 0x%04X \r\n", Flash_ID);

    /* Erase Chip */
    IC_W25Qxx_EraseChip();
    
    IC_W25Qxx_Read_Data(RxBuffer, 0, BUFFER_LENGTH);

    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        if (RxBuffer[i] != 0xFF) 
        {
            ErrCount++;
        } 
    }

    if (ErrCount) 
        printfS("Erase Chip Fail!!! \r\n");
    else 
        printfS("Erase Chip Success!!! \r\n");

    /* Clear Error Count */
    ErrCount = 0;
    
    for (i = 0; i < BUFFER_LENGTH; i++)
    {
        TxBuffer[i] = i;
    }
    
    /************************************* Test Prepare End **************************************/
    
    switch (TestMode)
    {
        case TEST_1X_MODE: 
        {
            IC_W25Qxx_PageProgram(TxBuffer, 0,   256);
            IC_W25Qxx_PageProgram(TxBuffer, 256, 256);
            IC_W25Qxx_PageProgram(TxBuffer, 512, 256);
            IC_W25Qxx_PageProgram(TxBuffer, 768, 256);
            
            IC_W25Qxx_Read_Data(RxBuffer, 0, BUFFER_LENGTH);
            
            for (i = 0; i < BUFFER_LENGTH; i++)
            {
                if (TxBuffer[i] != RxBuffer[i]) 
                {
                    ErrCount++;
                } 
            }
            
            if (ErrCount) 
                printfS("SPI TEST_1X_MODE is Fail!!! \r\n");
            else 
                printfS("SPI TEST_1X_MODE is Success!!! \r\n");
        }break;

        case TEST_2X_MODE: 
        {
            IC_W25Qxx_PageProgram(TxBuffer, 0,   256);
            IC_W25Qxx_PageProgram(TxBuffer, 256, 256);
            IC_W25Qxx_PageProgram(TxBuffer, 512, 256);
            IC_W25Qxx_PageProgram(TxBuffer, 768, 256);
            
            IC_W25Qxx_Read_Dual_Output(RxBuffer, 0, BUFFER_LENGTH);
            
            for (i = 0; i < BUFFER_LENGTH; i++)
            {
                if (TxBuffer[i] != RxBuffer[i]) 
                {
                    ErrCount++;
                } 
            }

            if (ErrCount) 
                printfS("SPI TEST_2X_MODE is Fail!!! \r\n");
            else 
                printfS("SPI TEST_2X_MODE is Success!!! \r\n");
        }break;

        case TEST_4X_MODE: 
        {
            IC_W25Qxx_QuadConfig(true);
            
            IC_W25Qxx_PageProgram_Quad(TxBuffer, 0,   256);
            IC_W25Qxx_PageProgram_Quad(TxBuffer, 256, 256);
            IC_W25Qxx_PageProgram_Quad(TxBuffer, 512, 256);
            IC_W25Qxx_PageProgram_Quad(TxBuffer, 768, 256);
            
            IC_W25Qxx_Read_Quad_Output(RxBuffer, 0, BUFFER_LENGTH);
            
            for (i = 0; i < BUFFER_LENGTH; i++)
            {
                if (TxBuffer[i] != RxBuffer[i]) 
                {
                    ErrCount++;
                } 
            }

            if (ErrCount) 
                printfS("SPI TEST_4X_MODE is Fail!!! \r\n");
            else 
                printfS("SPI TEST_4X_MODE is Success!!! \r\n");

            IC_W25Qxx_QuadConfig(false);
        }break;

        default: break; 
    }
}

/**
  * @brief  SPI_Master Demos
  * @param fe_Mode
  * @retval None
  */ 
void SPI_Master_Test(enum_TEST_MODE_t fe_Mode)
{
    switch (fe_Mode)
    {
        case TEST_MASTER_COMM: 
            SPI_Master_Comm_Loop();
            break; 
        
        case TEST_MASTER_IT:
            SPI_Master_Comm_IT();
            break;
        
        case TEST_MASTER_DMA: 
            SPI_Master_Comm_DMA();
            break;
        
        case TEST_MASTER_FULL_DUPLEX: 
            SPI_Master_FullDuplex_Test();
            break;
        
        case TEST_MASTER_NOR_FLASH: 
            SPI_Nor_Flash_Test();
            break;
        
        default: break;     
    }
}


