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
}
_
Solved! Go to Solution.
Hi Brent,
How are you starting the first DMA transfer?
As far as I see, you want to perform the next:
DMA channel 0 transfer value of ADC channel to ADC_SC1A then the ADC will trigger the DMA channel 1 to store the results.
This configuration seems to be correct. But I see that you are using a timer ISR to write in the SSRT to trigger a DMA transfer by software.
But I believe you are starting channel 1, not 0.
Maybe you can try with:
DMA_SSRT = 0x00;
Hi Alejandro,
I am seeing something unexpected. I am trying to configure ADC1 to use DMA channels 6 and 7 along with DMA_MUX 6. DMA channel 6 points to a mux of ADC 1 channels. The MUX has 12 channels for ADC1. DMA channel 7 points to ADC1_RA.
What I am seeing when I get my DMA channel 7 interrupt is the following (see inserted screen shot of DMA registers below):
DMA_TCD7_CSR = 0x82 => GOOD – MAJOR COMPLETE AND GET INTERRUPT
DMA_TCD6_CSR = 0x00 => BAD, DID NOT INDICATE MAJOR WAS COMPLETE, EXPECTING 0x80
DMA_TCD0_CSR = 0x80 => WHY IS THIS UPDATED??? THIS IS SAYING DMA channel 0 completed a MAJOR LOOP I DID NOT CONFIGURE THIS
I am not sure why anything is happening on DMA channel 0?? I am not configuring it at all. My configuration of ADC1 and DMA channels/MUX is below:
//************************************************************************* | ||
// configure ADC1 | ||
//************************************************************************* | ||
// enable clock gate control for ADC1 | ||
SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK; |
// set up the ADC1 interrupt | ||||
// BAW only used for debug | ||||
NVICISER1 |= (1<<26); | // Set Enable Register | |||
NVICICPR1 |= (1<<26); | // Clear Pending Register | |||
NVICIP58 = 0x10; | ||||
// Normal Power | ||||
// Divide by one | ||||
// Short Sample Time | ||||
// 12 bit conversion | ||||
// Bus clock divided by 2--12.0 MHz | ||||
ADC1_CFG1 = 0x0005; |
// Select ADC Mux A* | |
// Asynchronous Clock Output disabled | |
// Normal conversion | |
// shortest sample time selected* | |
ADC1_CFG2 = 0x0003; | |
// Software Trigger selected | |
// Compare fx disabled | |
// DMA enabled | |
// Voltage reference section is default* | |
ADC1_SC2 = 0x0004; | |
// Continuous Conversion disabled--i.e. do single conversion | |
// Hardware average disabled | |
ADC1_SC3 = 0; |
// select channel--0x1F disables (Chapter 3 in RM: 3.7.1.3.1.1 for 64 pin package) | |||||
ADC1_SC1A = 0x1F; |
// select channel--0x1F disables (Chapter 3 in RM: 3.7.1.3.1.1 for 64 pin package) | |||||
ADC1_SC1B = 0x1F; |
// Programmable Gain Amplifier is disabled | |
ADC1_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; |
DMA_CEEI |= 0x40; | |
DMA_CERR |= 0x40; | |
//************************************************************************* | |
//**** DMA channel 6, use for Write ADC mux channel, from SRAM to ADC ***** | |
//************************************************************************* | |
DMAMUX_CHCFG6 = 0x00; | |
// DMA source DMA Mux (60) | |
DMAMUX_CHCFG6 = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x3C); | |
// SADDR is a 32 bit number | |
// New mux setting | |
DMA_TCD6_SADDR = (Uint32) &uc_adc_mux2[1]; |
// SOFF is a signed 16 bit number | |
// Source address increment, adding "1" | |
DMA_TCD6_SOFF = 0x01; |
// SLAST is signed 32 bit number | |
// Source address decrement after major loop complete | |
DMA_TCD6_SLAST = (Uint32) (-NUM_CHANNELS+1); |
// DADDR is a 32 bit number | ||
// SC1A is a 32 bit number with only the meaning only in the LSbyte | ||
DMA_TCD6_DADDR = (Uint32) &ADC1_SC1A; // Destination address ADC1 mux selector | ||
DMA_TCD6_DOFF = 0x00; | // always the same destination--SC1A // Destination address increment, adding "0" | |
DMA_TCD6_DLASTSGA = 0x00; // always the same destination--SC1A // Destination address shift, go to back to [0] |
DMA_TCD6_NBYTES_MLNO = 0x01; // No of bytes minor loop | |||
DMA_TCD6_BITER_ELINKNO = (NUM_CHANNELS-1); // Major loop step, 3 ADC channel are scanning | |||
DMA_TCD6_CITER_ELINKNO = (NUM_CHANNELS-1); // Major loop step, 3 ADC channel are scanning | |||
// 0 = 8 bit | |||
// 1 = 16 bit | |||
// 2 = 32 bit | |||
DMA_TCD6_ATTR = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0); // Source a destination size, 8bit | |||
DMA_TCD6_CSR = 0x0000; | |||
//************************************************************************* | |||
//**** DMA channel 7, use for Read ADC result data, form ADC to SRAM ****** | |||
//************************************************************************* | |||
NVICISER0 |= (1<<7); | // Set Enable Register | ||
NVICICPR0 |= (1<<7); | // Clear Pending Register | ||
NVICIP7 = 0x20; | // Interrupt Priority--priority 0 is the highest, 15 is the lowest (Most Significant Nibble is priority) |
DMAMUX_CHCFG7 = 0x00; | ||
DMAMUX_CHCFG7 = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x29); // DMA source ADC1 (41) | ||
DMA_TCD7_SADDR = (Uint32) &ADC1_RA; // Source address ADC1 result register | ||
DMA_TCD7_SOFF = 0x00; | // always the same source--ADC1_RA // Source address increment, adding "0" | |
DMA_TCD7_SLAST = 0x00; | // always the same source--ADC1_RA // Source address decrement after major loop complete |
DMA_TCD7_DADDR = (Uint32) &ui_adc_result2[0]; // Destination address, ADC1 result buffer | |
DMA_TCD7_DOFF = 0x02; // Destination address increment, adding "+2" |
DMA_TCD7_DLASTSGA = (Uint32) -(NUM_CHANNELS*2); // Destination address decrement after major loop complete |
DMA_TCD7_NBYTES_MLNO = 0x02; // No of bytes minor loop, 16 bit ADC result |
DMA_TCD7_BITER_ELINKNO = (DMA_BITER_ELINKNO_ELINK_MASK|0x0000|NUM_CHANNELS); // Channel 0 Link, Channel 0, Major loop step NUM_CHANNELS | |
DMA_TCD7_CITER_ELINKNO = (DMA_CITER_ELINKNO_ELINK_MASK|NUM_CHANNELS); // Channel 0 Link, Major loop step NUM_CHANNELS | |
DMA_TCD7_ATTR = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1); // Source a destination size, 16 bit |
DMA_TCD7_CSR = DMA_CSR_INTMAJOR_MASK; |
DMA_ERQ |= DMA_ERQ_ERQ7_MASK; // HW request enable | ||
DMA_CINT = DMA_CINT_CINT(7); | // Clear the interrupt flag for channel 7 | |
DMA_CINT = DMA_CINT_CINT(7); | // Clear the interrupt flag for channel 7 |
}
Hi Brent,
How are you starting the first DMA transfer?
As far as I see, you want to perform the next:
DMA channel 0 transfer value of ADC channel to ADC_SC1A then the ADC will trigger the DMA channel 1 to store the results.
This configuration seems to be correct. But I see that you are using a timer ISR to write in the SSRT to trigger a DMA transfer by software.
But I believe you are starting channel 1, not 0.
Maybe you can try with:
DMA_SSRT = 0x00;
Thank you Alejandro.