

/**
 ******************************************************************************
 *
 * @file        Sample_SPI_Master_OPI_PSRAM.c
 * @brief       For LY68L6408 sample code. 
 *
 * @par         Project
 *              MG32
 * @version     V1.00
 * @date        2023/05/08
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2023 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"
#include "MG32_ChipInit.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
#define NSS PB0
#define DQS PB10

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
uint8_t API_PSRAM_Init (void);
void API_PSRAM_RstGlobal (void);
void API_PSRAM_GetModeReg (uint8_t ModAddr, uint8_t DatLeng, uint8_t* DestIndex);
void API_PSRAM_SetModeReg (uint8_t ModAddr, uint8_t DatLeng, uint8_t* DestIndex);
void API_PSRAM_Read (uint8_t StardAddress, uint32_t DatLeng, uint8_t* DestIndex);
void API_PSRAM_Write (uint8_t StardAddress, uint32_t DatLeng, uint8_t* SrcIndex);
int Sample_SPI_Master_OPI_PSRAM (void);

/* External vairables --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief  	    API PSRAM Init
 * @details  
 * @return	    uint8_t
 * 	@arg\b			0 Initial success
 *  @arg\b          1 Initial failure
 * @note        
 * @par         Example
 * @code
    while(API_PSRAM_Init() != 0);
 * @endcode
 *******************************************************************************
 */
uint8_t API_PSRAM_Init (void)
{
    PIN_InitTypeDef PINX_InitStruct;                                        // IO setting parament


    
    PINX_InitStruct.PINX_Mode				= PINX_Mode_OpenDrain_O;        // Open drain output
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Enable;      // Enable pull up resistor
    PINX_InitStruct.PINX_Speed              = PINX_Speed_Low;               // Speed low
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;         // Drive strength-full
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;    // Filter divider bypass
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;         // Disable inverse
    
    
    GPIO_PinMode_Config(PINB(0),&PINX_InitStruct);                          // DQS
    
    PINX_InitStruct.PINX_Mode				= PINX_Mode_PushPull_O;         // Push pull output
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable;     // Disable pull up resistor
    PINX_InitStruct.PINX_Alternate_Function = 0;                            // AFS = 0, GPIO
    GPIO_PinMode_Config(PINB(0),&PINX_InitStruct);                          // NSS
    
    PINX_InitStruct.PINX_Alternate_Function = 2;                            // AFS = 2, SPI function.
    GPIO_PinMode_Config(PINB(2),&PINX_InitStruct);                          // CLK
    GPIO_PinMode_Config(PINB(3),&PINX_InitStruct);                          // MOSI
    GPIO_PinMode_Config(PINB(1),&PINX_InitStruct);                          // MISO
    GPIO_PinMode_Config(PINB(5),&PINX_InitStruct);                          // D2
    GPIO_PinMode_Config(PINB(4),&PINX_InitStruct);                          // D3
    
    PINX_InitStruct.PINX_Alternate_Function = 7;                            // AFS = 7, SPI function.
    GPIO_PinMode_Config(PINA(15),&PINX_InitStruct);                         // D4
    GPIO_PinMode_Config(PINA(12),&PINX_InitStruct);                         // D5
    GPIO_PinMode_Config(PINA(13),&PINX_InitStruct);                         // D6
    GPIO_PinMode_Config(PINA(14),&PINX_InitStruct);                         // D7
    
    SPI_DeInit(SPI0);                                                       // DeInit SPI
    SPI_ModeAndNss_Select(SPI0, SPI_Master);                                // SPI mode setting master
    
    SPI_Clock_Select(SPI0, SPI_CK_SPIx_PR);                                 // SPI CLK = CK_SPIx_PR / (PDIV x PSC x DIV)
    SPI_PreDivider_Select(SPI0, SPI_PDIV_1);
    SPI_Prescaler_Select(SPI0, SPI_PSC_1);
    SPI_Divider_Select(SPI0, SPI_DIV_4);
    
    SPI_ClockPolarity_Select(SPI0, SPI_Low);                                // CPOL = 0
    SPI_ClockPhase_Select(SPI0, SPI_LeadingEdge);                           // CPHA = 0
    
    SPI_DualTransferRate_Select(SPI0, SPI_DualTransferRate);                // Dual transfer rate mode enable bit for SPI master mode
    
    SPI_DataSize_Select(SPI0, SPI_8bits);                                   // Data size 8-bit
    SPI_DataLine_Select(SPI0, SPI_8LinesBidirection);                       // SPI data line is 8-lines
    SPI_TransferBidirection_Select (SPI0, SPI_BDIR_OUT);                    // SPI data line output enable
    
    NSS = 1;                                                                // NSS = 1
    SPI_Cmd(SPI0, ENABLE);                                                  // Enable SPI
    SPI_ClearFlag(SPI0, SPI_ALLF);                                          // Clear SPI all flag
    
    return 0;
}


