

/**
 ******************************************************************************
 *
 * @file        MG32_DACOutput_API.c
 * @brief       Audio output by DAC control.
 *
 * @par         Project
 *              MG32
 * @version     V1.01
 * @date        2021/05/03
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 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.
 *******************************************************************************
 *******************************************************************************
 */


/* audio file is Untitled_222.c' */


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

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
typedef enum {
    HalfUpdateComplete,
    HalfUpdating,
} HalfUpdateEvent;

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static DMA_BaseInitTypeDef mDACDMA;
static uint32_t            LastCycleEvent = 0;         // The last DMA access cycle event.
static uint32_t            AudioBufIDX;                // AudioBufIDX : Audio Buffer source index.
static __ALIGNED(4) uint8_t  AudioBuf1[500];           // SRAM audio buffer.
static __ALIGNED(4) uint8_t  AudioBuf2[500];           // SRAM audio buffer.

/* Private function prototypes -----------------------------------------------*/
void DMA_IRQ(void);
void DAC_ConvCpltCallback(void);
void DAC_ConvHalfCpltCallback(void);
void API_DACOutput_Init(void);

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/
extern uint8_t      rawData[];


/**
 *******************************************************************************
 * @brief       Initial DAC Audio output (DAC + DMA + Timer). 
 * @return		None
 *******************************************************************************
 */
void API_DACOutput_Init(void)
{
    TM_TimeBaseInitTypeDef TM_TimeBase_InitStruct;
    
    
    // ------------------------------------------------------------------------
    // Config PB2 for DAC output. (AIO mode)
    // ------------------------------------------------------------------------
    // config in MG32_GPIO_Init.h
    
    // ------------------------------------------------------------------------
    // 1.Initial TM10 timer : counter range is 8K in 48MHz.
    // ------------------------------------------------------------------------
    TM_TimeBaseStruct_Init(&TM_TimeBase_InitStruct);
    {
        // modify parameter
        TM_TimeBase_InitStruct.TM_Period        = 6000 - 1; 
        TM_TimeBase_InitStruct.TM_Prescaler     = 0;
        TM_TimeBase_InitStruct.TM_CounterMode   = Cascade;
    }
    TM_TimeBase_Init(TM10, &TM_TimeBase_InitStruct);
    
    // ------------------------------------------------------------------------
    // 2.Initial TM10 TRGO configuration.
    // ------------------------------------------------------------------------
    TM_TRGO_Select(TM10, TRGO_UEV);
    TM_UEV_Config(TM10, UEV_TOF);
    TM_UEV_Cmd(TM10, ENABLE);
        
    // ------------------------------------------------------------------------
    // 3.Start TM10.
    // ------------------------------------------------------------------------
    TM_Timer_Cmd(TM10, ENABLE);

    // ------------------------------------------------------------------------
    // 4.Initial DAC. 
    // ------------------------------------------------------------------------
    DAC_DeInit(DAC);            
    DAC_TriggerSource_Select(DAC, DAC_TM10_TRGO);
    DAC_TriggerEdge_Select(DAC, DAC_AcceptRisingEdge);   // DAC_AcceptRisingEdge
    
    DAC_DataResolution_Select(DAC, DAC_10BitData);
    DAC_DataAlignment_Select(DAC, DAC_LeftJustified);
    DAC_SetDAT0(DAC, 0);
    DAC_CurrentMode_Select(DAC, DAC_M2);
    
    DAC_Cmd(DAC, ENABLE);       
    
    // ------------------------------------------------------------------------
    // 5.Update Audio buffer.
    // ------------------------------------------------------------------------
    AudioBufIDX = 0;
    DAC_ConvHalfCpltCallback();
    
    // ------------------------------------------------------------------------
    // 6.initial DMA. (M2P)
    // ------------------------------------------------------------------------
    DMA_DeInit(DMA);
    
    DMA_Cmd(ENABLE);
    // Disable DMA last cycle 
    DMA_LastCycle_Cmd(DMAChannel0, DISABLE);
    
    // DMA (M2P) configuration
    DMA_BaseInitStructure_Init(&mDACDMA);
    {
        mDACDMA.DMAChx                          = DMAChannel0;
        mDACDMA.DMALoopCmd                      = ENABLE;
        mDACDMA.SrcSINCSel                      = ENABLE;
        mDACDMA.BurstDataSize                   = DMA_BurstSize_2Byte;
        mDACDMA.DMATransferNUM                  = 500;
                        
        mDACDMA.SrcSymSel                       = DMA_MEM_Read;
        mDACDMA.DestSymSel                      = DMA_DAC0_OUT;
                        
        mDACDMA.DMASourceAddr                   = &AudioBuf1;
    }   
    DMA_Base_Init(&mDACDMA);

    DMA_Channel_Cmd(DMAChannel0, ENABLE);
    
    // ------------------------------------------------------------------------
    // 7.Enable DMA interrupt
    // ------------------------------------------------------------------------
    DMA_ClearFlag(DMA, 0xFFFFFFFF);
    DMA_IT_Config(DMAChannel0, DMA_Half_ITE | DMA_Complete_ITE, ENABLE);
    DMA_ITEA_Cmd(DMA, ENABLE);
    
    // Start DAC's DMA and DMA channel0 request
    DAC_DMA_Cmd(DAC, ENABLE);
    DMA_StartRequest(DMAChannel0);
    
}




