1
\$\begingroup\$

I am a newbie and I am trying to understand how particular register (in lpc1347) works. Maybe it's common problem, maybe it's specific to lpc boards. I'd like to learn how GPIO and PININT register works, so I have started learn lpc1347 manual, but I am stucked in point while changing GPIO register. Let's take, for example GPIO register called NOT, which toggle a pin to opposite state. I can modify it in two ways:

pointerToGPIO->NOT[0] |= 1 << pin;

or

pointerToGPIO->NOT[0] = 1 << pin;

NOTE: Both of them works correctly. The first way is called (surely) read-modify-write, because I must read NOT register, make OR operation and save it. The second way is to save pin mask directly. I have made a simple research and LPCOpen use the second way:

STATIC INLINE void Chip_GPIO_SetPinToggle(LPC_GPIO_T *pGPIO, uint8_t port, 
                   uint8_t pin)
{
    pGPIO->NOT[port] = (1 << pin);
}

Of course there are several registers in the GPIO that I have to modify with OR/AND masks...My question is How do I know when I don't have to make RMW operation and modify register directly? I have searched in the manual, but I didn't find any mention how to distinguish it. Is it any recipe how to do it properly? Should manual tell me the truth or this is general knowledge how to distinguish it?

\$\endgroup\$
0
\$\begingroup\$

There is no single method to be used; it all depends on your application. If you want to set a value directly and previous value is not useful, you assign directly because it is faster.

You need to do RMW when you want to preserve part of the previous value. Say you have a 32 bits register where each bit is state of a GPIO (output 1 or 0). If you want to modify only bit 0 you will use RMW such as:

PORTX |= 0x00000001; // Set bit 0.
PORTX &= 0x00000001; // Clear all but bit 0.
PORTX &= ~0x00000001; // Clear bit 0, but keep others.
PORTX ^= 0x00000001; // Toggle state of bit 0 whatever it is.

As you can see, using RMW, you can keep previous state of other bits if you want. Therefore if if you to create different independent modules, you can use RMW to modify your bits without have to care about the state of bits being set by other modules in your code. Using RMW is a little bit slower than direct assignment, though.

Now, some CPUs integrate special registers to perform so kind of RMW without actually having to read the registers such as with your chip. The "NOT" is because your chip has a special register whose purpose is to clear bits that you set. While this is common on ARM microcontrollers, it is not the case with every microcontroller. Such special registers allow to perform a hardware RMW, so that there is no performance penalty like with software RMW. Lower end microcontroller do not integrate such feature because it requires more transistors and complexity on the chip's hardware driving cost higher.

To answer your question directly: both are RMW. One is software implemented (first) and the other is hardware implemented. You should use hardware whenever possible. On your chip this is available. On lower end hardware you would have to use the software technique.

\$\endgroup\$
0
\$\begingroup\$

How do I know when I don't have to make RMW operation and modify register directly? I have searched in the manual, but I didn't find any mention how to distinguish it. Is it any recipe how to do it properly? Should manual tell me the truth or this is general knowledge how to distinguish it?

From LPC1315/16/17/45/46/47 User manual, section 9.5.3.9, (page 132) you can see about the NOT0/1 registers:

"0 = no operation"

"1 = Toggle output bit".

Therefore, the bits at 0 are not touched, the bits at 1 are modified.

enter image description here

These two particular registers (as well as others) also marked as write only. Performing a software read-modify-write would be just a waste of time. The compiler does not know that the location is write only, therefore it will actually make a useless read (which will be presumably 0), because also NOT[0] is correctly defined as "volatile".

EDIT: @Chris Stratton suggested that actually the read operation of a write-only register could yield any garbage (unless the manual states that the microcontroller implements a "0 results on read of write-only registers"). This could be indeed very dangerous, because that result will be used to compute the actual write value.

\$\endgroup\$
  • 1
    \$\begingroup\$ This suggests that a software read-modify-write is actually a serious mistake - given that the register is "write only" it's not clear that the value obtained on read is even defined, so a read-modify-write could end up writing random garbage captured from the invalid read back to the outputs, or could perhaps trigger an illegal access fault. \$\endgroup\$ – Chris Stratton Sep 20 '17 at 18:45
  • \$\begingroup\$ @ChrisStratton you're totally right, however playing with many ARM microcontrollers I have always seen that reading a write only register always yielded 0 (I was expecting garbage too). I don't know if this is just a coincidence, or if it's "the standard". Maybe there's something in the ARM manual, somewhere. Or maybe it's just microcontroller/manufacturer-dependent. \$\endgroup\$ – next-hack Sep 20 '17 at 18:53
  • 2
    \$\begingroup\$ The danger in things that aren't defined to have a certain behavior is that you may unknowingly be relying on something that is usually true, but will not be in some obscure case. Bugs that are hard to trigger are by far the worst. \$\endgroup\$ – Chris Stratton Sep 20 '17 at 18:57
  • \$\begingroup\$ I agree. Edited the post. \$\endgroup\$ – next-hack Sep 20 '17 at 19:04

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.