cancel
Showing results for 
Search instead for 
Did you mean: 

ADC continuous conversion with DMA, last sample error.

TonyFauci
Associate II

Using F401 ADC continuous conversion and DMA for multiple channels.

I have pins A0-7, B1, PC0-5 running conversions. For consecutive pins in a group (A0-7) (C0-5), the final pin in use always has a different offset error to the rest. Note this actually means the final /used/ pin in the group, e.g. If all 8 pins in group A are used, pinA7 has a different offset error to the rest. If only the first three 3 are used pinA2 has a different offset error to the rest. If the first 4 pins are used pinA2 no longer has the additional offset error but this is passed on to pinA3.

TonyFauci_0-1701046702057.png

These results are conversions from all pins being used. The ADC inputs are grounded with pull down resistors in all cases. The different sets of values (0-4 vs18- 25) represent different input impedances from input circuits. The ADC is 12 bits so the offset errors aren't particularly problematic, the issue for me is what could be causing the last value to have a different offset error?

I've measured the pins with my oscilloscope, the B and C group are at 0 volts and the A group are approximately 20mv. I think the issue is in firmware but it's mysterious to me.

My ADC initialization code;

 

/* Function:
 * Initializes the adc modules one by one.
 *
 *
 * Arguments:
 * Struct that gives access to arrays describing initialization parameters.
 *
 * Returns:
 * None.
 * */
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;
uint8_t num_cov = peripheral_config->adc_num_conv;
 
/* 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_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
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 = num_cov;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_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};
GPIO_InitStruct.Pin = 0;
for(int index = 0; index < 8; index++){
if(input_array[index]){
GPIO_InitStruct.Pin = GPIO_InitStruct.Pin|ADC_DI_PINS[index];
}
}
if(GPIO_InitStruct.Pin != 0) {
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] && ((adc_rank[index] >= 0) && (adc_rank[index] <= 7))) {
sConfig.Channel = ADC_CHANNELS[index];
sConfig.Rank = adc_rank[index];
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) Error_Handler();
}
}
 
for(int index = 8; index < 15; index++) {
if((adc_rank[index] >= 0) && (adc_rank[index] <= 14)) {
sConfig.Channel = ADC_CHANNELS[index];
sConfig.Rank = adc_rank[index];
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) Error_Handler();
}
}
 
/*
* ADC Channel Rank End
****************************************************************/
 
/*
* Starting ADC,
*/
 
if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*) ADC_Values, num_cov) != HAL_OK) Error_Handler();
}

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
TonyFauci
Associate II

The list of ADC Channels used didn't correspond to the pins specified. Simple mistake.

View solution in original post

3 REPLIES 3
TDK
Guru

> The ADC inputs are grounded with pull down resistors in all cases. The different sets of values (0-4 vs18- 25) represent different input impedances from input circuits.

25 is a lot of counts for a grounded input. Can you show a schematic? Clearly looks like PA pins are connected differently than PB. Might help guide the answer.

If you feel a post has answered your question, please click "Accept as Solution".

TonyFauci_0-1701050332537.png

It's a multifunction input. I've removed the pull up to make sure the 20mv on the input isn't due to it. I think it's due to the resistors to ground and the leakage current of the pins, 1-3uA and 10k 1.4k 15.6k to ground.

TonyFauci
Associate II

The list of ADC Channels used didn't correspond to the pins specified. Simple mistake.