/**
  ******************************************************************************
 *
 * @file        Sample_SPI_Master_OPI.c
 *
 * @brief       OPI master mode sample code.
 *
 * @par         Project
 *              MG32
 * @version     V1.01
 * @date        2025/06/16
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2022 Megawin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************
 * @par         Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */
 

/* Includes ------------------------------------------------------------------*/
#include "MG32_DRV.h"


/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define Dummy_Data 0xFFFFFFFF
#define SPI_NSS PB0     // SPI_NSS
#define SPI0_TDAT_4B    SPI0->TDAT.W
#define SPI0_TDAT_3B    SPI0->TDAT3.W
#define SPI0_TDAT_2B    SPI0->TDAT.H[0]
#define SPI0_TDAT_1B    SPI0->TDAT.B[0]
#define SPI0_RDAT_4B    SPI0->RDAT.W
#define SPI0_RDAT_2B    SPI0->RDAT.H[0]
#define SPI0_RDAT_1B    SPI0->RDAT.B[0]

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void Sample_SPI_Master_OPI (void);

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief       Sample SPI Master OPI code
 * @details     1. Enable CSC to SPI clock
 *      \n      2. Default Initial SPI
 *      \n      3. Configure clock divider
 *      \n      4. Configure SPI data line, mode and data size...
 *      \n      5. Config SPI0 IO
 *      \n      6. Enable SPI
 *      \n      7. Send data
 *      \n      8. Read data
 *      \n      9. Disable SPI
 * @return
 * @note        Support MG32F02A064/A0128/U064/U128
 * @par         Example
 * @code
    Sample_SPI_Master_OPI();
 * @endcode
 *******************************************************************************
 */