/**
 *******************************************************************************
 * @brief       Update AudioBuf from Untitled_222.c
 * @param[in]   mDAC : pointer to a DAC_HandleTypeDef
 * @return		None
 *******************************************************************************
 */
void DAC_ConvHalfCpltCallback(void)
{
    uint32_t i;
    volatile uint32_t *PosIDX;                              // The index of SRAM audio
    uint32_t *DestAddr;
    static uint32_t state = HalfUpdateComplete;
    
    
    if(state == HalfUpdateComplete)
    {
        // Avoid repeated entry.
        state = HalfUpdating;
        
        // copy rawData data of 'Untitled_222.c' to SRAM audio buffer
        // MG32F02A132 must be copy (manual)
        PosIDX = (uint32_t *) &rawData;
        i = AudioBufIDX * 125;                                  // 125 * 4 = 500 byte
        PosIDX += i;
        
        // AudioBuf1 or AudioBuf2
        if ((AudioBufIDX & 0x0001) == 0)
            DestAddr = (uint32_t *) &AudioBuf1;
        else 
            DestAddr = (uint32_t *) &AudioBuf2;
            
        // copy from flash to SRAM. Size is 125*4 = 500 bytes.
        for(i=0;i<125;i++, PosIDX++)
        {
            DestAddr[i] = ((uint32_t ) *PosIDX)+0x80008000;     // Audio data is 2byte with 2's complement
                                                                // DAC needs 0~0x3FF, So Audio needs transfer.
        }
        
        // update DMA parameters
        DMA_SetSourceAddress(DMAChannel0, (uint32_t *) DestAddr);
        
        // Disable DMA_Half_ITE interrupt
        DMA_IT_Config(DMAChannel0, DMA_Half_ITE, DISABLE);
        
        // is the last cycle ?
        AudioBufIDX++;
        if(AudioBufIDX == 128)
        {
            AudioBufIDX = 0;
            LastCycleEvent = 1;
        }
        
        // reset state
        state = HalfUpdateComplete;
    }
    
        
}


/**
 *******************************************************************************
 * @brief       Conversion complete callback in non blocking mode for DAC. 
 * @param[in]   mDAC : pointer to a DAC_HandleTypeDef
 * @return		None
 *******************************************************************************
 */
void DAC_ConvCpltCallback(void)
{
    if(LastCycleEvent == 1)
    {
        DMA_ClearChannelFlag(DMAChannel0, DMA_Chx_TCF);
        DMA_LastCycle_Cmd(DMAChannel0, ENABLE);
        LastCycleEvent = 0;
    }
    
    // Disable Half flag and enable next Half interrupt
    DMA_ClearChannelFlag(DMAChannel0, DMA_Chx_THF);
    DMA_IT_Config(DMAChannel0, DMA_Half_ITE, ENABLE);
}


/**
 *******************************************************************************
 * @brief       Update AudioBuf from Untitled_222.c
 * @param[in]   mDAC : pointer to a DAC_HandleTypeDef
 * @return		None
 *******************************************************************************
 */
void DMA_IRQ(void)
{
    // Half flag with interrupt control bit
    if ((DMA_GetChannelFlag(DMAChannel0, DMA_Chx_THF) == DRV_Happened) && (DMAChannel0->A.MBIT.HIE == 1))
    {
        DAC_ConvHalfCpltCallback();
        DMA_ClearChannelFlag(DMAChannel0, DMA_Chx_THF);
    }
    
    // Complete flag
    if (DMA_GetChannelFlag(DMAChannel0, DMA_Chx_TCF) == DRV_Happened)
    {
        DAC_ConvCpltCallback();
        DMA_ClearChannelFlag(DMAChannel0, DMA_Chx_TCF);
    }
    
    // clear all flag
    DMA_ClearFlag(DMA, 0xFFFFFFFF);
    
    
}
