Skip to content
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1cca96c
add stm32u5 debug image.
genan2003 Oct 17, 2025
f3a8f30
fix stm32u5 debug image.
genan2003 Oct 20, 2025
72e296b
update lab01
genan2003 Oct 21, 2025
80b79bf
Merge branch 'UPB-PMRust:main' into main
genan2003 Oct 21, 2025
13e1645
change defmt and cortex-m version.
genan2003 Oct 21, 2025
3204a6b
Merge branch 'main' of https://github.com/genan2003/website
genan2003 Oct 21, 2025
df20f10
Update website/lab/01/index.mdx
genan2003 Oct 21, 2025
c2a8f89
add defmt error snippet.
genan2003 Oct 21, 2025
82e55d1
Merge branch 'UPB-PMRust:main' into main
genan2003 Oct 26, 2025
8a3be44
update cargo.toml for stm32u5 and add waiting explanation for stm32.
genan2003 Oct 26, 2025
708b671
add informations about exti and update cargo.toml for rp2.
genan2003 Oct 27, 2025
b62f6f2
Update index.mdx with RP2350 and RP2040 dependencies
genan2003 Oct 28, 2025
3f22892
Remove comments from dependencies in index.mdx
genan2003 Oct 28, 2025
0954ccd
Update website/lab/02/index.mdx
genan2003 Oct 28, 2025
82e595f
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 3, 2025
a498bcb
add pin `D10` to lab03
genan2003 Nov 3, 2025
452dc08
add analog pins to lab03
genan2003 Nov 3, 2025
7515cb1
delete `Config` warning for ADC and PWM
genan2003 Nov 3, 2025
ccaab3c
delete the note about PWM channels
genan2003 Nov 3, 2025
48d8e0b
add `set_polarity` function to lab
genan2003 Nov 3, 2025
77da05c
add lab improvements
genan2003 Nov 3, 2025
fae2650
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 3, 2025
4d9cb47
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 4, 2025
5b79f3e
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 8, 2025
bcd5ad8
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 10, 2025
a940288
Remove `task_arena` from tip
genan2003 Nov 10, 2025
1f6745e
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 13, 2025
0a74356
Change screen_rst level from Low to High
genan2003 Nov 13, 2025
b58250b
Change screen_rst level from High to Low
genan2003 Nov 13, 2025
1439b94
Document required crate versions in index.mdx
genan2003 Nov 14, 2025
50ea692
Update website/lab/05/index.mdx
genan2003 Nov 17, 2025
5a8bbd8
Merge branch 'UPB-PMRust:main' into main
genan2003 Nov 18, 2025
42973f9
change spi config for screen
genan2003 Nov 19, 2025
6410e13
delete mipidsi dependency note
genan2003 Nov 19, 2025
ec374d2
Update index.mdx
genan2003 Nov 19, 2025
abfbbeb
Emphasize PLL configuration in system clock note
genan2003 Nov 19, 2025
c10180b
Update website/lab/05/index.mdx
genan2003 Nov 20, 2025
4996717
Update index.mdx
genan2003 Nov 20, 2025
d1134ca
Update PLL configuration for system clock speed
genan2003 Nov 20, 2025
fd2ce42
Merge branch 'UPB-PMRust:main' into main
genan2003 Dec 1, 2025
eb0251c
Merge branch 'UPB-PMRust:main' into main
genan2003 Feb 20, 2026
68542bf
add bitwise operations tutorial
genan2003 Feb 24, 2026
ef4e90b
Update website/tutorial/bitwise-operations.md
genan2003 Feb 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions website/tutorial/bitwise-operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
sidebar_position: 1
description: Bitwise operations to interact with hardware registers in Rust
---

# Bitwise Operations in Rust

When developing embedded software for the **STM32 Nucleo-U545RE-Q**, you are frequently required to configure specific hardware peripherals. Whether you are turning on one of the 5 LEDs or reading the state of the 4 buttons on your lab board, you communicate with the microcontroller by modifying specific bits within its hardware registers.

