
/******************************************************************************
*@file  : app.c
*@brief : application
******************************************************************************/

#include "app.h" 
#include "fxx_dac.h"

volatile uint32_t gtimer_Update_Flag; 
uint16_t gindex = 0; 


//正弦波单个周期的点数
#define POINT_NUM 250

/* DAC单通道sine波数据 */
uint16_t Singel_Sin_data_12bit[POINT_NUM] = {
    2099,2151,2202,2254,2305,2356,2406,2457,2507,2557,2607,2656,2705,2754,2802,
    2850,2897,2943,2989,3035,3079,3124,3167,3210,3252,3293,3334,3373,3412,3450,
    3487,3523,3558,3593,3626,3658,3690,3720,3749,3777,3804,3830,3855,3879,3901,
    3922,3943,3962,3979,3996,4011,4025,4038,4049,4060,4069,4076,4083,4088, 4092,
    4095,4095,4095,4095,4092,4088,4083,4076,4069,4060,4049,4038,4025,4011,3996,
    3979,3962,3943,3922,3901,3879,3855,3830,3804,3777,3749,3720,3690,3658,3626,
    3593,3558,3523,3487,3450,3412,3373,3334,3293,3252,3210,3167,3124,3079,3035,
    2989,2943,2897,2850,2802,2754,2705,2656,2607,2557,2507,2457,2406,2356,2305,
    2254,2202,2151,2099,2048,1997,1945,1894,1842,1791,1740,1690,1639,1589,1539,
    1489,1440,1391,1342,1294,1246,1199,1153,1107,1061,1017,972,929,886,844,803,
    762,723,684,646,609,573,538,503,470,438,406,376,347,319,292,266,241,217,195,
    174,153,134,117,100,85,71,58,47,36,27,20,13,8,4,1,0,0,1,4,8,13,20,27,36,47,
    58,71,85,100,117,134,153,174,195,217,241,266,292,319,347,376,406,438,470,503,
    538,573,609,646,684,723,762,803,844,886,929,972,1017,1061,1107,1153,1199,1246,
    1294,1342,1391,1440,1489,1539,1589,1639,1690,1740,1791,1842,1894,1945,1997,2048
};

/* DAC双通道sine波数据buffer */
uint32_t Dual_Sin_data_12bit[POINT_NUM];

/*DMA双数据模式 sine波数据buffer*/
uint32_t DAMDualData_Sine12bit[POINT_NUM / 2];


void DAC_TIM6_Base_Init(uint16_t Prescaler,uint16_t Period)
{
    TIM_Base_InitTypeDef tmp;
    
    System_Module_Enable(EN_TIM6);

	tmp.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
	tmp.CounterMode = TIM_COUNTERMODE_UP; 
	tmp.RepetitionCounter = 0;  
	tmp.Prescaler = Prescaler - 1;

	tmp.Period = Period - 1; 
	TIM_TimeBase_Init(TIM6, &tmp);
    
    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
    
    NVIC_ClearPendingIRQ(TIM6_IRQn);
    NVIC_SetPriority(TIM6_IRQn, 5);
    NVIC_EnableIRQ(TIM6_IRQn);
    
     
    TIM_Cmd(TIM6, ENABLE); 
} 

void DAC_TIM6_TRGOx_Init(uint8_t Trgo,uint16_t Prescaler,uint16_t Period)
{
    uint32_t timer_clock;
    
    TIM_Base_InitTypeDef tmp;
    
    TIM_MasterConfigTypeDef sMasterConfig={0};	
    
    System_Module_Enable(EN_TIM6);
    

	tmp.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
	tmp.CounterMode = TIM_COUNTERMODE_UP; 
	tmp.RepetitionCounter = 0;  
	tmp.Prescaler = Prescaler - 1;

	tmp.Period = Period - 1; 
	TIM_TimeBase_Init(TIM6, &tmp);        
     
    TIM_SelectOutputTrigger(TIM6, TIM_TRGO_UPDATE);            	
	TIM_SelectMasterSlaveMode(TIM6, TIM_MASTERSLAVEMODE_DISABLE);   


    TIM_Cmd(TIM6, ENABLE); 
} 


