/* 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) 2024. 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: V3.1.0  AC7840x  Demo
 ******************************************************************************/

/*!
 * @file adc_sample.c
 *
 * @brief This file provides ADC functions.
 */

/* ===============================  Includes  =============================== */
#include "adc_sample.h"
#include "adc_hw.h"
#include "dma_drv.h"
#include "dma_hw.h"

/* ===============================   Define   =============================== */
#define ADC0_INDEX        (0U)                   /* ADC模块号 */
#define ADC0_CHANNEL_NUM  (2U)                   /* ADC通道个数 */
#define ADC0_DMA_CHANNEL  (0U)                   /* ADC使用的DMA通道号 */
#define ADC0_DMA_DATA_LEN (ADC0_CHANNEL_NUM * 2) /* DMA传输数据长度 */

#define ADC1_INDEX        (1U)                   /* ADC模块号 */
#define ADC1_CHANNEL_NUM  (2U)                   /* ADC通道个数 */
#define ADC1_DMA_CHANNEL  (1U)                   /* ADC使用的DMA通道号 */
#define ADC1_DMA_DATA_LEN (ADC0_CHANNEL_NUM * 2) /* DMA传输数据长度 */

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

/* ===============================  Variables =============================== */
#if defined(__ICCARM__)                                    /* IAR Compiler */
uint16_t g_adc0_array[ADC0_CHANNEL_NUM] @0x20000000 = {0}; /* DMA搬运的RAM地址需要在SRAM_U区域 */
uint16_t g_adc1_array[ADC1_CHANNEL_NUM] @0x20000100 = {0}; /* DMA搬运的RAM地址需要在SRAM_U区域 */
#elif defined(__CC_ARM)                                    /* Arm Compiler */
uint16_t g_adc0_array[ADC0_CHANNEL_NUM] __attribute__((section(".ARM.__at_0x20000000"))) = {0}; /* DMA搬运的RAM地址需要在SRAM_U区域 */
uint16_t g_adc1_array[ADC1_CHANNEL_NUM] __attribute__((section(".ARM.__at_0x20000100"))) = {0}; /* DMA搬运的RAM地址需要在SRAM_U区域 */
#endif

dma_state_t g_dma_state;
dma_chn_state_t g_dma_adc0_state;
dma_chn_state_t g_dma_adc1_state;

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

/* =========================  Functions definition  ========================= */

/*!
 * @brief 打印DMA传输的ADC数据
 *
 * @param[in]  none
 *
 * @return none
 */
void ADC_PrintTest(void)
{
    /*! 打印ADC0各通道转换结果*/
    printf("ADC0_value:   VR1 = 0x%-5x VR2 = 0x%-5x\r\n", g_adc0_array[0], g_adc0_array[1]);

    /*! 打印ADC1各通道转换结果*/
    printf("ADC1_value:   TSENSOR = 0x%-5x SUPPLY = 0x%-5x\r\n", g_adc1_array[0], g_adc1_array[1]);
}

/*!
 * @brief 配置ADC使用DMA传输
 *
 * @param[in]  none
 *
 * @return none
 */
void DmaInit(void)
{
    dma_channel_config_t dma_adc0_config;
    dma_channel_config_t dma_adc1_config;

    DMA_DRV_Init(&g_dma_state, NULL, NULL, 0); /*! DMA模块初始化,只调用一次 */

    dma_adc0_config.channelPriority = DMA_CHN_PRIORITY_LOW;   /*!< dma channel priority */
    dma_adc0_config.virtChnConfig   = ADC0_DMA_CHANNEL;       /*!< dma virtual channel number */
    dma_adc0_config.source          = DMA_REQ_ADC0;           /*!< dma channel request adc0 tx */
    dma_adc0_config.callback        = NULL;                   /*!< no callback function */
    dma_adc0_config.enableTrigger   = false;                  /*!< dma periodic trigger disable */
    DMA_DRV_ChannelInit(&g_dma_adc0_state, &dma_adc0_config); /*! ADC0 DMA通道配置 */

    dma_adc1_config.channelPriority = DMA_CHN_PRIORITY_LOW;   /*!< dma channel priority */
    dma_adc1_config.virtChnConfig   = ADC1_DMA_CHANNEL;       /*!< dma virtual channel number */
    dma_adc1_config.source          = DMA_REQ_ADC1;           /*!< dma channel request adc1 tx */
    dma_adc1_config.callback        = NULL;                   /*!< no callback function */
    dma_adc1_config.enableTrigger   = false;                  /*!< dma periodic trigger disable */
    DMA_DRV_ChannelInit(&g_dma_adc1_state, &dma_adc1_config); /*! ADC1 DMA通道配置 */
}

