0
\$\begingroup\$

I made a simple custom board with a SAMD51 and am trying to get USB to enumerate on my computer, it works with Atmel START USB example so I know the board is ok. I have a problem where after sending device descriptors the first time, the computer doesn't ACK it sends a NACK instead and fails to proceed with enumeration properly. After this point it will continue to NACK for a few seconds and then gets to the set address function. In my ICE it shows that each time the MCU sends the device descriptor it fails with setting the TRFAIL1 bit. And windows device manager show that Set Address Failed, the last error I had was Invalid Device Descriptor so this is slightly better. I think the problem is in the writeUSB function, but I'm not sure it could be in the endpoint configuration for endpoint 0. Right now I'm a bit confused about how that works, thanks for any help. One problem is that the messageBuf array that I have is filled with error respones, so TRFAIL1 was set during transmission. I know this because I used my ICE to read the memory after enumeration.

Update1/2: I did some more work on this problem and I got rid of the TRFAIL1 errors, they were actually erroneous. So I don't think the issue is necessarily in the writeUSB function. But from the analyzer the first packet that's bad is ACK handshake from just after the device descriptor being a NACK handshake. This NACK handshake is the sign that something is wrong but I can't figure out why I'm getting a NACK handshake instead of an ACK handshake.

Here's the output from my analyzer.

First Packet

enter image description here

Second and Third Packet

enter image description here

Fourth and Repeating Packets

enter image description here

And this is the expected output (First 4 Packets).

enter image description here

enter image description here

enter image description here

enter image description here

Update2/2:Based on TurboJ's response I was able to get the first few setup packets to look very close to the Atmel START handshake. The main difference is that my code has an ACK in the place of the first NACK, I don't know if that's good or bad because it still fails to enumerate. With my signal analyzer I can see that it actually sets the address and resends the device descriptor with the assigned address, but then it goes silent and restarts then fails like it did in the first example. In the ICE it shows that the transmission of the second device descriptor fails and TRFAIL1 is set. Any advice on how to get the transmission to complete?

New handshake packet 2 and 3, it restarts properly after this

enter image description here

Setup Address

enter image description here

Second Device Descriptor, theres no ACK or NACK on the second packet, that might be a problem? In my good enumeration example there is an ACK packet after this part.

enter image description here

enter image description here

This is what the good transfers for the second device descriptors looks like.

Here's the code



uint32_t messagesSent;
uint32_t messageBuf[250];
uint32_t messagesAddr;
int writeUSB(UsbDeviceDescriptor *dev, uint8_t epnum, char * data, uint32_t length, bool zlp){
    
    memcpy((void *) endpointCache[0].buf, data, length);
    dev->DeviceDescBank[1].PCKSIZE.bit.BYTE_COUNT = length;
    dev->DeviceDescBank[1].PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
    dev->DeviceDescBank[1].PCKSIZE.bit.AUTO_ZLP = zlp;
    USB->DEVICE.DeviceEndpoint[epnum].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
    USB->DEVICE.DeviceEndpoint[epnum].EPINTFLAG.bit.TRFAIL = 1;
    USB->DEVICE.DeviceEndpoint[epnum].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK1RDY;
    while (!(USB->DEVICE.DeviceEndpoint[epnum].EPINTFLAG.reg & USB_DEVICE_EPINTFLAG_TRCPT1)) {
        if(USB->DEVICE.DeviceEndpoint[epnum].EPINTFLAG.bit.TRFAIL1 == 1){
            USB->DEVICE.DeviceEndpoint[epnum].EPINTFLAG.bit.TRFAIL1 = 1;
            return 0;
        }
    }
    USB->DEVICE.DeviceEndpoint[epnum].EPINTFLAG.bit.TRCPT1 = 1;
        
    return length;
}
void sendZLP(){
    uint8_t t = 0;
    writeUSB(&usbEndpointTable[0],0,(char *) &t,0,false);
}

void usbReset(){
    
    USB->DEVICE.DADD.bit.DADD = 0;  //set address to 0
    USB->DEVICE.DADD.bit.ADDEN = 1;
    USB->DEVICE.DeviceEndpoint[0].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1);    //configure ep0 for in/out
    USB->DEVICE.DeviceEndpoint[0].EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY;
    USB->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY;
    usbEndpointTable[0].DeviceDescBank[0].PCKSIZE.bit.SIZE = 3; //change endpoint size to 64 bytes
    usbEndpointTable[0].DeviceDescBank[1].PCKSIZE.bit.SIZE = 3; //change endpoint size to 64 bytes
    uint32_t t = (uint32_t) &(ctrlOutCache.buf);
    usbEndpointTable[0].DeviceDescBank[0].ADDR.reg = (uint32_t) &(ctrlOutCache.buf);    //set data buffer for control out endpoint
    usbEndpointTable[0].DeviceDescBank[1].ADDR.reg = (uint32_t) &endpointCache[0].buf;  //set data buffer for control in endpoint
    usbEndpointTable[0].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = 8;
    usbEndpointTable[0].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
    USB->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK0RDY;
    USB->DEVICE.DeviceEndpoint[0].EPINTENSET.bit.RXSTP = 1;


}
    uint32_t timeshandled;
    uint32_t handled[250];
    uint32_t handledAddr;
    char status[2] = {0,0};
        uint32_t timesEntered = 0;
