cancel
Showing results for 
Search instead for 
Did you mean: 

Why does the STM32F407 send a STALL on USB_FS?

waldi
Associate II

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.

0690X000009ZcDuQAK.png

Why does the MCU send a STALL?

19 REPLIES 19

I don't believe ITTXFE is of any relevance here.

> Is the USB hardware used in STM32F7 the same? Synopsys?

Yes, but it's almost certainly a different version, and they differ exactly in those subtle details which do matter.

Could this current thread be related to your problem?

JW

waldi
Associate II

I agree, it has no relevance. But my idea was to monitor all error flags and try to write implementation which behaves as intended by synopsys guys. For example setting SNAK means the uC is in definite state, it has no data. If this is set, I shouldn't be bothered with IN tokens, core will respond to them automatically with NAK. After ITTXFE, the core responds also with NAK, but this is ugly, imo) Maybe this flag gets really relevant in other than CDC examples, I don't know. Then I misunderstood the intended usage of the flags.

Nevertheless, I deactivated the ISR to prevent register access, still the same problem. The other idea is to move the buffer fill up into the DIEPINT_TXFE ISR as in the example, but it should be the same?

	NVIC->ICER[2] =     8;//disable 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;
	}
	NVIC->ISER[2] |=     8;//enable interrupt

Another point worth mentioning from the example: the DTXFSTS register is read out three times, two times before filling up TxFIFO, and one time directly thereafter. I will try this also.

waldi
Associate II

IN STM example ITTXFE is deactivated. I also deactivated ITTXFE and now it works. (ITTXFE flag is on all the time) It seems that this flag is really contra productive, at least in a CDC implementation. Maybe it is useful in isochronous transfers or somewhere else.

I will stop my investigations at this point. Thank you, Jan, for your suggestions.

I don't understand. So you have had OTG_FS_DIEPMSK.ITTXFEMSK=1, right? Then how did you handle the ITTXFE interrupt and how did that cause the STALL?

JW

waldi
Associate II

Yes, OTG_FS_DIEPMSK.ITTXFEMSK=1.

Interrrupt handler:

if (diepint_v.d32 & DIEPINT_ITTXFE){//IN token received when TxFIFO is empty
       USB.INEP_REGS[1]->DIEPINT = DIEPINT_ITTXFE;
       USB_error = USB_ERROR_EP1_IN_TOKEN_WHILE_TX_EMPTY;
}

and in main

if (USB_error!=0){
       nop();
}

with an breakpoint on nop();

As I already wrote, I'm not sure if STALL is really emitted, I'm seeing it only in Device Monitoring Studio output (see the very first picture). The uC reports only ITTXFE.

Ah, I see. So ignoring the ITTXFE interrupt removed the problem, whether it was stall or not.

Thanks for reporting the solution.

JW

waldi
Associate II

Yes, if OTG_FS_DIEPMSK.ITTXFEMSK is zero, it's working.

Sorry for another question):

I try to switch OTG_FS to 256 byte packets instead of 64. Two weeks ago I was able to do this. Then I switched to other problems and set it again to 64. Now 64 works but not 256.

Do I have only to change DIEPCTL and Endpoint IN Descriptor to switch to 256 byte transmission block like here?

diepctl1.d32 = USB.INEP_REGS[1]->DIEPCTL;
diepctl1.b.mpsiz = 256;
diepctl1.b.eptyp = 2;
diepctl1.b.txfnum = 1;
diepctl1.b.snak = 1;
diepctl1.b.sd0pid = 1;
diepctl1.b.usbaep = 1;
USB.INEP_REGS[1]->DIEPCTL = diepctl1.d32;

Of course I'm loading DIEPTSIZ accordingly, e.g.

0690X0000097yCbQAI.png

and fill the buffer with 60 words:

dieptsiz1.d32 = USB.INEP_REGS[1]->DIEPTSIZ;
dieptsiz1.b.xfrsiz = words_to_write*4;
dieptsiz1.b.pktcnt = (dieptsiz1.b.xfrsiz + IN1_MAX_PACKET_SIZE_CORE-1)/IN1_MAX_PACKET_SIZE_CORE;
USB.INEP_REGS[1]->DIEPTSIZ = dieptsiz1.d32;
USB.INEP_REGS[1]->DIEPCTL |= DIEPCTLx_EPENA|DIEPCTLx_CNAK;
for (uint32_t i = 0; i < words_to_write; i++){
   *(USB).DFIFO[1]=USB_buffer[i];
}

But there is nothing. After a while host tries to reset the endpoint.

waldi
Associate II

I'm aware of FS limitation to 64 bytes, but somehow it worked.

The USB standard does not allow 256-byte packets for FS. From USB2.0, 5.8.3 Bulk Transfer Packet Size Constraints:

The USB defines the allowable maximum bulk data payload sizes to be only 8, 16, 32, or 64 bytes for full-speed endpoints and 512 bytes for high-speed endpoints.

Of course, hosts ([EDIT] and hubs [/EDIT]) are free to support nonstandard features, but I wouldn't rely on that.

JW

waldi
Associate II

With 256 bytes, and 4 packets in one transmission I was able to get a stream with 1.2 MBytes/s. With 64 bytes and used 7 packets (maximum according to datasheet) in one transmission I get only 830.000 bytes/s. With 64 bytes I would like to get to at least 1Mbyte/s. According to community it should be possible.

I know, bulk transfer depends on free bandwidth, but there is nothing else connected to USB.

Is there any trick to get 1Mbyte/s?