2020-08-14 02:53 PM
Hello,
i'm doing my first project with the STM32F103, where ADC is involved.
I want to read out several potentiometers and send MIDI commands to a PC.
So far everything is working, but there is soo much noise on the ADC data. I'm using only the upper 7 bits of the ADC data and even there it's constantly jumping between +-1% of the actual value, as soon the input is above 0V or under Vcc. I tested pots from 1-100kOhm, even a battery on the ADC input. On the oscilloscope the 3.3V had a +-2,5mV ripple, so i added capacitors, tested a LiIon Cell with 3.4V as input, same results.
I'm using a genuine Nucleo F103RBT6 and blue pill boards. Both with the same problem.
So I think, I'm doing anything wrong. Here is my code:
/* USER CODE BEGIN PV */
uint16_t adc_data[2];
/* USER CODE END PV */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USB_DEVICE_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
mimuz_init();
HAL_Delay(5000);
int Wert, Wert2, controller;
uint16_t adc_alt[2];
uint8_t val[2];
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_data, 2);
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start(&hadc1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
int i = 0;
for(;i<2;i++){
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
if (adc_data[i]>>5 != adc_alt[i]){
controller = 14 + i;
sendCtlChange(0,controller,adc_data[i]>>5);
adc_alt[i] = adc_data[i]>>5;
}
}
processMidiMessage();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
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.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
I hope anyone can help me.
2020-08-14 03:03 PM
+/- 1% seems reasonable with a high impedance load. Averaging can typically get you 1-2 more bits of precision.
No silver bullet to get better results. Here you go:
2020-08-14 10:42 PM
According to the HAL_ADCEx_Calibration_Start function description:
"Perform an ADC automatic self-calibration
* Calibration prerequisite: ADC must be disabled (execute this
* function before HAL_ADC_Start() or after HAL_ADC_Stop() ).
* During calibration process, ADC is enabled. ADC is let enabled at
* the completion of this function."
so you should first calibrate ADC then start it: (line 41)
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_data, 2);