Question about manipulating bits

Status
Not open for further replies.

BLMinTenn

Well-known member
Gentlemen,
I have multiple questions... and I have searched the forums for a specific answer without any luck.
I am trying to learn how to toggle multiple bits on and off without affecting other bits already set. I understand the bitshift part, but not quite have a grasp on the matter.

I am currently setting 2 bits in the same register with two lines of code. It works!
Code:
GPIOD_PDOR |= (1<<6);      // HIGH
GPIOD_PDOR |= (1<<5);      // HIGH

However I want to acomplish the same by using only one line of code which compiles. Dont beat me up because I am not sure of the code below is correct.
Code:
GPIOD_PDOR |= ((1<<6) | (1<<5));

Am I doing this right...

Also if I want to set the same bits back to LOW, then is the code below correct?
Code:
GPIOD_PDOR &= ((1<<6) | (1<<5));


Also, in the instance of the following where...
Code:
GPIOD_PDOR &= ~(1<<6);     // LOW
GPIOD_PDOR |= (1<<5);        // HIGH

How do I write a one liner to do the same...
Thanks in advance
 
Gentlemen,
I have multiple questions... and I have searched the forums for a specific answer without any luck.
I am trying to learn how to toggle multiple bits on and off without affecting other bits already set. I understand the bitshift part, but not quite have a grasp on the matter.

I am currently setting 2 bits in the same register with two lines of code. It works!
Code:
GPIOD_PDOR |= (1<<6);      // HIGH
GPIOD_PDOR |= (1<<5);      // HIGH

However I want to acomplish the same by using only one line of code which compiles. Dont beat me up because I am not sure of the code below is correct.
Code:
GPIOD_PDOR |= ((1<<6) | (1<<5));

Am I doing this right...
Sure for setting the bits (providing the field you are referencing is a 32-bit int on a Teensy 3.x/LC, or 16-bit int on a Teensy 2.x). However generally you want to use names for each of the bits, rather than just using (1<<6) and (1<<5).

Typewise, you probably want to use the same type as the GPIOD_PDOR definition, which in this case is uint32_t:

Code:
#define GPIOD_PDOR                (*(volatile uint32_t *)0x400FF0C0)  // Port Data Output Register

I don't know the GPIOD structure, so I will just call the two fields ALPHA and BETA. You would define them like:

Code:
const uint32_t ALPHA = ((uint32_t)1) << 5;
const uint32_t BETA = ((uint32_t)1) << 6;

or if you prefer:

Code:
#define ALPHA (((uint32_t)1) << 5)
#define BETA (((uint32_t)2) << 6)

Casting the 1 to uint32_t insures that the resulting type after the shift is uin32_t. Otherwise, there might be issues if you use bit 31 due to int being signed. And if the type were a 64-bit type, you could get truncation if you go past 31.

Also if I want to set the same bits back to LOW, then is the code below correct?
Code:
GPIOD_PDOR &= ((1<<6) | (1<<5));

No, this is incorrect. You would clear all bits except (1<<5) and (1<<6), and those two bits would retain their value. What you are missing is the tilde ('~'), which reverses the bits values. To clear both bits (using my ALPHA and BETA from before):

Code:
GPIOD_PDOR &= ~(ALPHA | BETA);

Also, in the instance of the following where...
Code:
GPIOD_PDOR &= ~(1<<6);     // LOW
GPIOD_PDOR |= (1<<5);        // HIGH

How do I write a one liner to do the same...
Thanks in advance

You would do something like:

Code:
GPIOD_PDOR  = (GPIOD_PDOR  & ~BETA) | ALPHA;

The <op>= value operation is short hand for:

Code:
variable = variable <op> value;
 
Michael,
Thanks for the reply. To help you and the group understand, I am using a Teensy 3.2 and the GPIO_PDOR register to manipulate pins 20 & 21 high and low as as fast as possible.
So to summarize....

If I want to...
Code:
GPIOD_PDOR |= (1<<6);      // HIGH
GPIOD_PDOR |= (1<<5);      // HIGH

This works for single line application...
Code:
GPIOD_PDOR |= ((1<<6) | (1<<5));

To do this...
Code:
GPIOD_PDOR &= ~(1<<6);     // LOW
GPIOD_PDOR |= (1<<5);        // HIGH

is the equivalent 1 liner...
Code:
GPIOD_PDOR = (GPIOD_PDOR & ~(1<<6)) | (1<<5);

and last... this...
Code:
GPIOD_PDOR &= ~(1<<6);      // LOW
GPIOD_PDOR &= ~(1<<5);      // LOW

performs the same as...
Code:
GPIOD_PDOR &= ~((1<<6) | (1<<5));

Do I have this correct?
Thanks in Advance
 
Your one-liner does a read, a and/or/eor and a write. So it is 3 operations (plus loading the adress).
There are more specialized registers, for examplefor setting or clearing bits that don't need the read + and/or/eor operations.
Open the reference manual and look for GPIOx_PSOR (set Bits), PCOR (clear Bits), PTOR (toggle Bits)
 
Last edited:
All,
Thanks for the response I understand the madness behind the bits. Just one more question.

If I want to combine this...
Code:
if(GPIOD_PDIR & (1<<4) || GPIOD_PDIR & (1<<5)) {do something}

is the below the same?
Code:
if(GPIOD_PDIR & ((1<<4) ^ (1<<5))  {do something}

thanks in advance
 
All,
Thanks for the response I understand the madness behind the bits. Just one more question.

If I want to combine this...
Code:
if(GPIOD_PDIR & (1<<4) || GPIOD_PDIR & (1<<5)) {do something}

is the below the same?
Code:
if(GPIOD_PDIR & ((1<<4) ^ (1<<5))  {do something}

thanks in advance

No, you want inclusive-or, not exclusive-or, i.e.

Code:
if(GPIOD_PDIR & ((1<<4) | (1<<5))  {do something}

would be the same as:

Code:
if((GPIOD_PDIR & (1<<4)) || (GPIOD_PDIR & (1<<5))) {...}

If instead you wanted an '&&' replacement such as:
Code:
if((GPIOD_PDIR & (1<<4)) && (GPIOD_PDIR & (1<<5))) {...}

you would code it as:
Code:
if ((GPIOD_PDIR & ((1<<4)|(1<<5))) == ((1<<4)|(1<<5))) {...}
 
Status
Not open for further replies.
Back
Top