2014-01-11 10:31 AM
I've a small query about programming ADC in regular dual simultaneous mode. I'm using stmf4 discovery board.Though I've configured ADC1 channel 11(PC1) and ADC2 channel 12(PC2) in this mode using dma. But I've to constantly monitor the 2 ADC values and when they exceed certain threshold I need to store there values in buffer and then send them through usb. I've tested this job with single adc value without using dma. There is no problem there. But since using dma the cpu relinquishes, the job is getting messed up. Kindly go through the following code where I've tried to simply store the 2 adc values in regular simultaneous mode without using dma. The code runs. But I'm not sure if this program at all samples the 2 ADCs simultaneously. Kindly someone tell me if it works as I intend to do. If not then is there any way out to do dual adc simultaneous sampling without dma.
-----------------------------------------------------------------------------------------------#define ADC_CCR_ADDRESS ((uint32_t)0x40012308)/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*//* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/__IO uint16_t aADCDualConvertedValue[2];/* Private function prototypes -----------------------------------------------*/////static void DMA_Config(void);static void GPIO_Config(void);static void ADC1_CH11_Config(void);static void ADC2_CH12_Config(void);int adc_convert_adc1(void);int adc_convert_adc2(void);/* Private functions ---------------------------------------------------------*//** * @brief Main program * @param None * @retval None */int main(void){ ADC_CommonInitTypeDef ADC_CommonInitStructure; /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup files (startup_stm32f40_41xxx.s/startup_stm32f427_437xx.s/startup_stm32f429_439xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f4xx.c file */ /* Enable peripheral clocks *************************************************/ ////RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); /* DMA2 Stream0 channel0 configuration **************************************/ ////DMA_Config(); /* ADCs configuration ------------------------------------------------------*/ /* Configure ADC Channel10, 11, 12 pin as analog input */ GPIO_Config(); /* ADC Common Init */ ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult; 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); /* ADC1 regular channels 11 configuration */ ADC1_CH11_Config(); /* ADC2 regular channels 12 configuration */ ADC2_CH12_Config(); /* Enable DMA request after last transfer (Multi-ADC mode) */ ////ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); /* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE); /* Enable ADC2 */ ADC_Cmd(ADC2, ENABLE); /* Start ADC1 Software Conversion */ ADC_SoftwareStartConv(ADC1); while (1) { aADCDualConvertedValue[0] = adc_convert_adc1(); aADCDualConvertedValue[1] = adc_convert_adc2(); }}/** * @brief ADC1 regular channels 10 and 11 configuration * @param None * @retval None */static void ADC1_CH11_Config(void){ ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); /* ADC1 regular channels 10, 11 configuration */ //ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_480Cycles);}/** * @brief ADC2 regular channels 11, 12 configuration * @param None * @retval None */static void ADC2_CH12_Config(void){ ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC2, &ADC_InitStructure); /* ADC2 regular channels 11, 12 configuration */ //ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles); ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 1, ADC_SampleTime_480Cycles);}int adc_convert_adc1(){ ADC_SoftwareStartConv(ADC1);//Start the conversion while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion return ADC_GetConversionValue(ADC1); //Return the converted data}int adc_convert_adc2(){ ADC_SoftwareStartConv(ADC2);//Start the conversion while(!ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC));//Processing the conversion return ADC_GetConversionValue(ADC2); //Return the converted data}static void GPIO_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; /* ADC Channel 10 -> PC0 ADC Channel 11 -> PC1 ADC Channel 12 -> PC2 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOC, &GPIO_InitStructure);}-----------------------------------------------------------------------------------------------Thanks,Tapu2014-01-11 05:01 PM
Wouldn't you want to read the value from the CDR (Common Data Register), like the DMA would have?
2014-01-12 07:02 AM
yes, I thought about that too, but in reference manual I found that it is written''''A 32-bit DMA transfer request is generated (if DMA[1:0] bits in the ADC_CCR register
are equal to 0b10). This request transfers the ADC2 converted data stored in the upperhalf-word of the ADC_CDR 32-bit register to the SRAM and then the ADC1 converteddata stored in the lower half-word of ADC_CCR to the SRAM''''. When I read CDR content I found them to be zero(when I'm not using DMA) and ADCx_DR contains proper values. But how can I be sure that regular simultaneous conversion is taking place? When I just changed ''ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult'' to ''ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent'' still the conversions are taking place properly...I'm sampling the ADC at a low rate.2014-01-12 07:43 AM
The slowness of your conversion doesn't foreclose the use of DMA.
You access both DR/EOC independently, and you have continuous mode enabled, it's unlikely in these circumstances that the measurements will be aligned in the time domain. You need the values to be read from both ADC in an atomic fashion. Consider using a timer to trigger at your ''slow'' rate, whatever that is, or using a timer and DMA to simply automate that process, and interrupt once the transfer is complete, and you have measurements in hand. Try to think about doing things in an optimal way for the hardware, not the most awkward, and non-optimal fashion.