Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[ARM] STM32 Getting ADC Data Speed Problem

nadd

Member level 1
Joined
Oct 3, 2022
Messages
33
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
322
Hello everyone,

I'm trying to get ADC(DMA) data on the NucleoF303RE STM32 board. The sampling speed is 1Msamples/s. When I apply a sinus wave I see data losses on ADC data. I tried to read data with a serial port and save it to an sd card. Both of them have the same problem.

While saving to the sd card, I stopped ADC after the buffer is filled to see what's is the problem. There is no data loss when ADC is stopped after filling the buffer. But, I need continuous conversion, so it is not a solution for me. I guess the ADC uses the same buffer immediately, and saving data commands are not fast enough before ADC fills the buffer again.

Do you have any suggestions? Where am I doing wrong? or maybe any other algorithms?

Codes to save to the sd card I use:
C:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
   // HAL_ADC_Stop_DMA(&hadc1);
    for (int i = 0; i < ADC_BUF_LEN; i++) {
        fres = f_printf(&fil, "%d\n", adc_buf[i]);
        if (fres < 0) {
            myprintf("f_printf error (%i)\r\n", fres);
                while(1);
        }
    }
    f_close(&fil);
    f_mount(NULL, "", 0);
}

Codes to read from the serial port I use:
C:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    for (int i = 0; i < ADC_BUF_LEN; ) {
        myprintf("%i\r\n", adc_buf[i]);
        i++;
    }
}

I also tried to transfer data when the half buffer is filled, then transfer the second half when the full buffer is filled. But, It only uses the first half buffer with this code and keeps doing data losses.
C:
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
    for (int i = 0; i < ADC_BUF_LEN/2; ) {
        myprintf("%i\r\n", adc_buf[i]);
        i++;
    }
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    for (int i = ADC_BUF_LEN/2; i < ADC_BUF_LEN; ) {
        myprintf("%i\r\n", adc_buf[i]);
        i++;
    }
}
 
Hi,

I guess it's no ADC problem.
I guess the bottleneck is the data processing (sending, storing).

Sending data via UART.
Did you calculate the possible data rate via UART? (SD card). If not, then please do so.

Klaus
 
The serial port reading&plotting program gives some data rate information, would it provide the possible data rate correctly?

Regarding the program(right-bottom corner), the data rate is around 4524sps.
usartspeed.PNG


Also, does the buffer size affect the results? It's 12000 now, when I decrease it to around 5000, the wave seems very distorted.
 
Hi,

The math is really simple ... and indeed should be expected to be solved by anybody.

Per sample you get a 16 bit number ....
So with 1 million samples you get 16 million bits per second. (Just raw bits)

But now you translate this into an ASCII string:
The range of each sample is 0...4095 (assuming a 12 bit ADC), thus up to 4 digits
Now you form this into an ASCII string (mysprintf) you get up to 4 ASCII bytes (digits) plus CR plus LF (your \r \n).
This makes up to 6 bytes per sample.
Each byte is transferred by 10 bits (1 START, 8 data , 1 STOP).
So 60 bits per sample.
Multiplied with 1 MSPS this gives a (UART) data rate of 60 Million bits per second. 60Mbits/s, 60MBaud (in optimal case)

But you use 256,000 Baud = 256 kBaud = 0.256MBaud

You are a factor of 240 too slow!

*****

Even if you are not able to do the math without or with a calculator..

Just guessing that 1,000,000 = 1 million "informations per second" (1MSPS)
transferred with a speed of 256,000 informations per second (ignoring the size of information)
could cause trouble ... was the least you could do.

Klaus
 
Sending decimal formatted 10 or 12 bit data with \n terminator, 5 characters or 50 bits. Maximal 5.1 k samples per second with 256 kBaud.
--- Updated ---

In a short, STM32F303 doesn't provide a peripheral interface that can continuously stream 1 or 2 MSPS ADC data to a PC or a storage device. I would go for a faster F4xx device with 100 MBit ethernet.
 
