2016-05-31 07:38 AM
The task is to measure three phase power. ADC1 measures voltage, ADC2 measures current. Here is the adc configuration routine:
static void ADC_Config(void){ ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; /* Enable ADCx, DMA and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RCC_AHB1PeriphClockCmd(ADCx1_CHANNEL_GPIO_CLK, ENABLE); RCC_AHB1PeriphClockCmd(ADCx2_CHANNEL_GPIO_CLK, ENABLE); RCC_APB2PeriphClockCmd(ADCx1_CLK, ENABLE); RCC_APB2PeriphClockCmd(ADCx2_CLK, ENABLE); /* Enable the DMA2 Stream0 Global Interrupt (to handle the Transfer Complete Interrupt TCIF) */ NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* Modify the WAKEUP_BUTTON_EXTI_IRQn Interrupt Preemption Priority */ NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SW_VRMS_IRQ_PRIOR; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* DMA2 Stream0 channel15 configuration **************************************/ DMA_InitStructure.DMA_Channel = DMA_CHANNELx1; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_DR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADCxConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = DMA_BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 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(DMA_STREAMx1, &DMA_InitStructure); DMA_Cmd(DMA_STREAMx1, ENABLE); /* Configure ADC1 Channel15 pin as analog input ******************************/ GPIO_InitStructure.GPIO_Pin = ADCx1_GPIO_PIN_1_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADCx1_GPIO_PORT_1_2, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ADCx1_GPIO_PIN_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADCx1_GPIO_PORT_3, &GPIO_InitStructure); /* Configure ADC2 Channel15 pin as analog input ******************************/ GPIO_InitStructure.GPIO_Pin = ADCx2_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(ADCx2_GPIO_PORT, &GPIO_InitStructure); /* ADC Common Init **********************************************************/ ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;// ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_12Cycles; ADC_CommonInit(&ADC_CommonInitStructure); /* ADC1 Init ****************************************************************/ 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_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = N_CONV; ADC_Init(ADCx1, &ADC_InitStructure); // ADC_TempSensorVrefintCmd(ENABLE); /* ADC1 regular channel15 configuration **************************************/ ADC_RegularChannelConfig(ADCx1, ADC1_CHANNEL_1, 1, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADCx1, ADC1_CHANNEL_2, 2, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADCx1, ADC1_CHANNEL_3, 3, ADC_SampleTime_480Cycles); /* ADC2 Init ****************************************************************/ 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_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = N_CONV; ADC_Init(ADCx2, &ADC_InitStructure); /* ADC1 regular channel15 configuration **************************************/ ADC_RegularChannelConfig(ADCx2, ADC2_CHANNEL_1, 1, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADCx2, ADC2_CHANNEL_2, 2, ADC_SampleTime_480Cycles); ADC_RegularChannelConfig(ADCx2, ADC2_CHANNEL_3, 3, ADC_SampleTime_480Cycles); // ADC_TempSensorVrefintCmd(ENABLE);// /* Enable DMA request after last transfer (Single-ADC mode) */// ADC_DMARequestAfterLastTransferCmd(ADCx1, ENABLE);/* Enable DMA request after last transfer (Multi-ADC mode) */ ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); // /* Enable ADC1 DMA */// ADC_DMACmd(ADCx1, ENABLE); /* Enable ADC1 */ ADC_Cmd(ADCx1, ENABLE); /* Enable ADC2 */ ADC_Cmd(ADCx2, ENABLE); DMA_ITConfig(DMA_STREAMx1,DMA_IT_TC,ENABLE);}When I N_CONV=1 and I connect the first phase only, then it's working nice. Then if I connect the second or third phase with N_CONV=1, but ADC2_CHANNEL_1 changed to _2 or _3 on first place and all other commented, then it's working fine. The N_CONV=3 version is however not working i.e. the measured values are all wrong. Are the configuration done correctly?2016-05-31 10:11 AM
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; // NO
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; // NO It is not triggering, so nothing will have alignment to anything, just ADC1 to ADC2 for the specific sample The peripheral address needs to be the common data register, no define visible. The peripheral address does NOT increment The memory address should increment I'd use Word wide peripheral and memory access. Ie pulls 2x 16-bit half words from common, stuffs 2x 16-half words into array, size/definition not visible. I've posted dual mode examples to forum, review.2016-06-01 12:18 AM
Thank you for the answer.
About the first point ''It is not triggering, so nothing will have alignment to anything, just ADC1 to ADC2 for the specific sample'' I think exactly this is the main problem. Could you clarify or point out some reading articles that are explaining your point.Thanks.2016-06-01 01:06 AM
I have done some more tests and when DMA_BUFFER_SIZE=1, then nothing is alligned, when DMA_BUFFER_SIZE=3 it's alligned, but I want to process each dual sample in real time.
I realized that you probably meant that the external trigger is disabled, but that's ok because I don't have any external trigger. So the big question is why the results are not ordered. Here is the IRQ:void DMA2_Stream0_IRQHandler(void) { static uint8_t first_zero[Ph_N]={0}; static int32_t unscaled_voltage[Ph_N], unscaled_voltage_old[Ph_N], unscaled_current[Ph_N],unscaled_current_old[Ph_N]; static int32_t unscaled_centered_v[Ph_N], unscaled_centered_i[Ph_N]; static uint8_t current_phase=0; if(DMA_GetITStatus(DMA_STREAMx1,DMA_IT_TCIF0)!=RESET) { DMA_ClearITPendingBit(DMA_STREAMx1,DMA_IT_TCIF0|DMA_IT_HTIF0); unscaled_current_old[current_phase]=unscaled_current[current_phase]; unscaled_voltage_old[current_phase]=unscaled_voltage[current_phase]; unscaled_voltage[current_phase] = (uhADCxConvertedValue[0]&ADC_CDR_DATA1)<<W; unscaled_current[current_phase] = (uhADCxConvertedValue[0]&ADC_CDR_DATA2); unscaled_centered_v[current_phase]=(V0[current_phase]>>W)-(unscaled_voltage[current_phase]>>W); unscaled_centered_i[current_phase]=(I0[current_phase]>>W)-(unscaled_current[current_phase]>>W); if(first_zero[current_phase]==1) { S_v[current_phase]=S_v[current_phase]+(unscaled_centered_v[current_phase]*unscaled_centered_v[current_phase]); S_i[current_phase]=S_i[current_phase]+(unscaled_centered_i[current_phase]*unscaled_centered_i[current_phase]); S_p[current_phase]=S_p[current_phase]+(unscaled_centered_v[current_phase]*unscaled_centered_i[current_phase]); Nsamp[current_phase]++; } I0[current_phase]=I0[current_phase]-unscaled_centered_i[current_phase]; V0[current_phase]=V0[current_phase]-unscaled_centered_v[current_phase]; if((unscaled_current[0]<=I0[0] && unscaled_current_old[0]>I0[0]) || (unscaled_current[0]>=I0[0] && unscaled_current_old[0]<I0[0])) { if((unscaled_current[0]>=I0[0] && unscaled_voltage[0]<V0[0]) || (unscaled_current[0]<=I0[0] && unscaled_voltage[0]>V0[0])) { Q_sign=-1; } else { Q_sign=1; } } if((unscaled_voltage[0]<=V0[0] && unscaled_voltage_old[0]>V0[0]) || (unscaled_voltage[0]>=V0[0] && unscaled_voltage_old[0]<V0[0])) { if(first_zero[current_phase]) { //trigger the sw interrupt EXTI_GenerateSWInterrupt(EXTI_Line0); } else { first_zero[current_phase]=1; S_v[current_phase]=0; S_i[current_phase]=0; S_p[current_phase]=0; Nsamp[current_phase]=0; steady_Nsamp[current_phase]=Nsamp[current_phase]*P; } } irq_phase=current_phase; current_phase=(current_phase+1)%Ph_N; }}2016-06-01 03:25 AM
Hi georgiev.zdravko,
I recommend you to take a look to '' ADC_DualModeInterleaved'' in . I think it is the most suitable for your need. Example at thi path: STM32Cube_FW_F4_V1.12.0\Projects\STM324xG_EVAL\Examples\ADC\ADC_DualModeInterleaved -Hannibal-