cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 CDC Host - IN transaction always returns NAK

Paulus
Associate II

I've setup an STM32F407 as a CDC Host on the HS peripheral with Full Speed (FS) comms, but the IN transaction always returns a NAK and no Device data is received on the Bulk Data pipe. I used the USB Host example from ST.com (userfunction that only transmit a message when the application=ready and a button is pushed, a receive api USBH_CDC_Receive is called within the transmit call back. I also tried a while loop with just receive after sending a message).

The STM32 Host appears to enumerate the CDC device correctly (status=CDC_CLASS at end of process). The USBH_CDC_Transmit function correctly sends an OUT transaction, an ACK acknowledge byte is returned, the USBH_CDC_TransmitCallback is triggered, and everything is visible as expected via the packet sniffer.

When using the USBH_CDC_Receive for an IN transaction, the packet sniffer sees an apparently correct sequence, but the Device always returns NAK.

When using a PC based CDC Host, the IN transaction causes the Device to return data correctly, and is shown clearly on the packet sniffer.

STM32 CDC Host details

cube 6.0.1

discovery board F407VGT MB997D,

HAL version 2017,

ST example downloaded from ST.com, this a good slide pack that shows the example as well https://blog.brichacek.net/wp-content/uploads/2015/10/STM32F4-and-USB.pdf

clock details 8Mhz, USB 48 Mhz,

linecoding info - SetLineCoding[115200,0,0,8],

NVIC interrupt settings USB OTG Global (highest), USB OTG Endpoint IN (second), USB OTG Endpoint OUT(second) as per MxCube

]

Steps taken so far

  • Experimented with inserting Delay timings between subsequent reads
  • Used different OTG devices with same result (Comms setup but not receive). (I can see the various descriptors and see that they are different devices)
  • I have used messages with various lengths like newline, cr, Hello, Hello this is a test etc.
  • I have plugged and unplugged the device, with nicely re-enumerates
  • I added the line coding api call after the Application state is ready as per ST's application note and tried different line codings despite the device also being an OTG device
  • DMA is not enabled
  • single stepped the process thru STV2Link and IDE:

I can see with the IDE debugger that the USB Host channel interrupt for receive is working in STMF4xxx_HAL_HCD.c where the driver loops thru the 12 channels/endpoints and find channel 4 and calls HCD_HC_IN_IRQHandler. In this call I can see that it checks all statuses like BHERR, STALL and it lands on

"else if ((USBx_HC(ch_num)->HCINT & USB_OTG_HCINT_CHH) == USB_OTG_HCINT_CHH)" and ....

