I am doing current control with PWM. The switch provides a current sense pin which is going to my ADC.
I am using STM32F4. I am also using FreeRTOS, not sure if this is important though.
My ADC is set to run at 84MHz with 4x prescaler. The conversion is 10bit and the cycles are 15. ADC into circular buffer.
The PWM frequency to be measured is 250Hz, very small. I am watching the ADC values using STM Studio trace using genuine stlinkv2 and I am unable to capture every PWM pulse when the duty cycle is below ~15%. This is clearly due to aliasing. I assume it's due to the ADC being too slow but I'm also under the impression that the ADC is supposed to be capturing 750k samples per second, 21MHz/(15+12) >= 750k. Even 5000 samples per second should suffice so what could be happening?
My problem is similar to this but I am not currently concerned with gating, just being able to capture the low duty cycle PWM pulses.
https://community.st.com/t5/stm32-mcus-products/stm32-adc-sample-rate/td-p/240061#:~:text=the%20sample%20time%20is%20set,%2F(56%2B12)%3D397KHz.
@waclawek.jan @Jshan.1
code:
void ADC_Init(local_config* peripheral_config){
set_adc_order(peripheral_config);
uint16_t* ADC_Values = peripheral_config->ADC_Values;
uint8_t* adc_rank = peripheral_config->adc_rank;
uint8_t* input_array = peripheral_config->adc_input_array;
/* 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);
/*
* DMA Init End
****************************************************************/
/*
* ADC Init Start
****************************************************************/
/** 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_10B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = peripheral_config->adc_num_conv;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; //ADC_EOC_SINGLE_CONV
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/*
* ADC Init End
****************************************************************/
/*
* MSP Init Start
****************************************************************/
/* Peripheral clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*
* It appears GPIO pins have to be initialized together per PORTA
*
* Need to figure out what to do about other ports
*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
for(int index = 0; index < 8; index++){
if(input_array[index]){
GPIO_InitStruct.Pin = GPIO_InitStruct.Pin|ADC_DI_PINS[index];
}
}
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Feedback pins GPIO init ***************************************************/
GPIO_InitStruct.Pin = FB1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(FB1_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = FB2_Pin|FB3_Pin|FB4_Pin|FB5_Pin
|FB6_Pin|FB7_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(FB2_GPIO_Port, &GPIO_InitStruct);
/* Feedback pins GPIO init ***************************************************/
/* ADC1 DMA Init */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //DMA_MDATAALIGN_WORD
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
/* ADC1 Interrupt Enable */
HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
/*
* MSP Init End
****************************************************************/
/*
* ADC Channel Rank Start
****************************************************************/
/*
* Configuration of ADC Channels
*
* Discontinuous ranks are not allowed.
* First loop assigns the rank to customizable input pins.
*
* Second loop assigns rank for feedback pins.
*/
ADC_ChannelConfTypeDef sConfig = {0};
for(int index = 0; index < 8; index++){
if(input_array[index]) {
sConfig.Channel = ADC_CHANNELS[index];
sConfig.Rank = adc_rank[index];
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) Error_Handler();
}
}
for(int index = 8; index < 15; index++) { // 15 was changed to 9
sConfig.Channel = ADC_CHANNELS[index];
sConfig.Rank = adc_rank[index];
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) Error_Handler();
}
/*
* ADC Channel Rank End
****************************************************************/
/*
* Starting ADC,
*
* There may be a problem with not accounting for pin/channel order.
*/
//peripheral_config->adc_num_conv
if(HAL_ADC_Start_DMA(&hadc1, ADC_Values, peripheral_config->adc_num_conv) != HAL_OK) Error_Handler();
}