Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: USBHost_t36, how do I check if a transfer is NAK'ed?

  1. #1

    USBHost_t36, how do I check if a transfer is NAK'ed?

    I'm writing some code to control a mirrorless camera using PTP (picture transfer protocol), writing a class to inherit from USBDriver. I own a Beagle USB analyzer and from what I see, the camera gives an annoying amount of NAKs after any command transfer (libusb would timeout/io-error on any single NAK), and the host driver (Sony/Microsoft) on the PC simply does a retry only about 50 microseconds later.

    This means that my code for the Teensy must also be able to quickly detect a NAK and then reattempt the transfer.

    Once I submit my transfer with queue_Data_Transfer, I am expecting a callback to the pipe->callback_function, with a parameter "const Transfer_t *transfer". I need this callback to indicate if the transfer is NAK'ed.

    Looking through the code, there's some magic numbers being checked for the EHCI qTD's token before the callback_function is called. I am lost here, I don't actually think qtd.token is an indicator of the transfer's status.

    I need help here... the strategy of using a slow timeout isn't going to work, I actually do need a callback on a NAK so I can implement a retry mechanism.

    I believe on a STM32, the correct way to find it is using ???_GetURBState, which can give me one of: URB_IDLE, URB_DONE, URB_NOTREADY, URB_NYET, URB_ERROR, URB_STALL

    Thanks

    (don't ask me to use a linux/sbc host, libusb has a few problems that causes the camera to internally exception)

    (the end result of this project will allow for additional photography features such as focus stacking, more AI driven autofocus, etc)

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,120
    Only trick known to post is in {local install}\hardware\teensy\avr\libraries\USBHost_t36 \USBHost_t36.h
    line #62?:
    Code:
    // Uncomment this line to see lots of debugging info!
    //#define USBHOST_PRINT_DEBUG
    Already known ? ... May, or may not help directly - but this ping to the post may elicit a better answer.

  3. #3
    I've examined every single debug message that can come out of the entire library. None of it is helpful to a developer. I'm sure this is intentional as the debug messages are supposed to help the user.

    I did find "if (stat & USBHS_USBSTS_NAKI) println(" NAK");" and it disabled under a #if 0

    USBHS_USBSTS_NAKI is not being handled at all by the ISR

    I might end up needing to muck up the EHCI code, I don't know if it's right to detect the USBHS_USBSTS_NAKI and call followup_Error, or maybe I should just write my own version of followup_Error

    I am hoping for an answer wayyyyyy easier than that though, but seeing as how USBHS_USBSTS_NAKI is literally ignored, I think I need to rethink my expectations

    EDIT: You know what... I can just extend the Transfer_struct to include a snapshot of USBHS_USBSTS and check it
    Last edited by frank26080115; 09-22-2021 at 07:09 AM.

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,577
    Quote Originally Posted by frank26080115 View Post
    I've examined every single debug message that can come out of the entire library. None of it is helpful to a developer. I'm sure this is intentional as the debug messages are supposed to help the user.
    Darn sorry about that. I do enjoy putting in messages that are not helpful.

    Note: @Paul has done most (read that all) of the low level stuff here and as you have seen he has commented out or #if 0 out most of the really low level stuff, as typically he is the main one who debugs things at this level. I do at time enable them to help debug some things when we are not seeing something at higher level.

    As for NAK type stuff, my assumptions have been there are sort of two levels of this. That is the lowest level ones, which I have assumed were handled by the hardware. And then sort of protocol level ones where the device responds with something like, I am busy...

    Again with the lower level ones like you showed in:

    Quote Originally Posted by frank26080115 View Post
    I did find "if (stat & USBHS_USBSTS_NAKI) println(" NAK");" and it disabled under a #if 0

    USBHS_USBSTS_NAKI is not being handled at all by the ISR
    my assumption is that this is handled by the hardware...
    That is when a pipe is created: there is a call:
    Code:
    	pipe->qh.capabilities[0] = QH_capabilities1(15, c, maxlen, 0,
    		dtc, dev->speed, endpoint, 0, dev->address);
    And again could be wrong, but that first parameter 15 is nak_recount_reload which again I assume has to do with something to do with retry counts... Could be wrong...
    Again more something that Paul would need to answer.

  5. #5
    this is harrrrrd

    I can't seem to write into the USBHS_USBINTR_NAKE bit, it's almost as if it's a reserved bit, but the reference manual doesn't indicate so, USBHS_USBINTR_NAKE is bit 16 in the reference manual

    I have posted the problem to the Freescale/NXP forum: https://community.nxp.com/t5/Kinetis...st/m-p/1346020

    What I posted there:

    --------------------------

    Example code

    Code:
    #include "USBHost_t36.h"
    
    USBHost myusb;
    
    USBHIDParser hid1(myusb);
    
    USBDriver *drivers[] = { &hid1, };
    #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
    const char* driver_names [CNT_DEVICES] = { "hid1", };
          bool  driver_active[CNT_DEVICES] = { false, };
    
    void setup()
    {
      while (!Serial && (millis() < 5000)) ; // wait for Arduino Serial Monitor
      Serial.println("\n\nUSB Host Testing USBHS_USBINTR_NAKE");
      myusb.begin();
    }
    
    void loop()
    {
      myusb.Task();
      USBHS_USBINTR |= (1 << 16); // explicitly use the number 16 instead of USBHS_USBINTR_NAKE
      if ((USBHS_USBINTR & (1 << 16)) == 0)
      {
        Serial.printf("Error: NAKE not written, 0x%08X\n", USBHS_USBINTR);
        delay(500);
      }
    }
    The NAKE bit fails to be written, the register reads back as 0x030C0016, what is expected is 0x030D0016

    Another try

    Code:
    #include "USBHost_t36.h"
    
    USBHost myusb;
    
    USBHIDParser hid1(myusb);
    
    USBDriver *drivers[] = { &hid1, };
    #define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
    const char* driver_names [CNT_DEVICES] = { "hid1", };
          bool  driver_active[CNT_DEVICES] = { false, };
    
    void setup()
    {
      while (!Serial && (millis() < 5000)) ; // wait for Arduino Serial Monitor
      Serial.println("\n\nUSB Host Testing USBHS_USBINTR_NAKE");
      myusb.begin();
    }
    
    void loop()
    {
      myusb.Task();
    
      USBHS_USBINTR = 0xFFFFFFFF;
      Serial.printf("USBHS_USBINTR: 0x%08X\n", USBHS_USBINTR);
      delay(500);
    }
    The register reads back as 0x030C00BF, but I expected 0x030D00BF if bit position 16 was writable

    What is going on? Where is USBHS_USBINTR_NAKE? How do I generate a ISR when I get a NAK?

    (NOTE: there is no code that clears USBHS_USBINTR without me knowing about it)

    (NOTE: I have tried writing to USBHS_ENDPTNAKEN before writing to USBHS_USBINTR, it does NOT help)

    (NOTE: I am using a USB HS analyzer, TotalPhase Beagle USB 480, I can see every single ACK, NAK, SOF, ping, etc)

    (NOTE: I checked the errata about this)

    END OF WHAT I POSTED TO NXP FORUM

    ------------------------

    The behavior right now is that a transfer goes out, I can see it go out on my analyzer, but the ISR does NOT fire, so my callback never fires, and my code just waits in a loop. Subsequent calls to queue_Data_Transfer has no effect and nothing else goes out on the bus. The USBHS core seems to be continuously sending PINGs and continuously getting NAKs.

    If Freescale really did screw up their silicon, I need a way to kill an ongoing transfer so I can retry manually. What's the official method inside USBHost_t36 to do that? Or... should I make the ISR function public and call it from main thread with some fake status bits to fool it?

    (edit: explicitly calling followup_Error after a fixed duration timeout is not clearing the way for another transfer)

    Or maybe I can just make it work on a Teensy 4? Can anybody help me confirm that the NAKE and NAKI bits on a Teensy 4 are NOT reserved? (manual says it exists)
    Last edited by frank26080115; 09-24-2021 at 08:22 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •