cancel
Showing results for 
Search instead for 
Did you mean: 

Strange behavior with USB CDC as virtual COM port on NUCLEO-L476RG

Benjamin Brammer
Senior II

Hello everybody,

I am using the NUCLEO-L476RG to send simple ACII text over UART (RS232 adapter) or USB CDC as a virtual COM port. UART communication is working seamlessly but when I use the USB CDC library functions from STM there is hapenning something strange I cannot explain:

I am sending in regular intervalls ASCII-tesxt in the follwoing format: ABP;***;***;***\n

The * stands for different numbers. normally I would see this kind of text flow on a terminal like hterm:

ABP;***;***;***\n

ABP;***;***;***\n

ABP;***;***;***\n

... and so on

but with the USB CDC usage I see occasionally this:

ABP;***;***;***\n

ABP;ABP;***;***;***\n

ABP;***;***;***\n

ABP;***;***;***\n

ABP;ABP;***;***;***\n

when I halt the debugger to check if my character array is corrupted, it isn't. So my assumption is that there is something not working correctly with the USB CDC device library from STM. This is the code, that gets invoked when I transmit the ASCII-text:

sprintf(Communication.measure,"ABP;%ld;%ld;%ld\n",Patient.Systolic, Patient.Diastolic, Patient.MAP);
if(System.Mode == UART)
{
	LPUART_transmit_message(Communication.measure);
}
else if(System.Mode == USB)
{
	CDC_Transmit_FS(Communication.measure, strlen(Communication.measure));
}

as you can see, i am using the same array preparations for the USB CDC version as for the UART version, except that the UART version functions seamlessly. The big difference between both versions is that I only utilize USB CDC device library functions provided by STM, not my own.

Has anybody experienced something similar? Or has a good hint where to find the problem?

best regards

Benjamin

50 REPLIES 50

OK, I will implement and test everything tomorrow. thanks again!

Hey Bob,

sadly the problem still remains. At first it seamed to have disappeared but I did a lot of testing and it is still there.

i tested today for some long time and sadly the problem still remains. Any other suggestion what might be the cause?

Bob S
Principal

(1) Are you still using "measure" anywhere else in your program?

(2) Put HTerm into hex display mode. This will show you EVERY character. See if the lines with the replicated "ABP;" also have any non-visible bytes.

(2.5) I find it VERY curious that the corrupted lines always have the same corruption, the repeated "ABP;" string. This likes suspiciously like maybe the incoming command from the host to request the data (could the command string be "ABP;" ???) is once in a while getting echoed back out the USB port.

(3) Check your stack usage. Are you anywhere near using all of the 96KBytes of RAM in the main RAM section?

(4) Are you using an RTOS?

(5) Do you call CDC_Transmit_FS() anywhere else in your code?

(6) Where you call CDC_Transmit_FS(), also send that buffer out your USART using LPUART_transmit_message(). Run two terminal sessions and see if the output matches.

(7) Since your LPUART_transmit_message() copies the string into another buffer, add a buffer for the USB version.

else if(System.Mode == USB)
{
	static char tmpbuf[100];
	// NOTE the "-1" in the strncpy 3rd param, unlike snprintf(), strncpy() does NOT
	// guarantee it will NULL terminate the output string if the source string
	// is too long.
	strncpy( tmpbuf, Communication.measure, sizeof(tmpbuf)-1 );
	CDC_Transmit_FS( tmpbuf, strlen(tmpbuf) );
}

(8) Probably unrelated, but.... How big is LPUARTBufferTx used in LPUART_tramsnit_message()??? That has the same size and possible overrun issue that Communiocation.measure has. And use strncpy() in LPUART_transmit_message(), not plain strcpy() for same reasons as snprintf() vs. sprintf().

Hello Bob,

thanks again for your efforts and help. I can check everything you suggested in the next week, as I have to switch to some different task until next week. i will respond to you as soon as I have checked everything.

Benjamin

Hello Bob,

I finally had the time to check your questions and test again.

1) No, I am not using measure anywhere else in the code.

2) see the attached image:

