Hi mrandreas
I think the problem in your code is the setup of the ADC control DMA (channel 0). If you want to use DMA channel 0, you have to use DMA0->TCD[16] instead of [17].
Following, I send you my code which works for the 4 ADC. Hope it helps.
Arnold
/// <summary>
/// setup_AdcDma
/// - This method performs the setup for the DMA used for fast AD conversion
/// of all channels
/// - Two DMA channels are needed for this functionality. One channel for the
/// transfer of the converted AD data from ADC to RAM and one channel for
/// the next AD input channel selection control.
/// - we set the priority of the ADCREAD DMA channel higher than the prio of
/// ADCONTROL to make sure converted AD value is transfered to RAM before next
/// conversion is initiated
/// - sequene description (SW triggered):
/// 0. Setup of AD channel select RAM table, setup DMA
/// 1. Start sequence within start of DMA channel ADCONTROL within DMA_SSRT.
/// This start may be timed within Timer or SW state machine
/// 2. The start of DMA channel ADCONTROL writes the first AD channel input
/// selection from RAM to SC1A. This starts the AD conversion.
/// 3. The ADC0 CoCo triggers the ADCREAD DMA channel which transfers
/// the data from ADC RA to RAM table.
/// 4. The DMA channel ADCONTROL is linked to the DMA channel ADCREAD and
/// writes the next AD channel input selection from RAM to SC1A. This
/// starts the next AD conversion immediately.
/// 5. The ADC0 CoCo triggers again and the sequence from Pt.3 is repeated
/// until number of programmed transfers is reached
/// </summary>
void CAdcDiffChannels::setup_AdcDma() {
// Turn on the DMA Mux clock
if (cUseDmaMux1) {
// Turn on the DMA MUX1 clock
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
SET_BITMASK(SIM_SCGC6, SIM_SCGC6_DMAMUX1_MASK);
} else {
// Turn on the DMA MUX0 clock
SET_BITMASK(SIM_SCGC6, SIM_SCGC6_DMAMUX0_MASK);
}
// -------------------------------------------------------------------------------------
// setup ADC0 DMA channel selection table
// -------------------------------------------------------------------------------------
uint8_t adcUnit = 0;
// set channel to DAD0 voltage and use differential mode
adcChnSelectDma[adcUnit][ADC_DAD0_INDEX] = DIFF_DIFFERENTIAL | ADC_DAD0_CHANNEL;
// use single-ended mode for remaining channels
adcChnSelectDma[adcUnit][ADC_TEMP_SENS_INT_INDEX] = DIFF_SINGLE | ADC_TEMP_SENS_INT_CHANNEL;
adcChnSelectDma[adcUnit][ADC_BANDGAP_VOLT_INDEX] = DIFF_SINGLE | ADC_BANDGAP_VOLT_CHANNEL;
// -------------------------------------------------------------------------------------
// setup ADC0 DMA for this unit
// DMA channel 'ADCONTROL' used to transfer next ADC0 control from RAM to ADC0_SC1A.
// DMA channel 'ADCREAD' used to transfer ADC0 result data from ADC0_RA to RAM.
// -------------------------------------------------------------------------------------
configAdcDmaOfUnit(adcUnit, NUMBER_OF_ADC_A_CHANNELS,
ADC0_DMA_CHANNEL_ADCONTROL, ADC0_DMA_CHANNEL_ADCONTROL_MUX_SRC,
ADC0_DMA_CHANNEL_ADCREAD, ADC0_DMA_CHANNEL_ADCREAD_MUX_SRC);
// -------------------------------------------------------------------------------------
// setup ADC1 DMA channel selection table
// -------------------------------------------------------------------------------------
adcUnit = 1;
// set channel to DAD0 voltage and use differential mode
adcChnSelectDma[adcUnit][ADC_DAD0_INDEX] = ADC_SC1_DIFF_MASK | ADC_DAD0_CHANNEL;
// -------------------------------------------------------------------------------------
// setup ADC1 DMA for this unit
// DMA channel 'ADCONTROL' used to transfer next ADC1 control from RAM to ADC1_SC1A.
// DMA channel 'ADCREAD' used to transfer ADC1 result data from ADC1_RA to RAM.
// -------------------------------------------------------------------------------------
configAdcDmaOfUnit(adcUnit, 1,
ADC1_DMA_CHANNEL_ADCONTROL, ADC1_DMA_CHANNEL_ADCONTROL_MUX_SRC,
ADC1_DMA_CHANNEL_ADCREAD, ADC1_DMA_CHANNEL_ADCREAD_MUX_SRC);
// -------------------------------------------------------------------------------------
// setup ADC2 DMA channel selection table
// -------------------------------------------------------------------------------------
adcUnit = 2;
// set channel to DAD0 voltage and use differential mode
adcChnSelectDma[adcUnit][ADC_DAD0_INDEX] = ADC_SC1_DIFF_MASK | ADC_DAD0_CHANNEL;
// -------------------------------------------------------------------------------------
// setup ADC2 DMA for this unit
// DMA channel 'ADCONTROL' used to transfer next ADC2 control from RAM to ADC2_SC1A.
// DMA channel 'ADCREAD' used to transfer ADC2 result data from ADC2_RA to RAM.
// -------------------------------------------------------------------------------------
configAdcDmaOfUnit(adcUnit, 1,
ADC2_DMA_CHANNEL_ADCONTROL, ADC2_DMA_CHANNEL_ADCONTROL_MUX_SRC,
ADC2_DMA_CHANNEL_ADCREAD, ADC2_DMA_CHANNEL_ADCREAD_MUX_SRC);
// -------------------------------------------------------------------------------------
// setup ADC3 DMA channel selection table
// -------------------------------------------------------------------------------------
adcUnit = 3;
// set channel to DAD0 voltage and use differential mode
adcChnSelectDma[adcUnit][ADC_DAD0_INDEX] = ADC_SC1_DIFF_MASK | ADC_DAD0_CHANNEL;
// -------------------------------------------------------------------------------------
// setup ADC3 DMA for this unit
// DMA channel 'ADCONTROL' used to transfer next ADC3 control from RAM to ADC3_SC1A.
// DMA channel 'ADCREAD' used to transfer ADC3 result data from ADC3_RA to RAM.
// -------------------------------------------------------------------------------------
configAdcDmaOfUnit(adcUnit, 1,
ADC3_DMA_CHANNEL_ADCONTROL, ADC3_DMA_CHANNEL_ADCONTROL_MUX_SRC,
ADC3_DMA_CHANNEL_ADCREAD, ADC3_DMA_CHANNEL_ADCREAD_MUX_SRC);
}
/// <summary>
/// configAdcDmaOfUnit
/// - This method configures the ADC DMA settings for a given ADC unit.
/// two DMA channels are used per unit (channel ADCONTROL and channel ADREAD).
/// ADCONTROL is used to program the next AD conversion
/// ADREAD is used to copy the convertet result from the ADC to RAM
/// - parameters: - adcUnit the adc unit to use
/// - nbrOfChn the number of channles to transfer
/// - dmaChannelAdControl the DMA channel for the ADCONTROL DMA
/// - dmaReqSourceAdControl the DMA request source for the ADCONTROL DMA
/// - dmaChannelAdRead the DMA channel for the ADREAD DMA
/// - dmaReqSourceAdRead the DMA request source for the ADREAD DMA
/// </summary>
void CAdcDiffChannels::configAdcDmaOfUnit(uint8_t adcUnit,
uint8_t nbrOfChn,
uint8_t dmaChannelAdControl,
uint8_t dmaReqSourceAdControl,
uint8_t dmaChannelAdRead,
uint8_t dmaReqSourceAdRead) {
// get values which depends on used unit
const uint8_t cHalfwordBytes = sizeof(uint16_t)/sizeof(uint8_t);
uint32_t adrOfAdcSC1A;
uint32_t adrOfAdcRA;
switch (adcUnit) {
case 0:
adrOfAdcSC1A = (uint32_t)&ADC0_SC1A;
adrOfAdcRA = (uint32_t)&ADC0_RA;
break;
case 1:
adrOfAdcSC1A = (uint32_t)&ADC1_SC1A;
adrOfAdcRA = (uint32_t)&ADC1_RA;
break;
case 2:
adrOfAdcSC1A = (uint32_t)&ADC2_SC1A;
adrOfAdcRA = (uint32_t)&ADC2_RA;
break;
case 3:
adrOfAdcSC1A = (uint32_t)&ADC3_SC1A;
adrOfAdcRA = (uint32_t)&ADC3_RA;
break;
}
// -------------------------------------------------------------------------------------
// DMA channel 'ADCONTROL' used to transfer next ADCx control from RAM to ADCx_SC1A.
// -------------------------------------------------------------------------------------
// Configure this DMA channel to an always enabled request source and enable this channel
if (cUseDmaMux1) {
DMAMUX1_CHCFG(dmaChannelAdControl) = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(dmaReqSourceAdControl)); // Channel Activation Source: DMA MUX always enabled
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
dmaChannelAdControl += DMA_CHANNEL_OFFSET_USING_DMAMUX1;
}
else {
DMAMUX0_CHCFG(dmaChannelAdControl) = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(dmaReqSourceAdControl)); // Channel Activation Source: DMA MUX always enabled
}
// Configure the TCD for the ADC_DMA_CHANNEL 'ADCONTROL'
DMA_SADDR(dmaChannelAdControl) = (uint32_t)&adcChnSelectDma[adcUnit][0]; // set source address to first entry of adcChnSelectDma
DMA_SOFF(dmaChannelAdControl) = sizeof(uint8_t); // source address increment, adc channel select is 1 byte
DMA_SLAST(dmaChannelAdControl) = -nbrOfChn; // source address decrement after major loop of adcChnSelectDma is nbrOfChn*1Byte
DMA_DADDR(dmaChannelAdControl) = adrOfAdcSC1A; // dest address is ADCx SC1A control register
DMA_DOFF(dmaChannelAdControl) = 0; // dest address increment, no increment allowed
DMA_DLAST_SGA(dmaChannelAdControl) = 0; // dest address shift after major loop, no shift needed
DMA_NBYTES_MLNO(dmaChannelAdControl) = sizeof(uint8_t); // minor byte transfer count, ADC input select cmd -> 1byte
// channel linking and major loop setting, no linking after minor loop, major loop transfers = Nbr of channel transfers
DMA_BITER_ELINKNO(dmaChannelAdControl) = DMA_BITER_ELINKNO_BITER(nbrOfChn);
DMA_CITER_ELINKNO(dmaChannelAdControl) = DMA_CITER_ELINKNO_CITER(nbrOfChn);
// source and dest data transfer size is 8bit
DMA_ATTR(dmaChannelAdControl) = (DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0));
// no additional controls for this DMA
DMA_CSR(dmaChannelAdControl) = 0;
// -------------------------------------------------------------------------------------
// DMA channel 'ADCREAD' used to transfer ADCx result data from ADCx_RA to RAM.
// -------------------------------------------------------------------------------------
// Configure this DMA channel to use ADCx CoCo as transfer request source and enable this channel
if (cUseDmaMux1) {
DMAMUX1_CHCFG(dmaChannelAdRead) = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(dmaReqSourceAdRead));// Channel Activation Source: ADCx CoCo
// Attention: DMA MUX1 is routed to DMA channels 16-31 as described in
// Reference manual MK10FX: chapter '3.3.9.1 DMA MUX request sources'
// We have to use a DMA channel offset of 16 during setup of the DMAs
dmaChannelAdRead += DMA_CHANNEL_OFFSET_USING_DMAMUX1;
} else {
DMAMUX0_CHCFG(dmaChannelAdRead) = (DMAMUX_CHCFG_ENBL_MASK | // Enable routing of DMA request
DMAMUX_CHCFG_SOURCE(dmaReqSourceAdRead));// Channel Activation Source: ADCx CoCo
}
// Configure the TCD for the ADC_DMA_CHANNEL 'ADCREAD'
DMA_SADDR(dmaChannelAdRead) = adrOfAdcRA; // source address is ADCx RA result register
DMA_SOFF(dmaChannelAdRead) = 0; // source address increment, no increment allowed
DMA_SLAST(dmaChannelAdRead) = 0; // source address shift after major loop, no shift needed
DMA_DADDR(dmaChannelAdRead) = (uint32_t)&adcConvValuesDma[adcUnit][0];// set dest address to first entry of adcConvValuesDma,
DMA_DOFF(dmaChannelAdRead) = cHalfwordBytes; // dest address increment, adc conv values is 2 byte
DMA_DLAST_SGA(dmaChannelAdRead) = -nbrOfChn*cHalfwordBytes; // dest address shift after major loop of adcChnResdDma is nbrOfChn*2Byte
DMA_NBYTES_MLNO(dmaChannelAdRead) = cHalfwordBytes; // minor byte transfer count, ADC result 16bit -> 2byte
// channel linking and major loop setting,
// enable channel2channel linking on minor loop complete, link to ADCONTROL channel
// and set major loop transfers = Nbr of channel transfers
DMA_BITER_ELINKYES(dmaChannelAdRead) =
DMA_BITER_ELINKYES_ELINK_MASK | DMA_BITER_ELINKYES_LINKCH(dmaChannelAdControl) | DMA_BITER_ELINKYES_BITER(nbrOfChn);
DMA_CITER_ELINKYES(dmaChannelAdRead) =
DMA_CITER_ELINKYES_ELINK_MASK | DMA_CITER_ELINKYES_LINKCH(dmaChannelAdControl) | DMA_CITER_ELINKYES_CITER(nbrOfChn);
// source and dest data transfer size is 16bit
DMA_ATTR(dmaChannelAdRead) = (DMA_ATTR_SSIZE(1) | DMA_ATTR_DSIZE(1));
// enable HW request (ADC coco) for the ADC_DMA_CHANNEL 'ADCREAD'
DMA_SERQ = DMA_SERQ_SERQ(dmaChannelAdRead);
// setup interrupt which fires every time the ADC_DMA_CHANNEL 'ADCREAD' transfer is completed.
// no linking after major loop needed
DMA_CSR(dmaChannelAdRead) = DMA_CSR_INTMAJOR_MASK;
}
where
the constant cUseDmaMux1 ist set to 'true' if all ADCs are used. If ADC 0&1 is used only the constant may be set to false
// ADC DMA channels and DMA sources
#define ADC0_DMA_CHANNEL_ADCONTROL 0 // DMA channel used for AD control
#define ADC0_DMA_CHANNEL_ADCONTROL_MUX_SRC 54 // DMA MUX source used for AD0 control
#define ADC0_DMA_CHANNEL_ADCREAD 1 // DMA channel used for AD read
#define ADC0_DMA_CHANNEL_ADCREAD_MUX_SRC 40 // DMA MUX source used for AD0 read
#define ADC0_DMA_IRQChannel CAT3(DMA,ADC0_DMA_CHANNEL_ADCREAD,_IRQn)
#define ADC0_DMA_IRQHandler CAT3(DMA,ADC0_DMA_CHANNEL_ADCREAD,_IRQHandler)
#define ADC1_DMA_CHANNEL_ADCONTROL 4 // DMA channel used for AD1 control
#define ADC1_DMA_CHANNEL_ADCONTROL_MUX_SRC 55 // DMA MUX source used for AD1 control
#define ADC1_DMA_CHANNEL_ADCREAD 5 // DMA channel used for AD1 read
#define ADC1_DMA_CHANNEL_ADCREAD_MUX_SRC 41 // DMA MUX source used for AD1 read
#define ADC1_DMA_IRQChannel CAT3(DMA,ADC1_DMA_CHANNEL_ADCREAD,_IRQn)
#define ADC1_DMA_IRQHandler CAT3(DMA,ADC1_DMA_CHANNEL_ADCREAD,_IRQHandler)
#define ADC2_DMA_CHANNEL_ADCONTROL 6 // DMA channel used for AD2 control
#define ADC2_DMA_CHANNEL_ADCONTROL_MUX_SRC 56 // DMA MUX source used for AD2 control
#define ADC2_DMA_CHANNEL_ADCREAD 7 // DMA channel used for AD2 read
#define ADC2_DMA_CHANNEL_ADCREAD_MUX_SRC 42 // DMA MUX source used for AD2 read
#define ADC2_DMA_IRQChannel CAT3(DMA,ADC2_DMA_CHANNEL_ADCREAD,_IRQn)
#define ADC2_DMA_IRQHandler CAT3(DMA,ADC2_DMA_CHANNEL_ADCREAD,_IRQHandler)
#define ADC3_DMA_CHANNEL_ADCONTROL 8 // DMA channel used for AD3control
#define ADC3_DMA_CHANNEL_ADCONTROL_MUX_SRC 57 // DMA MUX source used for AD3 control
#define ADC3_DMA_CHANNEL_ADCREAD 9 // DMA channel used for AD3 read
#define ADC3_DMA_CHANNEL_ADCREAD_MUX_SRC 43 // DMA MUX source used for AD3 read
#define ADC3_DMA_IRQChannel CAT3(DMA,ADC3_DMA_CHANNEL_ADCREAD,_IRQn)
#define ADC3_DMA_IRQHandler CAT3(DMA,ADC3_DMA_CHANNEL_ADCREAD,_IRQHandler)