nrf-rs / nrf-pacs

Peripheral Access Crates (PACs) for nRF microcontrollers
BSD Zero Clause License
27 stars 11 forks source link

nRF52832 PSEL.{CLK,DIN} CONNECT field writer overwrites PIN field #19

Closed frankplow closed 5 months ago

frankplow commented 10 months ago

The PSEL registers of the PDM peripheral on the nRF52832 control which pins the PDM peripheral uses. There is one for the clock pin, and one for the data pin. These registers are similar and both look like this:

31 30 29 28 27 7 6 5 4 3 2 1 0
B A A A A A

where: A is the PIN field, describing the pin number; B is the CONNECTED field, which must be set to 0 to enable the PDM function on that pin.

The registers both default to 0xffffffff.

To set this register, I would expect to do something along the lines of:

pdm.psel.din.write(|w| w.pin().variant(din.pin()));
pdm.psel.din.write(|w| w.connect().connected());

However this does not work. The PIN field is set correctly by the first line, but then is overwritten to 31 = 0b11111 by the CONNECT_W writer in the second line.

I can't see anything obviously wrong in the relevant cluster of the svd file: https://github.com/nrf-rs/nrf-pacs/blob/90977499146de8444579538e7ad2466d1d9823db/svds/nrf52832.svd#L28306C12-L28377

rsarwas commented 5 months ago

@frankplow the behavior is correct. Reference the write API for svd2rust. The write method takes a closure which "specifies how the reset value will be modified before it’s written." Your second call to write resets the changes made in the first call to write.

To achieve your goal, either make all your changes in one call to write. This is typically done with method chaining, i.e.

pdm.psel.din.write(|w| w.pin().variant(din.pin()).connect().connected());

Or replace the second call to write with a call to modify (API) which reads the register and writes the changes to that value, not the reset value, thereby preserving the state of the unchanged bits.

frankplow commented 5 months ago

@rsarwas Ah, I see. Thanks a lot for the clarification.