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

Yes, that will (should) work.

As for where to put the delay, look in main() for MX_USB_DEVICE_Init(). After all of the MX_***_Init() calls, put the HAL_Delay(5000) line. See if that improves things.

julien12657
Associate III

Are you sure it is :

while(CDC_Transmit_FS(ADC_buffer,buffer_size) !=HAL_OK){}

usually there is HAL before. Something like while(HAL_CDC_Transmit......!=HAL_OK){}

Otherwise put a delay of 5000 ms after MX_USB_DEVICE_Init() does not improves things

There is no leading "HAL" on the CDC_Transmit_FS() call. This is at a level above the HAL code.

I am guessing you are powering your board from the USB port. In that case, yeah, 5 seconds probably isn't enough for the PC to enumerate and for you to start your application and open the serial port. If I am guessing correctly here, a REALLY CRUDE test would be to increase the delay to something like 60 seconds (60000). Then see if you can get your PC app running and opening the COM port during that delay.

Geeze this forum's search facility is REALLY TERRIBLE! I can't even find some of my old posts (from the previous forum software). Anyway...

Even better would be to have your STM32 code detect when the PC has opened the virtual com port, and only THEN start collecting ADC data. One way to detect this is mentioned here:

https://community.st.com/s/question/0D50X00009XkfHnSAJ/usb-vcp-how-to-know-if-host-com-port-is-open

But that only works if your PC app asserts DTR when it opens the com port, and de-asserts DTR when it closes the com port. This is often the case, but not always. There is another way to detect when the virtual com port has been opened, but I cannot find the forum posts about it, but I think it involved tapping in to one of the CDC state transition callbacks.

The other solution is to have your PC application send some character sequence to the STM32 when it is ready for data. The STM32 waits until it receives that character sequence, then starts collecting and sending data. For example, the PC sends the letter "G" (for "go").

S.Ma
Principal

binary is the wrong vocabulary.

your adc significant data is less than 16 bit. pass them directly to your buffer without any sscanf.

Note that these codes can't be display as ASCII codes properly on a text teraterm like console, they should be stored in a log file.

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

CDC_Transmit_FS(buffer,8);

becomes

uint16_t adcval = ADC_GetValue(&hadc);

buffer[0] = adcval >> 8; // MSB

buffer[1] = adcval & 0xFF; // LSB

CDC_Transmit_FS(buffer,8);

This is not the complete job done for you. you'll have to catch the beginning of the data stream to extract each 16 bit values.

How pack more ADC datas in each message to increase the throughput

How to probably implement a SW FIFO not to lose data between the continuous ADC and block by block message blips to the host.

...

julien12657
Associate III

@KIC8462852 EPIC204278916

Your last message leave me a very perplexed.

look at my last messages, now the code you gave seems to me wrong especially this line :

CDC_Transmit_FS(buffer,8);

should be remplaced by this line :

CDC_Transmit_FS(buffer,2);

because you only send two bytes (the MSB and the LSB)

@Bob S (Community Member) :

I've tried 60 secondes after MX..... but it doesn't work, also I am trying to use DMA but I don't know how to deal with the DMA buffer, do you have a line of code ?

here what I wrote :

 HAL_ADC_Start_DMA(&hadc, (uint32_t *)DMA_buffer, 1);
  while (1)
  {
	 	for (int i=0;i<1024;i++){
    ADC_buffer[i] = DMA_buffer[0];
			
  }		
			
    CDC_Transmit_FS(ADC_buffer,1024);
 
 
  }

S.Ma
Principal

This is the community web site which does not always show all the threads... Same story for accepting cookies on mobile phone forever, or the back button which goes back to the first thread... :(

The USB lib does not explain well if the USB data is packed to optimize the throughput or not. Always has been a bit puzzling to get HAL CDC functioning properly...

I'm only saying that the 2 bytes extracted from the ADC data can be directly put in the buffer for USB transmission, nothing more. Don't know the specifics of the code itself.

julien12657
Associate III

I am almost done. I have around 1MS/s with this code :

 while (1)
  {
		
		for (int i=0;i<512;i++)
		{
  
		  while ((ADC1->ISR & ADC_ISR_EOC) != ADC_ISR_EOC){}
			
      uint16_t val=ADC1->DR;
		
			ADC_buffer[2*i] = val  >> 8; // MSB
 
      ADC_buffer[2*i+1] = val & 0xFF; // LSB
		}
  CDC_Transmit_FS(ADC_buffer,1024);
		HAL_Delay(1);
  }

I've put a HAL_Delay after the CDC_Transmit and that has stabilized the strangeness of the bigibing.

here is a screen shot of a 10 kHz sine wave from a waveform generator :

0690X000006Cw7wQAC.png

uint16_t buffer[32]; would contain 64 bytes, just send that.

You could scale the values into milli volts if that helps on the other side

ie buffer[i] = (3300 * sample[i]) / 4096;

>>should I store the "0" and the "1" and how ?

Did you miss the basics of data representation in memory class? How 16-bit and 32-bit integers are represented as consecutive byte locations, or how floating point numbers are stored. Without understanding the mechanics here you're going to be challenged.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal

What do you get if you read more than 512 bytes? is it smooth? The while loop is run every 1 msec while the USB FS standard shouldn't empty the buffer in a single transaction... Wondering if the CDC_Transmit is blocking...

https://www.beyondlogic.org/usbnutshell/usb4.shtml