/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2024 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "fsl_common.h"
#include "fsl_debug_console.h"
#include "fsl_port.h"
#include "fsl_lpadc.h"
#include "fsl_edma.h"

#include "fsl_inputmux.h"
#include "fsl_spc.h"

#include "fsl_ctimer.h"
#include "afci_notification.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/
/* ADC Defines */
#define DEMO_LPADC_BASE                  ADC0
#define DEMO_LPADC_IRQn                  ADC0_IRQn
#define DEMO_LPADC_IRQ_HANDLER_FUNC      ADC0_IRQHandler
#define DEMO_LPADC_USER_CHANNEL          0U//2U
#define DEMO_LPADC_USER_CMDID            1U
#define DEMO_LPADC_DO_OFFSET_CALIBRATION true
#define DEMO_LPADC_OFFSET_VALUE_A        0x10U
#define DEMO_LPADC_OFFSET_VALUE_B        0x10U
#define DEMO_SPC_BASE                    SPC0
/* Use VREF_OUT driven from the VREF block as the reference volatage */
#define DEMO_LPADC_VREF_SOURCE kLPADC_ReferenceVoltageAlt3
#define DEMO_VREF_BASE         VREF0

/* EDMA Defines */
#define DEMO_DMA_BASEADDR    DMA0
#define DEMO_DMA_CHANNEL_0   0U
#define DEMO_DMA_IRQ         EDMA_0_CH0_IRQn
#define DEMO_DMA_IRQ_HANDLER EDMA_0_CH0_IRQHandler
#define DEMO_DMA_REQUEST     kDma0RequestMuxAdc0FifoARequest

/* Low power timer for ADC Trigger */
#define LPTMR_TRIG_BASE         LPTMR0
#define LPTMR_TRIG_USEC_COUNT   1000U
#define LPTMR_TRIG_IRQn         LPTMR0_IRQn
#define LPTMR_TRIG_HANDLER      LPTMR0_IRQHandler
#define ADC_LPTMR_TRIG_CLOCK    kLPTMR_PrescalerClock_0
#define LPTMR_TRIG_SOURCE_CLOCK (12000000U)

#define DEMO_LPADC_USE_HIGH_RESOLUTION 1


#if (defined(DEMO_LPADC_USE_HIGH_RESOLUTION) && DEMO_LPADC_USE_HIGH_RESOLUTION)
#define LPADC_FULLRANGE   65536U
#define LPADC_RESULTSHIFT 0U
#else
#define LPADC_FULLRANGE   4096U
#define LPADC_RESULTSHIFT 3U
#endif /* DEMO_LPADC_USE_HIGH_RESOLUTION */

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void BOARD_InitDebugConsole(void);

static void ADC0_Configuration(void);
static void ADC1_Configuration(void);
static void LowPowerTimerADCTrigger_Init(void);
static void CTIMER3_ADCTrigger_Init(void);
static void CTIMER0_ADCTrigger_Init(void);
static void EDMA0_Configuration(void);
static void EDMA1_Configuration(void);
/*******************************************************************************
 * Variables
 ******************************************************************************/

volatile uint32_t DMACounter                                              = 0U;
//AT_NONCACHEABLE_SECTION_ALIGN_INIT(uint32_t _destAddr_ping[BUFFER_LENGTH + 1], 32U) = {0x00U};
//uint32_t * destAddr_ping;

AT_NONCACHEABLE_SECTION_ALIGN_INIT(uint16_t _destAddr_ping[BUFFER_LENGTH + 2], 32U) = {0x00U};
uint16_t * destAddr_ping;

//AT_NONCACHEABLE_SECTION_ALIGN_INIT(uint32_t _destAddr_pong[BUFFER_LENGTH + 1], 32U) = {0x00U};
//uint32_t *destAddr_pong;

AT_NONCACHEABLE_SECTION_ALIGN_INIT(uint16_t _destAddr_pong[BUFFER_LENGTH + 2], 32U) = {0x00U};
uint16_t *destAddr_pong;

AT_NONCACHEABLE_SECTION_ALIGN_INIT(uint16_t _destAddr_ping1[BUFFER_LENGTH + 2], 32U) = {0x00U};
uint16_t * destAddr_ping1;

AT_NONCACHEABLE_SECTION_ALIGN_INIT(uint16_t _destAddr_pong1[BUFFER_LENGTH + 2], 32U) = {0x00U};
uint16_t *destAddr_pong1;