/******************************************************************************
* @brief : DAC output Sin initialization.
* @param : None.
* @return: None
******************************************************************************/
void DAC_Config_OutPut_Sinx()
{
    DAC_InitTypeDef sConfig;

    sConfig.DAC_Trigger = DAC_TRIGGER_SOFTWARE;
    sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
    
    sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
    sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_BOTH;  
    sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;

    DAC_Init(DAC,DAC_CHANNEL_1, &sConfig);    
    DAC_Init(DAC,DAC_CHANNEL_2, &sConfig);  
}

/******************************************************************************
* @brief : DAC output noise initialization.
* @param : None.
* @return: None
******************************************************************************/
void DAC_Config_OutPut_Noise(void)
{
    DAC_InitTypeDef sConfig={0};
    
    sConfig.DAC_Trigger = DAC_TRIGGER_SOFTWARE;

    sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
    sConfig.DAC_OutputBuffer =  DAC_OUTPUTBUFFER_DISABLE;
    sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;
    sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
    
    /* DAC_Init()一次只配置一个DAC通道 */
    /* DAC通道1配置使用软件触发 */
    DAC_Init(DAC,DAC_CHANNEL_1, &sConfig);   

    /* DAC通道2配置使用TIM6触发 */
    sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
    DAC_Init(DAC,DAC_CHANNEL_2, &sConfig); 
}
/******************************************************************************
* @brief : DAC output noise.
* @param : None.
* @return: None
******************************************************************************/
void DAC_OutPut_Noise()
{
    /* 设置DAC 输出的 基本电压 */
    DAC_SetDualChannelData(DAC,DAC_ALIGN_12B_R, 1000, 1000);
    
    /* 在DAC 通道1上叠加噪声 */
    SPL_DACEx_NoiseWaveGenerate(DAC, DAC_CHANNEL_1, DAC_LFSRUNMASK_BITS9_0); 
    
    /* 在DAC 通道2上叠加三角波 */
    SPL_DACEx_TriangleWaveGenerate(DAC, DAC_CHANNEL_2, DAC_TRIANGLEAMPLITUDE_2047);
    
    DAC_Cmd(DAC, DAC_CHANNEL_1,ENABLE);

    /* 启动DAC转换 */
    /* DAC通道2启动后， 后面由TIM6触发 */
    DAC_Cmd(DAC, DAC_CHANNEL_2,ENABLE); 
    
    while(1)
    {
        /* DAC通道1 需要软件来每次触发 */
        DAC_SoftwareTriggerCmd(DAC, DAC_CHANNEL_1,ENABLE);
    }
}

