cancel
Showing results for 
Search instead for 
Did you mean: 

STMu545 USB Host - Only getting NAKs on setup packet

bartosz_
Associate

Hey!

I'm working on implementing USB host functionality on the STM32U545 using the USB_DRD_FS peripheral. I've got the basic structure working, but I'm stuck at the enumeration stage, where the device responds with NAK to SETUP packets and enumeration never completes.

As I'm using the dev boad which has no power, I'm using an external 5V supply on USB VCC and GND pins to use host mode.

I ahve been trying the stm32u5xx_hal_hcd HAL file to get it working. Here's how I'm doing it:

First, I'm keeping these structures:

typedef struct {
    uint8_t dev_addr;
    uint8_t ep_addr;
    uint8_t ep_type;
    bool in_use;
} channel_info_t;

static channel_info_t _channel_info[FSDEV_EP_COUNT];

static uint8_t find_free_channel(uint8_t dev_addr, uint8_t ep_addr) {
    for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
        if (!_channel_info[i].in_use) {
            return i;
        }
    }
    return 0xFF;
}

static uint8_t find_channel(uint8_t dev_addr, uint8_t ep_addr) {
    for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
        if (_channel_info[i].in_use &&
            _channel_info[i].dev_addr == dev_addr &&
            _channel_info[i].ep_addr == ep_addr) {
            return i;
        }
    }
    return 0xFF;
}

And then initializing with:

// usb initialization, ran in main.c
static void MX_USB_DRD_FS_HCD_Init(void)
{

  /* USER CODE BEGIN USB_DRD_FS_Init 0 */

  /* USER CODE END USB_DRD_FS_Init 0 */

  /* USER CODE BEGIN USB_DRD_FS_Init 1 */

  /* USER CODE END USB_DRD_FS_Init 1 */
  hhcd_USB_DRD_FS.Instance = USB_DRD_FS;
  hhcd_USB_DRD_FS.Init.dev_endpoints = 8;
  hhcd_USB_DRD_FS.Init.Host_channels = 8;
  hhcd_USB_DRD_FS.Init.speed = HCD_SPEED_FULL;
  hhcd_USB_DRD_FS.Init.phy_itface = HCD_PHY_EMBEDDED;
  hhcd_USB_DRD_FS.Init.Sof_enable = DISABLE;
  hhcd_USB_DRD_FS.Init.low_power_enable = DISABLE;
  hhcd_USB_DRD_FS.Init.vbus_sensing_enable = DISABLE;
  hhcd_USB_DRD_FS.Init.bulk_doublebuffer_enable = DISABLE;
  hhcd_USB_DRD_FS.Init.iso_singlebuffer_enable = DISABLE;
  if (HAL_HCD_Init(&hhcd_USB_DRD_FS) != HAL_OK)
  {
    printf("Failed to initialize HCD\r\n");
    Error_Handler();
  }
  /* USER CODE BEGIN USB_DRD_FS_Init 2 */
  /* USER CODE END USB_DRD_FS_Init 2 */

}

// and then later in the driver code I call 
bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
    for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
        _channel_info[i].in_use = false;
        _channel_info[i].dev_addr = 0;
        _channel_info[i].ep_addr = 0;
        _channel_info[i].ep_type = 0;
    }

    connected = false;
    HAL_HCD_Start(&hhcd_USB_DRD_FS);

    return true;
}

 

I detect device connection using HAL_HCD_Connect and HAL_HCD_Disconnect (both are working fine).

When detecting a device, I first reset the port:

void hcd_port_reset(uint8_t rhport) {
    HAL_HCD_ResetPort(&hhcd_USB_DRD_FS);
}

void hcd_port_reset_end(uint8_t rhport) {
    HAL_HCD_ResumePort(&hhcd_USB_DRD_FS);
}

// first run hcd_port_reset, then wait 10 ms, then hcd_port_reset_end

 

After that, I open control endpoint 0, and send a setup packet through these functions:

bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const *ep_desc) {
    uint8_t const ep_addr = ep_desc->bEndpointAddress;
    uint8_t const ep_num = tu_edpt_number(ep_addr);
    uint8_t const ep_type = get_ep_type(ep_desc->bmAttributes.xfer);
    uint16_t const max_packet_size = tu_edpt_packet_size(ep_desc);

    // Find a free channel
    uint8_t ch_num = find_free_channel(daddr, ep_addr);
    if (ch_num == 0xFF) return false;

    // Mark channel as in use BEFORE activation (important!)
    _channel_info[ch_num].in_use = true;
    _channel_info[ch_num].dev_addr = daddr;
    _channel_info[ch_num].ep_addr = ep_addr;
    _channel_info[ch_num].ep_type = ep_type;

    // Initialize the HAL host channel
    HAL_HCD_HC_Init(&hhcd_USB_DRD_FS, ch_num, ep_num, daddr,
                    HCD_DEVICE_SPEED_FULL, ep_type, max_packet_size);

    // Activate the channel
    HAL_HCD_HC_Activate(&hhcd_USB_DRD_FS, ch_num);
    
    return true;
}

bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]) {
    uint8_t ep_addr = 0x00;
    uint8_t ch_num = find_channel(daddr, ep_addr);
    if (ch_num == 0xFF) return false;

    // Submit SETUP packet using HAL
    // token=0 means SETUP, token=1 means DATA
    HAL_StatusTypeDef status = HAL_HCD_HC_SubmitRequest(
        &hhcd_USB_DRD_FS,
        ch_num,
        0,              // Direction: OUT
        EP_TYPE_CTRL,   // Control endpoint
        0,              // Token: SETUP
        (uint8_t *) setup_packet,
        8,
        0
    );

    return (status == HAL_OK);
}

 

The problem is that after sending the SETUP packet, the HAL calls my callback with USB_NOTREADY, and after a while the device times out. I'm not really sure what I'm doing wrong, so all help is appreciated.

0 REPLIES 0