0
\$\begingroup\$

Is this code guaranteed to only effect pin 22?

int* FIO0PIN = (int*)0x2009C014;
*FIO0PIN ^= (1<<22);

At first it seems like a dumb question but I remember working with a PIC18 microcontroller where you could corrupt the port output by doing this. Corruption happened when a previous write to the the output latch was not yet reflected by the output state (pin is driving a capacitive load), XORing an unrelated bit meant reading the port, doing the XOR and writing back to the output latch (with the old value of said unrelated pin).

int* FIO0PIN = (int*)0x2009C014;
*FIO0PIN &= (1<<4);  //set bit 4
*FIO0PIN ^= (1<<22); //if pin 4 has not yet transitioned to 1 because of capacitive load
                    //will this clear it again?

How does the Cortex avoid this problem? Or does it?

I am aware of the FIOxSET and FIOxCLR registers, bit toggeling through them is however much less efficent if one does not know the current value of the bit in question. I am writing a domain specific language using C++ meta programming which abstracts all basic IO functions and preforms optomizations on sets of them. With the LPC11xx parts implementing the bit toggeling is super easy, I just use the dedicated register, I would like to get the LPC17xx implementation as efficient as possible.

Here is the code in case anyone is interested: https://github.com/porkybrain/Kvasir the "register action" is created by the "makeToggle" factory here https://github.com/kvasir-io/Kvasir/blob/master/Lib/Io/Io.hpp using a template specialization here https://github.com/kvasir-io/Kvasir/blob/master/Lib/Chip/NXP/LPC17/M3/5x6x/Io.hpp I currently make a XorAction out of it for this chip, however I am not sure if it is correct.

I am aware that the FIOxPIN is in the bit band addressable reigion, however according to UM10360.pdf page 749 "Data accesses to this region are remapped to bit band region. A write operation is performed as read-modify-write. Instruction accesses are not permitted" which in my opinion would be just as suseptable to the above mentioned problem.

\$\endgroup\$
  • \$\begingroup\$ Your code should read *FIO0PIN &= (1<<4), when you declare FIO0PIN as int *. You should also use unsinged int or better uin32_t. NXP also has downloadable header files, so you don't need to declare Registers yourself. \$\endgroup\$ – Turbo J Apr 7 '15 at 19:42
  • \$\begingroup\$ thanks turbo, thats what I get for not compiling it ;) \$\endgroup\$ – odinthenerd Apr 8 '15 at 20:44
1
\$\begingroup\$

That's exactly why there are FIOxSET and FIOxCLR registers:

FIO0CLR = (1<<4);
FIO0SET = (1<<22);

Those do not need a read-modify-write cycle to clear or set pins.

\$\endgroup\$
  • \$\begingroup\$ Some LPC series parts also have an FIOxNOT register which does the exact toggle operation that the OP wants that works like xSET and xCLR. I know the LPC8xx has it. I strongly suspect that the LPC17x family would too. \$\endgroup\$ – RBerteig Apr 7 '15 at 20:22
  • \$\begingroup\$ Nope. No Pin toggle register in LPC 175x and 176x. \$\endgroup\$ – Turbo J Apr 7 '15 at 20:28
  • \$\begingroup\$ Well, that's a shame. If you have it, and need a toggled output, it is clearly the way to go. Without it, you need to manage the toggle state on your own. Some parts also have separate registers per pin; for example the LPC8xxx family has byte and word registers containing single pin states. If available, that would at least get rid of the inter-thread risks of read-modify-write. \$\endgroup\$ – RBerteig Apr 7 '15 at 23:23
  • \$\begingroup\$ Those FIOx registers are in bit-band addressable memory space, so you can access bits individually. \$\endgroup\$ – Turbo J Apr 8 '15 at 0:04
  • \$\begingroup\$ @TurboJ thanks for the bit band idea, however I don't think it will solve my potential problem because bit band acces is translated into a read modify write sequence. See my updated question. \$\endgroup\$ – odinthenerd Apr 8 '15 at 21:03
0
\$\begingroup\$

On the LPC175x/6x parts you're using there's a set of FIOxMASK registers which restrict the bits which get modified when writing to the other pin registers, so you should be able to use that to avoid spurious changes to unrelated bits.

\$\endgroup\$
  • \$\begingroup\$ Thank you for your answer, in the case where one does not know the value of FIOxMASK at compile time one would need to store it, write a mask to it, read-modify-write to FIOxPIN and restore the old FIOxMASK value. This is not as efficient as my example in practice. \$\endgroup\$ – odinthenerd Apr 9 '15 at 10:58
0
\$\begingroup\$

This is what I came up with as the most efficient and guaranteed correct work around:

constexpr int mask{(1<<5)};
*FIOxPIN = *FIOxSET ^ mask; 

It works because the FIOxSET register will return the value of the output latch when read so no trouble if the output latch value differs from the FIOxPIN value. I am still interested in a better answer if anyone can offer one.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.