Just discovered something very useful about the AVR....

stuart0:
Does that "j = PINB" read back get done before the new port value makes it though the synchronizer?

Yes that's it. I just tested the code and you need a couple of instruction cycles delays before you can read back changes to PIN.

Note that the same limitation doesn't apply to reading back from PORT (the correct way to read the current state of an output port) because you're then reading back from the internal state and not the external input (the has to go through the synchronizer).

stuart0:
It's not the 2 clock delay on the input synchronizing latches is it?

Well done! Two NOPs are needed to ensure synchronization.

stuart0:
(the correct way to read the current state of an output port)

That is debatable. According to the General Digital I/O figure the PIN signal does go through a synchronizer but past that it is connected on the outside of the pin driver. Reading PIN tells you the actual state as seen by the world. If the pin driver has failed, the pin has accidentally been configured as input, or the pin is sinking too much current, reading PIN tells you that something has gone terribly wrong.

Yes good point. Reading PORT tells you what you previously wrote (internal state) whereas reading PIN tells you what's actually on the output pin. The two should be identical when the port is an output, provided that there is no hardware problems. But yeah, reading PIN could be useful to detect certain hardware issues like an overloaded output pin.

Regardless of all the hub-bub the original post created, the bottom line was and is ONLY that, as stated in the Atmel docs, writing a bit high via PINx TOGGLES that bit's state.

HOW it works, what bit patterns are nanoseconds before or after was never the point.

ALL I did was pass along a discovery that I made which (IMHO) was pretty neat and useful.

Sorry. I'll be more careful next time.

stuart0:
Just had another thought. It's not the 2 clock delay on the input synchronizing latches is it?

Does that "j = PINB" read back get done before the new port value makes it though the synchronizer?

Damn, I thought it was going to be the optimizer reordering things, but declaring j and n to be volatile did nothing.

Krupski:
Regardless of all the hub-bub the original post created, the bottom line was and is ONLY that, as stated in the Atmel docs, writing a bit high via PINx TOGGLES that bit's state.

HOW it works, what bit patterns are nanoseconds before or after was never the point.

ALL I did was pass along a discovery that I made which (IMHO) was pretty neat and useful.

Sorry. I'll be more careful next time.

Technically speaking, writing a PINx bit high toggles the corresponding bit in the PORTx register.

While you aren't the first person on this forum that's found this bit of obscure functionality, this thread has been a great (and unintentional on your part) demonstration of the mischief that compiler optimizations can cause.

Jiggy-Ninja:
While you aren't the first person on this forum that's found this bit of obscure functionality, this thread has been a great (and unintentional on your part) demonstration of the mischief that compiler optimizations can cause.

At the risk of beating an already dead horse.... I don't think "compiler optimizations" have anything to do with this subject. The useful but obscure data I found in the Atmel docs does indeed work as they say.

All of the "great mischief" seems to have been generated by the replies to the original post.......

    PINB |= _BV(6); // toggle port b, bit 6

Works as described in the Atmel documentation because of a quirk with the avr-gcc compiler...

  1. The address of PINB is between 0x00 and 0x1F

  2. AVR processors have single bit instructions

  3. The compiler's optimizer takes advantage of #1 and #2 to reduce your flawed code to a form that works as you expect it to work

The subject of this thread is not just what an AVR processor can do but how to get it to do that as expected. You made those two things the subject by including code that exploits the compiler quirk.

The simple fact is that your code from the original post would fail, badly fail, if it were not for that quirk. Your own later example actually proves that. The people reading this thread need to know that fact or they can easily cross paths with a nasty extremely difficult to diagnose bug. The "great mischief" is you failing to acknowledge to your readers that your original code only works because of a compiler quirk.