@@ -164,6 +164,55 @@ mode. For example, this snippet sets pin A3 to output mode:
164164 * (volatile uint32_t *) (0x40020000 + 0 ) |= 1 << 6 ; // Set bits 6-7 to 1
165165```
166166
167+ Let me explain those bit operations. Our goal is to set bits 6-7, which are
168+ responsible for the pin 3 of GPIOA peripheral, to a specific value (1, in our
169+ case). This is done in two steps. First, we must clear the current value of
170+ bits 6-7, because it may hold some value already. Then we must set bits 6-7
171+ to the value we want.
172+
173+ So, first, we must set bit range 6-7 to zero. How do we set
174+ a number of bits to zero? In four steps:
175+
176+ - Get a number that has N contiguous bits set:
177+ - 1 for 1 bit: ` 0b1 ` ,
178+ - 3 for 2 bits: ` 0b11 ` ,
179+ - 7 for 3 bits: ` 0b111 ` ,
180+ - 15 for 4 bits: ` 0b1111 ` ,
181+ - and so on: generally, for N bits, the number is ` 2^N - 1 `
182+ So, for 2 bits it is number ` 3 ` , or ` 0b00000000000000000000000000000011 `
183+ - Shift that number left. If we need to set bits X-Y, then shift on X positions
184+ left. In our case, shift on a 6 positions left: ` (3 << 6) ` , or
185+ ` 0b00000000000000000000000011000000 `
186+ - Invert the number: turn zeros to ones, and ones to zeroes:
187+ ` ~(3 << 6) ` , or ` 0xb11111111111111111111111100111111 `
188+ - Now, perform a "logical AND" operation of the register with our number. Bits
189+ 6-7, AND-ed with 0, will give zero - that's what we want! All other bits,
190+ AND-ed with 1, will retain their current value: ` REG &= ~(3 << 6) ` . Retaining
191+ values of all other bits is important: we don't want to change other settings
192+ in other bit ranges!
193+
194+ So, in general, if we want to clear bits X-Y (set them to zero), do:
195+
196+ ``` c
197+ PERIPHERAL->REGISTER &= ~(NUMBER_WITH_N_BITS << X);
198+ ```
199+
200+ And, finally, we want to set a given bit range to the value we want. We
201+ shift that value X positions left, and OR with the current value of the whole
202+ register:
203+
204+ ``` c
205+ PERIPHERAL->REGISTER |= VALUE << X;
206+ ```
207+
208+ Now, it should be clear to you, dear reader, the meaning of these two lines,
209+ which set bits 6-7 of the GPIOA MODER register to the value of 1 (output).
210+
211+ ``` c
212+ * (volatile uint32_t *) (0x40020000 + 0 ) &= ~(3 << 6 ); // CLear bits 6-7
213+ * (volatile uint32_t *) (0x40020000 + 0 ) |= 1 << 6 ; // Set bits 6-7 to 1
214+ ```
215+
167216Some registers are not mapped to the MCU peripherals, but they are mapped to
168217the ARM CPU configuration and control. For example, there is a "Reset at clock
169218control" unit (RCC), described in section 6 of the datasheet. It describes
0 commit comments