2015-04-29 02:18 PM
Dear Community,
I’ve investigated the ADC of the STM32L100RC (DISCO-Board) in continuous and in the triggered mode.In continuous mode I was able to reach a sample frequency of ~300 kHz which I investigated experimentally by connecting the ADC input with an RF Generator and monitoring 100 bytes of sampled data via UART as a graph on my PC (some kind of oscilloscope) . I noticed artifacts while sampling in the continuous mode which I didn’t observed in the triggered mode. I would be very happy if someone could either found a mistake in my code or maybe confirm that that the STM32L100RC ADC produces artifacts if operated in continuous mode.
Here is some code which I combined from examples given in the SPL.
uint16_t ADCBuffer[200];
void
Timer2enable() {
//NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//Timer
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 0x01;
TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
//TIM_TRGOSource_Update); // Copied from ST Form ''CLIVE1''
TIM_Cmd(TIM2, ENABLE);
//TIM_IT_Update Event
//TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //just for checking the timer is working as expected
};
void
ADC_IN18_DMA_INIT() {
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//DMA Interupt
// Enable DMA1 clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//DMA1 channel1 configuration
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCBuffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize =
sizeof
(ADCBuffer);
//buffersize
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//Memory will be incrementet-> yes
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//DMA_Mode_Normal; //
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// Enable DMA1 channel6 IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//DMA_IT_TC: Transfer complete interrupt mask
//DMA_IT_HT: Half transfer interrupt mask
//DMA_IT_TE: Transfer error interrupt mask
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
// Configure PB.12 (ADC Channel18) in analog mode
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
//PB12 --> ADC_IN18
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//GPIOSpeed ??
// Enable ADC1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// ADC1 configuration
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
//enable for conti - mode
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
//enable for conti - mode
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
//ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
//Trigger
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_18, 1, ADC_SampleTime_4Cycles);
// Enable the request after last transfer for DMA Circular mode
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
// Enable ADC1 DMA
ADC_DMACmd(ADC1, ENABLE);
// Enable ADC1
ADC_Cmd(ADC1, ENABLE);
// Wait until the ADC1 is ready
while
(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET) {}
// Start ADC1 Conversion
ADC_SoftwareStartConv(ADC1);
}
void
DMA1_Channel1_IRQHandler() {
int
count = 99;
ADC_Cmd(ADC1, DISABLE);
//ADC stop
//Send Sync
fputc_loc(0);
fputc_loc(10);
fputc_loc(100);
fputc_loc(101);
fputc_loc(103);
fputc_loc(7);
while
(count < 200) {
fputc_loc(ADCBuffer[count]);
// in conti- mode the first 100bytes are full of artifacts - I dont know why.
count++;
}
while
(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET){};
//GPIOC->ODR ^= GPIO_Pin_9; //just for checking the handler is working
ADC_Cmd(ADC1, ENABLE);
while
(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET) {}
ADC_SoftwareStartConv(ADC1);
//DMA1_IT_GL1: DMA1 Channel1 global interrupt.
DMA_ClearITPendingBit(DMA1_IT_GL1);
}
void
main() {
GPIO_outInit();
Timer2enable();//disable forcontinuousmode
//EnableTimerInterrupt();
ADC_IN18_DMA_INIT();
//START ADC (PB12)
while
(1);
}
2015-04-30 07:26 AM
Not sure what you mean by ''artifacts''. The DMA starts filling regular conversion values starting at location 0 in the buffer, and fills up to location 199, so there will be something in the first 100 locations also.
Read the ADC section describing DMA usage in the Reference Manual. There is no mention of being able to use DMA for injected channels. Injected conversions have 4 dedicated registers, and the results have to be read directly, i.e., no DMA. Cheers, Hal2015-05-03 07:43 AM
Thank you very much for responding.
“Artifact�? means a series of e.g. two spikes in the data stream I receive from the controller – however now I doubt this artifact is generated by the UART transmission itself – however I haven’t found yet why this is happening. Probably my software on the PC is not working correctly which I use to visualize the data.
2015-05-03 05:19 PM
DMA_InitStructure.DMA_BufferSize =
sizeof
(ADCBuffer);
//buffersize
It should be
sizeof(ADCBuffer) / sizeof(ADCBuffer[0])