RawHID recv and send timeout is always 1ms longer

I did a post on this subject a while back, this is the updated/revised suggestion.

I'm using RawHID with a Teensy 4.1 in my project and I need a control loop that run at at least 1kHz. The code looks a bit like this :

Code:
int main(int argc, char *argv[])
{
	/// Setup Code

	while(true)
	{
		RawHID.recv(buffer, 0);

		/// Some computing...

		RawHID.send(buffer, 0);
	}
}

I set the send and receive timeout to 0 and measured the computing time. To my surprise, the computing time is around 300 us (0,3 ms), but the loop frequency is at almost exactly 500 Hz (2000 us). I dug a little bit in the teensy4 core source code and I realized that the timeout is only compared with > instead of >=. Here is the said code from cores/teensy4/usb_rawhid.c :

Code:
int usb_rawhid_recv(void *buffer, uint32_t timeout)
{
	uint32_t wait_begin_at = systick_millis_count;
	uint32_t tail = rx_tail;
	while (1) {
		if (!usb_configuration) return -1; // usb not enumerated by host
		if (tail != rx_head) break;
		if (systick_millis_count - wait_begin_at > timeout)  {
			return 0;
		}
		yield();
	}
//	digitalWriteFast(0, LOW);
	if (++tail > RX_NUM) tail = 0;
	uint32_t i = rx_list[tail];
	rx_tail = tail;

	memcpy(buffer,  rx_buffer + i * RAWHID_RX_SIZE, RAWHID_RX_SIZE);
	rx_queue_transfer(i);
	//memset(rx_transfer, 0, sizeof(rx_transfer));
	//usb_prepare_transfer(rx_transfer + 0, rx_buffer, RAWHID_RX_SIZE, 0);
	//usb_receive(RAWHID_RX_ENDPOINT, rx_transfer + 0);
	return RAWHID_RX_SIZE;
}

int usb_rawhid_send(const void *buffer, uint32_t timeout)
{
	transfer_t *xfer = tx_transfer + tx_head;
	uint32_t wait_begin_at = systick_millis_count;

	while (1) {
		if (!usb_configuration) return -1; // usb not enumerated by host
		uint32_t status = usb_transfer_status(xfer);
		if (!(status & 0x80)) break; // transfer descriptor ready
		if (systick_millis_count - wait_begin_at > timeout) return 0;
		yield();
	}
	uint8_t *txdata = txbuffer + (tx_head * RAWHID_TX_SIZE);
	memcpy(txdata, buffer, RAWHID_TX_SIZE);
	arm_dcache_flush_delete(txdata, RAWHID_TX_SIZE );
	usb_prepare_transfer(xfer, txdata, RAWHID_TX_SIZE, 0);
	usb_transmit(RAWHID_TX_ENDPOINT, xfer);
	if (++tx_head >= TX_NUM) tx_head = 0;
	return RAWHID_TX_SIZE;
}

To solve this problem, I have 2 suggestions:

  • Change the timeout compare (line 107 and line 134) from:
    Code:
    if (systick_millis_count - wait_begin_at > timeout) return 0;
    to:
    Code:
    if (systick_millis_count - wait_begin_at >= timeout) return 0;
  • Change the timeout compare (line 107 and line 134) from:
    Code:
    if (systick_millis_count - wait_begin_at > timeout) return 0;
    to:
    Code:
    if (systick_millis_count - wait_begin_at > timeout || !timeout) return 0;

I think suggestion #1 is especially the best since it solve the issue that cause the timeout to always be at least 1 ms to long.

Request: Implement those changes or something similar in the source code.
 
Back
Top