2025-01-07 07:55 AM - last edited on 2025-01-07 08:11 AM by SofLit
I'm kind of stuck. I have USB_CDC running, data appears on the Kitty-Terminal in Windows10 via USB, presented as COM6: serial device in Windows.
Sending data vis USB_CDC is easy:
ret = CDC_Transmit_FS( buffer0, sizeof( buffer0 ) );
if( ret != USBD_OK ) { /* errors during sending ? .....
Receiving however doesn't work. That should be interrupt driven, not?
The interface code allocates one buffer. And AFAIK there is a callback routine
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
Callback would mean it gets called automatically "by the system" (acutally the ISR) when there is data.
Apparently I've to modify that routine into a non static version (correct?) and shovle away the *Len bytes at Buf
(USB_CDC ring buffer) into my application buffer, waiting for me.
However I think the callback never gets called. I type away at the terminal but nothing happens.
Thus there are some fundamental questions:
- is receiving via USB_CDC done interrupt driven?
- do I have to switch on that mechanism?
- bufferhandling: is CDC_Receive_FS the callback routine?
- when modifying it what about the "static" declaration ?
- what about concurrency? Do I need to prevent the callback from messing up my application buffer?
- how is flow control regulated on an USB_CDC serial connection?
Current non-functioning(?) callback :
extern uint8_t *buffer; /* application buffer reference , [0] != '\0' means data received */
int8_t CDC_Receive_FS( uint8_t *rec_buffer, uint32_t *sz )
{
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, rec_buffer);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
memset( buffer, '\0', 100 ); /* ugly, i know */
memcpy( buffer, rec_buffer, (size_t) *sz );
memset( rec_buffer, '\0', (size_t) *sz ) ;
return (USBD_OK);
}
Application code:
uint8_t *buffer; /* application buffer definition , [0] != '\0' means data received */
.. the following is inside a loop, ~2 seconds per iteration ...
HAL_Delay( 1000 ); /* wait a second */
if( buffer[0] != '\0' ) { /* did input data magically appear ? */
HD44780_SetCursor(1,1); HD44780_PrintStr( "DATA !" ); /* yes, tell the user about it */
HD44780_SetCursor(0,3); HD44780_PrintStr( (char *)buffer ); /* print the data */
buffer[0] = '\0'; /* indicate app buffer has been used/displayed */
} else { /* no data has been received */
HD44780_SetCursor(1,1); HD44780_PrintStr("-nix- "); /* tell the user the bad news */
}
Solved! Go to Solution.
2025-01-07 04:46 PM
Status: I tried to use some exmples on the Net, namely by Khaled Magdy https://deepbluembedded.com/stm32-usb-cdc-virtual-com-port-vcp-examples/ to no avail. Sending runs fine, receiving does not work.
Even after I fixed the (perceived) sequence mistake in CDC_Receive_FS (correct would be : first do something with the buffer data the callback was called and AFTERWARDS do set RX buffer and Receive packet), still no input.
Then I found JRahlf on GitHub where he posted stm32_usb_cdc_improved_if
https://github.com/jrahlf/stm32_usb_cdc_improved_if
What a great improvement over the stock ST code !
Simply replace usbd_cdc_if.c and usbd_cdc_if.h with his versions and you're done.
Sending ist done via CDC_Transmit(Buf, len) and receiving is done via overloading
uint8_t CDC_DataReceivedHandler(const uint8_t *Buf, uint32_t len)
So to create a mirror-app (sending back all it receives from the PC-Terminal via USB_CDC COMx: Port)
one simply codes in main.c
uint8_t CDC_DataReceivedHandler(const uint8_t *Buf, uint32_t len)
{
CDC_Transmit(Buf, len);
return USBD_OK;
}
That is all! In the case data arrives you get called with Buf and len and to process it (in my case send it back)
you simply call CDC_Transmit. I thought that was exactly what I've been try to get working the better half of today, alas w/o success. Won't get any easier and has a lot of nifty features :
The really cool part ist that you can peek if the automagically maintained send buffer has
enough space for your outgoing message OR you can call CDC_Transmit* and check for error!
Here is the API :
uint8_t CDC_Transmit(const void* Buf, uint32_t Len); uint8_t CDC_TransmitTimed(const void* Buf, uint32_t Len, uint32_t TimeoutMs); uint8_t CDC_TransmitString(const char *string); uint8_t CDC_IsBusy(); uint32_t CDC_RXQueue_Dequeue(void* Dst, uint32_t MaxLen); uint32_t CDC_TXQueue_GetReadAvailable(); uint32_t CDC_TXQueue_GetWriteAvailable(); uint32_t CDC_RXQueue_GetReadAvailable(); uint32_t CDC_RXQueue_GetWriteAvailable(); uint32_t CDC_GetDroppedTxPackets(); uint32_t CDC_GetDroppedRxPackets(); void CDC_ResetDroppedTxPackets(); void CDC_ResetDroppedRxPackets(); uint8_t CDC_DataReceivedHandler(const uint8_t *Data, uint32_t len); uint32_t CDC_GetLastTransmitStartTick(); uint32_t CDC_GetLastTransmitCompleteTick(); uint8_t CDC_IsComportOpen();
2025-01-07 04:46 PM
Status: I tried to use some exmples on the Net, namely by Khaled Magdy https://deepbluembedded.com/stm32-usb-cdc-virtual-com-port-vcp-examples/ to no avail. Sending runs fine, receiving does not work.
Even after I fixed the (perceived) sequence mistake in CDC_Receive_FS (correct would be : first do something with the buffer data the callback was called and AFTERWARDS do set RX buffer and Receive packet), still no input.
Then I found JRahlf on GitHub where he posted stm32_usb_cdc_improved_if
https://github.com/jrahlf/stm32_usb_cdc_improved_if
What a great improvement over the stock ST code !
Simply replace usbd_cdc_if.c and usbd_cdc_if.h with his versions and you're done.
Sending ist done via CDC_Transmit(Buf, len) and receiving is done via overloading
uint8_t CDC_DataReceivedHandler(const uint8_t *Buf, uint32_t len)
So to create a mirror-app (sending back all it receives from the PC-Terminal via USB_CDC COMx: Port)
one simply codes in main.c
uint8_t CDC_DataReceivedHandler(const uint8_t *Buf, uint32_t len)
{
CDC_Transmit(Buf, len);
return USBD_OK;
}
That is all! In the case data arrives you get called with Buf and len and to process it (in my case send it back)
you simply call CDC_Transmit. I thought that was exactly what I've been try to get working the better half of today, alas w/o success. Won't get any easier and has a lot of nifty features :
The really cool part ist that you can peek if the automagically maintained send buffer has
enough space for your outgoing message OR you can call CDC_Transmit* and check for error!
Here is the API :
uint8_t CDC_Transmit(const void* Buf, uint32_t Len); uint8_t CDC_TransmitTimed(const void* Buf, uint32_t Len, uint32_t TimeoutMs); uint8_t CDC_TransmitString(const char *string); uint8_t CDC_IsBusy(); uint32_t CDC_RXQueue_Dequeue(void* Dst, uint32_t MaxLen); uint32_t CDC_TXQueue_GetReadAvailable(); uint32_t CDC_TXQueue_GetWriteAvailable(); uint32_t CDC_RXQueue_GetReadAvailable(); uint32_t CDC_RXQueue_GetWriteAvailable(); uint32_t CDC_GetDroppedTxPackets(); uint32_t CDC_GetDroppedRxPackets(); void CDC_ResetDroppedTxPackets(); void CDC_ResetDroppedRxPackets(); uint8_t CDC_DataReceivedHandler(const uint8_t *Data, uint32_t len); uint32_t CDC_GetLastTransmitStartTick(); uint32_t CDC_GetLastTransmitCompleteTick(); uint8_t CDC_IsComportOpen();