Last edited:
Hi,

The math is really simple ... and indeed should be expected to be solved by anybody.

Per sample you get a 16 bit number ....
So with 1 million samples you get 16 million bits per second. (Just raw bits)

But now you translate this into an ASCII string:
The range of each sample is 0...4095 (assuming a 12 bit ADC), thus up to 4 digits
Now you form this into an ASCII string (mysprintf) you get up to 4 ASCII bytes (digits) plus CR plus LF (your \r \n).
This makes up to 6 bytes per sample.
Each byte is transferred by 10 bits (1 START, 8 data , 1 STOP).
So 60 bits per sample.
Multiplied with 1 MSPS this gives a (UART) data rate of 60 Million bits per second. 60Mbits/s, 60MBaud (in optimal case)

But you use 256,000 Baud = 256 kBaud = 0.256MBaud



*****

Even if you are not able to do the math without or with a calculator..

Just guessing that 1,000,000 = 1 million "informations per second" (1MSPS)
transferred with a speed of 256,000 informations per second (ignoring the size of information)
could cause trouble ... was the least you could do.

Klaus
Hi Klaus,

Thank you so much for the explanation. I had almost no idea about how to do it, I tried to find out but there was no clear explanation like yours.

May I ask about "You are a factor of 240 too slow!", do you mean the factors of 240 are the numbers that are multiplied in pairs resulting in the original number 240?

I have the same problem to save to an sd card, I guess the reason is the same. I realized that I left the Clock prescaler at a low rate, it provides a 281.25KBit/s baud rate. At the minimum prescaler(2), it can provide 18MBit/s. Is the calculation the same?
savesdcard-org.PNG

The "Data Size" in STM32CubeIDE can be minimum of 4 bits. 6 bytes per sample * 6 bits (1 START, 4 data, 1 STOP) = 36MBits/s, which is still not fast enough. Is this calculation correct for saving to an sd card?

Sending decimal formatted 10 or 12 bit data with \n terminator, 5 characters or 50 bits. Maximal 5.1 k samples per second with 256 kBaud.
--- Updated ---

In a short, STM32F303 doesn't provide a peripheral interface that can continuously stream 1 or 2 MSPS ADC data to a PC or a storage device. I would go for a faster F4xx device with 100 MBit ethernet.
Hi FvM,

Thank you so much. I'm looking for another board that has a 12bits ADC, min 1 Msamples/s and an ethernet port. I wonder does an onboard memory card slot, would be fast enough?
 
May I ask about "You are a factor of 240 too slow!", do you mean the factors of 240 are the numbers that are multiplied in pairs resulting in the original number 240?
Really? 250,000 (baud) x 240 (factor) = 60,000,000 (baud)
The "Data Size" in STM32CubeIDE can be minimum of 4 bits. 6 bytes per sample * 6 bits (1 START, 4 data, 1 STOP) = 36MBits/s, which is still not fast enough. Is this calculation correct for saving to an sd card?
You can't transmit 8 but data via UART (at least not with standard interfaces)

And 4 bits from an ADC? Really? 16 steps of resolution. Usually makes no sense.

SD card: you need to read SD card protocol, about file systems, data frames ....

Klaus
 
Hi all again,

I got a Nucleo H723ZG board for its ethernet port and SDMMC connection.

First, I tried to use SDMMC on 50MHz with a Sandisk class 10 card but I can't get over the sd card mount error problem.

Now, I'm trying to use ethernet. I wanted to start with this tutorial for figuring out ethernet.
I did everything in the link and video, but I can't get any return for pings. I guess my laptop doesn't connect it since there is no internet connection. How can I make it connect(Wi-fi disabled)?


Also, what method would be the simplest way to use SDMMC or Ethernet to get data from ADC?
 