0690X00000Bw1pUQAR.jpg

2.5) No, the fault is occuring independently of any command issued by the host. In fact I mostly test without issuing any command.

3) please see the attached image:

0690X00000Bw1qhQAB.jpg

4) No, I am not using RTOS.

5) No, I am not using the API function anywhere else.

6) The message over UART is not faulty, although I use the same buffer:

0690X00000Bw1tbQAB.jpg

7) I did the changes, still the error prevales..

8) The size of the LPUARTBufferTx is 64.

Independent of your suggestions when I first compile the project I get the following problems shown:

0690X00000Bw1vXQAR.jpg

it is also interesting that sometimes Windows doesn't recognizes the USB_CDC VCOMP. This allways triggers a hard_fault, where I reset the system. Sometimes this works good but sometimes this doesnt solve the problem and I have to detach the USB cable and replug it again.

After the test in 6) I am pretty sure this is no buffer overrun or memory problem. I think there is something not working correctly with the USB CDC driver lib. Maybe I did not implement something important? I implemented the driver lib according to the STM32 training video on USB CDC (https://www.youtube.com/watch?reload=9&reload=9&v=h9T0RTu9Muc)

Bob S
Principal

Regarding my question (5) "do you use CDC_Transmit_FS() anywhere else in your program" and your answer "No, I am not using the API function anywhere else", the image you posted of the compiler warnings says that you *DO* (or DID) call CDC_Transmit_FS() from 8 different places in your code.

BTW, those warnings are due to ST defining all of their API calls using "uint8_t *" instead of "char *", and I am guessing you messages are all "char" arrays. As you probably already know, to keep that compiler warning enabled (sometimes it indicates a real issue), you have to cast your buffers to uint8_t *, i.e.

CDC_Transmit_FS( (uint8_t *)Communication.measure, strlen(Communication.measure) );

For (6), does "The message over UART is not faulty, although I use the same buffer" mean you did something like this:

else if(System.Mode == USB)
{
	LPUART_transmit_message(Communication.measure);
	CDC_Transmit_FS(Communication.measure, strlen(Communication.measure));
}

And finally, if tracking down all the CDC_Transmit_FS() calls that show up in the compiler warnings you posted doesn't point you to the problem, try this. Arrange it so that you code always outputs the same string, or at least the same LENGTH string. Add code inside CDC_Transmit_FS() that checks the length parameter and if the length is not the same as your fixed string length add a line where you can set a breakpoint, and something the compiler won't optimize away, for example:

uint8_t CDC_Transmit_FS( uint8_t * Buf, uint16_t Len )
{
   uint8_t result = USBD_OK;
 
   if ( Len != MY_EXPECTED_LENGTH ) {
      *Buf = '!';  // BREAKPOINT HERE, Change 1st byte of string, compiler shouldn't optimize this out
   }
 
   // The rest of the normal CDC_Transmit_FS() code here....
   USBD_CDC_HandleTypeDef *hcdc = ......
}

Hello Bob,

on 5) ..you got me! :D . Truely this is a special debug use case, I did implement today. it is not the normal use case and will be changed again. Nevertheless the problem existed also prior to the change from today.

6) yes, that is exactly what I did.But I put the LPUART message ater the CDC_Transmit .

Ok I will try your last suggestion..

Hello Bob,

I tested your last suggestion. The error stil remains, so it is obvious no problem with buffer length or overflow.

i did have a hard fault again and have snapshotted it:

0690X00000BwDdLQAV.jpg

when I click to jump to the PC disassembly I get a lot of "Failed to exectue MI command..cannot access memory" for the 0x8405e2 nd a lot more addresses before and after. I don't know what this is telling me and how to correct this kind of error..

Bob S
Principal

0x8405e2 is not a valid FLASH address on the L476 parts. So something is getting corrupted. The HAL library has many structures that contain "pointers to functions" that the use to handle interrupts. USB in particular uses lots of these.

So look at the stack and see where the program was before the jump into oblivion. If you have a stray pointer overwriting data structures that could also explain the extra characters you see on the USB CDC output.