/**
  ******************************************************************************
 *
 * @file        Sample_SPI_Master_StandardSPI_DMA_M2P.c
 *
 * @brief       Standard-SPI master mode DMA SRAM-to-SPI sample code.
 *
 * @par         Project
 *              MG32
 * @version     V2.14
 * @date        2022/11/25
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2021 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_GPIO_DRV.h"
#include "MG32_SPI_DRV.h"
#include "MG32_DMA_DRV.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define MYBINARYIMAGE0_LENGTH   11
#define SPI_NSS                 PB0

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static const uint8_t Mst_StandardSPI_Src[11] = 
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B};

/* Private function prototypes -----------------------------------------------*/
void Sample_SPI_Master_StandardSPI_DMA_M2P (SPI_Struct* SPIx);

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



/**
 *******************************************************************************
 * @brief       Sample SPI Master Standard SPI use DMA Memory to SPI 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. Configure memory to SPI
 *      \n      8. Trigger DMA
 *      \n      9. Disable SPI
 * @param[in]   SPIx
 * 	@arg\b			SPI0
 * @return      None
 * @note
 * @par         Example
 * @code
    Sample_SPI_Master_StandardSPI_DMA_M2P(SPI0);
 * @endcode
 *******************************************************************************
 **/
void Sample_SPI_Master_StandardSPI_DMA_M2P (SPI_Struct* SPIx)
{
    uint8_t             CNT;
    DMA_BaseInitTypeDef DMATestPattern;
    PIN_InitTypeDef     PINX_InitStruct;
    uint8_t       *Index;
 
    

    //===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 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_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(SPIx);
    
#if defined(MG32_3RD)
    Index = (uint8_t *) 0x20003800;                                         // Settingn index 
#endif
#if defined(MG32_2ND) || defined(MG32_4TH)
    Index = (uint8_t *) 0x20000F00;                                         // Settingn index 
#endif
    for(CNT=0; CNT<12; CNT++)                                               // Move for flash to SRAM 11 bytes
    {
        *Index = Mst_StandardSPI_Src[CNT];
        Index++;
    }
    
    /*=== 3. Configure clock divider ===*/
    SPI_PreDivider_Select(SPIx, SPI_PDIV_1);
    SPI_Prescaler_Select(SPIx, SPI_PSC_3);
    SPI_Divider_Select(SPIx, SPI_DIV_4);
    SPI_Clock_Select(SPIx, SPI_CK_SPIx_PR);
    
    /*=== 4. Configure SPI data line, mode and data size... ===*/
    SPI_DataLine_Select(SPIx, SPI_Standard);
    SPI_ModeAndNss_Select(SPIx, SPI_Master);         
    SPI_FirstBit_Select(SPIx, SPI_LSB);
    // SPI transfer data size 8-bits
    SPI_DataSize_Select(SPIx, SPI_8bits);
    // Data bidirectional Output
    SPI_BidirectionalOutput_Cmd(SPIx, ENABLE);
    
    /*=== 5. Config SPI0 IO ===*/
    SPI_NSS = 1;
    PINX_InitStruct.PINX_Mode				= PINX_Mode_PushPull_O;         // Pin select pusu pull mode
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable;     // Enable 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;                            // AFS = 2
    GPIO_PinMode_Config(PINB(2),&PINX_InitStruct);                          // CLK
    GPIO_PinMode_Config(PINB(3),&PINX_InitStruct);                          // MOSI
    
    PINX_InitStruct.PINX_Alternate_Function = 0;                            // AFS = 0
    GPIO_PinMode_Config(PINB(0),&PINX_InitStruct);                          // NSS
    
    PINX_InitStruct.PINX_Mode				= PINX_Mode_Digital_I;          // Setting digital  mode
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Enable;      // Disable pull up resistor
    PINX_InitStruct.PINX_Alternate_Function = 2;                            // AFS = 2
    GPIO_PinMode_Config(PINB(1),&PINX_InitStruct);                          // MISO
    
    /*=== 6. Enable SPI ===*/
    SPI_Cmd(SPIx, ENABLE);
    
    /*=== 7. Configure memory to SPI ===*/
    // Enable DMA
    DMA_Cmd(ENABLE);
    // Enable Channel-0
    DMA_Channel_Cmd(DMAChannel0, ENABLE);
    // initial parameter of structure
    DMA_BaseInitStructure_Init(&DMATestPattern);

    // modify parameter
    {   
        // external trigger pin and mode config
        DMATestPattern.ExtTrgPin = DMA_ExtTRG0;
        DMATestPattern.ExtTrgMode = DMA_DisableExtTrg;
        // DMA channel select
        DMATestPattern.DMAChx = DMAChannel0;
        // channel x loop mode config
        DMATestPattern.DMALoopCmd = DISABLE;
        // channel x source/destination auto increase address
        DMATestPattern.SrcSINCSel = ENABLE;        
        DMATestPattern.DestDINCSel = DISABLE;
        // DMA Burst size config
        DMATestPattern.BurstDataSize = DMA_BurstSize_1Byte;
        // DMA transfer data count initial number (? Bytes ???)
        DMATestPattern.DMATransferNUM = MYBINARYIMAGE0_LENGTH;
        // DMA source peripheral config
        DMATestPattern.SrcSymSel = DMA_MEM_Read;
        // DMA destination peripheral config
        DMATestPattern.DestSymSel = DMA_SPI0_TX;
#if defined(MG32_3RD)
        // source config
        DMATestPattern.DMASourceAddr = (uint8_t *)0x20003800;               // Settingn index 
#endif
#if defined(MG32_2ND) || defined(MG32_4TH)
        // source config
        DMATestPattern.DMASourceAddr = (uint8_t *)0x20000F00;               // Settingn index 
#endif
    }
    // M2P(CH0) simple parameter
    DMA_Base_Init(&DMATestPattern);
    
    /*=== 8. Trigger DMA ===*/
    for(CNT=3; CNT>0; CNT--)
    {   // 
        SPI_NSS = 0;
        // start DMA request
        DMA_StartRequest(DMAChannel0);
        // Enable SPI TX DMA
        SPI_TXDMA_Cmd(SPIx, ENABLE); 
        // Waiting DMA transmit to SPI complete
        while(DMA_GetSingleFlagStatus(DMA, DMA_FLAG_CH0_TCF)== DRV_UnHappened);
        // Clear CH0_TCF and CH0_THF
        DMA_ClearFlag(DMA, DMA_FLAG_CH0_TCF | DMA_FLAG_CH0_THF);
        // Waiting SPI transmit complete
        while(SPI_GetSingleFlagStatus(SPIx, SPI_TCF) == DRV_Normal);
        // 
        SPI_NSS = 1;
        // Clear SPI all flag
        SPI_ClearFlag(SPIx, SPI_ALLF);
    }

    /*=== 9. Disable SPI ===*/
    SPI_Cmd(SPIx, DISABLE);
}



