cancel
Showing results for 
Search instead for 
Did you mean: 

ADC values via UART on STM32L011

Sid
Associate II
Posted on April 24, 2018 at 11:40

Hello Friends!

I am very new to STM coding and starting with the basics. I am using a STM32L011 uC and IAR compiler.

I am trying to measure voltage from a sensor that is dumping analog data at about 5Khz. The ADC values then need to be transferred to via UART to my laptop for post processing. 

The problem is that even though the STM32L011 is sampling with internal clock of 16Mhz and UART is dumping data at 56000 Baud Rate (WHTHOUT hardware flow control). The resulting graph of the ADC plot on my laptop has awful resolution. 

I dont understand where the problem is . Is it the transmission bottle neck which i doubt because the 

resulting graph of the ADC plot on my laptop is more or less the same even if i change the baudrate. Since i am using a simple while loop to pool for conversion for the ADC data and then transmitting to the system, the ADC conversion speed should be limited with the uart transmission rate and change with increasing or decreasing baud rate but this doesnt seem to happen.

Given below is the expected (oscilloscope) and actual plotted graphs (excel graphs which are no where close to expectations)

 0690X0000060AkcQAE.png

0690X0000060AkhQAE.png

Any help in how to get the ADC values on the Laptop in as much real time as possible is appreciated. 

8 REPLIES 8
AvaTar
Lead
Posted on April 24, 2018 at 12:35

I am trying to measure voltage from a sensor that is dumping analog data at about 5Khz.

...

The problem is that even though the STM32L011 is sampling with internal clock of 16Mhz and UART is dumping data at 56000 Baud Rate (WHTHOUT hardware flow control).

How many bytes per sample ?

Assuming 10 bits per byte (including start and stop bits), you have quite a problem here with single-byte data, and assured malfunction with 2 bytes per sample.

Since i am using a simple while loop to pool for conversion for the ADC data and then transmitting to the system, the ADC conversion speed should be limited with the uart transmission rate and change with increasing or decreasing baud rate but this doesnt seem to happen.

You will need a better strategy, the transmission needs to run quasi-parallel with sampling and preparation for send.

BTW, 'dumping' is not quite an appropriate word for sending data to an interface - even if others use it frequently.

Sid
Associate II
Posted on April 24, 2018 at 14:51

Thanks for the reply AvaTar, So what strategy do u recommend? this STM32 can go upto 4MBps but  that also doesnt help. Receiving at 2MBps baud rate gives a better graph (given below) but still no where near to what i expect.

0690X0000060AlgQAE.png

Regards

T J
Lead
Posted on April 24, 2018 at 17:28

You should use the DMA in production, otherwise there is no time for any other process.

above you have two parts that wait, you should combine them.

I dont approve of your method at all, but try something like this;

while (1)

{

      if (HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)

         {

            ADC_value = HAL_ADC_GetValue(&hadc);  //  

ADC_value is uint32_t 

            int txlength = sprintf(str, '%d\r\n', ADC_value);  // char str[7];

            HAL_UART_Transmit(&hlpuart1, (uint8_t*)(&str), txlength, 100);

            HAL_ADC_Start(&hadc); // start ADC

            /*##-6- Wait for the end of the transfer ###################################*/

            while (HAL_UART_GetState(&hlpuart1) == HAL_UART_STATE_BUSY_TX)

               {

               }

         }

}

T J
Lead
Posted on April 24, 2018 at 17:47

What are you transmitting ?

       int txlength = sprintf(str, '%d\r\n', ADC_value);  // char str[7];

       HAL_UART_Transmit(&hlpuart1, (uint8_t*)(&str), txlength, 100);

10bit ADC is maximum 1023

your print statement is %d\r\n   that's 1023\r\n, that's 6 bytes.

8 bits each, with start and stop bits is 10bits in the Uart Stream.

6 bytes, 10 bits, that's 60bits per cycle.

if the ADC cycle time is 5KHz approx, therefore the Uart must be running at

300KHz minimum,  you need to run the Uart at the next highest uart speed.

Posted on April 24, 2018 at 16:10

Not sure about your throughput requirements, i.e. which ADC sampling rates do you want.

However, the output bandwidth (UART) must at least match the input bandwidth (ADC).  Some reserve bandwidth won't hurt.

You want continuous sampling (don't you ?), so you can't do a sequential Sample->Send->Repeat cycle.

Sending a character via UART (or any other serial interface) takes much longer than just copying the character to the TX register. Waiting for the TC (Transmission Complete) flag for each character (as Cube code seems to do on occasions) will break your code.

The best option would be DMA.

Prepare a block of characters (values) in the background, and move it to UART->TX via DMA. Once you get the DMA TC (Transmission Complete), you can prepare and send the next block.

If you read the ADC via interrupt or DMA is up to you, but DMA is recommended, at least for multi-channel configurations.

Balancing and synchronizing both stream is your task, then.

No idea how to achieve that with Cube, never used it.

The M0 is relatively simple, doing it on register level should not be too difficult.

Sid
Associate II
Posted on April 24, 2018 at 16:52

Ok. so lets put it like this. 

My sensor gives new analogue value every 1/2600 seconds. Hence by Nyquist criteria i need atleast 5200 samples/sec (thats why i said 5KHz, to make it simple for readers to understand). So i need atleast 5200 samples sent from micro controller to my laptop, this is the minimum throughput requirements... I am happy with 10bit ADC.. 

So for one 10bit ADC result the UART needs 12 (1+10+1) bits to send...

So for 5600 samples we are looking at 5600x12 = 67200bits/sec which is well within the most common UART baud rates... so if my understanding and calculations are correct its very much feasible via UART communication alone. This makes me think that perhaps my software loop is very dumb (like its creator!)... Here is the loop:

while (1)

{

      HAL_ADC_Start(&hadc); // start ADC

      if (HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)

         {

            ADC_value = HAL_ADC_GetValue(&hadc);  //  

ADC_value is uint32_t 

            int txlength = sprintf(str, '%d\r\n', ADC_value);  // char str[7];

            HAL_UART_Transmit(&hlpuart1, (uint8_t*)(&str), txlength, 100);

            /*♯♯-6- Wait for the end of the transfer ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

            while (HAL_UART_GetState(&hlpuart1) == HAL_UART_STATE_BUSY_TX)

               {

               }

         }

}

If its the lazy loop then, how can i optimise the loop.

Since i am new to this STM32 i dont want to step into the DMA as of now, unless its very necessary. More over even with DMA the bottle neck with UART transmission will still remain an issue?

I am using only one ADC channel.

Thanks for all the help.

Posted on April 24, 2018 at 17:37

'So for one 10bit ADC result the UART needs 12 (1+10+1) bits to send...' No, I am quite certain that you can't send 10 databits at one go. You can send only 8 or 9 bits.

Posted on April 24, 2018 at 18:32

My sensor gives new analogue value every 1/2600 seconds. Hence by Nyquist criteria i need atleast 5200 samples/sec ...

This has nothing to do with the Nyquist criteria. it is for periodic functions (Think sine wave).

For digital sensors, you just need to match the update rate (2,6 kHz).

So for one 10bit ADC result the UART needs 12 (1+10+1) bits to send...

As mentioned, UART/RS232 only knows characters (8 bit). I would avoid 9-bit, you don't gain anything.

So, 10 or 12 bit, both need 2 bytes if you transmit binary data.

When sending data as ASCII strings, you maximal 4 characters per item, add the '\r' + '\n' (making 6).

And you might add a bit of redundancy to your protocol, to make up for data corruption and recovery.