/**
 *******************************************************************************
 * @brief  	    API PSRAM read
 * @details  
 * @param[in]   StardAddress:
 * 	@arg\b			0x0000_0000 ~ 0x007F_FFFF.
 * @param[in]   DatLeng:
 * 	@arg\b			1 ~ n;
 * @param[in]   DestIndex:
 * 	@arg\b			Destination data start index
 * @note        
 * @par         Example
 * @code
    API_PSRAM_Read(0x00000000, 13, &RX_BUF[0]);
 * @endcode
 *******************************************************************************
 */
void API_PSRAM_Read (uint8_t StardAddress, uint32_t DatLeng, uint8_t* DestIndex)
{
    uint32_t    REG;                        // Clear register
    ctype       WR_IN;                      // For change word order in
    ctype       WR_OUT;                     // For change word order out
    uint32_t     CNT = 0;                   // Counter
    
    
    
    WR_IN.W = StardAddress;                 // Change order B3, B2, B1 and B0 => B0, B1, B2 and B3.
    WR_OUT.B[0] = WR_IN.B[3];
    WR_OUT.B[1] = WR_IN.B[2];
    WR_OUT.B[2] = WR_IN.B[1];
    WR_OUT.B[3] = WR_IN.B[0];
    
    if(DatLeng%2 != 0)                      // When "DataLeng" is odd number
    {
        CNT = 1;                            // For loop CNT+1
    }    
    
    NSS = 0;                                // PSRAM CE# = 0
    /*=== Command and Address ===*/
    SPI0->CR2.MBIT.BDIR_OE = 1;             // SPI data line output
    SPI0->TDAT.H[0] = 0x0000;               // TX command 0x4040
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT.W = WR_OUT.W;                // TX address
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer            
    
    /*=== Dummy 8 clock ===*/
    SPI0->CR2.MBIT.BDIR_OE = 0;             // SPI data line input
    SPI0->TDAT.W = 0xFFFFFFFF;              // 
    while(SPI0->STA.MBIT.TXF == 0);         // 
    SPI0->TDAT.W = 0xFFFFFFFF;              // 
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer   
    
    /*=== Read data ===*/
    for(CNT+=DatLeng; CNT>0; CNT--)         // For loop counter
    {
        SPI0->TDAT.B[0] = 0xFF;             // Get 1 byte data
        while(SPI0->STA.MBIT.RXF == 0);     // Waiting receive flag happened
        *DestIndex = SPI0->RDAT.B[0];       // Move data to target 
        DestIndex++;
    }
    
    SPI0->STA.W = SPI_ALLF;                 // Clear SPI all flag
    NSS = 1;                                // PSRAM CE# = 1
}
 
 
 /**
 *******************************************************************************
 * @brief  	    Write PSRAM Write 
 * @details  
 * @param[in]   StardAddress:
 * 	@arg\b			0x0000_0000 ~ 0x007F_FFFF.
 * @param[in]   DatLeng:
 * 	@arg\b			4 ~ 1024;
 * @param[in]   SrcIndex:
 * 	@arg\b			Source data start index
 * @note        
 * @par         Example
 * @code
    API_PSRAM_Write(0x00000000, 13, &TX_BUF[0]);
 * @endcode
 *******************************************************************************
 */
