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