Hi, I am using a K20.
I want to set up the ADC so that I can use DMA to load TCD as well as for writing the ADC results to SRAM (i.e. utilizing linking of channels).
Specifically I have a array of 3 DMA TCDs = used to load ADC0_SC1A, with an array of 3 16 bit words for the ADC results.
I have tried following the "Using DMA to Emulate ADC Flexible Scan Mode on Kinetis K Series" app note without success.
What I am seeing is that I get two ADC interrupts (used only for debug) before I get the DMA interrupt signifying the end of my major loop.
I have 3 ADC result values in my SRAM buffer. I would assume I would get 3 ADC interrupts. One for each of the TCD mux values loaded into the ADC0_SC1A register.
DMA0_TCD0_CSR - 0x00 indicating that it is NOT done
DMA0_TCD1_CSR - 0x82 indicating that the major loop is done
DMA0_TCD0_CITER_ELINKYES = 0x0001 indicating I have one more TCD to load.
Looking at ADC0_SC1A = 65 (the second element in my MUX array)
My code is below. Any insight would be welcomed.
volatile unsigned short ui_adc_result[NUM_CHANNELS] = {0};
volatile unsigned char uc_adc_mux[NUM_CHANNELS] = {
64,
65,
66
};
void ADCSetup_InitADC(void)
{
// ADC 0:
// enable clock gate control for ADC 0
SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;
NVICISER1 |= (1<<25); // Set Enable Register
NVICICPR1 |= (1<<25); // Clear Pending Register
NVICIP57 = 0x10;
// Normal Power
// Divide by one
// Short Sample Time
// 12 bit conversion
// Bus clock divided by 2--12.5 MHz
ADC0_CFG1 = 0x0005;
// Select ADC Mux A*
// Asynchronous Clock Output disabled
// Normal conversion
// shortest sample time selected*
ADC0_CFG2 = 0x0003;
// Software Trigger selected
// Compare fx disabled
// DMA enabled
// Voltage reference section is default*
ADC0_SC2 = 0x0004;
// Continuous Conversion disabled--i.e. do single conversion
// Hardware average disabled
ADC0_SC3 = 0;
// select channel--0x1F disables
// enable in timer interrupt
ADC0_SC1A = 0x1F;
// select channel--0x1F disables
// enable in timer interrupt
ADC0_SC1B = 0x1F;
// Programmable Gain Amplifier is disabled
ADC0_PGA = 0;
// enable clock gate control for DMA Mux
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
// enable clock gate control for DMA Module
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;
// Clear All Enable Error Interrupts
DMA_CEEI |= 0x40;
DMA_CERR |= 0x40;
//****************************************************************************
//**** DMA channel 0, use for Write ADC mux channel, from SRAM to ADC ********
//****************************************************************************
DMAMUX_CHCFG0 = 0x00;
// DMA source DMA Mux (54)
DMAMUX_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x36);
// SADDR is a 32 bit number
// New mux setting
DMA_TCD0_SADDR = (Uint32) &uc_adc_mux[0];
// SOFF is a signed 16 bit number
// Source address increment, adding "1"
DMA_TCD0_SOFF = 0x01;
// SLAST is signed 32 bit number
// Source address decrement after major loop complete
DMA_TCD0_SLAST = (Uint32)-3;
// DADDR is a 32 bit number
// SC1A is a 32 bit number with only the meaning only in the LSbyte
DMA_TCD0_DADDR = (Uint32) &ADC0_SC1A; // Destination address ADC0 mux selector
DMA_TCD0_DOFF = 0x00; // always the same destination--SC1A // Destination address increment, adding "0"
DMA_TCD0_DLASTSGA = 0x00; // always the same destination--SC1A // Destination address shift, go to back to [0]
DMA_TCD0_NBYTES_MLNO = 0x01; // No of bytes minor loop
DMA_TCD0_BITER_ELINKNO = 0x03; // Major loop step, 3 ADC channel are scanning
DMA_TCD0_CITER_ELINKNO = 0x03; // Major loop step, 3 ADC channel are scanning
// 0 = 8 bit
// 1 = 16 bit
// 2 = 32 bit
DMA_TCD0_ATTR = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0); // Source a destination size, 8bit
DMA_TCD0_CSR = 0x0000;
//****************************************************************************
//**** DMA channel 1, use for Read ADC result data, form ADC to SRAM *********
//****************************************************************************
NVICISER0 |= (1<<1); // Set Enable Register
NVICICPR0 |= (1<<1); // Clear Pending Register
NVICIP1 = 0x20; // Interrupt Priority--priority 0 is the highest, 15 is the lowest (Most Significant Nibble is priority)
DMAMUX_CHCFG1 = 0x00;
DMAMUX_CHCFG1 = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x28); // DMA source ADC0 (40)
DMA_TCD1_SADDR = (Uint32) &ADC0_RA; // Source address ADC0 result register
DMA_TCD1_SOFF = 0x00; // always the same source--ADC0_RA // Source address increment, adding "0"
DMA_TCD1_SLAST = 0x00; // always the same source--ADC0_RA // Source address decrements after major loop complete
DMA_TCD1_DADDR = (Uint32) &ui_adc_result[0]; // Destination address, ADC0 result buffer
DMA_TCD1_DOFF = 0x02; // Destination address increment, adding "+2"
DMA_TCD1_DLASTSGA = (Uint32) -6; // Destination address decrements after major loop complete
DMA_TCD1_NBYTES_MLNO = 0x02; // No of bytes minor loop, 16 bit ADC result
DMA_TCD1_BITER_ELINKNO = (DMA_BITER_ELINKNO_ELINK_MASK|0x0000|0x03); // Channel 0 Link, Channel 0, Major loop step 3
DMA_TCD1_CITER_ELINKNO = (DMA_CITER_ELINKNO_ELINK_MASK|0x03); // Channel 0 Link, Major loop step 3
DMA_TCD1_ATTR = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0); // Source a destination size, 16 bit
DMA_TCD1_CSR = DMA_CSR_INTMAJOR_MASK;
DMA_ERQ |= DMA_ERQ_ERQ1_MASK; // HW request enable
DMA_CINT = DMA_CINT_CINT(1); // Clear the interrupt flag for channel 1
}
__ramfunc void dma_ch1_isr( void )
{
DMA_CINT = DMA_CINT_CINT(1); // clear the interrupt flag for channel 1
}
volatile int adcIntCount = 0;
__ramfunc void adc0_isr( void )
{
adcIntCount++;
}
__ramfunc void Timers_isr( void )
{
if( DMA_INT == 0 )
DMA_SSRT = 0x01; // start DMA channel 0, which triggers another round of ADC readings
}
_