2023-08-28 03:52 AM
Hello All,
I'm really stuck with USB CDC Communication speed using STM32F405 for past 20 days.
I'm trying to send ADC Data to PC . My ADC sampling rate is 32khz. My ADC is 8 channel , but I'm only sending 2 channel data to PC.
The ADC Data ready pin is connected to GPIO pin of the stm32 and it toggles at the rate of 32khz . So it toggles 32000 times per second and inside every toggle I read samples from the ADC. Below is the code I've written to capture data and send data to PC. I'm using FREE RTOS in my code. Total bytes that need to be send is
32000 samples x 2 channel x 3 bytes per sample = 192000 bytes. I have set the USB data packet size to 64 bytes and after sending one packet I'm sending a zero length packet.
void StartDefaultTask(void *argument)
{
/* init code for USB_DEVICE */
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 5 */
ADS_Init();
j=0;
/* Infinite loop */
for(;;)
{
if(dataready == 1) // this is set in DRDY PIN TOGGLE INTERRUPT
{
ADS_RDATA();
dataready = 0;
}
osDelay(1);
}
/* USER CODE END 5 */
}
void sendata(void *argument)
{
/* USER CODE BEGIN sendata */
/* Infinite loop */
for(;;)
{
if(datatype == 't')
{
if(senddat == 1)
{
CDC_Transmit_FS(buff_tx, sizeof(buff_tx));
CDC_Transmit_FS(ZLP, 0);
senddat=0;
}
}
if(datatype == 'z')
{
senddat=0;
}
osDelay(1);
}
//read data
void ADS_RDATA() { // use in Stop Read Continuous mode when DRDY goes low
uint8_t inByte,inByte1,inByte2,inByte3;
int i;
//int nchan = 2; //assume 8 channel. If needed, it automatically changes to 16 automatically in a later block.
stat_1 = 0; // clear the status registers
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12,GPIO_PIN_RESET); // open SPI
transferSPI( _RDATA);
// READ CHANNEL DATA FROM FIRST ADS IN DAISY LINE
for(i = 0; i < 3; i++){ // read 3 byte status register (1100+LOFF_STATP+LOFF_STATN+GPIO[7:4])
inByte = transferSPI( 0x00);
stat_1 = (stat_1<<8) | inByte;
}
for(i = 0; i < 2; i++) // this is where i read ADC DATA of two channels. 3 Bytes are read for each channel and stored in buff_tx array of size 64 bytes.
{
buff_tx[j]=transferSPI( 0x00);
j++;
buff_tx[j]=transferSPI( 0x00);
j++;
buff_tx[j]=transferSPI( 0x00);
j++;
}
if(j==60)
{
j=0;
senddat = 1;
}
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12,GPIO_PIN_SET); // open SPI
}
Since my data is not in multiple of 64 , I only store ADC Data upto 60 elements of the array and rest elements are always written 0. In my PC application I only read first 60 bytes of the received packet.
I'm not able to get 192000 samples in one second. It takes around 7-8 seconds to read 192000 samples. Kindly help.
2023-08-31 06:27 AM
RX buffer should be 64 bytes. You will never get any more data from a FS device.
TX buffer should be also 64 Bytes, with the proper handling in your application. 60 byte packets seem to be a good idea. Just remember that you should call the Transmit only from an ISR of the same priority as USB interrupt.
2023-09-01 05:26 AM
Just remember that you should call the Transmit only from an ISR of the same priority as USB interrupt.
I'm using CDC_Transmit_FS in a Free RTOS TASK.
I was reading that the ST USB CDC Library used in cubemx will send 64 bytes per 1 ms i.e 64Kbytes in a second???
In every 1 ms it send a maximum packet if 64 Bytes only. Is this correct??
2023-09-01 05:29 AM
This USB CDC Speed issue is really a pain now. Is it not possible to achieve a speed of 200k Bytes per second in USB Communication??
I have tried buffers of 4096,8192 and finally I tried a buffer of 19200 Bytes . At my PC application The first chunk of 19200 Bytes are received very quickly. But if I check for 38400 number of bytes , it stops after 2-3 seconds . Even If I'm sending 19200 bytes after every 100 ms
2023-09-01 07:33 AM
Sending in a task (= thread mode) while running the USB stack in an ISR will cause your USB comm to hang - sooner or later.
Yes, 64 KiB/s seems to be a practical limit for CDC ACM. And to achieve this rate, you should write the USB stuff in a smart way. Use TransmitCplt() callback.
2023-09-11 04:10 AM
Just an update in my thread for those who might ever get stuck in a situation like mine.
FREE RTOS task ticks at 1ms interval. If the sampling rate of an external ADC is more than 1khz (in my case it was 32khz) , then FREE RTOS task is of no use. Its better to use SPI/I2S + DMA & Call back functions to process data and send it via UART/USB.
The SPI+ DMA Code from the below link helped me