/******************************************************************************
* @brief : DAC output voltage initialization.
* @param : None.
* @return: None
******************************************************************************/
void DAC_Config_OutPut_Voltage()
{

    DAC_InitTypeDef sConfig; 
    sConfig.DAC_Trigger = DAC_TRIGGER_SOFTWARE;
    sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
    sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
    sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;  
    sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;

    DAC_Init(DAC,DAC_CHANNEL_1, &sConfig); 
    DAC_Init(DAC,DAC_CHANNEL_2, &sConfig); 

    /* 自动校准，可根据需要开启/关闭 */
    SPL_DACEx_SelfCalibrate(DAC, &sConfig,DAC_CHANNEL_1);
    SPL_DACEx_SelfCalibrate(DAC, &sConfig,DAC_CHANNEL_2);
    System_Delay(500000);
}
/******************************************************************************
* @brief : DAC output voltage.
* @param : voltage ：output voltage value.
* @return: None
******************************************************************************/
void DAC_OutPutVoltage(float voltage)
{
    if( voltage > 3.3)
    {
        return;
    }
    uint16_t data=((voltage / 3.3) * 4095);
    DAC_SetDualChannelData(DAC,DAC_ALIGN_12B_R,data,data);
    DAC_Cmd(DAC, DAC_CHANNEL_1,ENABLE);
    DAC_Cmd(DAC, DAC_CHANNEL_2,ENABLE); 
    DAC_SoftwareTriggerCmd(DAC, DAC_CHANNEL_1,ENABLE);
    DAC_SoftwareTriggerCmd(DAC, DAC_CHANNEL_2,ENABLE);
    while(1)
    {

    }
}
void DAC_GPIO_Init(void)
{
    System_Module_Enable(EN_GPIOAB);
    
    /* Initialization GPIO
    PB1  ------> DAC_OUT1 
    PB0  ------> DAC_OUT2 
    */
    GPIO_InitTypeDef GPIO_handle;
    GPIO_handle.Mode = GPIO_MODE_ANALOG;
    GPIO_handle.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_handle.Pull = GPIO_NOPULL;
    GPIO_Init(GPIOB, &GPIO_handle);

}
/******************************************************************************
* @brief : DAC Output config.
* @param : None.
* @return: None
******************************************************************************/
void DAC_Config_OutPut()
{
    DAC_InitTypeDef sConfig={0}; 

    sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
    sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
    sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
    sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_EXTERNAL;
    sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
    DAC_Init(DAC,DAC_CHANNEL_1, &sConfig);    
    DAC_Init(DAC,DAC_CHANNEL_2, &sConfig);  
    DAC_Cmd(DAC, DAC_CHANNEL_1,ENABLE);
    DAC_Cmd(DAC, DAC_CHANNEL_2,ENABLE); 
}
/******************************************************************************
* @brief : DMA config.
* @param : None.
* @return: None
******************************************************************************/
static void DAC_DMA_Config()
{
    DMA_InitTypeDef DMA_InitStruct = {0};
    uint32_t Idx=0;
    /* write Sinx data from   Singel_Sin_data_12bit to Dual_Sin_data_12bit */
    for (Idx = 0; Idx < POINT_NUM; Idx++)
    {
        Dual_Sin_data_12bit[Idx] = (Singel_Sin_data_12bit[Idx] << 16) + (Singel_Sin_data_12bit[Idx]);
    }

    System_Module_Enable(EN_DMA);
    
   /* 配置以下两者之一的DMA即可搬运到两个DAC通道。 
    即让DAC_CH1 产生搬运请求，或者让DAC_CH2产生搬运请求，DMA一次搬运的数据(WORD)将拆分给两个通道同时使用
    */ 
#if 0
    /* DAC DMA Init */
    /* DAC_CH1 Init */
    DMA_InitStruct.DMA_Mode         = DMA_CIRCULAR;
    DMA_InitStruct.Data_Flow        = DMA_DATA_FLOW_M2P;
    DMA_InitStruct.Request_ID       = REQ39_DAC1_CH1;
    DMA_InitStruct.Source_Inc       = DMA_SOURCE_ADDR_INCREASE_ENABLE;
    DMA_InitStruct.Desination_Inc   = DMA_DST_ADDR_INCREASE_DISABLE;
    DMA_InitStruct.Source_Width     = DMA_SRC_WIDTH_WORD;
    DMA_InitStruct.Desination_Width = DMA_DST_WIDTH_WORD;
    DMA_InitStruct.SrcAddr          = (uint32_t)Dual_Sin_data_12bit;
    DMA_InitStruct.DstAddr          = (uint32_t)(&(DAC->DHR12RD));
    DMA_InitStruct.DMA_BufferSize   = POINT_NUM;
    DMA_Init(DMA_Channel0, &DMA_InitStruct);
    DMA_Cmd(DMA_Channel0, ENABLE);
#else    
    /* DAC_CH2 Init */
    DMA_InitStruct.DMA_Mode         = DMA_CIRCULAR;
    DMA_InitStruct.Data_Flow        = DMA_DATA_FLOW_M2P;
    DMA_InitStruct.Request_ID       = REQ40_DAC1_CH2;
    DMA_InitStruct.Source_Inc       = DMA_SOURCE_ADDR_INCREASE_ENABLE;
    DMA_InitStruct.Desination_Inc   = DMA_DST_ADDR_INCREASE_DISABLE;
    DMA_InitStruct.Source_Width     = DMA_SRC_WIDTH_WORD;
    DMA_InitStruct.Desination_Width = DMA_DST_WIDTH_WORD;
    DMA_InitStruct.SrcAddr          = (uint32_t)Dual_Sin_data_12bit;
    DMA_InitStruct.DstAddr          = (uint32_t)(&(DAC->DHR12RD));
    DMA_InitStruct.DMA_BufferSize   = POINT_NUM;
    DMA_Init(DMA_Channel1, &DMA_InitStruct);
    DMA_Cmd(DMA_Channel1, ENABLE);    
#endif
    
    DAC_DMACmd(DAC, DAC_CHANNEL_1, ENABLE);
    DAC_DMACmd(DAC, DAC_CHANNEL_2, ENABLE);
}

