Skip to main content
Visitor II
May 14, 2025
Question

F446 Bitwise operator MODER & PUPDR

  • May 14, 2025
  • 2 replies
  • 795 views

Hello.. i m programming F446 using registers, and i found from F446 reference manual to configure PA1 as both input and pull-down mode. i don't understand , can anyone advise how could

1. MODER &= ~(3<<2)  is to set MODER1 as 00 input? 

2. PUPDR |=  (1<<3);    is to set  as 10 pull-down mode??  isn't that mean bit 3 set to '1' ??

 

GPIOA->MODER &= ~(3<<2); // 7.4.1 Bits (3:2) = 0:0 --> PA1 in Input Mode
GPIOA->PUPDR |= (1<<3); // 7.4.4 Bits (3:2) = 1:0 --> PA1 is in Pull Down mode
}

 

    This topic has been closed for replies.

    2 replies

    Explorer
    May 14, 2025

    These bits are quite comprehensively explained in the reference manual :

    Ozone_0-1747200877967.png

    This example is for a similiar MCU (the F4x5/F4x7).

    And second, I would highly recommend to use the constants defined in stm32f4xx.h, not magic numbers.
    Like here:

    Ozone_1-1747201014174.png

     



    Visitor II
    May 14, 2025

    yes, i know this as i read the rm of F446.. My question is how the bitwise operator shift left 2 from 3 ended up as selecting 00 as input for MODER1? and shift left 3 from 1 ended up as selecting 10 for PUPDR ??

    1. MODER &= ~(3<<2)  is to set MODER1 as 00 input? 

    2. PUPDR |=  (1<<3);    is to set  as 10 pull-down mode??  isn't that mean bit 3 set to '1' ??

    Anyone can kindly advise? 

    Explorer
    May 14, 2025

    > 1. MODER &= ~(3<<2)  is to set MODER1 as 00 input? 

    If you look at the RefManual description, two adjacent bits define the state of each GPIO.
    Bits 0 & 1 for pin 0 (e.g. PA0), bits 2 & 3 for pin 1 (e.g. PA1), and so on ...
    And the '~' operator clears those bits, thus they are reset to zero - which mean "input" according to the RefManual.
    Thus this instruction sets PA1 to inputs.

    The same goes for pull-up/pull-down settings :

    Ozone_0-1747208036801.png


    Such reference manuals are quite dense, information-wise.
    One needs to get used to read them.

     

    Had the author (not you, I guess), used something like this, it would have been more clear:
    MODER &= ~GPIO_MODER_MODER1

    Even if it's your own code, you forget those details after a few weeks, and you will have a hard time decoding the number magick.
    Speaking names and constants have definitely advantages.

     

    Graduate II
    May 14, 2025

    For register level interactions it's probably inadvisable to a) assume current bit states, b) used repetitive RMW action on the same 'volatile' memory space, the compiler can't fold the lines.

    Better to use the form, which does both things in a SINGLE LOAD-STORE interaction

    GPIOA>MODER = (GPIOA>MODER ^ ~bits_to_clear) | bits_to_set;

    Doing half-a-dozen load/store is NOT efficient, using subroutines and libraries, especially when defined INLINE, can result in cleaner, manageable and more efficient code.

    The (1 << 3) is assuming bit 2 is zero, which it might be at reset, but it's better to be explicit about what you want, that way the next person to use your code knows what the intent was, and if you copy-n-paste to another section or reuse it later for this, or a different pin, that the expectation continue to be true.

    Visitor II
    May 15, 2025

    Doing half-a-dozen load/store is NOT efficient, using subroutines and libraries, especially when defined INLINE, can result in cleaner, manageable and more efficient code.

    sound great, could you provide an example?

    Graduate II
    May 15, 2025

    @HMSEdinburge wrote:

    Doing half-a-dozen load/store is NOT efficient, using subroutines and libraries, especially when defined INLINE, can result in cleaner, manageable and more efficient code.

    sound great, could you provide an example?


    I don't fully agree that this is inefficient. If it is done only during initialization it won't effect program performance. Unless you want short boot times. But a few extra instructions won't be a problem.
    If you cannot make any assumptions about the value in the register, then read-modify-write is the only way to make sure you only edit the bits you want. Reading once and writing once is enough as @Tesla DeLorean wrote in his code example.

    Even faster would be not to read at all. Simply assign the pin configurations of all pins in that register at once, then there is no need to read the register. But then you need to do all pin configuration in one place.