Using a timer, I measured my sample rate of my ADC at ~3Msps.
I am using a k60f120 board, which according to k60P144M120SF3, has a max ADC sampling rate of only ~800ksps.
Is it plausible that my ADC is reading that much faster than the rated speed, or am I doing something wrong?
I set my ADC to sample continuously and trigger DMA with the DMAEN flag. I am sampling with 12 bit resolution. The DMA just reads the ADC1_RA and writes to a buffer.
To time, I am using the MQX _time_get_ticks and _time_diff_microseconds by triggering a DMA major loop interrupt after 256 samples. I measure 85 microseconds for 256 samples ~= 3Msps. I am running in debug mode, not release mode, but I am not setting breakpoints.
已解决! 转到解答。
The fADCK must below 18Mhz for your 12bit ADC.
I think you can use the ADIV in ADCx_CFG1 to divide down your fADCK.
6 ADCK clock cycles is the subsequent sample time of your 12bit ADC, the total conversion time for all configurations is summarized in the equation below.(For more information you can refer the "37.4.5.5 Sample time and total conversion time" of K60P144M150SF3RM)
ConversionTime=SFCAdder+AverageNum*(BCT+LSTAdder+HSCAdder)
Hi Richert
I think the ADC conversion rate in k60P144M120SF3 is right, for 12-bit ADC the max conversion time is about 800ksps.
This can be calculated by using the equation in "37.4.5.5 Sample time and total conversion time" of K60P144M150SF3RM.
Also you can use ADC calculator tool to evaluate the ADC conversion rate of different configuration.
Each time the ADC sampling, you can observed voltage disturbances (voltage drops/peaks) at the ADC input. AN4373(Cookbook for SAR ADC Measurements)
You can get the waveforms obtained by oscilloscope like below:
By measure the time between each sampling , you can get the real conversion rate.
Thanks for pointing me to the sample time subsection.
I now suspect that I am operating at too high of a clock frequency. The default bus clock frequency is the system clock (50Mhz.). The max allowable clock frequency is 18Mhz. I think I have the ADC configured to take 6 ADCK clock cycles. The DMA requires 11 to read, I think. 50/17 ~= 3Mhz.
I guess if the clock is too fast, the ADC still works, but loses precision?
The fADCK must below 18Mhz for your 12bit ADC.
I think you can use the ADIV in ADCx_CFG1 to divide down your fADCK.
6 ADCK clock cycles is the subsequent sample time of your 12bit ADC, the total conversion time for all configurations is summarized in the equation below.(For more information you can refer the "37.4.5.5 Sample time and total conversion time" of K60P144M150SF3RM)
ConversionTime=SFCAdder+AverageNum*(BCT+LSTAdder+HSCAdder)
My code:
#define MEMORY_BUFFER_SIZE 256
#define MEM_BUF_T uint16_t
MQX_TICK_STRUCT tick_last;
unsigned int counter = 0;
uint32_t timer[20];
dma_ch0_isr(void *ptr){
bool overflow;
MQX_TICK_STRUCT tick_temp;
DMA_CINT = DMA_CINT_CINT(0);//clear interrupt flag
if(counter < 20){//should use semophore
_time_get_ticks(&time_temp);
timer[counter++] = _time_diff_microseconds(&tick_temp);
tick_last = tick_temp;
}
}
void MAIN_task(uint32_t initial_data){
MEM_BUF_T dma_dst[MEMORY_BUFFER_SIZE] = {0};
unsigned int index;
_time_get_ticks(&tick_last);
//enable clocks
SIM_SCGC6 |= SIM_SCGC6_DMAMUX0_MASK;
SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
_int_install_isr(16, dma_ch0_isr, NULL);
_bsp_int_init(16, 3, 0, TRUE);
ADC_SC2 = ADC_SC2_DMAEN_MASK;//DMA interrupt
ADC1_SC3 = ADC1_SC3_ADC0_MASK;//continuous
ADC1_CFG1 = ADC_CFG1_MODE(1);//12 bit
DMAMUX0_CHCFG0 = 0;//disable hardware DMA request while config
DMAMUX1_CHCFG0 = 0;
DMA_TCD0_SADDR = &ADC1_RA;//read from ADC
DMA_TCD0_SOFF = 0;
DMA_TCD0_SLAST = 0;
DMA_TCD0_DADDR = &dma_dst[0];//write to buffer
DMA_TCD0_DOFF = sizeof(MEM_BUF_T);//destination increment
DMA_TCD0_DLASTSGA = -sizeof(MEM_BUF_T) * MEMORY_BUFFER_SIZE;//reset addr
DMA_TCD0_NBYTES_MLNO = sizeof(MEM_BUF_T);//minor loop 2 bytes
DMA_TCD0_BITER_ELINKNO = MEMORY_BUFFER_SIZE;//256 iterations
DMA_TCD0_CITER_ELINKNO = MEMORY_BUFFER_SIZE;
DMA_TCD0_ATTR = DMA_ATTR_SSIZE(1) | DMA_ATTR_DSIZE(1);//2 bytes transfer size
DMA_TCD0_CSR = DMA_CSR_INTMAJOR_MASK;//interrupt after major loop
DMA_ERQ |= DMA_ERQ_ERQ0_MASK;//allow ADC to trigger DMA
//ADC1 triggers DMA
DMAMUX0_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(41);
ADC1_SC1A = ADC_SC1_ADCH(20);//start reading ADC1 potentiometer
while(counter < 20){}
for(index = 1; index < 20; index++){printf(%4d: %6d\n\r", index, timer[index]);}
_mqx_exit(0);