cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F429 ADC problem

tasabao
Associate II

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;

}

}
4 REPLIES 4

> 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.