2024-10-20 01:42 AM - last edited on 2024-10-21 08:33 AM by SofLit
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:
ADC:
TIM:
Clock Configuration:
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;
}
}
Solved! Go to Solution.
2024-10-20 02:21 AM
> 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
2024-10-20 02:21 AM
> 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
2024-10-21 05:14 AM
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=5Ω+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?
2024-10-21 07:09 AM
> 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
2024-10-21 08:34 AM
Hello @tasabao ,
In next time, please use </> button to paste your code. I've edited your post then ..
2024-10-21 11:24 PM - edited 2024-10-21 11:26 PM
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.
2024-10-21 11:27 PM
Got it, thank you!!
2024-10-22 04:22 AM
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
2024-10-22 06:46 AM
> 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
2024-10-22 10:48 PM
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.