STM32F3探訪〜GPIOx_ODR vs GPIOx_BSRR 〜
STM32F3のGPIOピンのoutput用レジスタには、GPIOx_ODRというものと、GPIOx_BSRRという二種類ある。その違いを調べたので、書き留めておく。
ODRとBSRRは共に書き込み可能なレジスタであり、GPIOのoutput値を決めるのに使える。BSRRはリファレンスに、
Bits 31:16 BRy: Port x reset bit y (y = 0..15)
These bits are write-only. A read to these bits returns the value 0x0000.
0: No action on the corresponding ODRx bit
1: Resets the corresponding ODRx bit
Note: If both BSx and BRx are set, BSx has priority.
Bits 15:0 BSy: Port x set bit y (y= 0..15)
These bits are write-only. A read to these bits returns the value 0x0000.
0: No action on the corresponding ODRxODR
1: Sets the corresponding ODRx bit
と書いてあるように、ODRを設定するためのレジスタである。では、ODRだけでいいじゃないかと思うかもしれないが、次のような場合の為に、BSRRが必要だ。
例
Port xのbit yピンを1にしたいときを考える。
ODRだけ
uint32_t odr = GPIOx->ODR; # part 1 odr |= 1UL << y; # part 2 GPIOx->ODR = odr; # part 3
といった操作を行うことになる。しかし、part 1のあとに割り込みが入り、割り込みルーチンの中でODRが変更されたときを考えてほしい。part 3で書き戻したときに、その変更をなかったことにしてしまう。
ODRとBSRR
uint32_t bsrr = 1UL << y; # part 1 GPIOx->BSRR = bsrr; # part 2
という操作で実現できる。BSRRに0を書き込んでも何も起こらないからこのようにできる。この場合、part 1の後に割り込みが入っても、ODRのコピーをしていないので問題ない。また、命令数が単純に少なくなっているので実行が早くなる。
BSRRのこのような性質を指して、レファレンスではatomicという語を使っている。ただ、何の前置きもなしにatomicと言われても何のことかわからないので、例解してみた。
追記
ODRだけの時のコードは、
GPIOx->ODR |= 1UL << y;
と一行で書ける。しかし、この場合も生成されるバイナリ(ここでは擬似的なアセンブリで示す)は、
mv GPIOx->ODR, %r0 or 1UL << y, %r0 mv %r0, GPIO->ODR
といった感じになるので、一命令ではない。