Step 1 - stop darting from one solution to another without understanding the basics and what is wrong. You need to learn the basics of designing a solution so you don;t aste your time on a lot of fruitless 'trial and error' (mostly error)
Step 2 - understand what you are actually trying to do. You say you are sampling a sine wave at 1Msps but what is the frequency of the sine wave - it could well be that you can sample much slower
Step 3 - understand what you need to do with the samples. Are you just recording them for later use or could there be some processing that you can do on the MCU to reduce the data transfer rate
Step 4 - understand the best means of communication with whatever other device you need to talk to? This may be via a UART, SPI, I2C, USB or ethernet but it needs to be a design choice
Step 5 - break the whole project down to a sequence of steps - ADC data capture, UART/Ethernet/whatever communication etc and get each one working. Then try to to join them together.
Susan
 
To give the latest status:

I could solve the mount error problem by designing a PCB that can directly sit on my board. Cables were causing the problem. SDMMC is very fast enough to save that much data, but sometimes writing speed was fluctuating(gets slower than ADC) and it was causing data loss. I couldn't fix this problem, I tried all parameters that related to SDMMC(slowed it down too).

For the ethernet, I tried all the (ethernet)samples by ST. It didn't work. I couldn't solve this too.

Now I'm using a Discovery 2 Kit.
 
Your project is helpless without thorough understanding of memory card operation and respective coding of the SD driver. Recent cards supports multiple 10 MB/s "maintained" (continuous) writing speed, but not with simple single sector writes.
 
I also asked about this on St community. Currently, I'm not working on this board, but for other people that facing the same problem may read the full discussion there. I shared my latest algorithm too.

A half buffer(32k samples) gets ready in 28ms, and the writing half buffer process takes about 9ms. So speed is enough but writing speed fluctuates like 3ms-/+. Sometimes it takes more than 30ms which is the problem.

 
for maximum performance I recommend mem2mem data pumping, used it for adc/ethernet/dac/etc. for many times;
Code:
    #define ADC_BUFFER_SIZE 1024
   
    // do not forget to place these buffers in DMA-accesible RAM
    uint16_t adcBuffer[ADC_BUFFER_SIZE] ; // for ADC circular buffer
    uint16_t adcBuffer2[ADC_BUFFER_SIZE]; // copied from adcBuffer using mem2mem
   
    volatile uint8_t idx=255;
   
    void m2mCallback(DMA_HandleTypeDef *_hdma)
    {
        // you can track mem2mem complete here, something like
        if (idx==2)  {idx=3;}
    }
   
    // ...
    HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_CPLT_CB_ID, m2mCallback);
   
    while (1)
    {
        idx=0; // allow mem2mem
        while(idx!=3){asm("nop");
        // process data here
        // if processing fast enough, idx will be set to 0 before
        // HAL_ADC_ConvHalfCpltCallback
        // will be called again
        // idx=0 - need to copy, 1 - first half copy initiated,
        // 2 - second half copy initiated,
        // 3 - second half copy mem2mem completed
    }
   
   
    void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
    {
        if (idx==0) {
            // memmove(  (void *)&adcBuffer2[0],
            // (void *)&adcBuffer[0],
            // sizeof(adcBuffer)/2);
            HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0,
                    (uint32_t)&adcBuffer[0],
                    (uint32_t)&adcBuffer2[0],
                    sizeof(adcBuffer)/2/4);
            idx=1;
        }
    }
   
    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
    {
        if (idx==1) {
            //memmove(  (void *)&adcBuffer2[ADC_BUFFER_SIZE/2],
            // (void *)&adcBuffer[ADC_BUFFER_SIZE/2],
            // sizeof(adcBuffer)/2);
            HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0,
                    (uint32_t)&adcBuffer[ADC_BUFFER_SIZE/2],
                    (uint32_t)&adcBuffer2[ADC_BUFFER_SIZE/2],
                    sizeof(adcBuffer)/2/4);
            idx=2;
        }
    }
for more:

https://community.st.com/s/question...-list-or-double-buffering-and-adc-interleaved
and
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top