cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F37x, USB, Endpoints and their toggle bits

Workalot
Associate III

I'm not alone in my confusion I think, when taking in the information of RM0313, rev6, page 838. And that is how to handle the 't' (toggle bits) in the EP registers.

Where RM0313 mentions that read-modify-write is be avoided, I see in ST's code (and others), through the many perverse #define(s), that that very thing happens.

Could the take on this be that an r-m-w cycle is necessary, but care must be taken to adjust the temporary variable (used on the read) to clear those 't ' bits not involved (so they won't be toggled), before writing the variable back?

Further, about set/clr of involved 't' bit(s). To set a 't' bit is must be at the cleared state, conversely, to clear a 't ' bit it must be at the set state.

And may I take this opportunity to mention RM0313 rev 6, sec 29.6.2, page 843. The text has the word 'address' which I feel sure is not reflective. It should be 'offset'

Workalot

19 REPLIES 19

In this particular case, I don't see how RMW could be avoided. It should be used with utmost care, of course.

The STM32 device-only USB design is quite bizarre (just adding to the mess USB as such already is) and the toggle bits are one of its idiosyncracies. It also bears marks of a strong 16-bit legacy (probably it stems from one of the old 16-bit ST microcontroller).

The reason for toggle bits presumably is, that as the control register contains bits for both In and Out endpoints and the whole register is written at once, while most endpoints are simplex i.e. In and Out work independently on each other (EP0 being the only exception): if you write the portion for In endpoint you simply clear all the toggle bits for the Out endpoint, and vice versa - and thus it will be sure you won't rewrite bits which in the RMW process might've been changed by hardware for the other, potentially still active, endpoint.

Yes, this might've been solved much simpler and cleaner by separate In and Out endpoint registers, but again, I presume this bears strong legacy marks, the address space and transistors of address decoders were a considerable issue 20+ years ago.

> Further, about set/clr of involved 't' bit(s). To set a 't' bit is must be at the cleared state, conversely, to clear a 't ' bit it must be at the set state.

No. In cases, where software has to make the bit into a particular state, if it's already in that state, it may simply leave it so, by writing 0.

JW

Workalot
Associate III

Thank you,

Had a look at using bit-banding which for the data toggle at least, could be useful. Assigning a pointer to its bit-banded address we have...

*pDtog = *pDtog; // Clear toggle, sets EP to DISABLED

However, bit-banding doesn't work for the STAT_RX/TX 2 bit fields. That must be done in a single write.

Your mention of 20+ years reminded me that about that time I got a CDC VCP going on a uPSD3400, it wasn't a bad performing MCU. More recently I struggled to do the same on the F407Discovery, ably unassisted by the documentation. I suppose commercial imperatives come into play.

Workalot

Workalot
Associate III

Workalot struggles. The struggle is with the STM32F37x USB peripheral. Clever Workalot has got USB enumeration to the stage of setting the USB address. Unclever Workalot is stuck there. Am hopeful a kind soul may gaze upon the included image...

And further to bit-banding: while it has the desired effect of manipulating a particular bit, it has the undesired effect of affecting other bits in the register.

0693W00000Lvs0mQAB.png

Maybe

0693W00000Lvs8MQAR.png?

> And further to bit-banding: while it has the desired effect of manipulating a particular bit,

> it has the undesired effect of affecting other bits in the register.

Of course, because it *is* a RMW albeit performed by the hardware (an attachment at the processor's bus interface). I would expect it to clear all toggle bits except the one which is target of the bit-banded write.

JW

Workalot
Associate III

Well, it *is* a RMW certainly puts clarity where it was needed! Thank you.

I take your point about Set_Address, it is a deferred action that is executed on the Status stage of the transfer. On the receipt of the Set_Address I store the address and then on the OUT ZLP (Status stage) I apply the address to DADDR.

Maybe once I clean out the bit-banded writes thinks will improve.

Nevertheless, I'm grateful for your taking the time and effort.

Workalot

Workalot
Associate III

Pushing along...

I've got progress in that address setting is about, enumeration starts but later stumbles. Windows reports a code 10.

That's not why I appear here now. What has me wondering is ISTR.DIR. Elsewhere in this forum JW has put pseudo code explaining the logic of DIR's assertion.

The question I have is how could CTR_RX and CTR_TX co-exist? Is not USB a half-duplex data I/O stream? That is, request/response in a lock step arrangement.

For those who would care and dare - your input is encouraged.

> Elsewhere in this forum JW has put pseudo code explaining the logic of DIR's assertion.

This was honestly a surprise to me as I don't use the device-only USB actively, just tinkered with it... but indeed, I found it...

> The question I have is how could CTR_RX and CTR_TX co-exist? Is not USB a half-duplex data I/O stream?

No. Endpoints are simplex and mutually independent.

Endpoint 0 (and, strictly speaking, any other Control endpoint, which in theory is permitted by the specification but I believe no such thing is seen in the wild - these have to come in In-Out pairs but not necessarily with the same number, again except EP0 which is fixed to the In0/Out0 pair by the notion of "default pipe" - the USB specification is an utter mess, to put it very politely) has a prescribed additional protocol as an upper layer, which is the SETUP-DATA-STATUS (or SETUP-STATUS) sequence as per USB2.0 ch.8.5.3. This may bear resemblance of half-duplexness, and some USB hardware implementations which handle the STATUS portion of sequence in hardware, indeed may appear to the application as entirely half-duplex, i.e. data either come in or go out, never both.

However, the device-only USB in STM32 is a somewhat lower-level implementation, where STATUS phase of handhsake is to be performed "manually". This means, that you tell the hardware, "send out DATA", or after receiving data you tell it "send out STATUS"; and then your processor does something else while USB hardware does its thing; but by the time your processor has come back and looked again at the USB registers, it may quite well been that not only those DATA/STATUS had been sent out, but also that host succeeded to send the following STATUS/next SETUP, which means that hardware signals "there's something to be handled" at both EP0 Tx and EP0 Rx.

JW

 

Workalot
Associate III

Interesting. Its a consequence of the control endpoints having to share the one register. This then may explain why I see in other CDC code that EP2 is used for Rx and EP3 for Tx (or other way around).

Each endpoint would then effectively have its own register.

Workalot

While answering https://community.st.com/s/question/0D53W00001TgYGjSAN/stm32-usb-endpoints-capabilities-usage-questions it dawned to me, that in that device-only USB module, given USB_EPnR has only one EPTYPE/EPKIND field, it in fact restricts the user to the same type EP for both In and Out of the same number.

It may be that most of the real-world applications operate endpoints in such pairs, but there is no requirement for such restriction in the standard, thus it is just one more quirk of this IP module.

JW