/**
 *******************************************************************************
 *
 * @file        MG32_SPI_Init.c
 *
 * @brief       The SPI Init C file.
 *
 * @par         Project
 *              MG32
 * @version     V1.04
 * @date        2023/08/02
 * @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_SPI_Init.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
// Master Configuration
#if CONF_SPI0_MODE != 0
#if CONF_SPI0_MODE == 17    // 0x00000011
#define CONF_SPI0_CLK    CONF_SPI0_MST_PDIVIDER | CONF_SPI0_MST_PRESCALER | CONF_SPI0_MST_DIVIDER | CONF_SPI0_MST_CLOCK_SOURCE
#define CONF_SPI0_CR0    CONF_SPI0_MODE | CONF_SPI0_MST_NSSO_EN | CONF_SPI0_MST_NSS_SWEN | CONF_SPI0_MST_LSB | CONF_SPI0_MST_CPOL | CONF_SPI0_MST_CPHA | CONF_SPI0_MST_RX_CTL
#define CONF_SPI0_CR2    CONF_SPI0_MST_DATA_SIZE | CONF_SPI0_MST_DAT_LINE
#endif

// Slave Configuration
#if CONF_SPI0_MODE == 1	    // 0x00000001
#define CONF_SPI0_CLK    0x00000000 | CONF_SPI0_SLV_CLOCK_SOURCE
#define CONF_SPI0_CR0    CONF_SPI0_MODE | CONF_SPI0_SLV_NSSI_EN | CONF_SPI0_SLV_NSSI_SLE | CONF_SPI0_SLV_LSB | CONF_SPI0_SLV_CPOL | CONF_SPI0_SLV_CPHA | CONF_SPI0_SLV_ASYNC_EN | CONF_SPI0_SLV_HS_EN | CONF_SPI0_SLV_TX_CTL
#define CONF_SPI0_CR2    CONF_SPI0_SLV_DATA_SIZE | CONF_SPI0_SLV_DAT_LINE
#endif



#define CONF_SPI0_STA    SPI_TUDRF | SPI_ROVRF | SPI_WEF | SPI_MODF | SPI_TXF | SPI_RXF | SPI_RXDF | SPI_TCF | SPI_IDLF
#define CONF_SPI0_CR1    SPI_CR1_RDAT_CLR_mask_w | SPI_CR1_TDAT_CLR_mask_w
#define CONF_SPI0_INT    CONF_SPI0_INT_IEA | CONF_SPI0_INT_IDL_IE | CONF_SPI0_INT_TC_IE | CONF_SPI0_INT_RX_IE | CONF_SPI0_INT_TX_IE | CONF_SPI0_INT_MODF_IE | CONF_SPI0_INT_WE_IE | CONF_SPI0_INT_ROVR_IE | CONF_SPI0_INT_TUDR_IE
#endif

/* Private macro -------------------------------------------------------------*/
// For middleware parameter modify
#if defined(IRQHandler_Middleware_Level_)   

    // When CONF_SPI0_MODE is master mode
    #if CONF_SPI0_MODE == 0x00000011
    
        // When enable NSS output function
        #if CONF_SPI0_MST_NSSO_EN == 0x00000100
            // When NSS control by hardware
            #define MID_SPI_MODE    SPI_MODE_MASTER_NSS
            #if CONF_SPI0_MST_NSS_SWEN == 0x00000000
                #define MID_SPI_NSS     SPI_NSS_OUT_HARDWARE
            // When NSS control by software
            #elif CONF_SPI0_MST_NSS_SWEN == 0x00000800
                #define MID_SPI_NSS     SPI_NSS_OUT_SOFTWARE
            #endif
        // When disable NSS output function
        #else
            #define MID_SPI_MODE    SPI_MODE_MASTER
            #define MID_SPI_NSS     0x00000000
        #endif
    
        // Get PDIV value
        #if CONF_SPI0_MST_PDIVIDER == 0x00000000
            #define CLK_DIV_PDIVIDER    1
        #endif
        #if CONF_SPI0_MST_PDIVIDER == 0x00001000
            #define CLK_DIV_PDIVIDER    2
        #endif
        #if CONF_SPI0_MST_PDIVIDER == 0x00002000
            #define CLK_DIV_PDIVIDER    4
        #endif
        #if CONF_SPI0_MST_PDIVIDER == 0x00003000
            #define CLK_DIV_PDIVIDER    8
        #endif
        
        // Get Prescaler value
        #define CLK_DIV_PRESCALER       ((CONF_SPI0_MST_PRESCALER >> 8) + 1)
        
        // Get DIB value
        #if CONF_SPI0_MST_DIVIDER == 0x00000000
            #define CLK_DIV_DIVIDER       2
        #endif
        #if CONF_SPI0_MST_DIVIDER == 0x00000010
            #define CLK_DIV_DIVIDER       4
        #endif
        #if CONF_SPI0_MST_DIVIDER == 0x00000020
            #define CLK_DIV_DIVIDER       8
        #endif
        #if CONF_SPI0_MST_DIVIDER == 0x00000030
            #define CLK_DIV_DIVIDER       16
        #endif
        
        // Get clock divider
        #define CLK_DIV             CLK_DIV_PDIVIDER * CLK_DIV_PRESCALER * CLK_DIV_DIVIDER
        
        // Get middleware clock divider setting
        #if CLK_DIV == 2
            #define SPI_CLOCKDIVIDER_SET    0
        #endif
        #if ((CLK_DIV > 2) && (CLK_DIV <= 4))   
            #define SPI_CLOCKDIVIDER_SET    1 
        #endif
        #if ((CLK_DIV > 4) && (CLK_DIV <= 8))
            #define SPI_CLOCKDIVIDER_SET    2
        #endif
        #if ((CLK_DIV > 8) && (CLK_DIV <= 16))
            #define SPI_CLOCKDIVIDER_SET    3
        #endif
        #if ((CLK_DIV > 16) && (CLK_DIV <= 32))
            #define SPI_CLOCKDIVIDER_SET    4
        #endif
        #if ((CLK_DIV > 32) && (CLK_DIV <= 64))
            #define SPI_CLOCKDIVIDER_SET    5
        #endif
        #if ((CLK_DIV > 64) && (CLK_DIV <= 128))
            #define SPI_CLOCKDIVIDER_SET    6
        #endif
        #if ((CLK_DIV > 128) && (CLK_DIV <= 256))
            #define SPI_CLOCKDIVIDER_SET    7
        #endif
        #if ((CLK_DIV > 256) && (CLK_DIV <= 512))
            #define SPI_CLOCKDIVIDER_SET    8
        #endif
        #if ((CLK_DIV > 512) && (CLK_DIV <= 1024))
            #define SPI_CLOCKDIVIDER_SET    9
        #endif
        
                // When selecting first bit LSB
        #if CONF_SPI0_MST_LSB == 0x00000008
            #define MID_SPI_FIRSTBIT    SPI_FIRSTBIT_LSB
        #else
            #define MID_SPI_FIRSTBIT    SPI_FIRSTBIT_MSB
        #endif
    #endif
    
    // When CONF_SPI0_MODE is slave mode
    #if CONF_SPI0_MODE == 0x00000001
    
        // When enable NSS input function
        #if CONF_SPI0_SLV_NSSI_EN == 0x00000200
            #define MID_SPI_MODE    SPI_MODE_SLAVE_NSS
            
            // When selecting NSS input at NSS pin
            #if CONF_SPI0_SLV_NSSI_SLE == 0x00000000
                #define MID_SPI_NSS     SPI_NSS_IN_HARDWARE
            // When selecting NSSI input at NSS pin
            #elif CONF_SPI0_SLV_NSSI_SLE ==  0x00000400
                #define MID_SPI_NSS     SPI_NSSI_IN_HARDWARE
            #endif
        
        // When disable NSS input function
        #elif CONF_SPI0_SLV_NSSI_EN == 0x00000000
            #define MID_SPI_MODE    SPI_MODE_SLAVE
            #define MID_SPI_NSS     0x00000000
        #endif
        
        #define SPI_CLOCKDIVIDER_SET    0
        
        // When selecting first bit LSB
        #if CONF_SPI0_SLV_LSB == 0x00000008
            #define MID_SPI_FIRSTBIT    SPI_FIRSTBIT_LSB
        #else
            #define MID_SPI_FIRSTBIT    SPI_FIRSTBIT_MSB
        #endif
        
    #endif