/*!
 * @brief 启动ADC0 DMA传输
 *
 * @param[in]  none
 *
 * @return none
 */
void ADC0_DmaStart(void)
{
    DMA_DRV_ConfigTransfer(ADC0_DMA_CHANNEL, DMA_TRANSFER_PERIPH2MEM, (uint32_t)(ADC0->RDR), (uint32_t)g_adc0_array, DMA_TRANSFER_SIZE_2B, ADC0_DMA_DATA_LEN); /*! DMA传输配置 */

    DMA_DRV_SetSrcAddr(ADC0_DMA_CHANNEL, (uint32_t)(&(ADC0->RDR[0])), (uint32_t)(&(ADC0->RDR[ADC0_CHANNEL_NUM]))); /*! 由于需要读取的源地址为ADC的RDR0~RDRx寄存器，每个寄存器占四个字节，程序需要
                                                                                                                       读取每个寄存器的低位两个字节，此处需要修改DMA源地址的结束地址 */
    DMA_DRV_SetSrcOffset(ADC0_DMA_CHANNEL, 4);                                                                     /*! DMA_TRANSFER_PERIPH2MEM类型的DMA只能传输一个固定的寄存器地址，此处修改偏移量
                                                                                                                       为4，读取完一个寄存器后地址加4，指向下一个寄存器，实现多个寄存器的连续读取*/
    DMA_DRV_SetCircularMode(ADC0_DMA_CHANNEL, true);                                                               /*! 打开DMA循环模式 */
    DMA_DRV_StartChannel(ADC0_DMA_CHANNEL);                                                                        /*! 使能DMA通道 */
    ADC_DRV_SoftwareStartRegularConvert(ADC0_INDEX);                                                               /*! ADC软件触发转换*/
}

/*!
 * @brief 启动ADC1 DMA传输
 *
 * @param[in]  none
 *
 * @return none
 */
void ADC1_DmaStart(void)
{
    DMA_DRV_ConfigTransfer(ADC1_DMA_CHANNEL, DMA_TRANSFER_PERIPH2MEM, (uint32_t)(ADC1->RDR), (uint32_t)g_adc1_array, DMA_TRANSFER_SIZE_2B, ADC1_DMA_DATA_LEN); /*! DMA传输配置 */

    DMA_DRV_SetSrcAddr(ADC1_DMA_CHANNEL, (uint32_t)(&(ADC1->RDR[0])), (uint32_t)(&(ADC1->RDR[ADC1_CHANNEL_NUM]))); /*! 由于需要读取的源地址为ADC的RDR0~RDRx寄存器，每个寄存器占四个字节，程序需要
                                                                                                                       读取每个寄存器的低位两个字节，此处需要修改DMA源地址的结束地址 */
    DMA_DRV_SetSrcOffset(ADC1_DMA_CHANNEL, 4);                                                                     /*! DMA_TRANSFER_PERIPH2MEM类型的DMA只能传输一个固定的寄存器地址，此处修改偏移量
                                                                                                                       为4，读取完一个寄存器后地址加4，指向下一个寄存器，实现多个寄存器的连续读取*/
    DMA_DRV_SetCircularMode(ADC1_DMA_CHANNEL, true);                                                               /*! 打开DMA循环模式 */
    DMA_DRV_StartChannel(ADC1_DMA_CHANNEL);                                                                        /*! 使能DMA通道 */
    ADC_DRV_SoftwareStartRegularConvert(ADC1_INDEX);                                                               /*! ADC软件触发转换*/
}

/*!
 * @brief 配置ADC通道
 *
 * @param[in] instance: ADC模块号
 * @param[in] seq: adc转换顺序
 * @param[in] channel: adc通道
 * @return none
 */
