Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDC_ReceiveQueue fails after CPU halt #804

Open
gigaj0ule opened this issue Nov 29, 2019 · 7 comments
Open

CDC_ReceiveQueue fails after CPU halt #804

gigaj0ule opened this issue Nov 29, 2019 · 7 comments

Comments

@gigaj0ule
Copy link

I have not pinned down the source of this bug yet, but it is reproducible on both windows and linux.

  1. Initialize an STM32F1 (maybe others too) and enumerate as CDC device.
  2. Halt core with GDB
  3. Send stuff to device such that multiple USB packets are enqeued.
  4. Resume core

CDC_ReceiveQueue_ReadSize and other CDC_ReceiveQueue functions will now be out-of-sync with received packets until the device undergoes a host-initiated USB reset or unplug event.

@fpistm
Copy link
Member

fpistm commented Nov 29, 2019

Hi @adammunich
Not an expert about that but in that case I don't think this could be possible to keep it sync.

@gigaj0ule
Copy link
Author

gigaj0ule commented Nov 29, 2019

My understanding is that the host will receive NACKs when the 64 byte endpoint buffer is full, but send them after core resumes and empties the buffer. So, something must becoming out-of-sync on resume. I have not figured out what yet. But the behavior i encountered, is that the rxqueue size may be zero, but there are still "ghost" packet in the EP rx buffer which is not emptied until you send another packet from the host.

@gigaj0ule
Copy link
Author

gigaj0ule commented Nov 29, 2019

I think I fixed it after a solid 10 hours of late night troubleshooting.

We have to change the following line in usbd_ep_conf.c

{CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_DBL_BUF},

To use single buffer mode.

{CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_SNG_BUF},

The (ST hal?) software is otherwise unable to keep track of the ping-pong state of the double buffer when debugging with GDB (or if the core is halted some other way).

If I halt the STM32 and let the computer send two packets and timeout, when it resumes the USB is always one packet behind unless it is hardware reset by kernel. This ghost in the shell that doesn't make it out until you send another packet, which then takes place of the ghost packet.

Note: this is a really serious error that makes the microcontroller unrecoverable even in soft reset. It must be physically disconnected from the computer which is really bad news for reliability, so I suggest we push this fix to the arduino core.

@fpistm
Copy link
Member

fpistm commented Dec 2, 2019

@adammunich
thanks for feedback, anyway, I guess this should not be the good fix. For F1, double buffering is used so this seems not a good idea to change this. @makarenya made a lot of work around this and I know I've not backport all their fixes when I've updated the STM32 USB device middleware because it was hard to maintain them.

@fpistm fpistm added this to To do in STM32 core based on ST HAL via automation Jul 22, 2021
fpistm added a commit to fpistm/Arduino_Core_STM32 that referenced this issue Jul 23, 2021
Defining USBD_CDC_USE_SINGLE_BUFFER will set endpoint kind
as single buffer instead of double one per default.

Fixes stm32duino#804

Signed-off-by: Frederic Pillon <frederic.pillon@st.com>
@gigaj0ule
Copy link
Author

gigaj0ule commented Jun 24, 2022

This problem has re appeared as someone had over-written the fix fpistm@90b75cc had committed

It was very troublesome to figure out the source of garbage serial data again.

@gigaj0ule
Copy link
Author

To fix it we must update const ep_desc_t ep_def[] to:

/* Includes ------------------------------------------------------------------*/
#include "usbd_ep_conf.h"

#ifdef USBD_USE_CDC
const ep_desc_t ep_def[] = {
#ifdef USE_USB_HS
  {0x00,       CDC_DATA_HS_MAX_PACKET_SIZE},
  {0x80,       CDC_DATA_HS_MAX_PACKET_SIZE},
  {CDC_OUT_EP, CDC_DATA_HS_MAX_PACKET_SIZE},
  {CDC_IN_EP,  CDC_DATA_HS_MAX_PACKET_SIZE},
  {CDC_CMD_EP, CDC_CMD_PACKET_SIZE}
#else /* USE_USB_FS */
#ifdef USB_OTG_FS
  {0x00,       CDC_DATA_FS_MAX_PACKET_SIZE},
  {0x80,       CDC_DATA_FS_MAX_PACKET_SIZE},
  {CDC_OUT_EP, CDC_DATA_FS_MAX_PACKET_SIZE},
  {CDC_IN_EP,  CDC_DATA_FS_MAX_PACKET_SIZE},
  {CDC_CMD_EP, CDC_CMD_PACKET_SIZE}
#else
  {0x00,       PMA_EP0_OUT_ADDR, PCD_SNG_BUF},
  {0x80,       PMA_EP0_IN_ADDR,  PCD_SNG_BUF},
//  {CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_DBL_BUF},
#ifndef USBD_CDC_USE_SINGLE_BUFFER
  {CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_DBL_BUF},
#else
  {CDC_OUT_EP, PMA_CDC_OUT_ADDR, PCD_SNG_BUF},
#endif
  {CDC_IN_EP,  PMA_CDC_IN_ADDR,  PCD_SNG_BUF},
  {CDC_CMD_EP, PMA_CDC_CMD_ADDR, PCD_SNG_BUF}
#endif
#endif
};
#endif /* USBD_USE_CDC */

@fpistm
Copy link
Member

fpistm commented Jun 24, 2022

igure out the source of garbage serial data again

As stated, this commit is part of my fork and was never merged in the official repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

3 participants