質問やフィードバックがありましたら、フォームからお願いします
目次
本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください
avr-libc の中には <util/atomic.h>
というファイルがあります。最初の印象は、avr は単核であるべきなのに、なぜ atomic が必要なのかということです。そのため、無意識に説明を見てみました。
このヘッダーファイルのマクロは、原子性を持つか持たないかが保証されたコードブロックを扱います。この文脈での「Atomic」という用語は、該当するコードが中断されることができないことを指します。
マイクロコントローラーでも、さまざまな割り込みが利用できるため、コードの実行が途中で中断される可能性があります。atomic を使用することで、内部にあるコード片が割り込みの影響を受けないこと(割り込みを一時的に中止する)を保証できます。
ATOMIC_BLOCK(ATOMIC_FORCEON) {
// 重要な処理を行う
}
体感としては cli()
と sei()
の組み合わせのように見えますが、ドキュメントの説明によると、さらなる処理が行われているようです。内部の実装は次のようになります。
#define ATOMIC_BLOCK(type) for ( type, __ToDo = __iCliRetVal(); \
__ToDo ; __ToDo = 0 )
type
をパラメータとして受け取ることができ、渡すことができるパラメータには ATOMIC_RESTORESTATE
と ATOMIC_FORCEON
があります。
#define ATOMIC_RESTORESTATE uint8_t sreg_save \
__attribute__((__cleanup__(__iRestore))) = SREG
これは sei
の効果に似ていますが、興味深いのは __attribute__
の使用です。GCC では、変数や関数がどのように保存されるべきかを決定するために __attribute__
を使用できます。この動作は libc
の実装内で定義されています。例えば、AVR では次のように記述できます。
#include <avr/pgmspace.h>
const int my_var[2] PROGMEM = { 1, 2 };
ここでの PROGMEM
は実際には __attribute__
です。
#ifndef __ATTR_PROGMEM__
#define __ATTR_PROGMEM__ __attribute__((__progmem__))
#endif
一般的に変数はメモリに存在しますが、マイクロコントローラーではメモリが非常に限られています。しかし、一般的なコンピュータとは異なり、通常、マイクロコントローラーのコードは事前に書かれてコンパイルされ、直接プログラムメモリ(フラッシュメモリ)に書き込まれます。コードがあまり多くない場合、フラッシュメモリは逆に多くの空きスペースを残します。この場合、PROGMEM
を使用して変数をフラッシュメモリに存在させ、メモリの使用量を減らすことができます。読み取る際には pgm_read_word
を使用して変数を読み取ることができます。
ATOMIC_BLOCK
に戻ると、すべて展開するとコードは次のようになります。
for (uint8_t sreg_save __attribute__((__cleanup__(__iRestore))) = 0; __ToDo = __iCliRetVal(); __ToDo ; __ToDo = 0) {
// 重要な処理を行う
}
これにより、コードの実行が割り込みの影響を受けないことを確実にします。for loop
を使用するこの方法は非常に興味深く、こんな使い方ができるとは思いもしませんでした。
この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨
☕Buy me a coffee