Skip to content

Commit 74b7342

Browse files
zelenskiCS107E BOT
authored andcommitted
Comment to explain need for flag -fstrict-volatile-bitfields
commit 5da9c1d2636740d48650bc04d3ec77f910450c7d Author: Julie Zelenski <[email protected]> Date: Sun Dec 1 12:27:32 2024 -0800 Comment to explain need for flag -fstrict-volatile-bitfields
1 parent 3ed669a commit 74b7342

File tree

1 file changed

+26
-10
lines changed
  • lectures/Output/code/extras

1 file changed

+26
-10
lines changed

lectures/Output/code/extras/pwm.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@
1515
#include "gpio_extra.h"
1616
#include <stdarg.h>
1717

18+
/*
19+
* IMPORTANT: bitfields & hardware registers
20+
* -----------------------------------------
21+
* TL;DR Be sure to compile with gcc flag -fstrict-volatile-bitfields
22+
*
23+
* This flag tells gcc to generate 32-bit load/store instructions (i.e. lw/sw)
24+
* to access volatile bitfields. Without flag, gcc can generate 8 or 16-bit
25+
* instructions (i.e. sh or lb) that access subword. Subword access appears to
26+
* interact badly with pwm hardware registers. This did not appear to be documented
27+
* anywhere; I only found out the hard way when observing garbled bits and lost
28+
* updates.
29+
*
30+
* I don't know if this behavior is specific to pwm or affects all peripheral
31+
* registers. I think it best to assume it is needed for all volatile bitfields
32+
* (i.e. any bitfield within peripheral registers)
33+
*/
34+
1835
typedef union {
1936
struct {
2037
uint32_t pier;
@@ -152,22 +169,21 @@ static bool set_pin_fn_to_pwm(pwm_channel_id_t ch, gpio_id_t pin) {
152169
}
153170

154171
/*
155-
* IMPORTANT CAUTION: update of PPR (period) register
156-
* --------------------------------------------------
157-
* TLDR: must use single 32-bit write to ppr that sets both active/entire in one go
172+
* IMPORTANT: update of PPR (period) register
173+
* ------------------------------------------
174+
* TL;DR: must use single 32-bit write to ppr that sets both active/entire in one go
158175
*
159176
* I originally defined ppr as bitfield with upper/lower 16-bit.
160-
* However, writes to the fields did not seem to do correct thing.
161-
* The gcc-generated code was using lh/sh instructions and those were
162-
* did not place nice with hardware register.
163-
* Applying flag fstrict-volatile-bitfields forces gcc to generate
164-
* 32-bit lw/sw, which corrected some of the problems, but not all.
165-
* Write of active and entire field in two separate actions (
177+
* The gcc-generated code was using lh/sh instructions which
178+
* did not place nice with hardware register. (see note above)
179+
* Apply flag fstrict-volatile-bitfields forces gcc to generate
180+
* 32-bit lw/sw. This corrected most of the problems, but not all.
181+
* Write of active and entire field in two separate actions
166182
* (i.e. two read-modify-write) was still problematic.
167183
* The observed behavior was erratic (timing-sensitive?), sometimes second
168184
* update just silently dropped. (seemed most likely to happen on the
169185
* very first set of ppr after init module)
170-
* Instead write to ppr in single operation that sets
186+
* Change code to write to ppr in single operation that sets
171187
* both fields in one go seems to behave perfectly, no glitch
172188
*/
173189
static void set_period(pwm_channel_id_t ch, int n_active, int n_entire) {

0 commit comments

Comments
 (0)