3
\$\begingroup\$

I am developping a simple HID Device (a mouse) on a STM32F7 board.

The enumeration works great, the device is recognized as a mouse by the PC.

I use the IN endpoint 3 in interrupt mode. However, when the host (PC) sends IN token to this endpoint, asking for a 3-bytes report (as defined in my Report Descriptor), the device does not see it.

I've monitored the registers of my device, and I've noticed that the DAINT register never sets the 3rd bit. This bit is set when an event occurs at IN endpoint 3.

I've also checked my configuration registers for the IN endpoint 3, and I've noticed that I cannot set the SD0PID bit in the DIEPCTL_3 register. The firmware cannot set this bit although it is a R/W bit.

Here's the definition for this bit:

SD0PID: Set DATA0 PID Applies to interrupt/bulk IN endpoints only. Writing to this field sets the endpoint data PID (DPID) field in this register to DATA0.

This problem comes probably from my endpoint configuration, but I can't figure what's wrong. Here's my configuration:

    // Unmasks all interrupts of the targeted IN endpoint 3.
USB_OTG_FS_DEVICE->DAINTMSK |= ( 1 << 3);

// Activates the endpoint, sets endpoint handshake to NAK (not ready to send data), sets DATA0 packet identifier
IN_ENDPOINT(3)->DIEPCTL &= ~(USB_OTG_DIEPCTL_MPSIZ | USB_OTG_DIEPCTL_EPTYP | USB_OTG_DIEPCTL_TXFNUM);
IN_ENDPOINT(3)->DIEPCTL |= (USB_OTG_DIEPCTL_USBAEP | USB_OTG_DIEPCTL_SNAK | USB_OTG_DIEPCTL_SD0PID_SEVNFRM);

IN_ENDPOINT(3)->DIEPCTL |= (ENDPOINT_64_SIZE << USB_OTG_DIEPCTL_MPSIZ_Pos);     // max packet size = 64 bytes
IN_ENDPOINT(3)->DIEPCTL |= (ENDPOINT_INTERRUPT_TYPE << USB_OTG_DIEPCTL_EPTYP_Pos);  // interrupt endpoint
IN_ENDPOINT(3)->DIEPCTL |= (3 << USB_OTG_DIEPCTL_TXFNUM_Pos);       // assign TxFIFO_3 to the endpoint


/* configure the endpoint Tx FIFO */
TxFIFO_config(3, 64);

Note: there is only one RxFIFO in this microcontroller, which is shared between all endpoints. The address of this FIFO is hardwired, so the only thing to configure is its size. Its size has already been configured when configuring Endpoint 0, and was set to 46 words (46 uint32_t) as recommanded in the datasheet.

Thank you for any help.

\$\endgroup\$
7
  • \$\begingroup\$ just a wild guess ... may be a confusion between endpoint 3 and 3rd endpoint ... 0, 1, 2 ... third bit is bit #2 \$\endgroup\$
    – jsotola
    Oct 17, 2022 at 23:49
  • \$\begingroup\$ Are you writing an entire USB device stack yourself? If so, there are so many things that can go wrong. Or are you using a framework or library? \$\endgroup\$
    – Codo
    Oct 18, 2022 at 15:01
  • \$\begingroup\$ I note that the code sets NAK. As long as NAK is set, the device will not send anything. Additionally, you also need to write data to the endpoints TX FIFO. Without data, the device will not answer either. At the lowest level of the USB protocol, the host asks for data. But at the MCU level, you will never see this request. The USB peripheral handles everything if data is available and NAK is not set. The only time you have a request/response pattern at MCU level is for control requests. \$\endgroup\$
    – Codo
    Oct 18, 2022 at 17:04
  • \$\begingroup\$ @jsotola hi, unfortunately I have checked in the datasheet and the endpoint 3rd is the 4th endpoint (bit 3), bit 0 is reserved for endpoint 0 even if the register does not apply to it \$\endgroup\$
    – Wheatley
    Oct 19, 2022 at 14:18
  • \$\begingroup\$ @Codo Hi, yes I am writing a USB device stack from scratch, no third party nor library used. I have been able to make the control endpoint 0 work as expected, but not the endpoint 3 \$\endgroup\$
    – Wheatley
    Oct 19, 2022 at 14:20

1 Answer 1

1
\$\begingroup\$

Ok I've finally resolved this problem:

  1. The endpoint was stalled, I've made a typo in my "send data through endpoint" function: I've written Reg &= STALL instead of Reg &= ~STALL so I was breaking the register instead of clearing the STALL bit

  2. I don't know why, but the core de-activates an endpoint each time a transfer on this endpoint is completed. I've missed that in the datasheet. Hence we need to re-activate the endpoint for each transfer, by setting the EPENA bit in the DI(O)EPCTL register.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Glad to see it works now. The endpoint deactivation is an essential feature for flow control. Otherwise, more data would arrive with no place to store it, resulting in a data loss. \$\endgroup\$
    – Codo
    Oct 19, 2022 at 19:21
  • \$\begingroup\$ @Codo thank you ! I wasn't aware of this feature, but it makes sens \$\endgroup\$
    – Wheatley
    Oct 20, 2022 at 19:04
  • \$\begingroup\$ The endpoint is deactivated so as not to overwrite the data buffer with new transfer, and so as not to transmit the same data buffer twice. \$\endgroup\$ Dec 20, 2022 at 19:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.