2 Replies Latest reply on May 17, 2017 7:06 AM by dragonfly.synths

    USB Hub CY7C65634 NAKing IN transfer following Get Descriptor Request

    dragonfly.synths

      Good afternoon,

         

      I have a Cypress hub (CY7C65634) connected to a Cypress FX3 (CYUSB3014) by means of a Maxim SPI-to-USB bridge (MAX3421E). The hub seems to be reseting correctly, and receives control transfers without error. However, when I try to retrieve the descriptor via a BULK-IN transfer (as specified in MAX3421E datasheet), I am greeted first with a NAK, and subsequently by J-STATE. NAK seems to indicate that no data is available to send. Do you know of any reason why the hub has not prepared the descriptor?

      I've attached my code FWIW, though it may require some familiarity with the MAX3421E. Any help would be appreciated.

         
          

      <code>

          

      void configureUsb(void){

          

          /*The CPU sets this bit to instruct the SIE to issue a bus reset on the D+ and D- lines. After setting
          this bit, the CPU can detect the end of the 50ms interval either by polling the BUSRST bit for
          zero, or by responding to the BUSEVENTIRQ. To program a bus reset, follow this sequence of steps:

          

          1.   Set BUSRST = 1.
          2.   Test for BUSRST = 0 or respond to the BUSEVENTIRQ.
          3.   Turn on frame markers by setting SOFKAENAB = 1.
          4.   Wait for at least one FRAMEIRQ.
          Step 4 ensures that the host logic is ready to generate the
          first host transaction.
          */
          dragonDebug("configuring", 100);

          

          //reset the bus    
          maxWriteReg(rHCTL, bmBUSRST);
          dragonDebug("pre bus", 100);
          //wait for reset
          while(!(maxReadReg(rHIRQ) & bmBUSEVENTIRQ)){
              dragonDebug("bus reset", maxReadReg(rHCTL) & bmBUSRST);
              CyU3PThreadRelinquish ();
          }
          // clear reset interrupt
          maxWriteReg(rHIRQ, bmBUSEVENTIRQ);
          maxWriteReg(rMODE ,  bmDPPULLDN|bmDMPULLDN|bmSOFKAENAB|bmHOST|bmSEPIRQ); // set into full speed host mode, separate I/O interrupt line

          

          dragonDebug("post bus reset", 100);

          

          // Relinquish the thread
          //CyU3PThreadRelinquish ();
          CyU3PThreadSleep (1);

          

          // the following steps need to be completed:
          /*
           *    -- Plug-in of a hub, enumeration of hub --
                                                           SETUP data
           Bus Reset                                                                 --- (1)
           Get Device Descriptor                           80 06 00 01 00 00 08 00
           Set Address (0x03)                              00 05 03 00 00 00 00 00
           Get Device Descriptor                           80 06 00 01 00 00 12 00
           Get Configuration Descriptor                    80 06 00 02 00 00 04 00
           Get Configuration Descriptor                    80 06 00 02 00 00 19 00
           Set Configuration (0x01)                        00 09 01 00 00 00 00 00

          

           Get Descriptor (Hub)                            A0 06 00 29 00 00 17 00   --- (2)
                        09 29 04 00 00 32 40 00 1E
           Set Port Feature (Port1, PORT_POWER)            23 03 08 00 01 00 00 00   --- (3)
           Set Port Feature (Port2, PORT_POWER)            23 03 08 00 02 00 00 00
           Set Port Feature (Port3, PORT_POWER)            23 03 08 00 03 00 00 00
           Set Port Feature (Port4, PORT_POWER)            23 03 08 00 04 00 00 00

          

              -- Hub ports watch, periodical --
           Interrupt-IN (Hub Status Change EP) (0x81)                                --- (4)
              -- optionally, repeated port scan --
           Get Port Status (Port1)                         A3 00 00 00 01 00 04 00
                        00 01 00 00        PORT_POWER
           Get Port Status (Port2)                         A3 00 00 00 02 00 04 00
                        00 01 00 00        PORT_POWER
           Get Port Status (Port3)                         A3 00 00 00 03 00 04 00
                        00 01 00 00        PORT_POWER
           Get Port Status (Port4)                         A3 00 00 00 04 00 04 00
                        00 01 00 00        PORT_POWER

          

           */

          

          /*
           * USB Request Field Sizes
           * bmRequestType 1
           * bRequest      1
           * wValue        2
           * wIndex        2
           * wLength       2
           */

          


          CyU3PMutexGet(&usbmutex, 1000);
          uint8_t error1, error2, error3;
          uint8_t address = 0x00;
          // set address req to 3 : 00 05 03 00 00 00 00 00
          //uint8_t stdUSBReq[8] = {0x00, 0x05, address, 0x00, 0x00, 0x00, 0x00, 0x00};
          //CyU3PThreadSleep (1000);
          //error1 = usbControlTransfer(0, stdUSBReq);
          //dragonDebug("address", error1+1);
          //CyU3PThreadSleep (1000);

          

          //USB 2.0 9.4.3
          //80 06 00 01 00 00 08 00
          uint8_t stdDescReq[8] =
          // standard USB request
          {0x80,
          // request is to get descriptor
          0x06,
          // device type, index 0
          0x00, 0x01,
          // no language id
          0x00,0x00,
          // length 8 bytes
          0x08,0x00};

          

          uint8_t descript[512];

          

          error1 = usbControlTransfer(address, stdDescReq);
          dragonDebug("control", error1);

          

          int i;
          for(i = 0; i < 5; i++){
              error2 = usbBulkIn(address, 0, descript);
              dragonDebug("bulk in", error2);
              error3 = hsout();
              if(error2==0 && error3==0)
                  break;
              //CyU3PThreadRelinquish ();
          }

          

          CyU3PMutexPut(&usbmutex);

          

          dragonDebug("done     ", 10);

          


      }

          

      uint8_t usbBulkIn(uint8_t addr, uint8_t endpoint, uint8_t * receiveData){

          

          uint8_t error = 0;
          /*
          2. Data
          If a data stage is required, it is programmed as a BULK-IN or BULK-OUT transfer. Some
          CONTROL transfers, such as Set_Address, do not require a data stage because the command
          data fits into the 8 bytes in the SETUP packet.
          */

          

          /*
           * Programming BULK-IN Transfers
           *  The CPU issues an IN token to request a peripheral to send it BULK data . Then the SIE
           *  transfers data into its RCVFIFO, and ACKS the transfer. The CPU writes HXFR = 0000eeee
           *  (Table 4) to initiate the IN transfer, where eeee is the desired endpoint address.
           *  */

          

          maxWriteReg(rPERADDR, addr);
          maxWriteReg(rHXFR, endpoint & 0x0F);
          /*
          The SIE sends an IN token, the address in the PERADDR register, the endpoint number in
          EP[3:0], and a CRC5. It then waits 6.5 bit times for the peripheral to respond.
          If the peripheral responds with a DATA0 or DATA1 PID followed by data, the SIE loads the
          received data bytes into the RCVFIFO and counts the bytes. At the end of the packet
          the SIE checks the packet for errors, updates the RCVBC register and HRSLT bits, and then
          asserts the HXFRDNIRQ bit.
          */

          

          // wait for completion interrupt
          while(!(maxReadReg(rHIRQ) & bmHXFRDNIRQ));
          // check result error code
          error = maxReadReg(rHRSL) & 0x0F;

          

          if(maxReadReg(rHIRQ) & bmRCVDAVIRQ){

          

              // check bytecount
              uint8_t bytecount = maxReadReg(rRCVBC);
              dragonDebug("bytecount", bytecount+1);
              // read that byte count into provided buffer
              maxReadMultiple(rRCVFIFO, receiveData, bytecount);
              // clear receive interrupt
              maxWriteReg(rHIRQ, bmRCVDAVIRQ);
          }

          

          // clear completion interrupt
          maxWriteReg(rHIRQ, bmHXFRDNIRQ);
          /*
          Depending on the transfer outcome, the SIE may or may not assert the RCVDAVIRQ.
          If the IN data was error-free (HRSLT = 0000), the SIE sends an ACK token, complements the
          data toggle, and asserts the RCVDAVIRQ to indicate that new IN data is valid.
          If the IN data was error-free but there was a data toggle mismatch (the DATA0 or DATA1 PID
          send by the peripheral did not match the endpoint toggle value), the SIE sends the ACK
          handshake, but it does not complement the data toggle or assert the RCVDAVIRQ. The SIE sets
          HRSL = 0110 (Toggle Error) for this condition.
          This situation would happen if the peripheral received a corrupted ACK handshake from the previous
          IN transfer. In this case the host ignores the data in the RCVDATA FIFO, because it represents data
          that the peripheral mistakenly resent when it missed the last ACK handshake. By ACK-ing the transfer
          and not updating its own toggle bit, the SIE causes the peripheral to complement its toggle bit,
          thus forcing the data toggle mechanism back into sync.
          If the HRSLT bits indicate a data error, the SIE does not send the ACK, complement the data
          toggle, or assert the RCVDAVIRQ bit. The CPU responds to the HXFRDNIRQ indication
          by examining the result bits in HRSLT[3:0].
          If the result is 0000 (success), the CPU reads RCVBC to determine the byte count, and then
          reads that number of bytes using repeated reads to the RCVFIFO register (page 48). After the
          CPU retrieves the data, it clears the RCVDAVIRQ bit (by writing 1 to it). If there is another
          buffer of IN data in the double-buffered RCVFIFO, the SIE immediately re-asserts the CVDAVIRQ bit.
           */

          

          return error;
      }

          

      </code>