/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */

/******************************************************************************
 * @version: V1.0.0  demo
 ******************************************************************************/

/*!
 * @file adc_sample.c
 *
 * @brief This file contains the user ADC function.
 *
 */

/* ===========================================  Includes  =========================================== */

#include "adc.h"
#include <string.h>

/* ============================================  Define  ============================================ */

#define VDDA_VOLTAGE    (3.3f)

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */

adc_value_t g_adcValue;
BOOL_Type g_adcDMAFinish = FALSE;

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */

/*!
 * @brief The real voltage is calculated from the ADC sampled values and printed
 *
 * @param[in] none
 *
 * @return none
 */
void ADC_Calculate(void)
{
    while (!g_adcDMAFinish);

    /* Average from multiple ADC samples */
    g_adcValue.aveAdcRegularValue[0] = (g_adcValue.adcRegularValue[0] + g_adcValue.adcRegularValue[3] + g_adcValue.adcRegularValue[6] + g_adcValue.adcRegularValue[9]) / 4;
    g_adcValue.aveAdcRegularValue[1] = (g_adcValue.adcRegularValue[1] + g_adcValue.adcRegularValue[4] + g_adcValue.adcRegularValue[7] + g_adcValue.adcRegularValue[10]) / 4;
    g_adcValue.aveAdcRegularValue[2] = (g_adcValue.adcRegularValue[2] + g_adcValue.adcRegularValue[5] + g_adcValue.adcRegularValue[8] + g_adcValue.adcRegularValue[11]) / 4;

    /* The real voltage is calculated from the ADC sample value */
    g_adcValue.realVoltage[0] = g_adcValue.aveAdcRegularValue[0] * VDDA_VOLTAGE / 4095.0f;
    g_adcValue.realVoltage[1] = g_adcValue.aveAdcRegularValue[1] * VDDA_VOLTAGE / 4095.0f;
    g_adcValue.realVoltage[2] = g_adcValue.aveAdcRegularValue[2] * VDDA_VOLTAGE / 4095.0f;

    printf("\r\nADC Regular value:  VR1 = %d, VR2 = %d, Bandgap = %d \r\n", g_adcValue.aveAdcRegularValue[0], g_adcValue.aveAdcRegularValue[1], g_adcValue.aveAdcRegularValue[2]);
    printf("Real voltage:  VR1 = %f, VR2 = %f, Bandgap = %f", g_adcValue.realVoltage[0], g_adcValue.realVoltage[1], g_adcValue.realVoltage[2]);

    g_adcDMAFinish = FALSE;
}

/*!
 * @brief DMA interrupts user callback function
 *
 * @param[in] device: DMA channel
 *
 * @param[in] wpara: DMA channel status flag
 *
 * @param[in] lpara: not used
 *
 * @return none
 */
void ADC_DMA_Callback(void *device, uint32_t wpara, uint32_t lpara)
{
    if (((DMA_ChannelType *)device == DMA0_CHANNEL0) && (wpara & DMA_CHANNEL_STATUS_FINISH_Msk))
    {
        /* DMA transfer length of 12 has been set, and the DMA completion interrupt will only be generated after the TIMER triggers ADC sampling 12/3=4 times. */
        if (!g_adcDMAFinish)
        {
            g_adcDMAFinish = TRUE;
        }
    }
}

/*!
 * @brief ADC initialization
 *
 * @param[in] none
 *
 * @return none
 */