void API_PSRAM_Write (uint8_t StardAddress, uint32_t DatLeng, uint8_t* SrcIndex)
{
    uint32_t REG;                           // Clear register
    ctype WR_IN;                            // For change word order in
    ctype WR_OUT;                           // For change word order out
    uint32_t  CNT = 0;                       // Counter
    
    
    
    WR_IN.W = StardAddress;                 // Change order B3, B2, B1 and B0 => B0, B1, B2 and B3.
    WR_OUT.B[0] = WR_IN.B[3];
    WR_OUT.B[1] = WR_IN.B[2];
    WR_OUT.B[2] = WR_IN.B[1];
    WR_OUT.B[3] = WR_IN.B[0];
    
    if(DatLeng%2 == 0)                      // When "DataLeng" is even number
    {
        CNT = 1;                            // For loop CNT+1
    }    
    
    NSS = 0;                                // PSAM CE# = 0
    /*=== Command and Address ===*/
    SPI0->CR2.MBIT.BDIR_OE = 1;             // SPI data line output
    SPI0->TDAT.H[0] = 0x8080;               // TX command 0x0000
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT.W = WR_OUT.W;                // TX address
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer            
    
    DQS = 0;   
    /*=== Dunny 7 clock ===*/
    SPI0->TDAT.W = 0xFFFFFFFF;              //
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT3.W = 0xFFFFFFFF;             //
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;   
    
    /*=== Write data ===*/
    for(CNT+=DatLeng; CNT>0; CNT--)         // For loop counter
    {
        SPI0->TDAT.B[0] = *SrcIndex;        // Get 1 byte data
        SrcIndex++;
        while(SPI0->STA.MBIT.TXF == 0);     // Waiting receive flag happened
        REG = SPI0->RDAT.W;                 // Move data to target 
    }
    
    SPI0->STA.W = SPI_ALLF;                 // Clear SPI all flag
    NSS = 1;                                // PSRAM CE# = 1
    DQS = 1;   
}


/**
 *******************************************************************************
 * @brief  	    Get PSRAM mode register
 * @details  
 * @param[in]   ModAddr:
 * 	@arg\b          0x00 ~ 0xFF 
 * @param[in]   DatLeng:
 * 	@arg\b			1 ~ 255;
 * @param[in]   DestIndex:
 * 	@arg\b			Destination data start index
 * @note        
 * @par         Example
 * @code
    PSRAM_REG = API_PSRAM_GetModeReg (0x00, 255, &PSRAM_REG[0]);
 * @endcode
 *******************************************************************************
 */
void API_PSRAM_GetModeReg (uint8_t ModAddr, uint8_t DatLeng, uint8_t* DestIndex)
{
    uint32_t REG;                           // Register
    uint8_t  CNT=0;                         // Counter
    
    
    
    if(DatLeng%2 != 0)                      // When "DataLeng" is odd number
    {
        CNT = 1;                            // For loop CNT+1
    }    
    
    NSS = 0;                                // PSRAM CE# = 0
    /*=== Command and Address ===*/
    SPI0->CR2.MBIT.BDIR_OE = 1;             // SPI data line output
    SPI0->TDAT.W = 0xFFFF4040;              // TX command 0x4040, not care 3 bytes data and 1 byte mode address
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT.H[0] = (uint16_t) ModAddr;
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer            
    
    SPI0->CR2.MBIT.BDIR_OE = 0;             // SPI data line input
    /*=== Dunny 8 clock ===*/
    SPI0->CR2.MBIT.BDIR_OE = 0;             // SPI data line input
    SPI0->TDAT.W = 0xFFFFFFFF;              // TX 4 bytes dummy data
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT.W = 0xFFFFFFFF;              // TX 4 bytes dummy data
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer         
    
    /*=== Read data ===*/
    for(CNT+=DatLeng; CNT>0; CNT--)         // Loop
    {
        SPI0->TDAT.B[0] = 0xFF;             // Get 1 byte data
        while(SPI0->STA.MBIT.RXF == 0);     // Waiting receive flag happened
        *DestIndex = SPI0->RDAT.B[0];       // Move data to target data. 
        DestIndex++;                        // Index address ++
    }
    
    SPI0->STA.W = SPI_ALLF;                 // Clear SPI all flag
    NSS = 1;                                // PSRAM CE# = 1
}
 

