cancel
Showing results for 
Search instead for 
Did you mean: 

Controlling toggle-only bits in STM32F10Xxx USB registers

STM32F10Xxx USB endpoint registers contain several bits that can only be controlled from software by toggling their value. For example, from RM0008 section 23.5.2, Endpoint-specific registers, USB endpoint n register (USB_EPnR), n=[0..7]:

Bits 13:12 STAT_RX [1:0]: Status bits, for reception transfers

...

These bits can be toggled by software to initialize their value. When the application software writes ‘0, the value remains unchanged, while writing ‘1 makes the bit value toggle.

...

These bits are read/write but they can be only toggled by writing ‘1.

Prior to this, the same section states:

Read-modify-write cycles on these registers should be avoided because between the read and the write operations some bits could be set by the hardware and the next write would modify them before the CPU has the time to detect the change.

This is logically inconsistent. To set bits to some required state necessitates reading them before deciding whether to toggle or not. And setting them is required, for example as per "the application software should set the STAT_RX bits to ‘11 (Valid) in the USB_EPnR" in section 23.4.2, System and power-on reset.

My particular use-case is when replying to the USB host's first "Setup Packet" request by sending the required USB Device Descriptor data. I have written the descriptor data to the correct USB_PMAADDR packet memory buffer location and believe I have to set the USB_EP0R register's STAT_TX bits (which are toggle-only) to 0b11 (VALID) to inform the peripheral to send the data at the next USB host poll. I have observed the bits dynamically changing at the point in the protocol where this is necessary, and there doesn't seem to be a definitive "quiescent" state at which the read-modify-write/toggling is safe.

Any corrections to my assumptions about how to send descriptors welcome, but mainly to the generic question of how to control toggle-only/no-read-modify-write bits.

2 REPLIES 2
Pavel A.
Evangelist III

This isn't inconsistent. What you want is: read the current value, decide whether to toggle some bit, write only this bit (as mask).

This is not a read-modify-write.

-- pa

Thanks for your answer. Yes, it's not exactly the same as classic read-modify-write, but has a similar non-atomic "test and set" problem.

I understand how to read the register, decide which bits need toggling, and write 1's to them. As RM0008 says, "... between the read

and the write operations some bits could be set by the hardware and the next write would modify them before the CPU has the time to detect the change". In the classic read-modify-write case, the problem is when bits other than the intended ones change between read and write:

// set bits 2 and 3 (LSB is bit 0) to 1
temp = read_reg();  // current value is 0b10010101
temp = (temp & 0b11110011) | 0b00001100;
// hardware changes register to 0b00010101 before write
write_reg(temp);  // reg now 0b10011101,  should be 0b00011101

With "toggle-only" bits the problem is when the bits to be toggled change between read and write:

// set bits 2 and 3 (LSB is bit 0) to 1
temp = read_reg();  // current value is 0b10010101
// need to toggle bit 3 (bit 2 is already 1), but ...
// ... hardware changes register to 0b10011101 before write
write_reg(0b00001000);  // reg now 0b10010101, wanted 0b00011101

As I said, I am seeing this happen with the USB endpoint registers.