void ADC_Sample_Init(void)
{
    ADC_ConfigType adcConfig;
    memset(&adcConfig, 0x00, sizeof(adcConfig));

    GPIO_SetFunc(GPIOA, GPIO_PIN4, GPIO_FUN2); /* PA4 is configured as function 2, which corresponds to ADC_IN6 and is connected to potentiometer VR1. */
    GPIO_SetFunc(GPIOA, GPIO_PIN5, GPIO_FUN2); /* PA5 is configured as function 2, which corresponds to ADC_IN5 and is connected to potentiometer VR2. */

    adcConfig.clkPsc                     = ADC_CLK_PRESCALER_2; /* ADC clock prescaler setting, with a maximum operating clock of 16M */
    adcConfig.scanModeEn                 = ENABLE;              /* Scan mode enable bit: For multiple channels, scan mode needs to be enabled. */
    adcConfig.continuousModeEn           = DISABLE;             /* Continuous mode enable bit: 0 for single conversion (only convert once after trigger), 1 for continuous conversion (convert continuously after trigger). */
    adcConfig.regularDiscontinuousModeEn = DISABLE;             /* regular group discontinuous conversion mode. */
    adcConfig.injectDiscontinuousModeEn  = DISABLE;             /* injecte group discontinuous conversion mode. */
    adcConfig.injectAutoModeEn           = DISABLE;             /* Automatic injection mode. */
    adcConfig.intervalModeEn             = DISABLE;             /* Injecte group interval conversion mode. */
    adcConfig.regularDiscontinuousNum    = 0;                   /* Regular group discontinuous mode number */
    adcConfig.EOCInterruptEn             = DISABLE;             /* Regular or injecte group conversion completed interruption enable bit. */
    adcConfig.IEOCInterruptEn            = DISABLE;             /* All injecte group conversion completed interruption enable bit. */
    adcConfig.interruptEn                = DISABLE;             /* Overall interrupt enable bit */
    adcConfig.regularDMAEn               = ENABLE;              /* regular group dma mode enable bit */
    adcConfig.regularTriggerMode         = ADC_TRIGGER_EXTERNAL;/* regular group trigger source type selection. */
    adcConfig.injectTriggerMode          = ADC_TRIGGER_INTERNAL;/* Injecte group trigger source type selection. */
    adcConfig.regularSequenceLength      = 3;                   /* regular group length. */
    adcConfig.injectSequenceLength       = 0;                   /* Injecte group length. */
    adcConfig.dataAlign                  = ADC_DATA_ALIGN_RIGHT;/* Right alignment of data. */
    adcConfig.voltageRef                 = ADC_VOLTAGEREF_VDDA; /* ADC reference source selection. */
    adcConfig.callBack                   = NULL;                /* ADC interrupt user callback function. */
    adcConfig.powerMode                  = ADC_POWER_ON;        /* ADC power on */

    ADC_Init(ADC0, &adcConfig);                                 /* ADC works Mode Config*/

    /* You can consider calling this interface when not powered by 5V, and VREF on the hardware must be connected to the power supply. */
    // ADC_DRV_AutoCalibration(ADC0);

    /* Configuration of the internal channels for Bandgap or T-sensor. */
    ADC_SetInternalChannel(ADC0, ADC_INTERNAL_BG);              /* Internal voltage signal selection (only configured when using ADC_CH_VIN). */
    ADC_SetInternalChannelState(ADC0, ENABLE);                  /* Enable internal channels for Bandgap and T-sensor (only configured when using ADC_CH_VIN). */

    /* The total conversion time is calculated using the formula:
       Total Conversion Time = (SPT + 12) / ADC clock cycles + 4 APB clock cycles.
       Here, SPT refers to the Sample & Hold Time, which is the time it takes for the ADC to sample the input voltage.
       The ADC clock frequency determines the speed at which the ADC performs the conversion.
       The 4 APB clock cycles represent the additional time required for processing and synchronization within the microcontroller's bus system.

       ADC Clock Frequency = APB Clock Frequency / Prescaler.
       The ADC maximum clock can be configured as 16MHz, which requires a minimum clock prescaler of 2

       The maximum sampling rate supported by the AC7803x ADC is 0.727Msps (corresponding to a conversion time of no less than 1.375μs).
       If you configure a sampling rate higher than this value, it may significantly reduce the accuracy of the sampling results. */

    /* Configuration of rule group channel conversion sequence and conversion rate */
    ADC_SetRegularGroupChannel(ADC0, ADC_CH_6, ADC_SPT_CLK_8, 0);   /* Sampling & Conversion Time = (8+12)/16000000 + 4/32000000 = 1.375μs */
    ADC_SetRegularGroupChannel(ADC0, ADC_CH_5, ADC_SPT_CLK_8, 1);   /* Sampling & Conversion Time = (8+12)/16000000 + 4/32000000 = 1.375μs */
    ADC_SetRegularGroupChannel(ADC0, ADC_CH_VIN, ADC_SPT_CLK_8, 2); /* Sampling & Conversion Time = (8+12)/16000000 + 4/32000000 = 1.375μs */

    ADC_SetReceiveDMA(ADC0, DMA0_CHANNEL0, &g_adcValue.adcRegularValue[0], 12, ADC_DMA_Callback);   /* Configuring DMA */
}

/* =============================================  EOF  ============================================== */
