cancel
Showing results for 
Search instead for 
Did you mean: 

Isochronous usb feedback problem and even/odd frame

peterd.lundgren9
Associate
Posted on September 14, 2012 at 10:40

Hi

We are developing an audio application with the stm32F405RG that streams the audio from the host asynchronously as a full speed device.

Our problem is that we keep loosing feedback packets (24 bit values) and we suspect that this is the reason to why we get an extraneous noise in the sound, induced by the host.

We suspect that this could be due to that we don't understand the interpretation of even and odd frames on the end point. How are these meant to be programmed in DIEPCTL to be right?

We have set the descriptors to define the IN token to be generated on the feedback end point every 16 frames, which only MacOSX does (Linux and Windows seem to diverge from the standard quite a lot) which leaves us with the problem of how to fill the buffer with accurate feedback values (since we only get a transfer complete interrupt after we actually know a packet was sent). Does anyone know how to handle this?

Best regards,

Peter

#cortex-m4 #asynchronous-usb
4 REPLIES 4
tsuneo
Senior
Posted on September 18, 2012 at 13:53

> the problem of how to fill the buffer with accurate feedback values

 

Feedback value is measured relatively to SOF timing. On STM32F2/F4, SOF pulse is routed to timer2 (TIM2_OR.ITR1_RMP). In this reason, timer2 capture is a good instrument to generate the feedback value. The source of sampling clock (before divider) is fed to timer2 as its clock source. At SOF timing, timer2 value is captured. Using captured value of current frame and last frame, feedback value is calculated as follows.

feedback value = {(current capture value) - (last capture value)} / (divider value) * 2^14

> since we only get a transfer complete interrupt after we actually know a packet was sent

The end of periodic frame interrupt (GINTSTS/EOPF) is available to know drop (or absence) of isoc transaction in current frame, before the next SOF comes.

Tsuneo

jjackbauer7
Associate III
Posted on March 16, 2013 at 00:17

Hi Tsuneo,

I don't understand the formula:

feedback value = {(current capture value) - (last capture value)} / (divider value) * 2^14

I think that we get directly the value from TIM2 capture register.

Why we have to subtruct current from last and divide by divider value (what is the divider value stands for) and why we multiply by 2^14

drtune
Associate
Posted on February 24, 2015 at 00:34

This is an old thread but I just banged my head against a bug for several days and here's the answer....

When doing asynchronous USB audio (where you have a feedback endpoint that sends a 3-byte feedback value to the host, typically every 32ms (e.g. 1<<5 in the 'refresh' field of the endpoint descriptor) this is the problem you have...

When tx'ing data to the host on an ISO IN endpoint, the STM OTG controller will only send a queued packet when the host issues an IN on the endpoint *IF* 

DIEPCTL for the endpoint has the ''DIEPCTL_SEVNFRM'' or ''DIEPCTL_SODDFRM'' (i.e. the queued frame has the ODD or EVEN bit set) to match the current USB frame number when the IN appears from the host. (USB frame number is sent by host in the SOF packet).  

IF (for example) you queue up a packet with SODDFRM set (i.e. send it only on odd frame) and at the moment the PC sends an IN packet it's an even frame - the packet won't be sent (it just sits there) - the STM sends an empty packet to the host instead.  errrr...thanks a lot. 

When sending streaming audio (which is typically polled every frame) you need to alternate between setting SODDFRM and SEVENFRM on your packets.

If you really want something sent on the next frame you should check the value sent in the last SOF (by reading the frame number from OTG_FS_DSTS) and use the opposite, i.e. AND it with 1 and invert.  

For audio streaming endpoints doesn't matter too much because the EP is polled every frame and if you get it wrong your frame is just delayed by 1ms until on the next frame ODD/EVEN matches and your data is sent.

*HOWEVER*

For the feedback endpoint, you typically set it in the descriptor to only be polled every 32ms (=32 frames, in fact you can only set power-of-two times, e.g. 4ms, 8ms, 16ms etc).

Hence, when the host issues an IN on your feedback endpoint, it will ALWAYS be either an odd or even frame (randomly determined by the host when it starts playing audio), so if you get the ODD/EVEN bit wrong on your queued packet, your endpoint will never send any feedback data!!  (bangs head on nearest wall)

This is super annoying; the symptom is that about 50% of the time when you hit ''play'' to stream audio you see empty packets transmitted on your feedback endpoint.

The solution is rather fiddly; because you have no idea when first queuing your feedback packet whether the host is going to issue the IN on an even or odd frame; you just pick one, queue the packet, then keep checking your endpoint every SOF to see if the packet has been transmitted yet. IF your packet is still sitting in the endpoint after >32ms, then flip the odd/even bit (just set SEVENFRM or SODDFRM to the opposite of what you set when you queued the packet, you don't need to re-queue the packet itself) and wait another 32ms.  

Once you find which odd/even frame phase the host is issuing the IN command on, it will (should) keep in the same phase until it shuts down the endpoint (on a windows host, typically when you stop playing audio) 

I don't think there is any better way to do it than this hack.  (!!!!)

That was exceedingly annoying to find. I have no idea why on earth the OTG controller implements an odd/even filter (which can't be disabled!) for ISO IN endpoints; there seems no purpose in it.
tsuneo
Senior
Posted on February 25, 2015 at 17:04

> I don't think there is any better way to do it than this hack.

I believe the Incomplete isochronous IN transfer interrupt (OTG_FS_GINTSTS.IISOIXFR) or GINTSTS.EOPF is the supposed way by the designer of this SIE.

While your firmware primes a packet to an isoc IN endpoint, the SIE should raise this interrupt, if the host wouldn't retrieve the packet in the current frame. In this interrupt, your firmware toggles even/odd setting (OTG_FS_DIEPCTLx.EONUM) of the isoc endpoint by OTG_FS_DIEPCTLx.SODDFRM/SEVNFRM, so that it matches to the next frame number.

At the next frame,

If the host sends isoc transaction to the endpoint, no incomplete interrupt occurs.

If the host doesn't put isoc transaction, the incomplete interrupt hits again, and above even/odd tuning is applied.

Tsuneo