edma_handle_t g_DMA0_Handle;
edma_handle_t g_DMA1_Handle;
AT_NONCACHEABLE_SECTION_ALIGN(edma_tcd_t g_DMA0_Tcd[2], sizeof(edma_tcd_t));
AT_NONCACHEABLE_SECTION_ALIGN(edma_tcd_t g_DMA1_Tcd[2], sizeof(edma_tcd_t));
//sample rate 320K/250K
static uint32_t sampleFreq = SAMPLE_RATE*1000;

/*******************************************************************************
 * Code
 ******************************************************************************/
extern void DMA0_Callback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
extern void DMA1_Callback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
/*!
 * @brief afci_sig_init function
 */

void afci_sig_init(void)
{
    uint32_t i                       = 0U;
    volatile uint32_t currentCounter = 0U;

    /* Enable INPUTMUX0 */
    CLOCK_EnableClock(kCLOCK_InputMux0);

    /* enable VREF */
    SPC_EnableActiveModeAnalogModules(DEMO_SPC_BASE, kSPC_controlVref);
    /* Connect ADC FIFO flag to DMA0 Channel 0 trigger */
    INPUTMUX_EnableSignal(INPUTMUX0, kINPUTMUX_Adc0FifoARequestToDma0Ch21Ena, true);

    /* Connect LPTMR trigger output to ADC0 trigger input */
//    INPUTMUX_AttachSignal(INPUTMUX0, 0U, kINPUTMUX_Lptmr0ToAdc0Trigger);
    INPUTMUX_AttachSignal(INPUTMUX0, 0U, kINPUTMUX_Ctimer3M3ToAdc0Trigger);

    INPUTMUX_EnableSignal(INPUTMUX0, kINPUTMUX_Adc1FifoARequestToDma1Ch23Ena, true);

    /* Connect LPTMR trigger output to ADC1 trigger input */
    INPUTMUX_AttachSignal(INPUTMUX0, 0U, kINPUTMUX_Ctimer0M3ToAdc1Trigger);

    PRINTF("\r\nLPADC EDMA Example");

    /* CTimer Initialization */
    CTIMER0_ADCTrigger_Init();
    CTIMER3_ADCTrigger_Init();

    /* ADC Initialization */
    PRINTF("\r\nConfiguring LPADC...");
    ADC0_Configuration();
    /* EDMA Initialization */
    PRINTF("\r\nConfiguring LPADC EDMA...");
    EDMA0_Configuration();
#if	(CHANNEL_MODLE == CHANNEL_VERSION_8)
    ADC1_Configuration();
    /* EDMA Initialization */
    EDMA1_Configuration();
#endif
    /* Start CTimer which will trigger ADC conversions */
    CTIMER_StartTimer(CTIMER3);
    SDK_DelayAtLeastUs(DEMO_CHANNEL_BUFF_LENGTH*500/SAMPLE_RATE, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    CTIMER_StartTimer(CTIMER0);
}

/*!
 * @brief EDMA configuration
 */
static void EDMA0_Configuration(void)
{
//    edma_transfer_config_t transferConfig;
    edma_transfer_config_t transferConfig[2];
    edma_channel_config_t lpadcDmaChnlConfig;
    edma_config_t userConfig;

//    _destAddr_ping[0] = 0x02805A5A;
//    _destAddr_pong[0] = 0x02805A5A;
//    destAddr_ping = &_destAddr_ping[1];
//    destAddr_pong = &_destAddr_pong[1];

    _destAddr_ping[0] = 0x5A5A;
    _destAddr_ping[1] = DEMO_CHANNEL_BUFF_LENGTH * 4;
    _destAddr_pong[0] = 0x5A5A;
    _destAddr_pong[1] = DEMO_CHANNEL_BUFF_LENGTH * 4;
    destAddr_ping = &_destAddr_ping[2];
    destAddr_pong = &_destAddr_pong[2];

    PRINTF("destAddr_ping = 0x%d, destAddr_ping[1] = 0x%d\r\n",sizeof(destAddr_ping),sizeof(destAddr_ping[0]));

    lpadcDmaChnlConfig.channelDataSignExtensionBitPosition             = 0U;
    lpadcDmaChnlConfig.channelPreemptionConfig.enableChannelPreemption = false;
    lpadcDmaChnlConfig.channelPreemptionConfig.enablePreemptAbility    = true;
    lpadcDmaChnlConfig.channelRequestSource                            = DEMO_DMA_REQUEST;
    lpadcDmaChnlConfig.protectionLevel                                 = kEDMA_ChannelProtectionLevelUser;
#if !(defined(FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) && FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC)
    lpadcDmaChnlConfig.securityLevel = kEDMA_ChannelSecurityLevelNonSecure;
#endif /* !(defined(FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) && FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) */

    /* Configure EDMA channel for one shot transfer */
    EDMA_GetDefaultConfig(&userConfig);
    EDMA_Init(DEMO_DMA_BASEADDR, &userConfig);

    EDMA_CreateHandle(&g_DMA0_Handle, DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL_0);
    EDMA_SetCallback(&g_DMA0_Handle, DMA0_Callback, NULL);
    EDMA_InstallTCDMemory(&g_DMA0_Handle, g_DMA0_Tcd, 2);

#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U))
    void *srcAddr = (uint32_t *)&(DEMO_LPADC_BASE->RESFIFO[0U]);
#else
    void *srcAddr = (uint32_t *)&(DEMO_LPADC_BASE->RESFIFO);
#endif /* (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U)) */
    EDMA_PrepareTransfer(&transferConfig[0], srcAddr, sizeof(uint16_t), destAddr_ping, sizeof(destAddr_ping[0]), sizeof(destAddr_ping[0])*4,
    		DEMO_CHANNEL_BUFF_LENGTH * 4 * 2, kEDMA_PeripheralToMemory);

    transferConfig[0].destOffset = DEMO_CHANNEL_BUFF_LENGTH*2;
    transferConfig[0].minorLoopOffset = (int32_t)(-1)*((DEMO_CHANNEL_BUFF_LENGTH * 4-1)*2);
    transferConfig[0].enableDstMinorLoopOffset = true;

    /* Used to change the destination address to the original value */
    transferConfig[0].dstMajorLoopOffset = (int32_t)((-1) * sizeof(destAddr_ping));

    EDMA_PrepareTransfer(&transferConfig[1], srcAddr, sizeof(uint16_t), destAddr_pong, sizeof(destAddr_pong[0]), sizeof(destAddr_pong[0])*4,
    		DEMO_CHANNEL_BUFF_LENGTH * 4 * 2, kEDMA_PeripheralToMemory);

    transferConfig[1].destOffset = DEMO_CHANNEL_BUFF_LENGTH*2;
    transferConfig[1].minorLoopOffset = (int32_t)(-1)*((DEMO_CHANNEL_BUFF_LENGTH * 4-1)*2);
    transferConfig[1].enableDstMinorLoopOffset = true;

    /* Used to change the destination address to the original value */
    transferConfig[1].dstMajorLoopOffset = (int32_t)((-1) * sizeof(destAddr_pong));

    EDMA_SubmitLoopTransfer(&g_DMA0_Handle, transferConfig, 2);

//    EDMA_SetTransferConfig(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, &transferConfig, NULL);
    EDMA_InitChannel(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, &lpadcDmaChnlConfig);

    EDMA_EnableAutoStopRequest(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, false);

    EnableIRQ(DEMO_DMA_IRQ);
    EDMA_EnableChannelRequest(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL_0);

//    EDMA_StartTransfer(&g_DMA_Handle);
}

/*!
 * @brief EDMA configuration
 */
static void EDMA1_Configuration(void)
{
//    edma_transfer_config_t transferConfig;
    edma_transfer_config_t transferConfig[2];
    edma_channel_config_t lpadcDmaChnlConfig;
    edma_config_t userConfig;

//    _destAddr_ping[0] = 0x02805A5A;
//    _destAddr_pong[0] = 0x02805A5A;
//    destAddr_ping = &_destAddr_ping[1];
//    destAddr_pong = &_destAddr_pong[1];

    _destAddr_ping1[0] = 0x5A5A;
    _destAddr_ping1[1] = DEMO_CHANNEL_BUFF_LENGTH * 4;
    _destAddr_pong1[0] = 0x5A5A;
    _destAddr_pong1[1] = DEMO_CHANNEL_BUFF_LENGTH * 4;
    destAddr_ping1 = &_destAddr_ping1[2];
    destAddr_pong1 = &_destAddr_pong1[2];

    PRINTF("destAddr_ping = 0x%d, destAddr_ping[1] = 0x%d\r\n",sizeof(destAddr_ping),sizeof(destAddr_ping[0]));

    lpadcDmaChnlConfig.channelDataSignExtensionBitPosition             = 0U;
    lpadcDmaChnlConfig.channelPreemptionConfig.enableChannelPreemption = false;
    lpadcDmaChnlConfig.channelPreemptionConfig.enablePreemptAbility    = true;
    lpadcDmaChnlConfig.channelRequestSource                            = kDma1RequestMuxAdc1FifoARequest;
    lpadcDmaChnlConfig.protectionLevel                                 = kEDMA_ChannelProtectionLevelUser;
#if !(defined(FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) && FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC)
    lpadcDmaChnlConfig.securityLevel = kEDMA_ChannelSecurityLevelNonSecure;
#endif /* !(defined(FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) && FSL_FEATURE_EDMA_HAS_NO_CH_SBR_SEC) */

    /* Configure EDMA channel for one shot transfer */
    EDMA_GetDefaultConfig(&userConfig);
    EDMA_Init(DMA1, &userConfig);

    EDMA_CreateHandle(&g_DMA1_Handle, DMA1, DEMO_DMA_CHANNEL_0);
    EDMA_SetCallback(&g_DMA1_Handle, DMA1_Callback, NULL);
    EDMA_InstallTCDMemory(&g_DMA1_Handle, g_DMA1_Tcd, 2);

#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U))
    void *srcAddr = (uint32_t *)&(ADC1->RESFIFO[0U]);
#else
    void *srcAddr = (uint32_t *)&(ADC1->RESFIFO);
#endif /* (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U)) */
    EDMA_PrepareTransfer(&transferConfig[0], srcAddr, sizeof(uint16_t), destAddr_ping1, sizeof(destAddr_ping1[0]), sizeof(destAddr_ping1[0])*4,
    		DEMO_CHANNEL_BUFF_LENGTH * 4 * 2, kEDMA_PeripheralToMemory);

    transferConfig[0].destOffset = DEMO_CHANNEL_BUFF_LENGTH*2;
    transferConfig[0].minorLoopOffset = (int32_t)(-1)*((DEMO_CHANNEL_BUFF_LENGTH * 4-1)*2);
    transferConfig[0].enableDstMinorLoopOffset = true;
    /* Used to change the destination address to the original value */
    transferConfig[0].dstMajorLoopOffset = (int32_t)((-1) * sizeof(destAddr_ping1));

    EDMA_PrepareTransfer(&transferConfig[1], srcAddr, sizeof(uint16_t), destAddr_pong1, sizeof(destAddr_pong1[0]), sizeof(destAddr_pong1[0])*4,
    		DEMO_CHANNEL_BUFF_LENGTH * 4 * 2, kEDMA_PeripheralToMemory);

    transferConfig[1].destOffset = DEMO_CHANNEL_BUFF_LENGTH*2;
    transferConfig[1].minorLoopOffset = (int32_t)(-1)*((DEMO_CHANNEL_BUFF_LENGTH * 4-1)*2);
    transferConfig[1].enableDstMinorLoopOffset = true;
    /* Used to change the destination address to the original value */
    transferConfig[1].dstMajorLoopOffset = (int32_t)((-1) * sizeof(destAddr_pong1));

    EDMA_SubmitLoopTransfer(&g_DMA1_Handle, transferConfig, 2);

//    EDMA_SetTransferConfig(DEMO_DMA_BASEADDR, DEMO_DMA_CHANNEL_0, &transferConfig, NULL);
    EDMA_InitChannel(DMA1, DEMO_DMA_CHANNEL_0, &lpadcDmaChnlConfig);

    EDMA_EnableAutoStopRequest(DMA1, DEMO_DMA_CHANNEL_0, false);

    EnableIRQ(EDMA_1_CH0_IRQn);
    EDMA_EnableChannelRequest(DMA1, DEMO_DMA_CHANNEL_0);

//    EDMA_StartTransfer(&g_DMA_Handle);
}

/*!
 * @brief ADC configuration
 */
static void ADC0_Configuration(void)
{
    lpadc_config_t lpadcConfigStruct;
    lpadc_conv_trigger_config_t lpadcTriggerConfigStruct;
    lpadc_conv_command_config_t lpadcCommandConfigStruct;

    /* Sets the converter configuration structure with an available settings.
     * code
     *   config->enableInDozeMode        = true;
     *   config->conversionAverageMode   = kLPADC_ConversionAverage1;
     *   config->enableAnalogPreliminary = true;
     *   config->powerUpDelay            = 0x10;
     *   config->referenceVoltageSource  = kLPADC_ReferenceVoltageAlt3;
     *   config->powerLevelMode          = kLPADC_PowerLevelAlt1;
     *   config->triggerPriorityPolicy   = kLPADC_TriggerPriorityPreemptImmediately;
     *   config->enableConvPause         = false;
     *   config->convPauseDelay          = 0U;
     *   config->FIFO0Watermark          = 0U;
     *   config->FIFO1Watermark          = 0U;
     *   config->FIFOWatermark           = 0U;
     * endcode
     */
    LPADC_GetDefaultConfig(&lpadcConfigStruct);
    lpadcConfigStruct.enableAnalogPreliminary = true;
    lpadcConfigStruct.powerUpDelay            = 0x01U;//0x10U;
    lpadcConfigStruct.powerLevelMode          = kLPADC_PowerLevelAlt4;
#if defined(DEMO_LPADC_VREF_SOURCE)
    lpadcConfigStruct.referenceVoltageSource = DEMO_LPADC_VREF_SOURCE;
#endif /* DEMO_LPADC_VREF_SOURCE */
#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
    lpadcConfigStruct.conversionAverageMode = kLPADC_ConversionAverage1;//kLPADC_ConversionAverage128;
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
    lpadcConfigStruct.enableInDozeMode = true;


    lpadcConfigStruct.FIFO0Watermark = 3;
    LPADC_Init(DEMO_LPADC_BASE, &lpadcConfigStruct);

    /* Request LPADC calibration. */
#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
    LPADC_SetOffsetCalibrationMode(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_CALIBRATION_MODE);
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */

#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFS) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFS
#if defined(DEMO_LPADC_DO_OFFSET_CALIBRATION) && DEMO_LPADC_DO_OFFSET_CALIBRATION
    LPADC_DoOffsetCalibration(DEMO_LPADC_BASE); /* Request offset calibration, automatic update OFSTRIM register. */
#else                                           /* Update OFSTRIM register manually. */

#if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
#if defined(FSL_FEATURE_LPADC_OFSTRIM_COUNT) && (FSL_FEATURE_LPADC_OFSTRIM_COUNT == 2U)
    LPADC_SetOffsetValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B);
#elif defined(FSL_FEATURE_LPADC_OFSTRIM_COUNT) && (FSL_FEATURE_LPADC_OFSTRIM_COUNT == 1U)
    LPADC_SetOffsetValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE);