void ADC_ConfigChannel(const uint32_t instance, const adc_sequence_t seq, adc_inputchannel_t channel)
{
    adc_chan_config_t adcChConfig;

    /*!
    ADC采样转换时间计算：
        FCLK 时钟源为SPLLDIV2_CLK,频率为60MHz
        ADCCLK = FCLK/clockDivide = 60/6 = 10MHz
        总转换时间 = (SPT+ resolution（12/10/8）)×ADCCLK周期+5个FCLK = (5+12)/10+5/60 ≈ 1.78us

    注意：12bit分辨率最大转换率为1Msps，10bit分辨率最大转换率为1.2Msps，8bit分辨率最大转换率为1.4Msps
    */
    ADC_DRV_InitChanStruct(&adcChConfig);            /*! 结构体初始化为默认值*/
    adcChConfig.channel     = channel;               /*! 输入通道选择*/
    adcChConfig.spt         = ADC_SPT_CLK_5;         /*! 采样时间*/
    adcChConfig.interruptEn = false;                 /*! EOC中断使能*/
    ADC_DRV_ConfigChan(instance, seq, &adcChConfig); /*! 应用通道配置*/
}

/*!
 * @brief ADC模块初始化
 *
 * @param[in]  none
 *
 * @return none
 */
void ADC0_Init(void)
{
    adc_converter_config_t adcConfig;

    /*! ADC输入端口（电位器）配置*/
    GPIO_DRV_SetMuxModeSel(VR1_PORT, VR1_PIN, PORT_PIN_DISABLED); /*! 电位器VR1*/
    GPIO_DRV_SetMuxModeSel(VR2_PORT, VR2_PIN, PORT_PIN_DISABLED); /*! 电位器VR2*/

    /*! ADC配置
    配置ADC为12位分辨率，工作模式为MODE5 规则组扫描+注入组扫描模式多通道连续转换，规则组长度为4。
    软件触发后ADC开始连续转换，规则组中的4个通道按顺序进行连续转换。
    */
    ADC_DRV_Init(ADC0_INDEX);
    ADC_DRV_InitConverterStruct(&adcConfig);
    adcConfig.clockDivide                = ADC_CLK_DIVIDE_6;     /*! ADC时钟分频。ADC时钟源选择在时钟初始化里配置，此例程选择为SPLLDIV2_CLK,频率为60MHz*/
    adcConfig.resolution                 = ADC_RESOLUTION_12BIT; /*! ADC分辨率设置*/
    adcConfig.regularTrigger             = ADC_TRIGGER_INTERNAL; /*! 规则组触发源类型选择*/
    adcConfig.injectTrigger              = ADC_TRIGGER_INTERNAL; /*! 注入组触发源类型选择*/
    adcConfig.dmaEnable                  = true;                 /*! DMA使能位*/
    adcConfig.voltageRef                 = ADC_VOLTAGEREF_VREF;  /*! ADC参考电压源选择，VREF/VDDA*/
    adcConfig.scanModeEn                 = true;                 /*! 工作模式配置：扫描模式使能位，多通道时需要使能扫描模式，单个通道时不需要使能扫描*/
    adcConfig.continuousModeEn           = true;                 /*! 工作模式配置：连续模式使能位，1：触发后可连续转换，0：触发一次只转换一次，转换完成后停止*/
    adcConfig.regularDiscontinuousModeEn = false;                /*! 工作模式配置：规则组不连续模式使能位*/
    adcConfig.injectDiscontinuousModeEn  = false;                /*! 工作模式配置：注入组不连续模式使能位*/
    adcConfig.injectAutoModeEn           = false;                /*! 工作模式配置：自动注入模式使能位*/
    adcConfig.intervalModeEn             = false;                /*! 工作模式配置：间隔模式使能位*/
    adcConfig.regularDiscontinuousNum    = 0;                    /*! 规则组子组长度 (用于mode7)*/
    adcConfig.regularSequenceLength      = ADC0_CHANNEL_NUM;     /*! 规则组长度设置*/
    adcConfig.injectSequenceLength       = 0;                    /*! 注入组长度设置*/
    adcConfig.powerEn                    = true;                 /*! ADC上电*/
    ADC_DRV_ConfigConverter(ADC0_INDEX, &adcConfig);             /*! 初始化ADC配置*/

    /*! ADC通道配置*/
    ADC_ConfigChannel(ADC0_INDEX, ADC_RSEQ_0, VR1_ADC_CH); /*! 电位器VR1对应通道*/
    ADC_ConfigChannel(ADC0_INDEX, ADC_RSEQ_1, VR2_ADC_CH); /*! 电位器VR2对应通道*/
}