if (hhcd->hc[ch_num].state == HC_NAK)

  {

   hhcd->hc[ch_num].urb_state = URB_NOTREADY;

and returns to main and the whole process repeats

Questions

1 Does there need to be a specific step between completion of Enumeration and issuing an IN transaction?

2 Are and What line codings are necessary?

3 Any suggestions for further debugging and or tests?

Thanks Paul

edits: I used the transmit callback routine to trigger my oscilloscope to catch the rx/tx line data. See attached screenshot. As you can see data packets do occur although these could be the NAKs.0693W000004KK8VQAW.jpg

5 REPLIES 5

It's the device which does not respond with data, but you told us nothing about it. I assume it's a 3rd party device and you have no control over it.

It may expect handshake (both directions) or line coding information before it starts receiving on its UART and then retransmitting that to the host. Or anything else.

Sniff and try to closely reproduce the sequence of events after enumeration with PC.

USB is more a collection of widely set frameworks and vague operational hints, rather than a precise and concise specification, leaving ample space for interpretation of details. You are then usually left with no option but to find out the particular implementation's idiosyncrasies by trial and error, and then cater for them.

JW

Pavel A.
Evangelist III

> 1 Does there need to be a specific step between completion of Enumeration and issuing an IN transaction?

Maybe yes. When you test with the PC host, doesn't it send any setup command, like set baudrate and other parameters?

-- pa

The device does go thru all enumeration stages successfully. After it finishes and the Application state goes to Application Ready, I set the linecoding to 230400 baud and read out the linecoding after a pause but the baudrate stays 115200...

So definitely something is not working in the exchange between host and device.

SO next step I took was to implement all devices (Mass storage, audio, hid) to see if the enumeration or the device state machine or both have an issue.

I discovered that the mouse does fully work, so something does work. The Mass storage and Audio devices do not work and get stuck in the enumeration process after opening the pipes see code fragment below.

/**
  * @brief  USBH_HandleEnum
  *         This function includes the complete enumeration process
  * @param  phost: Host Handle
  * @retval USBH_Status
  */
static USBH_StatusTypeDef USBH_HandleEnum(USBH_HandleTypeDef *phost)
{
  USBH_StatusTypeDef Status = USBH_BUSY;
  USBH_StatusTypeDef ReqStatus = USBH_BUSY;
 
  switch (phost->EnumState)
  {
    case ENUM_IDLE:
      /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
      ReqStatus = USBH_Get_DevDesc(phost, 8U);
      if (ReqStatus == USBH_OK)
      {
        phost->Control.pipe_size = phost->device.DevDesc.bMaxPacketSize;
 
        phost->EnumState = ENUM_GET_FULL_DEV_DESC;
 
        /* modify control channels configuration for MaxPacket size */
        USBH_OpenPipe(phost, phost->Control.pipe_in, 0x80U, phost->device.address,
                      phost->device.speed, USBH_EP_CONTROL,
                      (uint16_t)phost->Control.pipe_size);
 
        /* Open Control pipes */
        USBH_OpenPipe(phost, phost->Control.pipe_out, 0x00U, phost->device.address,
                      phost->device.speed, USBH_EP_CONTROL,
                      (uint16_t)phost->Control.pipe_size);
      }
      else if (ReqStatus == USBH_NOT_SUPPORTED)
      {
        USBH_ErrLog("Control error: Get Device Descriptor request failed");
        phost->device.EnumCnt++;
        if (phost->device.EnumCnt > 3U)
        {
          /* Buggy Device can't complete get device desc request */
          USBH_UsrLog("Control error, Device not Responding Please unplug the Device.");
          phost->gState = HOST_ABORT_STATE;
        }
        else
        {
          /* free control pipes */
          USBH_FreePipe(phost, phost->Control.pipe_out);
          USBH_FreePipe(phost, phost->Control.pipe_in);
 
          /* Reset the USB Device */
          phost->gState = HOST_IDLE;
        }
      }
      else
      {
        /* .. */
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14); <---- Here I get stuck with Audio and MSC
      }
      break;
 
    case ENUM_GET_FULL_DEV_DESC:
      /* Get FULL Device Desc  */
etc....

i toggle a led to give me a real-time debugging status so I can plug in and out devices and see if they get stuck rather then single step thru the IDE.

The USB status is USBH_BUSY until the device times out and goes thru the enumeration again... attach, enumerate, flashing led, etc.

So I am after suggestions and some next step that I can undertake. My ezSniffer broke so ordered a better alternative Beagle sniffer and hopefully I can add some USB packets pics as well when it arrives=) .

Sorry for the delayed reply but indeed, I used a stm32 board with a STM VCP CDC device (STM32F103) to connect to the DiscoF407 board. I have sniffed the PC to STM VCP CDC device and it goes thru a lot of line coding.

Between DIscoF4 and VCP device, my linecoding api to set the line coding gives a USBH_Busy response. Get_LineCoding does work but it is always 115200 Baud.

Unfortunately ezSniffer died:sad_but_relieved_face: when I press its reset button. So ordered the more expensive Beagle sniffer. Added some more details in Pavels reply. Thanks for the advice.

Fejit.1
Associate

Note, that for AN2606/pattern6 (as is L412), the "flash empty" detection in fact simplest assessments the very first word of FLASH against 0xFFFFFFFF; and also that once that is detected actual blender reviews, it may not leave the use of "everyday" reset despite the fact that the FLASH is reprogrammed, you want both poweron reset or compelled reloading of the choice bytes.