cancel
Showing results for 
Search instead for 
Did you mean: 

implement maximum speed adc to usb transfert

julien12657
Associate III

I am trying that :

sprintf((char*)buffer,"%d\r",HAL_ADC_GetValue(&hadc));

CDC_Transmit_FS(buffer,8);

but the speed is only 3 or 4kS/s

Someone has something better ?

53 REPLIES 53
julien12657
Associate III

Hi Clive Two.Zero,

Look at my last messages on this thread, it is way more clear for me now. Do you have an opinion on my very last message ?

julien12657
Associate III

last question though :

OK I managed to get 1MS/s, it is obviously quicker, but, but, but...

When I was using my first code (the slow one), I took one sample then I sent it by USB.

There was no "missing" point on the signal, I mean there was no "hole" even if the sampling rate was slow.

With the fast code where I fill a buffer, there is only one part of the signal which is sampled every loop.

Then when the USB transmits its data, the signal is no more sampled, so it is not continuous.

I guess there are clever tricks to have a "continuous sampling" but if at one moment there is no parallel tasks (sending data by USB while sampling data with the ADC) I don't see how it can work. Do we need some kinds of advance embeded systems like FPGA to do this ?

Bob S
Principal

You do not need an FPGA to do this, as long as your overall throughput will fit in a USB FS (i.e. 12 MB/s) connection (more on this below).

(1) I *think* that adding the delay after the CDC_Transmit_FS() call works because CDC_Transmit_FS() doesn't actually SEND the data, it only tells the USB interface that it is OK to start sending data FROM YOUR BUFFER when the PC requests data. CDC_Transmit_FS() does NOT copy data from your buffer to some other buffer, it leaves it in your ADC_buffer until it copied (64 bytes at a time) into the USB transmit buffer to be sent. That means that if you call CDC_Transmit_FS() with a buffer full of data, then immediately start writing back into that buffer, you will OVERWRITE data that the USB driver is in the middle of sending. I am guessing that the 1ms delay that you added gives the USB driver enough of a head start pulling data from ADC_buffer[] that your loop putting data into ADC_buffer[] only overwrites data that has already been sent.

However....

(2) If you are sampling at 1MS/s, a 1ms delay will cause you to miss 1000 data samples, since you are polling the ADC. If you are sampling at lower rates, you will still loose 1ms worth of data due to that delay.

(3) If you want continuous sampling, 12-bit data at 1 MS/s will overrun a 12 MB/s USB connection. Sending each sample as 16 bit data would be 16 Mbit/sec just for the data. You have to allow for the USB overhead, and the CDC control channel (which is an interrupt endpoint, so it takes up a fixed amount of bandwidth every 1 ms frame.

(4) If you really want continuous sampling, you need to use DMA (preferred) or interrupts (less desirable) to store ADC data into a LARGE buffer. Polling will never get you there without data loss. Then take data from this buffer and send it out via USB (checking the return value and keep trying until HAL_OK). With the DMA in "circular" mode, it will continually take ADC data and put it in the buffer, regardless of what the rest of your program is doing (i.e. it acts as a parallel task to your main code loop).

I've been trying to "teach you to fish" (https://quoteinvestigator.com/2015/08/28/fish/) by pointing you to threads that show how to use DMA. Granted, the example uses the USART not ADC, but the principle is the same regarding how to tell when there is data available in the DMA buffer. Perhaps someone else has the time to write this for you.

I don't see a HAL_CDC function that directly tells you that the USB interface is ready to accept data. It looks like your choices are to see what CDC_Transmit_FS() does to see when it can send data. Or, once you have DMA running and a large enough buffer, it may be sufficient to simply do the "while( CDC_Transmit_FS(***) != HAL_OK) {}" loop like you had at one time but seem to have taken out of your code (hint: please put that back in your code, it is important).

julien12657
Associate III

Thanks very much Bob for your patience.

I will try to implement DMA, I understood that DMA doesn't use CPU, so during sampling ADC with DMA, CPU can send data over USB, it is a kind of parallel task !

However it is not easy to find example on the internet, most examples I've found deals with multiples channels in DMA even with USART. Anyway, I will find the solution !