cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F (429) USB EP0 IN with DMA does not work, always sends zero bytes

dmitrygr
Associate II

program EP0 for an simple IN transmit

   epIn->DIEPINT = -1; //clear ints

   epIn->DIEPTSIZ &=~ (USB_OTG_DIEPTSIZ_PKTCNT_Msk | USB_OTG_DIEPTSIZ_XFRSIZ_Msk);

   epIn->DIEPTSIZ |= (numPackets << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | (len << USB_OTG_DIEPTSIZ_XFRSIZ_Pos);

//set pointer to data (in ram, 4 byte aligned)

   epIn->DIEPDMA = (uintptr_t)data;

//go (i have tried EVERY POSSIBLE BIT COMBINTATION HERE, not just these two)

epIn->DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;

yes, data is 4-byte aligned

length is 18

packet count is 1

then you wait for interrupt..it comes, and what do we see?

chip sent a zero sized packet instead, and claimed fifo undrran. all the while it had DMA pointer set, and could have slurped up all the data it wanted!

what gives?

in interrupt for EP0 in, i see this

out0.DIEPCTL = 0x00008000

out0.DIEPINT = 0x000020D2

out0.DIEPTSIZ = 0x00080012

out0.DIEPDMA = 0x20000004

out0.DTXFSTS = 0x00000020

I've spent *A WEEK* trying every which way to get this thing to send a reply to GET_DESCRIPTOR **USING DMA**, no luck. all i can get it to do is send a ZLP

i even tried writing to fifo (so i can send PIO, RX via DMA since RX path works)

no go

yes yes yes i know: i can use the st library, but that is not an option, and the docs SHOULD be good enough to actually use them to make the thing work, no?

complete code attached

1 ACCEPTED SOLUTION

Accepted Solutions
dmitrygr
Associate II

Of course just as i wrote the angry poist, i figured it out

(turns out that the synopsys controller is utter crap and it is VERY VERY EASY to wedge it into a weird state)

for example, try to set EPDIS twice in a row. until you power cycle the controller, that EP will never again work!

View solution in original post

6 REPLIES 6
dmitrygr
Associate II

.

dmitrygr
Associate II

it looks like DMA never sent my data to the FIFO

except .. .WTF??? how can DMA mess up that badly? and how can the controller?

and yes i reliaze that

out0.DIEPCTL = 0x00008000

loks supicious, but it ALWAYS Reads that way. somehow for EP0, MPSIZ field always reads as zero, no matter what was written there (i wrote 64)

dmitrygr
Associate II

Of course just as i wrote the angry poist, i figured it out

(turns out that the synopsys controller is utter crap and it is VERY VERY EASY to wedge it into a weird state)

for example, try to set EPDIS twice in a row. until you power cycle the controller, that EP will never again work!

@dmitrygr​ 

Can you please tell us what exactly was the cause for the problem you described? Was it the mentioned EPDIS being set twice, or something else?

Thanks,

JW

yes, in a convoluted way. basically, it is NEVER safe to do this to disable an EP

epIn->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS

you should instead use this

if (epIn->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
	epIn->DIEPCTL |= USB_OTG_DIEPCTL_EPDIS;
	while (epIn->DIEPCTL & USB_OTG_DIEPCTL_EPDIS);
}

because if EP is not enabled (as per the core's weird ideas of when that is), disabling it will wedge the EP forever

Thanks for sharing this piece of information, fills in part of the puzzle.

Yes, the Synopsys OTG is huge, laden with various, obviously historically-given and often badly designed, gotchas, resulting in very fragile handling; and all this accompanied by grossly inadequate (to be polite) documentation.

EPDIS was puzzling me for a long time, as its handling changes throughout various versions of the drivers (in various incarnations, including the linux "gadget" driver), throughout various settings of the IP (e.g. DMA/non-DMA; but also different for - what's not available in STM32 due to settings when the IP was "instantiated" into silicon - scatter-gather DMA), and also various versions of the IP as given in the - by ST undocumented - GSNPSID register (offset 0x40). For example, in the newer-than-in-'F4 version of Synopsys OTG in the 'L4, the procedure recommended by the respective RM to disable the EP is to simply set DIEPCTL to 0.

I don't use DMA and after lots of investigation I came to the conclusion that in that case it's safe to ignore it.

JW