AnsweredAssumed Answered

Bus timeout on K20 USB host transfers

Question asked by Avelino Herrera Morales on Mar 31, 2018
Latest reply on Apr 6, 2018 by Avelino Herrera Morales

Hi all,

I am writting a simple USB host example code from scratch (without libraries). A minimalistic host that detects a USB device plugged, sends a SET_ADDRESS(1) setup packet (with all seems to be ok until here) and runs into "bus timeout" when send a second SET_CONFIGURATION setup packet:

 

void usbHostInit() {
    // usbotg clock gate enable
    SIM_SCGC4 |= 0x00040000;
    // hard reset the usb module
    USB0_USBTRC0 |= 0x80;
    while (USB0_USBTRC0 & 0x80)
        ;
    // enable usb transceiver (disable suspend state)
    USB0_USBCTRL &= 0x7F;
    // clear interrupt flags
    USB0_ISTAT = 0xFF;
    USB0_ERRSTAT = 0xFF;
    USB0_OTGISTAT = 0xFF;
    USB0_USBTRC0 |= 0x40;    // undocumented
    // configure both d+ and d- pulldown resistors
    USB0_OTGCTL = 0x30;
    // enable ATTACH interrupt
    USB0_INTEN |= 0x40;
    // enable usbotg irq
    NVIC_SER[USBOTG_IRQ >> 5] = (1ULL << (USBOTG_IRQ & 0x1F));
    // enable host mode
    USB0_CTL |= 0x08;
    // disable SOF generation
    USB0_CTL &= 0xFE;
    // configure BDT
    memset((void *) usbBufferDescriptorTable, 0, 512);
    USB0_BDTPAGE1 = (((uint32_t) usbBufferDescriptorTable) >> 8) & 0x000000FF;
    USB0_BDTPAGE2 = (((uint32_t) usbBufferDescriptorTable) >> 16) & 0x000000FF;
    USB0_BDTPAGE3 = (((uint32_t) usbBufferDescriptorTable) >> 24) & 0x000000FF;
    usbHostStatus = USB_HOST_STATUS_IDLE;
}

 

void usbISR() {
    uint8_t istat = USB0_ISTAT;
    if (istat & 0x40) {
        // usb device attached
        // disable all usb interrupts
        USB0_INTEN = 0x00;
        // set packet size to 8 bytes (minimum)
        USB0_SOFTHLD = 18;
        // check device speed
        if (!(USB0_CTL & 0x80)) {
            // low speed device
            USB0_ADDR = 0x80;
            // host without hub = 1
            USB0_ENDPT0 = 0x80;
        }
        else {
            // full speed device
            USB0_ADDR = 0x00;
            USB0_ENDPT0 = 0x00;
        }
        // send usb reset for 10 ms
        USB0_CTL |= 0x10;
        wait10ms();
        USB0_CTL &= 0xEF;
        // start generation of SOF packets
        USB0_CTL |= 0x01;
        // set device address to 0 (keep low speed bit)
        USB0_ADDR &= 0x80;
        USB0_ENDPT0 |= 0x1D;    // txen, rxen, enable setup transfers
        // configure endpoint 0 for tx a SET_ADDRESS(1) setup token
        UsbSetupPacket *setupPacket = (UsbSetupPacket *) txBuffer;
        setupPacket->bmRequestType = 0x00;
        setupPacket->bRequest = 0x05;   // 5 = set_address
        setupPacket->wValue = 1;   // 1 = address
        setupPacket->wIndex = 0;
        setupPacket->wLength = 0;
        usbBufferDescriptorTable[0].evenTx.buffer = (uint8_t *) txBuffer;
        usbBufferDescriptorTable[0].evenTx.r = (((uint32_t) 8) << 16) | 0x80;   // 8 bytes, data0, own
        USB0_TOKEN = 0xD0;      // setup token
        // enable transfer completed and disable attach interrupt
        USB0_INTEN = 0x08;
        usbHostStatus = USB_HOST_STATUS_WAIT_SET_ADDRESS_SETUP_TX;
        USB0_ISTAT = 0x40;
    }
    else if (istat & 0x08) {
        // usb transfer completed
        if (usbHostStatus == USB_HOST_STATUS_WAIT_SET_ADDRESS_SETUP_TX) {
            usbBufferDescriptorTable[0].evenRx.buffer = (uint8_t *) rxBuffer;
            usbBufferDescriptorTable[0].evenRx.r = (((uint32_t) 0) << 16) | 0xC0;  // 0 bytes, data1, own
            USB0_TOKEN = 0x90;      // in token
            usbHostStatus = USB_HOST_STATUS_WAIT_SET_ADDRESS_IN_RX;
        }
        else if (usbHostStatus == USB_HOST_STATUS_WAIT_SET_ADDRESS_IN_RX) {

            // ...

            // AT THIS POINT I GET A DATA1 PID FROM BUFFER DESCRIPTOR (I THINK THAT IS CORRECT, IS'N IT?)

            // ...

            // configure device address = 1
            USB0_ADDR |= 0x01;
            // reset to even banks again (the "bus timeout" appears reseting to even banks or not reseting at all)
            USB0_CTL |= 0x02;
            // send SET_CONFIGURATION(1) setup packet
            UsbSetupPacket *setupPacket = (UsbSetupPacket *) txBuffer;
            setupPacket->bmRequestType = 0x00;
            setupPacket->bRequest = 0x09;  // 9 = set_configuration
            setupPacket->wValue = 1;       // 1st configuration
            setupPacket->wIndex = 0;
            setupPacket->wLength = 0;
            usbBufferDescriptorTable[0].evenTx.buffer = (uint8_t *) txBuffer;
            usbBufferDescriptorTable[0].evenTx.r = (((uint32_t) 8) << 16) | 0x80;   // 8 bytes, data0, own
            // setup token
            USB0_TOKEN = 0xD0;
            usbHostStatus = USB_HOST_STATUS_WAIT_SET_CONFIGURATION_SETUP_TX;
        }
        else if (usbHostStatus == USB_HOST_STATUS_WAIT_SET_CONFIGURATION_SETUP_TX) {

            // ...

            // BUT HERE I GET A BUS TIMEOUT PID FROM BUFFER DESCRIPTOR  (TOK_PID = 0) :-(

            // ...

            usbBufferDescriptorTable[0].evenRx.buffer = (uint8_t *) rxBuffer;
            usbBufferDescriptorTable[0].evenRx.r = (((uint32_t) 0) << 16) | 0xC0;  // 0 bytes, data1, own
            USB0_TOKEN = 0x90;      // in token
            usbHostStatus = USB_HOST_STATUS_WAIT_SET_CONFIGURATION_IN_RX;
        }
        else if (usbHostStatus == USB_HOST_STATUS_WAIT_SET_CONFIGURATION_IN_RX) {
            // configure endpoint 1
            USB0_ENDPT1 = 0x19;    // rxen

            // ...

            // ...
            usbHostStatus = USB_HOST_STATUS_IDLE_CONFIGURED;
        }
        USB0_ISTAT = 0x08;
    }
    else
        USB0_ISTAT = 0xFF;
}

 

I have tested different setup commands and always get the same error: The first setup packet returns a PID of a non error but the second setup packet generates a TOK_PID value of 0x00 (bus timeout) instead of DATA0/DATA1.

 

Can any body help me? Thanks in advance!!

Outcomes