#endif /* FSL_FEATURE_LPADC_OFSTRIM_COUNT */

#else  /* For other OFSTRIM register type. */
    if (DEMO_LPADC_OFFSET_CALIBRATION_MODE == kLPADC_OffsetCalibration12bitMode)
    {
        LPADC_SetOffset12BitValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B);
    }
    else
    {
        LPADC_SetOffset16BitValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B);
    }
#endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */

#endif /* DEMO_LPADC_DO_OFFSET_CALIBRATION */
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFS */

#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ
    /* Request auto calibration (including gain error calibration and linearity error calibration). */
    LPADC_DoAutoCalibration(DEMO_LPADC_BASE);
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ */

#if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS)
    /* Do auto calibration. */
    LPADC_DoAutoCalibration(DEMO_LPADC_BASE);
#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */

#if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS)
    /* Do auto calibration. */
    LPADC_DoAutoCalibration(DEMO_LPADC_BASE);
#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */

    /* Sets the conversion command's configuration structure with an available settings.
     * code
     *   config->sampleScaleMode            = kLPADC_SampleFullScale;
     *   config->channelBScaleMode          = kLPADC_SampleFullScale;
     *   config->channelSampleMode          = kLPADC_SampleChannelSingleEndSideA;
     *   config->channelNumber              = 2U;
     *   config->alternateChannelNumber     = 0U;
     *   config->chainedNextCmdNumber       = 0U;
     *   config->enableAutoChannelIncrement = false;
     *   config->loopCount                  = 0U;
     *   config->hardwareAverageMode        = kLPADC_HardwareAverageCount1;
     *   config->sampleTimeMode             = kLPADC_SampleTimeADCK3;
     *   config->hardwareCompareMode        = kLPADC_HardwareCompareDisabled;
     *   config->hardwareCompareValueHigh   = 0U;
     *   config->hardwareCompareValueLow    = 0U;
     *   config->conversionResolutionMode   = kLPADC_ConversionResolutionStandard;
     *   config->enableWaitTrigger          = false;
     *   config->enableChannelB             = false;
     * endcode
     */
    LPADC_GetDefaultConvCommandConfig(&lpadcCommandConfigStruct);
    lpadcCommandConfigStruct.channelNumber = DEMO_LPADC_USER_CHANNEL;
