2019-07-30 03:45 AM
Hi,
I'm using STM32F407 and try to establish a USB communication. Until now the device is present in the system and is also able to send and receive bulk transfers. To test the functionality I wrote a simple example:
if MCU receives a string of 5 characters it responds with 60 characters.
The response:
dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
dieptsiz1.b.xfrsiz = 60;
dieptsiz1.b.pktcnt = 1;
USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
for (uint32_t i = 0; i < 15; i++){
*(USB).DFIFO[1]=USB_buffer[i];
}
If transfer is complete I set
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_SNAK;
in IN(1) Transfer completed interrupt to prevent firing ITTXFE (IN token received when TxFIFO is empty) which is activated.
This is working 5 to 10 times but suddenly the MCU does not respond normally. Instead of sending the next 60 characters it responses with status 0xc0000004 - STALL_PID.
Why does the MCU send a STALL?
2019-07-30 05:43 AM
What's the read-out content of the relevant DIEPCTL, DIEPTSIZ and DTXFSTS when the problem occurs? Is their content as expected?
How are the Tx FIFOs set up?
JW
2019-07-30 06:20 AM
sent[siz1cnt].diepint1_1.d32 = USB.INEP_REGS[1]->DIEPINT;
sent[siz1cnt].diepctl1_1.d32 = USB.INEP_REGS[1]->DIEPCTL;
sent[siz1cnt].dieptsiz1_1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
sent[siz1cnt].dtxfsts1_1 = USB.INEP_REGS[1]->DTXFSTS;
dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
dieptsiz1.b.xfrsiz = 60;
dieptsiz1.b.pktcnt = 1;
USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
for (uint32_t i = 0; i < 15; i++){
*(USB).DFIFO[1]=siz1cnt;//USB_buffer[i];
}
sent[siz1cnt].diepint1_2.d32 = USB.INEP_REGS[1]->DIEPINT;
sent[siz1cnt].diepctl1_2.d32 = USB.INEP_REGS[1]->DIEPCTL;
sent[siz1cnt].dieptsiz1_2.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
sent[siz1cnt].dtxfsts1_2 = USB.INEP_REGS[1]->DTXFSTS;
DIEPINT before and after:
DIEPCTL before and after:
DIEPTSIZ & DTXFSTS before and after:
FIFO set up:
USB.GREGS->GRXFSIZ &=~ GRXFSIZ_RXFD;
USB.GREGS->GRXFSIZ |= RxFIFO_SIZE << GRXFSIZ_RXFD_POS;
//#define RxFIFO_SIZE 0x23
USB.GREGS->DIEPTXF0_HNPTXFSIZ &=~ ((DIEPTXF0_NPTXFD)|(DIEPTXF0_NPTXFSA));
USB.GREGS->DIEPTXF0_HNPTXFSIZ |= (Tx0_FIFO_SIZE << DIEPTXF0_NPTXFD_POS)|(RxFIFO_SIZE << DIEPTXF0_NPTXFSA_POS);
//#define Tx0_FIFO_SIZE 0x10
USB.GREGS->DIEPTXF[0] &=~ ((DIEPTXFx_INEPTXFD_MSK)|(DIEPTXFx_INEPTXSA_MSK));
USB.GREGS->DIEPTXF[0] |= ((0x140-(RxFIFO_SIZE + Tx0_FIFO_SIZE)) << DIEPTXF0_NPTXFD_POS)|((RxFIFO_SIZE + Tx0_FIFO_SIZE) << DIEPTXF0_NPTXFSA_POS);
//rest, 0x140 - (0x10 + 0x23)
USB.GREGS->DIEPTXF[1] &=~ (DIEPTXFx_INEPTXFD_MSK)|(DIEPTXFx_INEPTXSA_MSK);
USB.GREGS->DIEPTXF[1] = (0x0 << DIEPTXF0_NPTXFD_POS)|(0x140 << DIEPTXF0_NPTXFSA_POS);
//nothing
USB.GREGS->DIEPTXF[2] &=~ (DIEPTXFx_INEPTXFD_MSK)|(DIEPTXFx_INEPTXSA_MSK);
USB.GREGS->DIEPTXF[2] = (0x0 << DIEPTXF0_NPTXFD_POS)|(0x140 << DIEPTXF0_NPTXFSA_POS);
//nothing
2019-07-30 06:22 AM
Register content before and after failed response.
2019-07-30 06:50 AM
I can't see anything irregular, sorry.
I know this is a hard question to answer, but does the STALL response start only after the last transfer has been started? I mean, couldn't STALL result from something else, that happened already before the routine starting the last transfer (and then that the last transfer has not completed is only a consequence of this)?
A bus protocol decoder would help. There are relatively cheap options around, at least for FS, e.g. https://www.totalphase.com/products/beagle-usb12/, and also some LA/oscilloscopes can decode USB, e.g. I use http://www.asix.net/dbg_sigma.htm with the USB licence.
JW
2019-07-30 07:23 AM
"Bit 2 NZLSOHSK: Non-zero-length status OUT handshake
The application can use this field to select the handshake the core sends on receiving a
nonzero-length data packet during the OUT transaction of a control transfer’s Status stage.
1: Send a STALL handshake on a nonzero-length status OUT transaction and do not send
the received OUT packet to the application.
0: Send the received OUT packet to the application (zero-length or nonzero-length) and send a handshake based on the NAK and STALL bits for the endpoint in the Device endpoint control register."
Thank you for USB beagle hint. I thought I could avoid it)
I have separated the transfer init, which is loaded if I receive 5 chars:
dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
dieptsiz1.b.xfrsiz = 60;
dieptsiz1.b.pktcnt = 1;
USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
and transfer load, which is stats if I receive 2 chars:
if ((received_byte_count ==2)){
for (uint32_t i = 0; i < 15; i++){
*(USB).DFIFO[1]=siz1cnt;
}
received_byte_count=0;
}
The behavior is the same after ca. 10 successful transmissions. And: the STALL is detected after transfer load:
2019-07-30 08:49 AM
Another very important point: If I load the transmission as fast as I can, looking for transfer complete interrupt and do immediate the next load, then the data transmission has NO errors, no STALLs are emitted or ITTXFE(IN token received when TxFIFO is empty).
//received_byte_count=0; // if commented out continuous load after receiving first 5 chars
USB_transfer_complete=0; //is set in DIEPINT_XFRC (IN Transfer completed interrupt)
dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
dieptsiz1.b.xfrsiz = 60;
dieptsiz1.b.pktcnt = 1;
USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
for (uint32_t i = 0; i < 15; i++){
*(USB).DFIFO[1]=siz1cnt;//USB_buffer[i];
}
do{} while(USB_transfer_complete==0);//wait until DIEPINT_XFRC, then start next transmission
2019-07-30 09:03 AM
The Synopsys OTG IP is very fragile and easily breaks down in surprising ways when it's not handled exactly as the IP authors intended, even if you'd think your actions are reasonable. Therefore, one way to handle such problems is to swallow the frog and analyze/follow closely the Cube or whatever other implementations there are out there for this IP.
JW
PS What happens if you decrease the Tx FIFO space for this EP?
2019-07-30 09:26 AM
I've reduced the EP1 TxFIFO size to 16 words, after 30 transmission the same result.
I should mention, the STALL response I see in Device Monitor Studio, whereas MCU shows this error as ITTXFE for EP1.
2019-07-31 07:34 AM
My problem is that the ITTXFE(IN token received when TxFIFO is empty) interrupt is deactivated and not analyzed in the VCP example (en.stm32_f105-07_f2_f4_usb-host-device_lib). I thought it's there for a reason and I have activated it, trying to avoid its firing by setting SNAK after successful transmission. In the VCP example ITTXFE is active all the time. This USB implementation is really ugly and weird.
Is the USB hardware used in STM32F7 the same? Synopsys?