cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC data loss

LLope.31
Associate III

Hello,

I am trying to transmit some data on my STM32F042F6P6. But my PC's serial monitor only picks up some of it. Here is the code and the serial monitor output:

void readAllRegs(void){
uint8_t value;
for (uint8_t addr = 0x00; addr <= 0x2E; addr++) {
value = readReg(addr);
printf("0x%x: 0x%x (%d) \n", addr, value, value);
fflush(stdout);
}
}
int _write(int file, char *ptr, int len){
CDC_Transmit_FS((uint8_t *)ptr, len);
return len;
}
0x0: 0x29 (41) 
0x1: 0x2e (46)
0x4: 0xd3 (211)
0x6: 0xff (255)
0x7: 0x4 (4)
0xa: 0x0 (0)
0xd: 0x1e (30)
0x10: 0x8c (140)
0x13: 0x22 (34)
0x14: 0xf8 (248)
0x16: 0x7 (7)
0x19: 0x76 (118)
0x1a: 0x6c (108)
0x1d: 0x91 (145)
0x1f: 0x6b (107)
0x20: 0xf8 (248)
0x23: 0xa9 (169)
0x25: 0x20 (32)
0x26: 0xd (13)
0x29: 0x59 (89)
0x2c: 0x88 (136)

When I change the Tx buffer size from 128 bytes to 512 bytes, there is even more data loss:

0090 
5f040x00 f80230x07406 :(
:(0210002(001xb

Can someone explain to me what is happening here? I thought CDC was reliable

Thank you

1 ACCEPTED SOLUTION

Accepted Solutions

> Isn't the data supposed to be transmitted at full speed once CDC_Transmit_FS() is called, without data loss?

No :( USB device can send anything only when the host polls it. So CDC_Transmit_FS should not be called again until the previous call succeeds. Else it will stomp on the previously sent data and data loss will occur.

View solution in original post

7 REPLIES 7
Pavel A.
Evangelist III

CDC is reliable if used correctly. Where have you found this implementation of _write? Look for good examples.

I don't think the problem is _write. I modified the function and removed _write:

void readAllRegs(void){
uint8_t value;
for (uint8_t addr = 0x00; addr <= 0x2E; addr++) {
//value = readReg(addr);
//printf("0x%x: 0x%x (%d) \n", addr, value, value);
//fflush(stdout);
uint8_t strings[] = "register \n";
value = addr + 48;
CDC_Transmit_FS(&value, 1);
CDC_Transmit_FS(strings, sizeof(strings));
}
}

Now there is no _write, but the results are similar: the loop is supposed to run 0x2E times, and my PC's serial monitor picks up just a few chars:

0?Q

If I instead transmit the string before, it sometimes prints "register" once, sometimes 3 times, when it should print 0x2E times ...

Pavel A.
Evangelist III

Again, please look for *good* examples of using CDC_Transmit_FS.

What do you mean by good examples? Isn't the data supposed to be transmitted at full speed once CDC_Transmit_FS() is called, without data loss? Are you suggesting it is some kind of memory or buffer issue? Do I need more code to guaranty that the data is transmitted successfully?

> Isn't the data supposed to be transmitted at full speed once CDC_Transmit_FS() is called, without data loss?

No :( USB device can send anything only when the host polls it. So CDC_Transmit_FS should not be called again until the previous call succeeds. Else it will stomp on the previously sent data and data loss will occur.

Ok thanks, I was using CDC_Transmit_FS() as a serial.print() equivalent of the arduino, I will look at some examples on how to properly implement it.

I tried the following which seems to fix the issue:

int _write(int file, char *ptr, int len){
while(CDC_Transmit_FS((uint8_t *)ptr, len));
return len;
}

Now, if the transmission returns USBD_BUSY, it retries. Not sure if it is the best way, but it seems to work fine

mcagriaksoy
Associate II

Hi LLope31,

You can use a _write alternative on STM32 like:

int _write(int file, char *data, int len)
{
	if (file != STDOUT_FILENO && file != STDERR_FILENO)
	{
		return -1;
	}

	while(CDC_Transmit_FS((uint8_t *)data, len))
	{
		HAL_Delay(1);
	};

	return len;
}