#if defined(DEMO_LPADC_USE_HIGH_RESOLUTION) && DEMO_LPADC_USE_HIGH_RESOLUTION
    lpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionHigh;
#endif /* DEMO_LPADC_USE_HIGH_RESOLUTION */

    lpadcCommandConfigStruct.sampleTimeMode = kLPADC_SampleTimeADCK5;//kLPADC_SampleTimeADCK35;//kLPADC_SampleTimeADCK7;

    /* Chain the next command */
    lpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID + 1;

    LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID, &lpadcCommandConfigStruct);

    /* Configure other channel, the configuration is same */
    lpadcCommandConfigStruct.channelNumber = 14;//1;
    lpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID + 2;
    LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID + 1, &lpadcCommandConfigStruct);

    /* Configure other channel, the configuration is same */
    lpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB;
    lpadcCommandConfigStruct.channelNumber = 0;
    lpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID + 3;
    LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID + 2, &lpadcCommandConfigStruct);

    /* Configure other channel, the configuration is same */
	lpadcCommandConfigStruct.channelNumber = 14;//1;
	lpadcCommandConfigStruct.chainedNextCommandNumber = 0;
	LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, DEMO_LPADC_USER_CMDID + 3, &lpadcCommandConfigStruct);
    /* Sets the trigger's configuration structure with an available settings.
     *   config->targetCommandId       = 1U;
     *   config->delayPower            = 0U;
     *   config->priority              = 0U;
     *   config->enableHardwareTrigger = true;
     *   config->channelAFIFOSelect    = 0U;
     *   config->channelBFIFOSelect    = 0U;
     * endcode
     */
    LPADC_GetDefaultConvTriggerConfig(&lpadcTriggerConfigStruct);
    lpadcTriggerConfigStruct.targetCommandId = DEMO_LPADC_USER_CMDID; /* CMD1 is executed. */

    /* Enable the hardware trigger function in the ADC block */
    lpadcTriggerConfigStruct.enableHardwareTrigger = true;

    /* Configured the trigger0. */
    LPADC_SetConvTriggerConfig(DEMO_LPADC_BASE, 0U, &lpadcTriggerConfigStruct);

    /* Enable the watermark DMA in the ADC block */
