cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F429 ADC problem

tasabao
Associate III

I am currently using STM32CubeIDE and want to input an external sine wave. The signal has a voltage of 2.6V and a frequency of 10kHz, and I am using DMA + TIM + ADC. The following is the screenshot of my settings.

Currently, I can only capture the peak value of 2.6V, and this is only achievable when the ADC Sampling Time is set to 480 Cycles. With a lower number of cycles, I can only get lower values. Please help me resolve this issue, thank you!

DMA:

tasabao_2-1729413430489.png

 

ADC:

tasabao_1-1729413412132.png

 

TIM:

tasabao_0-1729413380782.png

Clock Configuration:

tasabao_3-1729413475914.png

Below is my code:

///////////////ADC////////////////

int test = 0;

uint32_t lastTick = 0;

uint16_t ADC_Value[4095] = {0};

float ADC_MaxValue = 0;

float ADC_MinValue = 0;

int count = 0;

double ADC_Value_Sum = 0;

int ADC_Value_AVG = 0;

float clock_AVG = 0;

uint16_t max_value = 0;

uint16_t min_value = 0;

char buffer[20];



HAL_TIM_Base_Start(&htim2);

/* USER CODE BEGIN WHILE */

while (1)

{

if (uart_received)

{

uart_received = 0;



if (uart_command == 'A')

{

check = 1;

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Value, 4095);

}

else if (uart_command == 'Z')

{

check = 0;

m = 10000;

ADC_Value_Sum = 0;

memset(ADC_Value, 0, sizeof(ADC_Value));

HAL_ADC_Stop_DMA(&hadc1);

count = 0;

high_time_Sum = 0;

count_phase = 0;

zero_remove = 0;

max_value = 0;

min_value = 0;

}

else if (uart_command == 'S')

{

check = 2;

}

}



if (adc_conversion_complete)

{

adc_conversion_complete = 0;



sprintf(buffer, "Max: %.3f V, Min: %.3f V\r\n", ADC_MaxValue, ADC_MinValue);

HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);

}





if (check == 1)

{

if (HAL_GetTick() - lastTick >= 50000)

{

m += 10000;

ADC_Value_Sum = 0;

memset(ADC_Value, 0, sizeof(ADC_Value));

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Value, 4095);

lastTick = HAL_GetTick();

}

ad9850_wr(0x00, m);

}

else if (check == 0)

{

ad9850_wr(0x00, 0);

}

else if (check == 2)

{

ad9850_wr(0x00, m);

}

}





/* USER CODE END WHILE */

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

{

if(TIM2 == htim->Instance){

if(HAL_TIM_ACTIVE_CHANNEL_1 == htim->Channel){

switch(capture_cnt){

case 1:

capture_buf[0] = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_1);

__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);

capture_cnt++;

break;

case 2:

capture_buf[1] = __HAL_TIM_GET_COMPARE(htim,TIM_CHANNEL_1);

HAL_TIM_IC_Stop_IT(htim,TIM_CHANNEL_1);

capture_cnt++;

break;

default:

break;

}

}

}

}



void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{

test = 1;

if (hadc->Instance == ADC1)

{

max_value = ADC_Value[0];

min_value = ADC_Value[0];

for (int i = 0; i < 4095; i++)

{



if (ADC_Value[i] > max_value)

{

max_value = ADC_Value[i];

}



if (ADC_Value[i] < min_value)

{

min_value = ADC_Value[i];

}

}

ADC_MaxValue = ((float)max_value * 3.3f) / 4095.0f;

ADC_MinValue = ((float)min_value * 3.3f) / 4095.0f;

processFFT();



if (m >= 1000000)

{

m = 10000; // Reset frequency to 10 kHz

check = 0;

}



HAL_ADC_Stop_DMA(&hadc1);

lastTick = HAL_GetTick();



adc_conversion_complete = 1;

}

}
1 ACCEPTED SOLUTION

Accepted Solutions

> this is only achievable when the ADC Sampling Time is set to 480 Cycles.  With a lower number of cycles, I can only get lower values.

This usually means, that your input signal has too high impedance. My guess is, that you derive the sine wave using a high-resistance divider. You'll need to use a buffer (an amplifier with amplifiacation 1) before feeding that signal to ADC.

JW

View solution in original post

11 REPLIES 11

> this is only achievable when the ADC Sampling Time is set to 480 Cycles.  With a lower number of cycles, I can only get lower values.

This usually means, that your input signal has too high impedance. My guess is, that you derive the sine wave using a high-resistance divider. You'll need to use a buffer (an amplifier with amplifiacation 1) before feeding that signal to ADC.

JW

Hello, thank you for your response. Since the internal ADC forms an RC charging circuit, the time constant (τ) must be used to determine whether the charging is sufficient. By using 3 times the τ constant, I ensure that the capacitor is properly charged to the voltage I want to input.

So, based on the current total resistance Rtotal=RBUF+RADC=5Ω+6kΩ=6005ΩR_{total} = R_{BUF} + R_{ADC} = 5Ω + 6kΩ = 6005ΩRtotal=RBUF+RADC=+6kΩ=6005Ω, and the table showing CADC=4×10−12C_{ADC} = 4 \times 10^{-12}CADC=4×10−12, we can calculate τ=Rtotal×CADC=6005×4×10−12=24.02×10−9τ = R_{total} \times C_{ADC} = 6005 \times 4 \times 10^{-12} = 24.02 \times 10^{-9}τ=Rtotal×CADC=6005×4×10−12=24.02×10−9 seconds or 24.02ns.

After multiplying by 3 times τττ, the ideal sampling time becomes:

ts=3×τ=3×24.02ns=72.06nst_s = 3 \times τ = 3 \times 24.02 \text{ns} = 72.06 \text{ns}ts=3×τ=3×24.02ns=72.06ns

Additionally, the ADC clock frequency is 36MHz, and the STM32’s internal ADC has a fixed 12 ADC cycles for internal conversion, so the minimum conversion period would be 15 cycles.

Thus, the ADC’s minimum total conversion time is:

12.4M=416ns\frac{1}{2.4M} = 416 \text{ns}2.4M1=416ns

Therefore, there should be more than enough time for the conversion.

Is my understanding correct?

> By using 3 times the τ constant, I ensure that the capacitor is properly charged to the voltage I want to input.

Not really. tau means, that the capacitor is charged to 1/e i.e. cca 1/3 within the target voltage, 3x that is cca 1/10, i.e. cca 10% error (not quite, because the initial capacitor charge depends on its history).

See the input impedance values in datasheet.

JW

 

Hello @tasabao ,

In next time, please use </> button to paste your code. I've edited your post then ..

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Thank you for your reply. May I ask, does this mean that the capacitor will not fully discharge before each new voltage input? Also, when you mentioned referencing the input impedance values, are you referring to RADC and RAIN in the table below? Should I mainly refer to RAIN for the calculations?

I am currently using a buffer with an output impedance of 7 ohms, but it still seems to affect my ADC readings. Could this be due to my configuration? Thank you.

tasabao_0-1729578383003.png

 

Got it, thank you!!

tasabao
Associate III

This is my current situation: after passing through the buffer, the ADC values are concentrated within a specific range, and the input sine wave is normal. 

Thanks

tasabao_0-1729596156813.png

 

 

> input sine wave is normal

Centered around VREF+/2 with amplitude slightly below VREF+? Have you checked it with an oscilloscope, preferrably directly at the ADC pin in question? Did you verify the correct ADC channel is used?

Try perhaps converting discrete DC levels first.

JW

Hello, thank you for your reply. I have tried using the 3V power supply pin on the STM32, and I can normally get a value of 4095.