/*!
 * @brief ADC模块初始化
 *
 * @param[in]  none
 *
 * @return none
 */
void ADC1_Init(void)
{
    adc_converter_config_t adcConfig;

    /*! ADC输入端口配置（内部通道，无需配置）*/

    /*! ADC配置
    配置ADC为12位分辨率，工作模式为MODE5 规则组扫描+注入组扫描模式多通道连续转换，规则组长度为4。
    软件触发后ADC开始连续转换，规则组中的4个通道按顺序进行连续转换。
    */
    ADC_DRV_Init(ADC1_INDEX);
    ADC_DRV_InitConverterStruct(&adcConfig);
    adcConfig.clockDivide                = ADC_CLK_DIVIDE_6;     /*! ADC时钟分频。ADC时钟源选择在时钟初始化里配置，此例程选择为SPLLDIV2_CLK,频率为60MHz*/
    adcConfig.resolution                 = ADC_RESOLUTION_12BIT; /*! ADC分辨率设置*/
    adcConfig.regularTrigger             = ADC_TRIGGER_INTERNAL; /*! 规则组触发源类型选择*/
    adcConfig.injectTrigger              = ADC_TRIGGER_INTERNAL; /*! 注入组触发源类型选择*/
    adcConfig.dmaEnable                  = true;                 /*! DMA使能位*/
    adcConfig.voltageRef                 = ADC_VOLTAGEREF_VREF;  /*! ADC参考电压源选择，VREF/VDDA*/
    adcConfig.scanModeEn                 = true;                 /*! 工作模式配置：扫描模式使能位，多通道时需要使能扫描模式，单个通道时不需要使能扫描*/
    adcConfig.continuousModeEn           = true;                 /*! 工作模式配置：连续模式使能位，1：触发后可连续转换，0：触发一次只转换一次，转换完成后停止*/
    adcConfig.regularDiscontinuousModeEn = false;                /*! 工作模式配置：规则组不连续模式使能位*/
    adcConfig.injectDiscontinuousModeEn  = false;                /*! 工作模式配置：注入组不连续模式使能位*/
    adcConfig.injectAutoModeEn           = false;                /*! 工作模式配置：自动注入模式使能位*/
    adcConfig.intervalModeEn             = false;                /*! 工作模式配置：间隔模式使能位*/
    adcConfig.regularDiscontinuousNum    = 0;                    /*! 规则组子组长度 (用于mode7)*/
    adcConfig.regularSequenceLength      = ADC1_CHANNEL_NUM;     /*! 规则组长度设置*/
    adcConfig.injectSequenceLength       = 0;                    /*! 注入组长度设置*/
    adcConfig.powerEn                    = true;                 /*! ADC上电*/
    ADC_DRV_ConfigConverter(ADC1_INDEX, &adcConfig);             /*! 初始化ADC配置*/

    /*! ADC通道配置*/
    ADC_ConfigChannel(ADC1_INDEX, ADC_RSEQ_0, ADC_CH_TSENSOR); /*! 内部温度传感器通道*/
    ADC_ConfigChannel(ADC1_INDEX, ADC_RSEQ_1, ADC_CH_SUPPLY);  /*! 内部供电电压通道*/
}

/*!
 * @brief ADC DMA初始化
 *
 * @param[in]  none
 *
 * @return none
 */
void ADC_DmaInit(void)
{
    DmaInit(); /*! DMA初始化*/

    ADC0_Init(); /*! ADC0初始化*/
    ADC1_Init(); /*! ADC1初始化*/

    ADC0_DmaStart(); /*! 启动ADC0转换*/
    ADC1_DmaStart(); /*! 启动ADC1转换*/
}

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