#endif


/* Private variables ---------------------------------------------------------*/
// (Middleware level)
// (Middleware level)
#if defined(IRQHandler_Middleware_Level_)   
    #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
        #pragma clang diagnostic push
        #pragma clang diagnostic ignored "-Wmissing-variable-declarations"
        SPI_HandleTypeDef           mSPI0;
    // ------------------------------------------------------------------------
    #else
        SPI_HandleTypeDef           mSPI0;
    #endif
#endif


/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/


/**
 *******************************************************************************
 * @brief  	    initialized SPI module.
 * @details  
 * @return	    None	
 * @note
 * @par         Example
 * @code
    SPI_Init (SPI0);
 * @endcode
 *******************************************************************************
 */
void SPI_Init (void)
{
#if CONF_SPI0_MODE != 0
    #if !defined(IRQHandler_Middleware_Level_)   
        SPI0->CR0.W = CONF_SPI0_CR0 & (~SPI_CR0_EN_mask_w);
        SPI0->CR1.W = CONF_SPI0_CR1;
        SPI0->CR2.W = CONF_SPI0_CR2;
        SPI0->STA.W = CONF_SPI0_STA;
        SPI0->CLK.W = CONF_SPI0_CLK;
        SPI0->INT.W = CONF_SPI0_INT;
        SPI0->CR0.W = CONF_SPI0_CR0;
    #endif
    
    
    // When include middleware
    #if defined(IRQHandler_Middleware_Level_)   
        
        // When SPI mode select master
        #if ((MID_SPI_MODE == SPI_MODE_MASTER) || (MID_SPI_MODE == SPI_MODE_MASTER_NSS))
            mSPI0.Instance = SPI_SPI0;
            mSPI0.Init.Mode = MID_SPI_MODE;
            mSPI0.Init.DataLine = (CONF_SPI0_MST_DAT_LINE >> 4);
            mSPI0.Init.DataSize = (CONF_SPI0_MST_DATA_SIZE >> 16);
            mSPI0.Init.CLKPolarity = CONF_SPI0_MST_CPOL;
            mSPI0.Init.CLKPhase = CONF_SPI0_MST_CPHA;
            mSPI0.Init.NSS = MID_SPI_NSS;
            
            mSPI0.Init.ClockDivider = SPI_CLOCKDIVIDER_SET;
            mSPI0.Init.FirstBit = MID_SPI_FIRSTBIT;
            mSPI0.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
            mSPI0.Init.Swap = SPI_SWAP_DISABLE;
            mSPI0.Init.IdleDataOut = SPI_IDLE_DATA_OUT_TRISTATE;
            
            // Support MG32F02U128/U064/A128/A064 and MG32F02V032
            mSPI0.Init.SlaveClockInputControl = SPI_SLV_ClockSynchronous;
            
            // Support MG32F02V032
            mSPI0.Init.SlaveTransmitTimingControl = SPI_SLV_TransmitTiming_Normal;    
            
            MID_SPI_Init(&mSPI0);
            SPI0->INT.W = CONF_SPI0_INT;
        #endif
        

        // When SPI mode select slave
        #if ((MID_SPI_MODE == SPI_MODE_SLAVE) || (MID_SPI_MODE == SPI_MODE_SLAVE_NSS))
         
            mSPI0.Instance = SPI_SPI0;
            mSPI0.Init.Mode = MID_SPI_MODE;
            mSPI0.Init.DataLine = (CONF_SPI0_SLV_DAT_LINE >> 4);
            mSPI0.Init.DataSize = (CONF_SPI0_SLV_DATA_SIZE >> 16);
            mSPI0.Init.CLKPolarity = CONF_SPI0_SLV_CPOL;
            mSPI0.Init.CLKPhase = CONF_SPI0_SLV_CPHA;
            mSPI0.Init.NSS = MID_SPI_NSS;
            
            mSPI0.Init.ClockDivider = SPI_CLOCKDIVIDER_SET;
            mSPI0.Init.FirstBit = MID_SPI_FIRSTBIT;
            mSPI0.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
            mSPI0.Init.Swap = SPI_SWAP_DISABLE;
            mSPI0.Init.IdleDataOut = SPI_IDLE_DATA_OUT_TRISTATE;
            
            // Support MG32F02U128/U064/A128/A064 and MG32F02V032
            mSPI0.Init.SlaveClockInputControl = CONF_SPI0_SLV_ASYNC_EN;
            
            // Support MG32F02V032
            mSPI0.Init.SlaveTransmitTimingControl = CONF_SPI0_SLV_TX_CTL;    
            
            MID_SPI_Init(&mSPI0);
            SPI0->INT.W = CONF_SPI0_INT;
        #endif
    #endif
#endif
}

