Skip to main content
Graduate
October 7, 2023
Solved

USB CDC data loss

  • October 7, 2023
  • 3 replies
  • 4759 views

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

    This topic has been closed for replies.
    Best answer by Pavel A.

    > 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.

    3 replies

    Super User
    October 7, 2023

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

    LLope.31Author
    Graduate
    October 7, 2023

    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 ...

    Super User
    October 8, 2023

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

    LLope.31Author
    Graduate
    October 8, 2023

    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?

    Pavel A.Answer
    Super User
    October 8, 2023

    > 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.

    Explorer II
    March 1, 2024

    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;
    }