Hi Kerry,
Here is my Code.
#define WITH_DMA (0) /*with DMA */
#if WITH_DMA
#define DMA_INTERRUPT (1) /*with DMA Interrupt*/
#define AUTONOM (0) /*automatic triggering of ADC conversions*/
#define CYCLIC_CONTINUOUS (0) /*continuous triggering of ADC conversions*/
#endif
#define HZ_TO_MHZ(x) (x / 1000000)
#define TEST_TOGGLE_PIN (0)
#define WITH_FTM_INTERRUPT (0)
#define HARDWARE_TRIGGER (1)
#define AVERAGING_HARDWARE (0)
/*------------------------------------------------------------------------*/ /**
* \brief Initializes the two instances of the ADC and configures the DMA
* such that the ADC conversions are started by a DMA channel and
* the other DMA channel reads the result from the ADC Data register
* and saves them in a RAM buffer.
* \param[in] none
* \return none
*/ //---------------------------------------------------------------------------
void CADC_MK24FN1M0::init()
{
adc16_chn_config_t adcChnConfig;
ADC_Type * bases[NUMBER_OF_INSTANCES] = {m_stADC[0]->base, m_stADC[1]->base};
uint32 Instances[NUMBER_OF_INSTANCES] = {m_stADC[0]->instances, m_stADC[1]->instances};
adc16_chn_t channelIndex[NUMBER_OF_INSTANCES] = {m_stADC[0]->chnIdx, m_stADC[1]->chnIdx};
adc16_chn_mux_mode_t muxConfig[NUMBER_OF_INSTANCES] = {m_stADC[0]->adcMuxChannel, m_stADC[1]->adcMuxChannel};
/* Config ADC module */
const adc16_converter_config_t convConfig =
{
false, /*!< Enables low power. @internal gui name="Low power mode" id="LowPowerMode" */
kAdc16ClkDividerOf8, /*!< Selects the divider of input clock source. @internal gui name="Clock divider" id="ClockDivider" */
true, /*!< Enables the long sample time. @internal gui name="Long sample time" id="LongSampleTime" */
kAdc16ResolutionBitOf16, /*!< Selects the sample resolution mode. @internal gui name="Resolution" id="Resolution" */
kAdc16ClkSrcOfBusClk, /*!< Selects the input clock source to converter. @internal gui name="Clock source" id="ClockSource" */
false, /*!< Enables the asynchronous clock inside the ADC. @internal gui name="Internal async. clock" id="InternalAsyncClock" */
false, /*!< Enables the high-speed mode. @internal gui name="High speed mode" id="HighSpeed" */
kAdc16LongSampleCycleOf10, /*!< Selects the long sample mode. @internal gui name="Long sample mode" id="LongSampleMode" */
#if HARDWARE_TRIGGER
true, /*!< Enables the hardware trigger function. @internal gui name="Hardware trigger" id="HwTrigger" */
#else
false,
#endif
kAdc16RefVoltSrcOfVref, /*!< Selects the reference voltage source. @internal gui name="Voltage reference" id="ReferenceVoltage" */
false, /*!< Enables continuous conversion mode. @internal gui name="Continuous mode" id="ContinuousMode" */
#if FSL_FEATURE_ADC16_HAS_DMA
#if WITH_DMA
true
#else
false /*!< Enables the DMA for ADC converter. @internal gui name="DMA mode" id="DMASupport" */
#endif /*WITH_DMA*/
#endif /*FSL_FEATURE_ADC16_HAS_DMA*/
};
/* Config hardware average function */
const adc16_hw_average_config_t averageConfig =
{
#if AVERAGING_HARDWARE
true,
#else
false, /*!< Enable the hardware average function. */
#endif
kAdc16HwAverageCountOf32 /*!< Select the count of conversion result for accumulator. */
};
for (uint32 i = 0; i < m_numberOfUsedInstances; ++i)
{
/* Disable ADC interrupt */
NVIC_DisableIRQ(m_stADC[i]->ADC_IRQn);
#if WITH_DMA
/* De-Init DMAMUX */
DMAMUX_HAL_SetChannelCmd(m_stADC[i]->DMAMUX_Peripheral, static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel1), false);
/* De-Init EDMA */
EDMA_HAL_HTCDClearReg(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel1);
EDMA_HAL_ClearIntStatusFlag(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel1);
EDMA_HAL_ClearErrorIntStatusFlag(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel1);
/* Disable DMA ADC interrupt */
NVIC_DisableIRQ(m_stADC[i]->EDMA_ADCIRQn);
#endif /*WITH_DMA*/
/* Un-gate ADC clock */
CLOCK_SYS_EnableAdcClock(Instances[i]);
/* Enable ADC module clock*/
ADC16_HAL_Init(bases[i]);
/* Calibrate ADC module */
ADC16_HAL_SetAutoCalibrationCmd(bases[i], true);
while (ADC16_HAL_GetAutoCalibrationActiveFlag(bases[i]))
;
ASSERT_ALWAYS(!ADC16_HAL_GetAutoCalibrationFailedFlag(bases[i]));
#if FSL_FEATURE_ADC16_HAS_DIFF_MODE
uint16 minusGain = ADC16_HAL_GetAutoMinusSideGainValue(bases[i]);
ADC16_HAL_SetMinusSideGainValue(bases[i], minusGain);
uint16 plusGain = ADC16_HAL_GetAutoPlusSideGainValue(bases[i]);
ADC16_HAL_SetPlusSideGainValue(bases[i], plusGain);
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
ADC16_HAL_ConfigConverter(bases[i], &convConfig);
ADC16_HAL_ConfigHwAverage(bases[i], &averageConfig);
/* Configure ADC channel, Interrupt and differential enable */
adcChnConfig.chnIdx = channelIndex[i];
#if WITH_DMA
adcChnConfig.convCompletedIntEnable = false; // Disables the ADC interrupt
#else
adcChnConfig.convCompletedIntEnable = true; // Enables the ADC interrupt
#endif /*WITH_DMA*/
#if FSL_FEATURE_ADC16_HAS_DIFF_MODE
adcChnConfig.diffConvEnable = false; /*!< Enable/ Disable the differential conversion. */
#endif /*FSL_FEATURE_ADC16_HAS_DIFF_MODE*/
ADC16_HAL_ConfigChn(bases[i], muxConfig[i], &adcChnConfig);
ADC16_HAL_SetChnMuxMode(bases[i], muxConfig[i]);
/* Initialise and reset TCD Buffers for the two DMA Channels */
edma_software_tcd_t stcd[TCD_COUNT];
memset(stcd, 0, sizeof(stcd));
memset(m_configDMA, 0, sizeof(m_configDMA));
#if WITH_DMA
/* Configure ADC DMA */
m_configDMA[0].srcAddr = reinterpret_cast<uint32_t>(&ADC_R_REG(m_stADC[i]->base, 0));
m_configDMA[0].destAddr = reinterpret_cast<uint32_t>(&m_stDMA_Collect[ (3*i) + 2]);
m_configDMA[0].srcTransferSize = kEDMATransferSize_2Bytes;
m_configDMA[0].destTransferSize = kEDMATransferSize_2Bytes;
m_configDMA[0].srcOffset = 0x00;
m_configDMA[0].destOffset = 0x00; // 2 Bytes
m_configDMA[0].srcLastAddrAdjust = 0x00;
m_configDMA[0].destLastAddrAdjust = 0x00; //static_cast<uint32_t>(-6);
m_configDMA[0].srcModulo = kEDMAModuloDisable;
m_configDMA[0].destModulo = kEDMAModuloDisable;
m_configDMA[0].minorLoopCount = 2U;
m_configDMA[0].majorLoopCount = 1U;
/* DMAMUX init */
DMAMUX_HAL_SetTriggerSource(m_stADC[i]->DMAMUX_Peripheral, static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel1),
static_cast<uint8>(m_stADC[i]->DMAMUX_ADC_Source));
DMAMUX_HAL_SetChannelCmd(m_stADC[i]->DMAMUX_Peripheral, static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel1), true);
#ifdef AUTONOM /*automatic triggering of ADC conversions*/
EDMA_HAL_STCDSetChannelMinorLink(&stcd[0], static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel2), true);
#else
EDMA_HAL_STCDSetChannelMinorLink(&stcd[0], static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel1), false);
#endif /*AUTONOM*/
#ifdef DMA_INTERRUPT
EDMA_HAL_STCDSetBasicTransfer(m_stADC[i]->EDMA_Peripheral, &stcd[0], &m_configDMA[0], true, false);
#else
EDMA_HAL_STCDSetBasicTransfer(m_stADC[i]->EDMA_Peripheral, &stcd[0], &m_configDMA[0], false, false);
#endif /*DMA_INTERRUPT*/
EDMA_HAL_PushSTCDToHTCD(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel1, &stcd[0]);
EDMA_HAL_SetDmaRequestCmd(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel1, true);
// ------------------------------------------------
// For transferring from SRAM to ADC_SC1A
// ------------------------------------------------
#ifdef AUTONOM /*automatic triggering of ADC conversions*/
EDMA_HAL_ClearIntStatusFlag(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel2);
EDMA_HAL_ClearErrorIntStatusFlag(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel2);
/* DMAMUX init */
DMAMUX_HAL_SetChannelCmd(m_stADC[i]->DMAMUX_Peripheral, static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel2), false);
DMAMUX_HAL_SetChannelCmd(m_stADC[i]->DMAMUX_Peripheral, static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel2), true);
uint8 channel2Scan = ADC_Channel_NTC_IN;
if (1 == i)
{
channel2Scan = SECOND_ADC_FIRST_CHANNEL;
}
/* Configure ADC DMA */
m_configDMA[1].srcAddr = reinterpret_cast<uint32_t>(&m_stChannels->channels[channel2Scan]);
m_configDMA[1].destAddr = reinterpret_cast<uint32_t>(&m_stADC[i]->base->SC1[0]);
m_configDMA[1].srcTransferSize = kEDMATransferSize_1Bytes;
m_configDMA[1].destTransferSize = kEDMATransferSize_1Bytes;
m_configDMA[1].srcOffset = 0x01;
m_configDMA[1].destOffset = 0x00;
m_configDMA[1].srcLastAddrAdjust = static_cast<uint32_t>(-3);
m_configDMA[1].destLastAddrAdjust = 0x00;
m_configDMA[1].srcModulo = kEDMAModuloDisable;
m_configDMA[1].destModulo = kEDMAModuloDisable;
m_configDMA[1].minorLoopCount = 1U;
m_configDMA[1].majorLoopCount = 3U;
/* Links the second DMA Channel to the TCD of the first DMA Channel */
EDMA_HAL_STCDSetChannelMinorLink(&stcd[1], static_cast<uint32>(m_stADC[i]->EDMA_ADC_Channel2), false);
EDMA_HAL_STCDSetBasicTransfer(m_stADC[i]->EDMA_Peripheral, &stcd[1], &m_configDMA[1], true, false);
EDMA_HAL_PushSTCDToHTCD(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel2, &stcd[1]);
EDMA_HAL_SetDmaRequestCmd(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel2, true);
EDMA_HAL_TriggerChannelStart(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel2);
// EDMA_HAL_SetChannelPriority(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel1, m_stADC[i]->EDMA_CH1_Priortity);
// EDMA_HAL_SetChannelPriority(m_stADC[i]->EDMA_Peripheral, m_stADC[i]->EDMA_ADC_Channel2, m_stADC[i]->EDMA_CH2_Priortity);
#endif /*AUTONOM*/
#ifdef DMA_INTERRUPT
/* Initialize EDMA interrupts */
NVIC_ClearPendingIRQ(m_stADC[i]->EDMA_ADCIRQn);
NVIC_SetPriority(m_stADC[i]->EDMA_ADCIRQn, m_stADC[i]->EDMA_IRQPriority);
NVIC_EnableIRQ(m_stADC[i]->EDMA_ADCIRQn);
#endif /*DMA_INTERRUPT*/
#else
/* Initialize ADC interrupts */
NVIC_ClearPendingIRQ(m_stADC[i]->ADC_IRQn);
NVIC_SetPriority(m_stADC[i]->ADC_IRQn, m_stADC[i]->ADC_IRQPriority);
NVIC_EnableIRQ(m_stADC[i]->ADC_IRQn);
#endif /*WITH_DMA*/
// ###########################################################################
#if HARDWARE_TRIGGER
// Timer Configuration to generate trigger for ADC
CLOCK_SYS_EnableFtmClock(m_stADC[0]->FTM_Instance);
/* Use FTM mode */
FTM_HAL_Enable(m_stADC[0]->FTM_base, true);
// Set prescaler to 1
FTM_HAL_SetClockPs(m_stADC[0]->FTM_base, kFtmDividedBy1);
// Configure outputs
FTM_HAL_SetWriteProtectionCmd(m_stADC[0]->FTM_base, false);
FTM_HAL_SetClockSource(m_stADC[0]->FTM_base, kClock_source_FTM_None);
//Set FTM external trigger
FTM_HAL_SetInitTriggerCmd(m_stADC[0]->FTM_base, true);
#if WITH_FTM_INTERRUPT
// Configure and enable FTM overflow interrupt
NVIC_EnableIRQ(m_stADC[0]->FTM_OverflowIrq);
// Enable interrupt on counter overflow
FTM_HAL_EnableTimerOverflowInt(m_stADC[0]->FTM_base);
#else
SIM_HAL_SetAdcTriggerModeOneStep(SIM, i, true, kSimAdcPretrgselA, kSimAdcTrgSelFtm2);
EN_ADC_CHANNELS channel;
if (1 == i)
{
channel = ADC_Channel_PHOTO2;
}
else
{
channel = ADC_Channel_PHOTO1;
}
setADCTriggerInput(channel, true);
#endif
#endif
// ###########################################################################
}
}
/*------------------------------------------------------------------------*/ /**
Configures Timer to the new on Time
If on_time_us is 0 then no timer will be started
*/ //---------------------------------------------------------------------------
void CADC_MK24FN1M0::setTriggerInterval(const uint16 triggerInterval_us)
{
#if HARDWARE_TRIGGER
m_trigTime_us = triggerInterval_us;
const uint64 fmtClockFrequency = SystemCoreClock;
const uint8 prescaler = 1;
m_clocksforTImer = static_cast<uint16>( HZ_TO_MHZ( (fmtClockFrequency / prescaler) * m_trigTime_us) );
FTM_HAL_SetMod(m_stADC[0]->FTM_base, m_clocksforTImer);
#endif
}
/*------------------------------------------------------------------------*/ /**
Sets the trigger for m_trigTime_us to high to start the ADC conversion
*/ //---------------------------------------------------------------------------
void CADC_MK24FN1M0::startTrigger()
{
#if HARDWARE_TRIGGER
if (m_trigTime_us != 0)
{
#if TEST_TOGGLE_PIN
g_testToggleFlag = false;
#endif
FTM_HAL_SetCounterInitVal(m_stADC[0]->FTM_base, 0);
FTM_HAL_SetWriteProtectionCmd(m_stADC[0]->FTM_base, false);
FTM_HAL_ClearTimerOverflow(m_stADC[0]->FTM_base);
FTM_HAL_SetClockSource(m_stADC[0]->FTM_base, kClock_source_FTM_SystemClk);
}
#else
setADCTriggerInput(IADC::ADC_Channel_PHOTO1, true);
setADCTriggerInput(IADC::ADC_Channel_PHOTO2, true );
#endif
}
void CADC_MK24FN1M0::stopTrigger()
{
#if HARDWARE_TRIGGER
FTM_HAL_ClearTimerOverflow(m_stADC[0]->FTM_base);
FTM_HAL_SetWriteProtectionCmd(m_stADC[0]->FTM_base, false);
FTM_HAL_SetClockSource(m_stADC[0]->FTM_base, kClock_source_FTM_None);
#else
setADCTriggerInput(IADC::ADC_Channel_PHOTO1, false);
setADCTriggerInput(IADC::ADC_Channel_PHOTO2, false);
#endif
}
/*------------------------------------------------------------------------*/ /**
* \brief irq Handler routine for the ADC IRQ
* \param[in] any one of the "EN_ADC_CHANNELS"
* \return none
*/ //---------------------------------------------------------------------------
void CADC_MK24FN1M0::irqADC(uint32 adcInstance)
{
static uint16 measureCount[NUMBER_OF_INSTANCES] = { 0 , 0 };
uint8 channelNumber = ( static_cast<uint8>(m_stADC[adcInstance]->base->SC1[0]) & 0x1F );
GPIO_HAL_WritePinOutput(PTA, 14, 1);
EN_ADC_CHANNELS channel2Scan = getADCChannel2Scan(adcInstance, channelNumber);
m_stDMA_Collect[channel2Scan] = ADC16_HAL_GetChnConvValue(m_stADC[adcInstance]->base, 0);
#if AVERAGING_HARDWARE
m_ADCConversionFinish[channel2Scan] = true;
#else
m_ADC_Measurements[adcInstance] += m_stDMA_Collect[channel2Scan];
if (MAX_ADC_MEASUREMENTS <= ++measureCount[adcInstance])
{
GPIO_HAL_WritePinOutput(PTB, 16, 1);
m_AverageADC[adcInstance] = static_cast<uint16>(m_ADC_Measurements[adcInstance] / MAX_ADC_MEASUREMENTS);
measureCount[adcInstance] = 0;
m_ADCConversionFinish[channel2Scan] = true;
GPIO_HAL_WritePinOutput(PTB, 16, 0);
}
#endif
GPIO_HAL_WritePinOutput(PTA, 14, 0);
#if 0
if (adcInstance)
{
setADCTriggerInput(IADC::ADC_Channel_PHOTO1, true);
}
else
{
setADCTriggerInput(IADC::ADC_Channel_PHOTO2, true);
}
#endif
}
// ##############################################################################################
in ADC.h file the following Struct is declared.
// ##############################################################################################
struct STADCHardware
{
FTM_Type * FTM_base;
uint32 FTM_Instance;
IRQn_Type FTM_OverflowIrq;
ADC_Type * base;
uint32 instances;
adc16_chn_t chnIdx;
adc16_chn_mux_mode_t adcMuxChannel;
IRQn_Type ADC_IRQn; // IRQ channel ADC
uint8 ADC_IRQPriority; // IRQ preemption priority
DMAMUX_Type * DMAMUX_Peripheral; // DMAMUX peripheral
uint32 DMAMUX_Instance; // DMAMUX instance
dma_request_source_t DMAMUX_ADC_Source; // Source configuration for ADC
DMA_Type * EDMA_Peripheral; // DMA peripheral
uint32 EDMA_Instance; // instance in library(eg. 0 = DMA0)
edma_channel_indicator_t EDMA_ADC_Channel1; // DMA ADC channel
edma_channel_indicator_t EDMA_ADC_Channel2; // DMA ADC channel
IRQn_Type EDMA_ADCIRQn; // IRQ channel DMA ADC
uint8 EDMA_IRQPriority; // IRQ preemption priority
edma_channel_priority_t EDMA_CH1_Priortity;
edma_channel_priority_t EDMA_CH2_Priortity;
};
// ##############################################################################################
// ##############################################################################################
in my Config.h file the following ADC configurations are used
// ##############################################################################################
#if 1
static const CADC_MK24FN1M0::STADCHardware stADC1 = {
FTM3, // FTM_Type *base;
3, // uint32 FTM_Instance;
FTM3_IRQn, // IRQn_Type FTM_OverflowIrq;
ADC1, // ADC_Type *base;
1, // instances ADC_Instance
kAdc16Chn1d, // adc16_chn_t
kAdc16ChnMuxOfA, // All Channels use multiplexer setting b
ADC1_IRQn, // IRQ channel ADC
0, // IRQ preemption priority
DMAMUX, // DMAMUX_Type *DMAMUX_Peripheral;// DMAMUX peripheral
0, // uint32 DMAMUX_Instance; // DMAMUX instance
kDmaRequestMux0ADC1, // dma_request_source_t DMAMUX_ADC_Source; // Source configuration for ADC
DMA0, // DMA_Type *EDMA_Peripheral; // DMA peripheral
0, // uint32 EDMA_Instance; // instance in library(eg. 0 = DMA0)
kEDMAChannel10, // edma_channel_indicator_t EDMA_ADC_Channel; // DMA channel
kEDMAChannel11,
DMA10_IRQn, // IRQn_Type EDMA_ADCIRQn; // IRQ DMA ADC
0, // IRQ preemption Priority
kEDMAChnPriority11,
kEDMAChnPriority10};
#endif
#if 1
static const CADC_MK24FN1M0::STADCHardware stADC0 = {
FTM2, // FTM_Type *base;
2, // uint32 FTM_Instance;
FTM2_IRQn, // IRQn_Type FTM_OverflowIrq;
ADC0, // ADC_Type *base;
0, // instances ADC_Instance
kAdc16Chn1d, // adc16_chn_t
kAdc16ChnMuxOfA, // All Channels use multiplexer setting b
ADC0_IRQn, // IRQ channel ADC
0, // IRQ preemption Priority
DMAMUX, // DMAMUX_Type *DMAMUX_Peripheral;// DMAMUX peripheral
0, // uint32 DMAMUX_Instance; // DMAMUX instance
kDmaRequestMux0ADC0, // dma_request_source_t DMAMUX_ADC_Source; // Source configuration for ADC
DMA0, // DMA_Type *EDMA_Peripheral; // DMA peripheral
0, // uint32 EDMA_Instance; // instance in library(eg. 0 = DMA0)
kEDMAChannel12, // edma_channel_indicator_t EDMA_ADC_Channel; // DMA channel
kEDMAChannel13,
DMA12_IRQn, // IRQn_Type EDMA_ADCIRQn; // IRQ DMA ADC
0, // IRQ preemption Priority
kEDMAChnPriority13,
kEDMAChnPriority12};
#endif
// ##############################################################################################
Hoping to get some help in the right direction!
Thanks and have a nice day!