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

といった感じになるので、一命令ではない。