/**
 *******************************************************************************
 * @brief  	    Set PSRAM mode register
 * @details  
 * @param[in]   ModAddr:
 * 	@arg\b          0x00 ~ 0xFF 
 * @param[in]   DatLeng:
 * 	@arg\b			1 ~ 255;
 * @param[in]   DestIndex:
 * 	@arg\b			Source data start index
 * @note        
 * @par         Example
 * @code
    PSRAM_REG = API_PSRAM_SetModeReg (0x00, 255, &PSRAM_REG[0]);
 * @endcode
 *******************************************************************************
 */
void API_PSRAM_SetModeReg (uint8_t ModAddr, uint8_t DatLeng, uint8_t* DestIndex)
{
    uint32_t REG;                           // Register
    uint8_t  CNT=0;                         // Counter
    
    
    
    if(DatLeng%2 != 0)                      // When "DataLeng" is odd number
    {
        CNT = 1;                            // For loop CNT+1
    }    
    
    NSS = 0;                                // DDR RAM CE# = 0
    SPI0->CR2.MBIT.BDIR_OE = 1;             // SPI data line output
    SPI0->TDAT.W = 0xFFFF4040;              // TX command 0x4040, not care 3 bytes data and 1 byte mode address
    SPI0->RDAT.H[0] = (uint16_t) ModAddr;   
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer            
    
    /*=== Dunny 8 clock ===*/
    SPI0->TDAT.W = 0xFFFFFFFF;              // TX 4 bytes dummy data
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT.W = 0xFFFFFFFF;              // TX 4 bytes dummy data
    while(SPI0->STA.MBIT.TCF == 0);         // Waiting transmit comple
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer   
    
    for(CNT+=DatLeng; CNT>0; CNT--)
    {
        SPI0->TDAT.B[0] = *DestIndex;       // Set 1 byte data
        DestIndex++;                        // 
        while(SPI0->STA.MBIT.TCF == 0);     // Waiting receive flag happened
    }
    REG = SPI0->RDAT.W;                     // Clear SPI RX buffer
    REG ++;
    REG = SPI0->RDAT.W;                     // Clear SPI RX shadow buffer     
    SPI0->STA.W = SPI_ALLF;                 // Clear SPI all flag
    NSS = 1;                                // DDR RAM CE# = 1
}


/**
 *******************************************************************************
 * @brief  	    Reset global PSRAM
 * @details  
 * @note        
 * @par         Example
 * @code
    API_PSRAM_RstGlobal();
 * @endcode
 *******************************************************************************
 */
void API_PSRAM_RstGlobal (void)
{
    uint32_t REG;
    

    
    NSS = 0;                            // PSRAM CE# = 0
    SPI0->CR2.MBIT.BDIR_OE = 1;         // SPI data line output
    SPI0->TDAT.W = 0xFFFFFFFF;          // TX command 0xFFFF, not care 4 bytes data.
    while(SPI0->STA.MBIT.TXF == 0);
    SPI0->TDAT.H[0] = 0xFFFF;
    while(SPI0->STA.MBIT.TCF == 0);     // Waiting transmit comple
    REG = SPI0->RDAT.W;
    REG ++;
    REG = SPI0->RDAT.W;
    SPI0->STA.W = SPI_ALLF;             // Clear All flag
    NSS = 1;
}


int Sample_SPI_Master_OPI_PSRAM (void)
{    
//    uint8_t PSRAM_REG[16] = {0};
    uint8_t TX_BUF[256] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
                           0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
                           0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
                           0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
                           0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
                           0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
                           0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
                           0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
                           0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
                           0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
                           0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
                           0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
                           0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
                           0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
                           0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
                           0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF};
    uint8_t RX_BUF[256] = {0};
    
    

    API_PSRAM_Init();                               // API PSRAM init GPIO setting
    
    API_PSRAM_Read(0x00000000, 256, &RX_BUF[0]);    // API PSRAM read 256 bytes
    
    API_PSRAM_Write (0x00000000, 256, &TX_BUF[0]);  // API PSRAM write 256 bytes
    
    API_PSRAM_Read(0x00000000, 256, &RX_BUF[0]);    // API PSRAM read 256 bytes
    
    while(1)
    {
        //To do......
    }
}




















