cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC receive: How do I send a NACK in order to implement flow control?

Nathan Conrad
Associate II

I'm using a STM32F070RB nucleo board with STM32CubeMX to implement a USB CDC device. After generating my project (and increasing the stack size minimum), I'm able to transmit data from the Windows 10 host to the CDC device by editing the CDC_Recive_FS(...) function. In this function, how do I reject the packet (sending a USB NACK) in the case that a local receive buffer is full?

My attempt is (I'm not actually storing into a local buffer... only simulating that it's full three of four times) :

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
	static int x = 0;
	x++;
	if((x % 4) == 1) {
		USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
		USBD_CDC_ReceivePacket(&hUsbDeviceFS);
 
		uart_tx_sync(Buf, *Len);
 
		return (USBD_OK);
	} else
		return (USBD_BUSY);
  /* USER CODE END 6 */
}

When I run this, the USB connection seems to hang. The first character is repeated on my UART, but the following characters never are sent. If I remove the "if" statement and always receive the packet, data continues being transmitted (so I think USB and such are properly setup in the firmware).

I'm using the HAL FW F0 v1.10.1.

1 REPLY 1
Nathan Conrad
Associate II

Oops, I had a grave misconception. Once execution gets to this function, the packet has already been accepted (with an ACK). It's too late to NACK it. I also misordered the Receive and uart_tx_sync(), handling the data should be done before ReceivePacket is called.

What USBD_CDC_ReceivePacket() actually does is configure the endpoint to accept another packet at the RxBuffer location.

So, to properly NACK buffers, the USBD_CDC_ReceivePacket() function needs to be called only when it is ready to accept more data (likely in the function which frees the buffer space).