void USB_0_Handler(){
    uint32_t volatile flags = 0;
    atomic_enter_critical(&flags);
    
    //PORT->Group[0].OUTSET.reg |= (1<<2);
    if(USB->DEVICE.INTFLAG.bit.EORST == 1){ //end of reset
        USB->DEVICE.INTFLAG.bit.EORST = 1;
        //init endpoint zero
        usbReset();
        handled[timeshandled] = 0xfe;
        //USB->DEVICE.DeviceEndpoint[0].EPINTENSET.bit.RXSTP = 1;
    }
    else if(USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP == 1){
        //PORT->Group[0].OUTTGL.reg |= (1<<2);
        //handled[timeshandled] = 1;
        //get info from packet
        uint8_t bmRequestType, bRequest;
        uint16_t wValue, wLength, wIndex;
        USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP = 1;

        //USB->DEVICE.DeviceEndpoint[0].EPSTATUSSET.bit.BK0RDY = 1; //clear the bank ready for control out
        //while(!USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRCPT0 && !USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRFAIL0);


        bmRequestType = ctrlOutCache.buf[0];
        bRequest = ctrlOutCache.buf[1];
        wValue = (ctrlOutCache.buf[2] & 0xFF);
        wValue |= (ctrlOutCache.buf[3] << 8);
        wIndex = (ctrlOutCache.buf[4] & 0xFF);
        wIndex |= (ctrlOutCache.buf[5] << 8);
        wLength = (ctrlOutCache.buf[6] & 0xFF);
        wLength |= (ctrlOutCache.buf[7] << 8);
        
        

        handled[timeshandled] =  ((uint32_t)bRequest << 8) | ((uint32_t)bmRequestType << 16) | ((uint32_t) wValue << 24);   //get debugging data
        //handled[timeshandled] = wValue | (wIndex << 16);
        USB->DEVICE.DeviceEndpoint[0].EPSTATUSCLR.bit.BK0RDY = 1;   //clear the bank ready for control out
        
        
        
        //Handle Standard Requests
        if((bmRequestType & 0x60) == 0){
            switch(bRequest){
                case 0x00: //Get Status (3 Phases)
                
                messageBuf[messagesSent++] = writeUSB(&usbEndpointTable[0], 0, (char *) &status[0], 2, false);  //Send back 16 bit response. Not self powered, no wakeup, not halted
                //PORT->Group[0].OUTTGL.reg |= (1<<2);
                break;
                case 0x05: //Set Status (2 Phases)
                
                PORT->Group[0].OUTSET.reg |= (1<<2);
                //USB->DEVICE.DADD.bit.DADD = wValue & 0x7F;    //Save address at UADD (ADDEN = 0)
                USB->DEVICE.DADD.reg = USB_DEVICE_DADD_ADDEN | wValue;
                sendZLP();  //Send IN package (ZLP) and clear bank
                USB->DEVICE.DADD.bit.ADDEN = 1; //Enable address
                
                break;
                case 0x06: //Get Descriptor
                switch(((wValue & 0xFF00)>>8)){
                    case 1: //Device Descriptor
                    
                    messageBuf[messagesSent++] = writeUSB(&usbEndpointTable[0], 0, (char *) devDesc, sizeof(devDesc),false);
                    //PORT->Group[0].OUTSET.reg |= (1<<2);
                    
                    break;
                    case 2: //Configuration Descriptor
                    
                    messageBuf[messagesSent++] = writeUSB(&usbEndpointTable[0], 0, (char *) conf_des, sizeof(conf_des), false);
                    //PORT->Group[0].OUTSET.reg |= (1<<2);
                    
                    break;
                    case 3: //String Descriptor
                    switch((wValue & 0xFF)){
                        case Lang_i:
                        break;
                        case Manu_i:
                        break;
                        case Prod_i:
                        break;
                        case Seri_i:
                        break;
                        default:
                        break;
                    }
                    break;
                    default:
                    break;
                }
                break;
                case 0x09: //Set Configuration
                //Reset endpoints here

                break;
                default:
                PORT->Group[0].OUTSET.reg |= (1<<2);//Send STALL
                break;
            }
                
        }
        else if((bmRequestType & 0x60) == 0x40){
            //Vendor specific request

        }
        else{
            //SBI(UECONX, STALLRQ); //Send STALL
            handled[timeshandled] |= 0xFF << 24;
        }
            
        
        //PORT->Group[0].OUTSET.reg |= (1<<2);
        USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP = 1;
        //USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.TRFAIL1 = 1;
        

    }
    //PORT->Group[0].OUTCLR.reg |= (1<<2);
    timeshandled++;
    
    
    
    

    atomic_leave_critical(&flags);
}
/*
void USB_1_Handler(){
    USB_0_Handler();
}
void USB_2_Handler(){
    USB_0_Handler();
}
void USB_3_Handler(){
    USB_0_Handler();
}
*/
int main(void)
{
    
    //setup the clocks
    NVMCTRL->CTRLA.bit.RWS = 6; //setup wait states for main clock
    
    //setup degbug led pin
    PORT->Group[0].DIR.reg |= (1 << 2);
    //PORT->Group[0].OUT.reg |= (1 << 2);


    
    //Setup USB
    MCLK->AHBMASK.bit.USB_ = 1; //setup the AHB mask
    MCLK->APBBMASK.bit.USB_ = 1;    //setup the APB mask
    //setup the generic clock for usb
    GCLK->GENCTRL[2].reg = GCLK_GENCTRL_DIV(1) | //DIV 1
                            GCLK_GENCTRL_GENEN | //ENABLE
                            GCLK_GENCTRL_SRC_DFLL; //SOURCE DFLL48
    while(GCLK->SYNCBUSY.bit.GENCTRL2); //wait for generator 2 to sync
    GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK2 | GCLK_PCHCTRL_CHEN; //setup USB to use GCLK2
    //Turn the pins on
    PORT->Group[0].DIR.reg |= (1 << 24) | (1 << 25);

    //MULTIPLEX THE IO PINS
    PORT->Group[0].PINCFG[24].bit.PULLEN = 0;
    PORT->Group[0].PINCFG[25].bit.PULLEN = 0;
    PORT->Group[0].PINCFG[24].bit.PMUXEN = 1; //ENABLE PA24 FOR PERIPHERAL CONTROL
    PORT->Group[0].PINCFG[25].bit.PMUXEN = 1; //ENABLE PA25 FOR PERIPHERAL CONTROL
    PORT->Group[0].PMUX[12].bit.PMUXE = 0x7; //SET PIN PA24 MUX MODE TO H
    PORT->Group[0].PMUX[12].bit.PMUXO = 0X7;    //SET PIN PA25 MUX MODE TO H
    
    
    
    //reset the usb module
    USB->DEVICE.CTRLA.bit.SWRST = 1;
    while(USB->DEVICE.SYNCBUSY.bit.SWRST);
    //enable usb
    USB->DEVICE.CTRLA.bit.MODE = 0;
    USB->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val;
    //set calibration
    uint32_t t = ((*((uint32_t*) USB_FUSES_TRANSN_ADDR)) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
    if(t == 0x1F){
        t = 5;
    }
    USB->DEVICE.PADCAL.bit.TRANSN = t;
    t = ((*((uint32_t*) USB_FUSES_TRANSP_ADDR)) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
    if (t == 0x1F) {
        t = 29;
    }
    t = ((*((uint32_t*) USB_FUSES_TRIM_ADDR)) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
    if (t == 0x7) {
        t = 3;
    }
    
    USB->DEVICE.PADCAL.bit.TRIM = t;
    USB->DEVICE.CTRLA.bit.ENABLE = 1;
    while(USB->DEVICE.SYNCBUSY.bit.ENABLE);
    USB->DEVICE.DeviceEndpoint[0].EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1);    //configure ep0 for in/out
    USB->DEVICE.DESCADD.reg = (uint32_t) devDesc;
    memset(usbEndpointTable, 0, sizeof(usbEndpointTable));
    USB->DEVICE.DESCADD.reg = (uint32_t) &usbEndpointTable[0];
    uint32_t tt = USB->DEVICE.DESCADD.reg;



    //enable interrupts
    USB->DEVICE.CTRLB.bit.DETACH = 0;   // attach the usb lines
    USB->DEVICE.INTENSET.bit.EORST = 1;
    USB->DEVICE.INTENSET.bit.SOF = 1;
    
    timeshandled = 0;
    messagesSent = 0;
    handledAddr = (uint32_t) (handled);
    messagesAddr = (uint32_t) (messageBuf);
    for(int i = 0; i < 250; i++) handled[i] = 0xFFFFFFFF;
    for(int i = 0; i < 250; i++) messageBuf[i] = 0xFFFFFFFF;
    //setup usb interrupts
    NVIC_DisableIRQ(USB_0_IRQn);
    NVIC_ClearPendingIRQ(USB_0_IRQn);
    NVIC_SetPriority(USB_0_IRQn, 1);
    NVIC_EnableIRQ(USB_0_IRQn);

    //uint32_t t;
    while (1) 
    {
        t++;
    }
    
}


\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

TL;DR Normal behavior.

Long answer: The MCU needs some time for processing the setup packet in the first image. The IN request was fired very rapidly from the host - too soon, thus its answered with a NACK.

The NACKs just mean "retry later, I need more processing time" here.

\$\endgroup\$
2
  • \$\begingroup\$ I figured something out based on your response thanks. I found out that the BKRDY0 flag wasn't being used correctly, it thought the bank was full, so was probably causing the NAK because it couldn't take in data. \$\endgroup\$
    – daannn
    Commented Nov 5, 2023 at 2:15
  • \$\begingroup\$ Any ideas about why it wouldn't send an ACK on the second device descriptor? I'm out of ideas. \$\endgroup\$
    – daannn
    Commented Nov 5, 2023 at 23:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.