#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U))
    LPADC_EnableFIFO0WatermarkDMA(DEMO_LPADC_BASE, true);
#else
    LPADC_EnableFIFOWatermarkDMA(DEMO_LPADC_BASE, true);
#endif /* (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U)) */

    PRINTF("\r\nADC Full Range: %d", LPADC_FULLRANGE);
#if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
    if (kLPADC_SampleFullScale == lpadcCommandConfigStruct.sampleScaleMode)
    {
        PRINTF("Full channel scale (Factor of 1).\r\n");
    }
    else if (kLPADC_SamplePartScale == lpadcCommandConfigStruct.sampleScaleMode)
    {
        PRINTF("Divided input voltage signal. (Factor of 30/64).\r\n");
    }
#endif
}

/*!
 * @brief ADC configuration
 */
static void ADC1_Configuration(void)
{
    lpadc_config_t lpadcConfigStruct;
    lpadc_conv_trigger_config_t lpadcTriggerConfigStruct;
    lpadc_conv_command_config_t lpadcCommandConfigStruct;

    /* Sets the converter configuration structure with an available settings.
     * code
     *   config->enableInDozeMode        = true;
     *   config->conversionAverageMode   = kLPADC_ConversionAverage1;
     *   config->enableAnalogPreliminary = true;
     *   config->powerUpDelay            = 0x10;
     *   config->referenceVoltageSource  = kLPADC_ReferenceVoltageAlt3;
     *   config->powerLevelMode          = kLPADC_PowerLevelAlt1;
     *   config->triggerPriorityPolicy   = kLPADC_TriggerPriorityPreemptImmediately;
     *   config->enableConvPause         = false;
     *   config->convPauseDelay          = 0U;
     *   config->FIFO0Watermark          = 0U;
     *   config->FIFO1Watermark          = 0U;
     *   config->FIFOWatermark           = 0U;
     * endcode
     */
    LPADC_GetDefaultConfig(&lpadcConfigStruct);
    lpadcConfigStruct.enableAnalogPreliminary = true;
    lpadcConfigStruct.powerUpDelay            = 0x01U;//0x10U;
    lpadcConfigStruct.powerLevelMode          = kLPADC_PowerLevelAlt4;
#if defined(DEMO_LPADC_VREF_SOURCE)
    lpadcConfigStruct.referenceVoltageSource = DEMO_LPADC_VREF_SOURCE;
#endif /* DEMO_LPADC_VREF_SOURCE */
#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS
    lpadcConfigStruct.conversionAverageMode = kLPADC_ConversionAverage1;//kLPADC_ConversionAverage128;
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_AVGS */
    lpadcConfigStruct.enableInDozeMode = true;

    lpadcConfigStruct.FIFO0Watermark = 3;

    LPADC_Init(ADC1, &lpadcConfigStruct);

    /* Request LPADC calibration. */
#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE
    LPADC_SetOffsetCalibrationMode(ADC1, DEMO_LPADC_OFFSET_CALIBRATION_MODE);
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFSMODE */

#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CALOFS) && FSL_FEATURE_LPADC_HAS_CTRL_CALOFS
#if defined(DEMO_LPADC_DO_OFFSET_CALIBRATION) && DEMO_LPADC_DO_OFFSET_CALIBRATION
    LPADC_DoOffsetCalibration(ADC1); /* Request offset calibration, automatic update OFSTRIM register. */
#else                                           /* Update OFSTRIM register manually. */

#if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
#if defined(FSL_FEATURE_LPADC_OFSTRIM_COUNT) && (FSL_FEATURE_LPADC_OFSTRIM_COUNT == 2U)
    LPADC_SetOffsetValue(DEMO_LPADC_BASE, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B);
#elif defined(FSL_FEATURE_LPADC_OFSTRIM_COUNT) && (FSL_FEATURE_LPADC_OFSTRIM_COUNT == 1U)
    LPADC_SetOffsetValue(ADC1, DEMO_LPADC_OFFSET_VALUE);
#endif /* FSL_FEATURE_LPADC_OFSTRIM_COUNT */

#else  /* For other OFSTRIM register type. */
    if (DEMO_LPADC_OFFSET_CALIBRATION_MODE == kLPADC_OffsetCalibration12bitMode)
    {
        LPADC_SetOffset12BitValue(ADC1, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B);
    }
    else
    {
        LPADC_SetOffset16BitValue(ADC1, DEMO_LPADC_OFFSET_VALUE_A, DEMO_LPADC_OFFSET_VALUE_B);
    }
#endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */

#endif /* DEMO_LPADC_DO_OFFSET_CALIBRATION */
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CALOFS */

#if defined(FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ) && FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ
    /* Request auto calibration (including gain error calibration and linearity error calibration). */
    LPADC_DoAutoCalibration(ADC1);
#endif /* FSL_FEATURE_LPADC_HAS_CTRL_CAL_REQ */

#if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS)
    /* Do auto calibration. */
    LPADC_DoAutoCalibration(ADC1);
#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */

#if (defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS)
    /* Do auto calibration. */
    LPADC_DoAutoCalibration(ADC1);
#endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */

    /* Sets the conversion command's configuration structure with an available settings.
     * code
     *   config->sampleScaleMode            = kLPADC_SampleFullScale;
     *   config->channelBScaleMode          = kLPADC_SampleFullScale;
     *   config->channelSampleMode          = kLPADC_SampleChannelSingleEndSideA;
     *   config->channelNumber              = 2U;
     *   config->alternateChannelNumber     = 0U;
     *   config->chainedNextCmdNumber       = 0U;
     *   config->enableAutoChannelIncrement = false;
     *   config->loopCount                  = 0U;
     *   config->hardwareAverageMode        = kLPADC_HardwareAverageCount1;
     *   config->sampleTimeMode             = kLPADC_SampleTimeADCK3;
     *   config->hardwareCompareMode        = kLPADC_HardwareCompareDisabled;
     *   config->hardwareCompareValueHigh   = 0U;
     *   config->hardwareCompareValueLow    = 0U;
     *   config->conversionResolutionMode   = kLPADC_ConversionResolutionStandard;
     *   config->enableWaitTrigger          = false;
     *   config->enableChannelB             = false;
     * endcode
     */
    LPADC_GetDefaultConvCommandConfig(&lpadcCommandConfigStruct);
    lpadcCommandConfigStruct.channelNumber = 12;
#if defined(DEMO_LPADC_USE_HIGH_RESOLUTION) && DEMO_LPADC_USE_HIGH_RESOLUTION
    lpadcCommandConfigStruct.conversionResolutionMode = kLPADC_ConversionResolutionHigh;
#endif /* DEMO_LPADC_USE_HIGH_RESOLUTION */

    lpadcCommandConfigStruct.sampleTimeMode = kLPADC_SampleTimeADCK5;//kLPADC_SampleTimeADCK35;//kLPADC_SampleTimeADCK7;

    /* Chain the next command */
    lpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID + 1;

    LPADC_SetConvCommandConfig(ADC1, DEMO_LPADC_USER_CMDID, &lpadcCommandConfigStruct);

    /* Configure other channel, the configuration is same */
    lpadcCommandConfigStruct.channelNumber = 13;//1;
    lpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID + 2;
    LPADC_SetConvCommandConfig(ADC1, DEMO_LPADC_USER_CMDID + 1, &lpadcCommandConfigStruct);

    /* Configure other channel, the configuration is same */
    lpadcCommandConfigStruct.channelNumber = 14;
    lpadcCommandConfigStruct.chainedNextCommandNumber = DEMO_LPADC_USER_CMDID + 3;
    LPADC_SetConvCommandConfig(ADC1, DEMO_LPADC_USER_CMDID + 2, &lpadcCommandConfigStruct);

    /* Configure other channel, the configuration is same */
	lpadcCommandConfigStruct.channelNumber = 15;//1;
	lpadcCommandConfigStruct.chainedNextCommandNumber = 0;
	LPADC_SetConvCommandConfig(ADC1, DEMO_LPADC_USER_CMDID + 3, &lpadcCommandConfigStruct);
    /* Sets the trigger's configuration structure with an available settings.
     *   config->targetCommandId       = 1U;
     *   config->delayPower            = 0U;
     *   config->priority              = 0U;
     *   config->enableHardwareTrigger = true;
     *   config->channelAFIFOSelect    = 0U;
     *   config->channelBFIFOSelect    = 0U;
     * endcode
     */
    LPADC_GetDefaultConvTriggerConfig(&lpadcTriggerConfigStruct);
    lpadcTriggerConfigStruct.targetCommandId = DEMO_LPADC_USER_CMDID; /* CMD1 is executed. */

    /* Enable the hardware trigger function in the ADC block */
    lpadcTriggerConfigStruct.enableHardwareTrigger = true;

    /* Configured the trigger0. */
    LPADC_SetConvTriggerConfig(ADC1, 0U, &lpadcTriggerConfigStruct);

    /* Enable the watermark DMA in the ADC block */
#if (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U))
    LPADC_EnableFIFO0WatermarkDMA(ADC1, true);
#else
    LPADC_EnableFIFOWatermarkDMA(ADC1, true);
#endif /* (defined(FSL_FEATURE_LPADC_FIFO_COUNT) && (FSL_FEATURE_LPADC_FIFO_COUNT == 2U)) */

    PRINTF("\r\nADC Full Range: %d", LPADC_FULLRANGE);
#if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
    if (kLPADC_SampleFullScale == lpadcCommandConfigStruct.sampleScaleMode)
    {
        PRINTF("Full channel scale (Factor of 1).\r\n");
    }
    else if (kLPADC_SamplePartScale == lpadcCommandConfigStruct.sampleScaleMode)
        PRINTF("Divided input voltage signal. (Factor of 30/64).\r\n");
    }
#endif
}


static void CTIMER3_ADCTrigger_Init(void)
{
    ctimer_config_t config;
    ctimer_match_config_t matchConfig;

    CTIMER_GetDefaultConfig(&config);

    CTIMER_Init(CTIMER3, &config);

    matchConfig.enableCounterReset = true;
    matchConfig.enableCounterStop  = false;
    matchConfig.matchValue         = CLOCK_GetCTimerClkFreq(0U) / sampleFreq / 2 - 1;
    matchConfig.outControl         = kCTIMER_Output_Toggle;
    matchConfig.outPinInitState    = true;
    matchConfig.enableInterrupt    = false;
    CTIMER_SetupMatch(CTIMER3, kCTIMER_Match_3, &matchConfig);

}

static void CTIMER0_ADCTrigger_Init(void)
{
    ctimer_config_t config;
    ctimer_match_config_t matchConfig;

    CTIMER_GetDefaultConfig(&config);

    CTIMER_Init(CTIMER0, &config);

    matchConfig.enableCounterReset = true;
    matchConfig.enableCounterStop  = false;
    matchConfig.matchValue         = CLOCK_GetCTimerClkFreq(0U) / sampleFreq / 2 - 1;;
    matchConfig.outControl         = kCTIMER_Output_Toggle;
    matchConfig.outPinInitState    = true;
    matchConfig.enableInterrupt    = false;
    CTIMER_SetupMatch(CTIMER0, kCTIMER_Match_3, &matchConfig);
}

