2019-01-06 05:38 AM
2019-01-06 05:44 AM
Elaborate more, especially not a timing, more like which signals feeds who? Schematics sketch would help understand better what is the system and what is really the challenge. Thanks for providing mode details, otherwise the answers may not be relevant enough...
2019-01-06 05:58 AM
That PWM supplies a coil and there is a sense coil. The voltage drops on an sense coil and want to measure its voltage according to each state of supplying PWM.
2019-01-06 06:45 AM
If I use a timer 1Mhz for ADC as sampling rate is 61.5, how long does it take the canversion to finish for 450 samples? I guess that if I use ADC DMA conversion complete callback, I can toggle IO just as PWM. However, I don’t how to calculate correctly.
2019-01-06 06:45 AM
If it is a kind of motor control or digital power supply, there are specific app notes and examples for this, including 3 phase sense for sensored brushless motor. Check on IHM demo boards.
Otherwise, take a timer to generate the pwm(s) and use the spare channel to generate a pulse which you can shape and position during the PWM period time. This trigger goes to a pin which feeds the ADC trgger input pin. It will enable you to time position the sampling at the correct place (assuming the ADC input signall is low impedence, otherwise, get ready for voltage droops as the ADC behave like an RC filter during the sampling time. If you use an injected ADC channel, you can directly read the voltage as LSB or have a digital min/max comparator if the target is to be within a specific range.
2019-01-06 07:30 AM
Well, how can I calculate the conversion timing for reading ADC via DMA? Are the followings correct?
TIM2 clock 32Mhz and set the prescaler 31 it will be 1Mhz. Counter Period is 1. The timing will be 1us.
The sample cycle 61.5, then total cycle 12+61.5=73.5 cycle.
The number of sample is 450, then it takes 33075 cycles.
So, it takes 33,075ms, it gets interrupt after 33ms.
2019-01-06 07:48 AM
Maybe still the understanding of what you'd like to implement is still subject to various interpretations.
Thanks.
2019-01-06 09:14 AM
Thanks @S.Ma for your answers.
2019-01-06 09:40 AM
So if I understand correctly: STM32 generates 1.1kHz with 50% duty cycle
==> So this is one of the timer output channel : Let's say the timer runs at 4MHz, so its toggle is 1800 ticks, period is 3600 ticks with overflow.
==> For example, create a second channel which output will toggle based on compares coming from a DMA scanned table, say toggle at 4, 8, 12, 16, 20, 24 (that's the first 3 pulses for 3 usec, go on until 3600 is done. You could use another timer to generate a 1MHz pulse triggering the ADC, however, you probably want the fine shifting convenience and synchronisation of the ADC firering with 1/8 usec accuracy (or twice better is using 16MHz timer). DMA for Timer can run in cyclical mode.
==> These 1 MHz time shitable pulses are used to trigger the ADC conversion, one sample by one sample. Use the physical trigger pin to monitor what's going on.
Then use another DMA channel to save the ADC results into a RAM table, which you will have to handle by SW its backup every 900 usec.
You will only have to make sure that the ADC total sampling time is same or shorter than the ADC trigger period. DMA transfer complete will give you the event to analyse and perform the average. If you;d like to run it continuously, you'll probably have to implement double buffering.
If not known exactly the ADC sampling time, run the code using debugger and count how many samples were collected over 900 usec.
There are probably simpler implementations, however, if there are some system fine tuning required down the road, a bit more complex HW use provides extra tuning knobs.
The earlier Invested time the shorter debug time...
2019-01-06 10:38 PM
I don't understand what you meant.
I have tried something but confused the calculation of ADC DMA conversion time. I'm using the following code.
TIM2:
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 63;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
ADC:
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/**Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_19CYCLES_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
Callback:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
uint32_t wResult1 = 0, wResult2 = 0, wResult3 = 0;
uint32_t dwHighTotal = 0, dwLowTotatl = 0;
static uint32_t dwCounter;
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);
if (flag != 2) {
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2)) {
for (uint32_t i = 0; i < 225; i++) {
sADCValues.wHighData[i] = data[i];
dwHighTotal += data[i];
}
sADCValues.wHighAverage = dwHighTotal / 225;
} else {
for (uint32_t i = 0; i < 225; i++) {
sADCValues.wLowData[i] = data[i];
dwLowTotatl += data[i];
}
sADCValues.wLowAverage = dwLowTotatl / 225;
}
flag++;
}
}
In main, the ADC is started via DMA.
if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &data, 225) != HAL_OK){
Error_Handler();
}
And it generate 1.1KHz signal but I can't calculate how to do that.