2013-01-04 12:21 PM
I need to sample 2 ADC channels at a rate of 200KHz I also need to sample another ADC channel at a rate of kHz.
Currently I use the same ADC (ADC3) for all 3 channels.During the initialization, I supply the DMA with a buffer (of 9000 longs) and I set ADC_NbrOfConversion=3.Everything looks fine (the whole buffer is filled)The problem is that all channels are sampled with the same rate. Is there a way to sample the first two with a high rate and the other channel with lower rate? Is there a way of using different buffers (one buffer for the fast channels 1,2 and another buffer for the slow channel 3)?When I look at the buffer I see:Buff[0] = adc1_valBuff[1] = adc2_valBuff[2] = adc3_valBuff[3] = adc1_valBuff[4] = adc2_valBuff[5] = adc3_valI would like to see a buffer like that: Buff[0] = adc1_valBuff[1] = adc2_valBuff[2] = adc1_valBuff[3] = adc2_valBuff[4] = adc1_valBuff[5] = adc2_valBuff[6] = adc3_valBuff[7] = adc1_valBuff[8] = adc2_valBuff[9] = adc1_valBuff[10] = adc2_valBuff[11] = adc1_valBuff[12] = adc2_valBuff[13] = adc3_valOr two different buffers.Here is the code i use to initialize the ADC:void ADC_HW_Init(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&val[0]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = 9000 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOF, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 3; ADC_InitStructure.ADC_ExternalTrigConv = 0; ADC_Init(ADC3, &ADC_InitStructure); ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 2, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 3, ADC_SampleTime_56Cycles); ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); } #stm32-adc #stm32-adc #stm32-adc #stm32-adc #stm32-adc #atm32-adc2013-01-04 12:40 PM
May be you should use a different ADCx unit, or inject slower requests periodically, though I think that will complicate the buffer management.
2013-01-04 09:11 PM
I cannot see how you can achieve this using DMA.
One solution would be to use interrupts and manage the data storage in the ISR.2013-01-05 05:11 AM
Or, for simplicity, you could just drop some results of the third channel, using every second, third or fourth.
The sample rate for ch3 could than only be a fraction of that for ch1+2, though.2013-01-06 02:02 AM
Thanks for the answers. Since I brought it up, I got some new requirements:
1. It is OK to use 2 ADCs (one for the fast channel and another for the other two slow channels)2. All data has 8bit resolution and not 12 as I previously configured.My system clock is 120MHz and my biggest issue now is to configure the ADC to a sample rate of 200 KHz.I configured these parameters:Div = 8ADC_SampleTime_15Cycles = 15ADC_delay_between_2_sampling_phases = 5 Are these correct? Will the code bellow do the job?void ADC_HW_Init(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOF, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_2; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&val[0]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BUFF_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOF, &GPIO_InitStructure); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_InitStructure.ADC_ExternalTrigConv = 0; ADC_Init(ADC3, &ADC_InitStructure); ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 1, ADC_SampleTime_15Cycles); ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); }2013-01-07 01:06 AM
Not sure which derivate you use, but 120MHz suggests F2xx or F4xx.
My system clock is 120MHz and my biggest issue now is to configure the ADC to a sample rate of 200 KHz.The best solution is to use a timer to trigger the ADC. You will need to set the ADC_ExternalTrigxxx entries correctly for the initialisation, and setup the timer. I don't have an appropriate F2 example at hand, but there should be some in the FW lib.
2013-01-07 08:39 AM
Thanks for the reply.
You are right I forgot to mention I use the F2xx on the STM3220G-EVAL.I know I can use timer as an external trigger but power consumption is a critical issue in this project and to save as much power as I can I prefer not using hardware blocks that I can do without.Are you saying there is no way to configure the ADC to work at 200KHz at all?What are these parameters for? ADC_Prescaler_DivxADC_SampleTime_xCyclesADC_delay_between_2_sampling_phases2013-01-07 09:07 AM
Are you saying there is no way to configure the ADC to work at 200KHz at all?
At least I think it is not the intended way, and IMHO an inconvenient and ponderous method. The trigger timing itself is not part of the ADC functionality, instead you have options for external triggers, such as timers. I often used a SW trigger from the Systick handler, which is not really a recommended option for a 200kHz rate. And I'm sure one timer unit will not make much difference for the power consumption. Scaling down the system clock to 100/80/60 MHz would save much more.ADC_Prescaler_Divx
ADC_SampleTime_xCycles
ADC_delay_between_2_sampling_phases
The meaning is documented in the reference manual, but citing from memory:ADC_Prescaler_Divx sets the prescaler for the ADC clock generation, basically the speed of the SA sequencer.ADC_SampleTime_xCycles is the time (number of cycles) the S&H stage is sensing the input voltage.ADC_delay_between_2_sampling_phases is an additional, configurable delay between two samplings. I came across that only in dual/triple ADC modes yet.
2013-01-07 11:12 AM
I'd look to pace the ADC from one of the TIM units. If you prescale down to 1MHz (say), the bulk of the high frequency consumption would be in the prescaler and not the whole TIM unit. Consider also a timer on APB1, and keep the speed of it down.
In terms of power consumption you want to watch the pin drivers, especially ones outputting clocks or periodic signals. Use the lowest frequency slew rate settings. As fm suggests look at cutting the clocking down, figure out how much work there is to do, and the clock required to meet dead-lines. Look at the power envelope, and use WFI went idling.2013-01-08 03:40 AM
Thanks,
First of all I use the __WFI() in the vApplicationIdleHook() function of FreeRTOS.Now, about the ADC + timer, what would be better to create a timer interrupt and call ADC_SoftwareStartConv(ADCx) from the timer ISR (may not be as accurate due to a clock shift in a multi tasking environment) or to set the ADC to work with an external trigger (probably more accurate but harder to verify)?Does anyone have an example of how to connect a timer to an ADC (sorry, but I need to provide a working solution by the end of this week)?