AnsweredAssumed Answered

usb host channel interrupt register is always zero after a transaction

Question asked by ka.rin on Mar 5, 2016
I use stm32f105's usb otg interface in forced host mode. When I issued a bulk in transaction, after some nak returned (which is ok), keep retrying, then data came, this first transaction completed successfully. Then I halted the channel, enabled it again for another transaction, and the channel interrupt register value was always zero, no data, no nak, no ack, no error, and program stuck there.

This code is part of the program:

void OTG_FS_IRQHandler()  // Only rfxlvl interrupt unmasked
{
    usb_gregs->GINTMSK = 0; //mask rfxlvl
    USB_OTG_GRXFSTS grxsts;
    grxsts.d32 = usb_gregs->GRXSTSP;
    if (grxsts.b.pktsts == 2)
    {
        u8 numword = (grxsts.b.bcnt + 3) / 4;
        u32* fifo = usb_fifo0 + grxsts.b.chnum * USB_OTG_DATA_FIFO_SIZE;
        if (!usb_state || (usb_state && usb_channel != grxsts.b.chnum))
        {
            for (u8 i = 0; i < numword; i++)
                *fifo;
        }
        else
        {
            for (u8 i = 0; i < numword; i++)
                *rxbuff++ = *fifo;
            rxnumbyte = grxsts.b.bcnt;
            usb_state = 0;
        }
    }
    usb_gregs->GINTMSK = 1 << 4;  //unmask rfxlvl
 
}
 
u16 bulkin(u32* buff, u16 len)
{
    u16 ret = 0;
    USB_OTG_HCINTn hcint;
    USB_OTG_HCTSIZn hctsiz;
    u16 numpacket = len / MPS;
 
    usb_gregs->GINTSTS = 0xffffffff;
    usb_hc3regs->HCINT = 0xffffffff;
    hctsiz.d32 = usb_hc3regs->HCTSIZ;
    hctsiz.b.pktcnt = numpacket;
    hctsiz.b.xfersize = numpacket * MPS;//
    usb_hc3regs->HCTSIZ = hctsiz.d32;
 
    rxbuff = buff;
    usb_channel = 3;
    while (!(usb_hc3regs->HCINT & 1)) //check for XFRC
    {
        usb_state = 1;
 
        usb_hc3regs->HCINT = 0xffffffff;
        usb_hc3regs->HCCHAR = MPS | (1 << 31) | (device_address << 22) | (1 << 11) | (2 << 18) | (1<<15);   //max packet size 64 byte, chenable, endpoint 2
        while(!(hcint.d32 = usb_hc3regs->HCINT));   //issue in token, any flag? <<<ALWAYS ZERO, PROGRAM STUCK
        if (hcint.b.nak)
        {
            cn++;
            continue;
        }
        else if (hcint.b.ack)
        {
            while(usb_state);
            ret += rxnumbyte;
            rxbuff = (u8*)buff + ret;
        }
        else
            while(1);
    }
 
    if (!(usb_hc3regs->HCINT & (1 << 1)))
        usb_hc3regs->HCCHAR = MPS | (1 << 31) | (1 << 30) | (device_address << 22) | (1 << 11) | (2 << 18) | (1<<15); // halt channel
    while(!(usb_hc3regs->HCINT & (1 << 1)));
    return ret;
}

The program stuck at while(!(hcint.d32 = usb_hc3regs->HCINT)); beacause HCINT always zero.
Why is this happening ? I'm willing to provide any additional information.

EDIT: I solved it after some weeks pulling my hair out.
The problem come from this code:
   
hctsiz.d32 = usb_hc3regs->HCTSIZ;
    hctsiz.b.pktcnt = numpacket;
    hctsiz.b.xfersize = numpacket * MPS;//
    usb_hc3regs->HCTSIZ = hctsiz.d32;
The idea for this code is when a bulk transfer is divided to many packets, the core will automatically alternate the data pid for us while transfering. This code keep the last data pid, just change packet count and transfer size.
So before the first transfer this register content is 0x0. After the first transfer complete, for some reason the core changes the 31 bit to 1, and the second transfer will fail because this bit is not at its reset value.
Fix this and it works like a charm. Hope this help somebody out there.

Outcomes