void APP_DAC_Demo(DAC_TEST_MODE_t fe_Mode)
{
    DAC_GPIO_Init();

    System_Module_Enable(EN_DAC);
    
    switch (fe_Mode)
    {
        /* 输出噪音 */
        case DAC_Output_Noise: 
        {
            printfS("DAC Output Noise wave\r\n\r\n");
            DAC_Config_OutPut_Noise();
            DAC_TIM6_TRGOx_Init(1, 300, 2);
            DAC_OutPut_Noise();
        }
        break;

        /* 输出电压 */
        case DAC_OutPut_Voltage: 
        {
            printfS("DAC Output Voltage\r\n\r\n");
            DAC_Config_OutPut_Voltage();
            DAC_OutPutVoltage(2.5);
        }
        break;
  
        /* TIM6 update中断，软件设置DAC值来输出正弦波 */
        case DAC_OutPut_Sinx:
        {
            printfS("DAC Output SINE Wave by software dynamically setting DAC output Value\r\n\r\n");
            DAC_Config_OutPut_Sinx(); 
            DAC_TIM6_Base_Init(300, 50);
            gtimer_Update_Flag = 0;
            while(1) 
            {
                //System_Delay(1000);
                if(gtimer_Update_Flag) 
                {
                    gtimer_Update_Flag = 0;
                    DAC_SetDualChannelData(DAC,DAC_ALIGN_12B_R,Singel_Sin_data_12bit[gindex],Singel_Sin_data_12bit[gindex]);
                    DAC_Cmd(DAC, DAC_CHANNEL_1,ENABLE);
                    DAC_Cmd(DAC, DAC_CHANNEL_2,ENABLE); 
                    DAC_SoftwareTriggerCmd(DAC, DAC_CHANNEL_1,ENABLE);
                    DAC_SoftwareTriggerCmd(DAC, DAC_CHANNEL_2,ENABLE);
                    gindex++;
                    //若Sin表已到达结尾，重新指向表头
                    if( gindex >=  POINT_NUM)			
                    {
                        gindex=0;								
                    }                      
                }
            }
        }
        break;   
       
        /* DAC双通道 DMA方式输出正弦波 */
        /* 一次DMA搬运(WORD)，DAC两个通道同时使用 */
        case DAC_DMA_Output_Sinx:
        {
            printfS("DAC Output SINE Wave by DMA transferring data to both channels(DAC_DHR8RD)\r\n\r\n");
            /* DAC 通道1选择 TIM6 作为触发输入*/
            DAC_Config_OutPut(); 
            DAC_TIM6_TRGOx_Init(1, 300, 100);
            DAC_DMA_Config();
            while(1)
            {

            }        
        }
        break;

        default: break; 
    }

}

