I am using the Nucleo board STML073Rz to sample a sine wave of frequency 1khz. My STMCubeIDE configuration is given below.
System Clock : HSE 8Mhz
Tiimer2
prescalar : 8-1, ARR : 100-1, Timer Over flow frequency : 10000Hz, Trigger Event Selection: Update Event
ADC
Prescalar: Synchronous clock mode devided by 2, ADC resolution : 8bit resolution, Data alignment : right, External trigger conversion source : Timer2 trigger out event
UART2
clock : sysclock 8Mhz, baud rate : 115200, word length : 8bit, overrun : disabled
My requirement is sample the sine wave which is given into the ADC6 channel at a sampling frequency of 10000Hz. I have used the following logic to send the samples to gateway.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
endOfConversion = 1;
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
}
HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start_IT(&hadc);
numsamples=4500;
txcount = 0;
endOfConversion=0;
do
{
if(endOfConversion==1)
{
adc_value = HAL_ADC_GetValue(&hadc);
HAL_UART_Transmit(&huart1, &adc_value, 1, 10);
endOfConversion=0;
txcount+=1;
}
}while(txcount<=numsamples);
HAL_ADC_Stop_IT(&hadc);
Here only the logic is displayed not the whole code. At the gateway I plot the fft from the samples and it was showing peak at 2000Hz instead of 1000Hz.
After some debug I came to know that the HAL delay the transmission of 1byte and hence only alteranate samples were sent to gateway.
Why the HAL UART delay the transmission?
Lets say this is the timeline of events with
|
marking off 10000Hz (100us) intervals.The way Timer2 and the ADC are configured, there'll be a TIM2 and an ADC trigger on every conversion. From the datasheet, ADC conversions are so fast(0.4uz) relative to 100us intervals that we can pretend the ADC conversion callback happens at the same time as the trigger in the diagram.
Like @the-busybee's comment mentioned, UART speed is relevant. The UART is configured in poll mode, so that's going to be relevant too.
HAL_UART_Transmit(&huart1, &adc_value, 1, 10);
sends 10 bits (not ~bytes~, thanks @pmacfarlane) over the 115200Hz baud rate line, which will take about ~100us (this is a rough magnitude guess coming from 10/115200).The previous timeline with timer and ADC events happen in hardware in the background. Meanwhile, the code runnning in the main
do {} while
loop is happening in software in the foreground at the same time. If the UART transmit time takes over 100us, then here's a likely timeline of what's happening:The UART transmission is still ongoing when the next irq happens, but because
endOfConversion
gets reset after the UART finishes, then the loop has to wait for another TIM2 IRQ to read and transmit another sample.I think you can fix this by resetting
endOfConversion
before the UART transmit to take out all of those "." states in the software timeline above like this:If this solution causes funny sample rate issues, then you'll need to do something fancier like cache the data to transmit later, or use a higher baud rate UART (if possible).
Here's what I mean by caching the data to transmit later if you have enough memory.