2018-03-11 03:41 PM
Hi !
I'm excited to join the ST community!
I hope someone can solve my problem.
I am experiencing timing issues when converting an ADC.
Here is the configuration of my project:
- The timer 3 is configured in center aligned mode, Trigger output ENABLE on update events, PWM signal generation
- ADC: Scan conversion mode enabled, DMA in continuous request ENABLE, NB of conversion: 4, EOC: flag at the end of all conversion.
External trigger source Timer 3 out event on rising edge.
What I want to do: I want to start the conversion of 4 channels(scan conversion) when the timer 3 is in the middle of the PWM pulse.
My problem: Actually my conversion seems well started on rising edge but also on falling edge.
I join screenshots of the oscilloscope illustrating the problem.
In blue it is the PWM signal.
In red is the time spent in the DMA2_Stream0_IRQhandler () function.
I do not understand two things about this capture: Why I do not fit in the DMA2_Stream0_IRQhandler () function in the middle of the high level and the low level because I am in the center aligned mode and that normally the UEV (update event) should be done
between.
Second remark it seems that the conversion is done on high level and on low level while I set externa trigger conversion conversion edge only on rising on rising edge ....
Here's another screenshot that shows the PWM signal and the time spent in the HAL_ADC_ConvCpltCallback () function.
Again we see that the conversions are on a rising and falling front.
I think I have to make a mistake in configuring my DMA ....
Here is the configuration generated from Cube MX:
[CODE]
/* ADC1 init function */
static void MX_ADC1_Init(void){ ADC_ChannelConfTypeDef sConfig; /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 4; hadc1.Init.DMAContinuousRequests = ENABLE; hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_7; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_14; sConfig.Rank = 2; sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_15; sConfig.Rank = 3; sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_5; sConfig.Rank = 4; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }}/* TIM3 init function */
static void MX_TIM3_Init(void){TIM_SlaveConfigTypeDef sSlaveConfig;
TIM_MasterConfigTypeDef sMasterConfig; TIM_OC_InitTypeDef sConfigOC;htim3.Instance = TIM3;
htim3.Init.Prescaler = 0; htim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; htim3.Init.Period = 1999; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim3) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{ _Error_Handler(__FILE__, __LINE__); }sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
sSlaveConfig.InputTrigger = TIM_TS_ITR3; if (HAL_TIM_SlaveConfigSynchronization(&htim3, &sSlaveConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); }HAL_TIM_MspPostInit(&htim3);
}
/**
* Enable DMA controller clock */static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);}[/CODE]
2018-03-11 03:56 PM
What is the expected duration of the 4 ADC conversions?
The DMA ISR is invoked at the end of them.
[EDIT]
It may perhaps confuse you that there are 2 conversions per PWM cycle - but then there are also 2 Update events you are using as TRGO->ADC conversion start per period, in the up-down (a.k.a. center-aligned) mode:
[/EDIT]
Btw., which STM32 are you using?
JW
2018-03-12 02:31 AM
First, thanks waclawek.jan for responding so quickly !
I'm using an STM32F413. HSE --> 84MHz
What I actually want to do is neither more nor less than what is described in the following picture :
I want to run a conversion cycle only in the middle of the high time of the PWM.
I understand that using UEV there are two events generated per PWM period.
Only I thought I would filter the first UEV using hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; but maybe I don't understand the TRIGCONVEDGE_RISING option.
Is there a better configuration to make this ?
2018-03-12 07:56 AM
I honestly don't know.
Try setting TRGO to compare event of some of the channels, and then set that channel's CCRx equal to ARR.
JW
2018-03-12 08:24 PM
I think Jan is correct. The Update Events occur at the center of the pwm Pulse (overflow event) and the center of the gaps (underflow event). Using your second scope trace....
The update events (green) are positioned as above.
Your 4 conversions take place over the intervals shown by the blue arrows, then followed by your EOC callbacks (red).
Do a test, shorten your adc conversion cycles to the minimum. The callbacks that currently look symmetric around the pwm pulse, will probably shift (not symmetric). The red pulse leading the pwm pulse will shift more to the center of the gap, and the lagging red pulse will shift to the center of the pulse. If shortened, your may finish inside the pwm pulse as you want.
Basically your sampling twice, once in the gap, and a second time starting at the pulse center, but the conversion don't finish inside the pwm pulse!
As Jan suggested, using the compare events, the events occur on the rising edge and following edges of the pwm. Rising compare will get you sampling in the pulse, but not centered on the pulse.
2018-03-12 08:52 PM
You could set you adc clk and conversion cycles, and calculate the period required for the 4 channels.
Then add CH4 on timer, with a pulse width equal to the conversion period.
Use the compare event from CH4 at the trigger.
One event will center the samples on the CH1-CH3 pulses.
But you will have a second trigger and conversion cycle to deal with or discard.