Because hardware registers group multiple independent configuration settings into a single 32-bit (or 8-bit) word, you cannot simply overwrite the entire register without risking the disruption of other settings. This is where bitwise operations come in.

## The Anatomy of a Hardware Register

Registers in microcontrollers generally consist of bits grouped by their specific roles. Here is what those bits actually do under the hood:

- **Control bits**: These are used to control different operating modes of the microcontroller or to activate specific hardware components. For example, setting a specific control bit might turn on the UART communication peripheral.
- **Status bits**: These are generally read-only bits used to check the state of an action or hardware peripheral. For instance, a status bit might turn to `1` automatically when new data has arrived in a buffer.
- **Data bits**: These bits are used to provide the microcontroller with data to be processed, or to retrieve data from it.
- **Reserved bits**: These bits are not currently used by the microcontroller. As a general rule in embedded programming, you should never modify reserved bits.


## Bit Shifting

Before modifying registers, you need to know how to target a specific bit. We do this by taking the number `1` and "shifting" it to the correct position.

- Right Shift (`>>`): This moves each bit of the operand to the right by a specified number of positions. Zeros are added to the left to maintain the dimension of the number. Mathematically, shifting right is a highly efficient way to divide a binary number by $ 2^n $ in a single operation.

:::info

`1010 >> 1 = 0101` (In decimal: 10 divided by 2 becomes 5).

:::

- Left Shift (`<<`): Moves bits to the left, filling the empty spaces on the right with zeros. Shifting left by n is mathematically equivalent to multiplying by $ 2^n $.

:::info

`0011 << 1 = 0110` (In decimal: 3 multiplied by 2 becomes 6).

:::

## Modifying Registers

Here are the primary operations you will use daily to manipulate bits without corrupting the rest of the register.

### Setting Bits (Making them `1`)

To set a specific bit to `1` while leaving the rest of the register untouched, we use the bitwise **OR** (`|`) operator.

- **Set a single bit**: `register | 1 << bit`
- **Set multiple bits**: `register | bits`

### Clearing Bits (Making them `0`)

To clear a specific bit to `0`, we use a combination of the bitwise **AND** (`&`) and bitwise **NOT** (`!`) operators.

- **Clear a single bit**: `register & !(1 << bit)`
- **Clear multiple bits**: `register & !bits`

### Toggling / Flipping Bits

If you need to invert the current state of a bit (change `1` to `0`, or `0` to `1`), use the bitwise **XOR** (`^`) operator.

- **Flip a single bit**: `register ^ (1 << bit)`
- **Flip multiple bits**: `register ^ bits`

## Value Extraction(Masking)

Often, a hardware register contains a specific multi-bit "field" (like a 4-bit configuration value) packed into a larger 32-bit word. To read just that field, you need to shift the bits down to the zero position and apply a **Mask** to zero-out everything else.

Here is a practical example of extracting a specific portion of a 32-bit ID:

```rust
// We define a mask that isolates the bottom 12 bits
const MASK: u32 = 0b0000_0000_0000_0000_0000_1111_1111_1111;

fn main() {
// A 32-bit register value
let large_id: u32 = 0b1100_1010_1111_1100_0000_1111_0110_1101;

// 1. Shift right by 20 to bring the target bits to the bottom
// 2. Apply the AND mask to clear all upper bits
let extracted_bits = (large_id >> 20) & MASK;

// Result: 00000000_0000_0000_0000_1100_1010_1111
}
```

## Common Pitfalls

Bitwise operations are prone to logical typos. Watch out for these common errors:

:::warning

Using the assignment operator (`=`) instead of the compound bitwise operator (`|=` or `&=`).

- **Wrong**: `register = 1 << 4` (This wipes out the entire register and only sets bit 4)
- **Correct**: `register |= 1 << 4` (This preserves the rest of the register while setting bit 4).

:::

:::warning

Do not confuse **logical** operators with **bitwise** operators!

- `&&` and `||` evaluate truthiness (e.g., `true && false`)
- `&` and `|` perform mathematically accurate bit-by-bit operations (e.g., `0b1100 & 0b0101 = 0b0100`).

:::