void Sample_SPI_Master_OPI (void)
{
    PIN_InitTypeDef PINX_InitStruct;
    uint32_t RDAT1, RDAT2, RDAT3;
    uint32_t TDAT1, TDAT2, TDAT3;
    uint8_t  LOOP;

    
    
    //===Set CSC init====
    //MG32_CSC_Init.h(Configuration Wizard)
    //Select CK_HS source = CK_IHRCO
    //Select IHRCO = 12Mz
    //Select CK_MAIN Source = CK_HS
    //Configure PLL->Select APB Prescaler = CK_MAIN/1
    
    /*=== 1. Enable CSC to SPI clock ===*/
    //[A] When Use Wizard
    //Configure Peripheral On Mode Clock->SPI0 = Enable and Select SPI0_PR Source = CK_APB
    //Configure Peripheral On Mode Clock->Port A = Enable
    //Configure Peripheral On Mode Clock->Port B = Enable
    //[B] When Use Driver
//    UnProtectModuleReg(CSCprotect);                             // Unprotect CSC module
//    CSC_PeriphOnModeClock_Config(CSC_ON_SPI0, ENABLE);          // Enable SPI0 module clock
//    CSC_PeriphOnModeClock_Config(CSC_ON_PortA, ENABLE);		  // Enable PortA clock
//    CSC_PeriphOnModeClock_Config(CSC_ON_PortB, ENABLE);		  // Enable PortB clock
//    CSC_PeriphProcessClockSource_Config(CSC_SPI0_CKS, CK_APB);  // CK_SPIx_PR = CK_APB = 12MHz
//    ProtectModuleReg(CSCprotect);                               // protect CSC module
       
    /*=== 2. Default Initial SPI ===*/
    SPI_DeInit(SPI0);
    
    /*=== 3. Configure clock divider ===*/                      // SPI clock = 1MHz
    SPI_Clock_Select(SPI0, SPI_CK_SPIx_PR);                     // CK_SPIx = CK_SPIx_PR
    SPI_PreDivider_Select(SPI0, SPI_PDIV_1);                    // PDIV outpu = CK_SPIx /1
    SPI_Prescaler_Select(SPI0, SPI_PSC_3);                      // Prescaler outpu = PDIV outpu /3
    SPI_Divider_Select(SPI0, SPI_DIV_4);                        // DIV outpu = PDIV outpu /4
    
    /*=== 4. Configure SPI data line, mode and data size... ===*/
    SPI_DataLine_Select(SPI0, SPI_8LinesBidirection);           // SPI data line 8-lines Bidirectional~ SPI0_D0 ~ SPI0_D7
    SPI_ModeAndNss_Select(SPI0, SPI_Master);                    // Master without NSS
    SPI_ClockPhase_Select(SPI0, SPI_LeadingEdge);               // CPHA = 0
    SPI_ClockPolarity_Select(SPI0, SPI_Low);                    // CPOL = 0
    SPI_FirstBit_Select(SPI0, SPI_MSB);                         // MSB first
    SPI_DataSize_Select(SPI0, SPI_8bits);                       // Data size 8bits
    
    /*=== 5. Config SPI0 IO ===*/
    PINX_InitStruct.PINX_Mode               = PINX_Mode_PushPull_O;     // Pin select pusu pull mode
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable; // Disable pull up resistor
    PINX_InitStruct.PINX_Speed              = PINX_Speed_High;          // Output high speed mode enable 
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;     // Pin output driver full strength.
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;// Pin input deglitch filter clock divider bypass
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;     // Pin input data not inverse
    PINX_InitStruct.PINX_Alternate_Function = 2;                        // Pin AFS = 2
    GPIO_PinMode_Config(PINB(2),&PINX_InitStruct);                      // CLK setup at PB2
    
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level2;     // Pin output drive strength 1/4
    GPIO_PinMode_Config(PINB(3),&PINX_InitStruct);                      // D0(MOSI) at PB3
    GPIO_PinMode_Config(PINB(1),&PINX_InitStruct);                      // D1(MISO) at PB1
    GPIO_PinMode_Config(PINA(10),&PINX_InitStruct);                     // D2 at PA10
    GPIO_PinMode_Config(PINA(11),&PINX_InitStruct);                     // D3 at PA11
    
    PINX_InitStruct.PINX_Alternate_Function = 7;                        // Pin AFS = 7
    GPIO_PinMode_Config(PINA(15),&PINX_InitStruct);                     // D4 at PA15
    GPIO_PinMode_Config(PINA(12),&PINX_InitStruct);                     // D5 at PA12
    GPIO_PinMode_Config(PINA(13),&PINX_InitStruct);                     // D6 at PA13
    GPIO_PinMode_Config(PINA(14),&PINX_InitStruct);                     // D7 at PA14
    
    PINX_InitStruct.PINX_Speed              = PINX_Speed_Low;           // Output high speed mode enable 
    PINX_InitStruct.PINX_Alternate_Function = 0;                        // Pin AFS = 0
    GPIO_PinMode_Config(PINB(0),&PINX_InitStruct);                      // NSS setup at PB0

    /*=== 6. Enable SPI ===*/
    SPI_Cmd(SPI0, ENABLE);                                              // Enable SPI
    

    RDAT1 = RDAT2 = RDAT3 = 0;
    for(LOOP=3; LOOP>0; LOOP--)
    {
        /*=== 7. Send data ===*/    // Total transmit 9 bytes
        // [By Driver level]
        SPI_TransferBidirection_Select(SPI0, SPI_BDIR_OUT);                 // OPI data direction output
        TDAT1 = RDAT1 + 0x08040201;
        TDAT2 = RDAT2 + 0x80402010;
        TDAT3 = RDAT3 + 0x00000001;
        
        SPI_NSS = 0;                                                        // NSS = 0
        SPI_SetTxData(SPI0, SPI_4Byte, TDAT1);                               // Send 4 byte and received 4 byte the same time
        SPI_SetTxData(SPI0, SPI_4Byte, TDAT2);                               // Send 4 byte and received 4 byte the same time
        while(SPI_GetSingleFlagStatus(SPI0, SPI_TXF) == DRV_UnHappened);    // Wait TXF flag
        SPI_SetTxData(SPI0, SPI_1Byte, TDAT3);                               // Send 1 byte and received 1 byte the same time
        while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TCF flag
        
        SPI_NSS = 1;                                                        // NSS = 1
        SPI_ClearRxData(SPI0);                                              // Clear RX 
        SPI_ClearRxData(SPI0);                                              // Clear RX 
        SPI_ClearFlag(SPI0, SPI_ALLF);                                      // Clear flag

        // [By Register level]
//        SPI0_CR2_BDIR_OE = 1;                                               // OPI data direction output
//        TDAT1 = RDAT1 + 0x08040201;
//        TDAT2 = RDAT2 + 0x80402010;
//        TDAT3 = RDAT3 + 0x00000001;
//        
//        SPI_NSS = 0;                                                        // NSS = 0
//        SPI0_TDAT_4B = TDAT1;                                               // Send 4 byte and received 4 byte the same time
//        SPI0_TDAT_4B = TDAT2;                                               // Send 4 byte and received 4 byte the same time
//        while(SPI0_STA_TXF == 0);                                           // Wait TXF flag (TDAT empty)
//        SPI0_TDAT_1B = (uint8_t)TDAT3;                                      // Send 1 byte and received 1 byte the same time
//        while(SPI0_STA_TCF == 0);                                           // Wait TCF flag (SPI0 transmit complete)
//        SPI_NSS = 1;                                                        // NSS = 1
//        
//        SPI0_CR1_RDAT_CLR = 1;                                              // Clear RX 
//        SPI0_CR1_RDAT_CLR = 1;                                              // Clear RX 
//        SPI0_STA = SPI_ALLF;                                                // Clear flag
        
        
        /*=== 8. Read data ===*/    // Total receive 9 bytes
        // [By Driver level]
        SPI_TransferBidirection_Select(SPI0, SPI_BDIR_IN);                  // OPI data direction input
        SPI_NSS = 0;                                                        // NSS = 0
        SPI_SetTxData(SPI0, SPI_4Byte, Dummy_Data);                         // Received 4 byte and send 4 byte the same time
        SPI_SetTxData(SPI0, SPI_4Byte, Dummy_Data);                         // Received 4 byte and send 4 byte the same time
        while(SPI_GetSingleFlagStatus(SPI0, SPI_TXF) == DRV_UnHappened);    // Wait TCF flag
        RDAT1 = SPI_GetRxData(SPI0);      
        SPI_SetTxData(SPI0, SPI_1Byte, Dummy_Data);                         // Received 4 byte and send 4 byte the same time
        while(SPI_GetSingleFlagStatus(SPI0, SPI_TCF) == DRV_UnHappened);    // Wait TCF flag
        RDAT2 = SPI_GetRxData(SPI0);      
        RDAT3 = SPI_GetRxData(SPI0);      
        SPI_NSS = 1;                                                        // NSS = 1

        SPI_ClearFlag(SPI0, (SPI_TXF | SPI_RXF | SPI_TCF));                 // Clear TCF, TXF and RXF

        // [By Register level]
//        SPI0_CR2_BDIR_OE = 0;                                               // OPI data direction input
//        SPI_NSS = 0;                                                        // NSS = 0
//        SPI0_TDAT_4B = Dummy_Data;                                          // Received 4 byte and send 4 byte the same time
//        SPI0_TDAT_4B = Dummy_Data;                                          // Received 4 byte and send 4 byte the same time
//        while(SPI0_STA_TXF == 0);                                           // Wait TXF flag (TDAT empty)
//        RDAT1 = SPI0_RDAT_4B;                                               // Get received data
//        SPI0_TDAT_1B = (uint8_t)TDAT3;                                      // Received 1 byte and send 1 byte the same time
//        while(SPI0_STA_TCF == 0);                                           // Wait TCF flag (SPI0 transmit complete)
//        RDAT2 = SPI0_RDAT_4B;                                               // Get received data
//        RDAT3 = SPI0_RDAT_1B;                                               // Get received data
//        SPI_NSS = 1;                                                        // NSS = 1
//        
//        SPI0_STA = (SPI_TXF | SPI_RXF | SPI_TCF);                           // Clear TCF, TXF and RXF
    }
    
    /*=== 9. Disable SPI ===*/
    SPI_Cmd(SPI0, DISABLE);                                             // Disable SPI
}


