TL; DR:
- なぜと
(unsigned long)(0x400253FC)
同等ではないの(unsigned long)((*((volatile unsigned long *)0x400253FC)))
ですか? - 前者で動作するマクロを後者で動作させるにはどうすればよいですか?
背景情報
環境
私は、ARM Cortex-M3プロセッサであるTIのLM3S6965と、 StellarisWare(無料ダウンロード、輸出管理)の定義を使用しています。gccバージョン4.6.1(Sourcery CodeBench Lite 2011.09-69)を使用しています。Stellarisは、「inc / lm3s6965.h」で約5,000個のレジスタとメモリアドレスの定義を提供していますが、これらすべてをやり直したくはありません。しかし、私が書きたいマクロとは互換性がないようです。
ビットバンディング
ARM Cortex-M3では、メモリの一部が、ペリフェラルおよびRAMメモリスペースのビットごとに1つの32ビットワードでエイリアスされます。アドレス0x42000000のメモリを0x00000001に設定すると、アドレス0x40000000のメモリの最初のビットが1に設定されますが、ワードの残りの部分には影響しません。ビット2を変更するには、0x42000004の単語を1に変更します。これは優れた機能であり、非常に便利です。ARMテクニカルリファレンスマニュアルによると、アドレスを計算するためのアルゴリズムは次のとおりです。
bit_word_offset = (byte_offset x 32) + (bit_number × 4)
bit_word_addr = bit_band_base + bit_word_offset
どこ:
bit_word_offset
は、ビットバンドメモリ領域内のターゲットビットの位置です。bit_word_addr
は、ターゲットビットにマップされるエイリアスメモリ領域内のワードのアドレスです。bit_band_base
エイリアス領域の開始アドレスです。byte_offset
は、ターゲットビットを含むビットバンド領域のバイト数です。bit_number
ターゲットビットの0〜7のビット位置です
ビットバンディングの実装
この"inc/hw_types.h"
ファイルには、このアルゴリズムを実装する次のマクロが含まれています。明確にするために、4バイトに整列されたワードと0〜31ビットのオフセットを受け入れるワードベースのモデルに実装されていますが、結果のアドレスは同等です。
#define HWREGBITB(x, b) \
HWREGB(((unsigned long)(x) & 0xF0000000) | 0x02000000 | \
(((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
このアルゴリズムは、0x20000000のSRAMまたは0x40000000のペリフェラルメモリスペースのいずれかにあるベースを取得し、それを0x02000000とOR演算して、ビットバンドベースオフセットを追加します。次に、ベースからのオフセットを32倍し(5ポジションの左シフトに相当)、ビット番号を加算します。
参照されるHWREGは、メモリ内の特定の場所に書き込むために必要なキャストを実行するだけです。
#define HWREG(x) \
(*((volatile unsigned long *)(x)))
これは、次のような割り当てで非常にうまく機能します
HWREGBITW(0x400253FC, 0) = 1;
ここで、0x400253FCはメモリマップドペリフェラルのマジックナンバーであり、このペリフェラルのビット0を1に設定したいと思います。上記のコードは(もちろんコンパイル時に)ビットオフセットを計算し、そのワードを1に設定します。
動作しないもの
残念ながら、「inc / lm3s6965.h」の前述の定義は、HWREGによって行われたキャストをすでに実行しています。マジックナンバーを避け、代わりに次のような提供された定義を使用したい
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
これをHWREGBITWに貼り付けようとすると、キャストが干渉するため、マクロが機能しなくなります。
HWREGBITW(GPIO_PORTF_DATA_R, 0) = 1;
プリプロセッサは、次の混乱を生成します(インデントが追加されました)。
(*((volatile unsigned long *)
((((unsigned long)((*((volatile unsigned long *)0x400253FC)))) & 0xF0000000)
| 0x02000000 |
((((unsigned long)((*((volatile unsigned long *)0x400253FC)))) & 0x000FFFFF) << 5)
| ((0) << 2))
)) = 1;
の2つのインスタンスに注意してください
(((unsigned long)((*((volatile unsigned long *)0x400253FC)))))
これらの余分なキャストが私のプロセスの失敗の原因であると私は信じています。次の前処理の結果はHWREGBITW(0x400253FC, 0) = 1;
機能し、私の主張を裏付けています。
(*((volatile unsigned long *)
((((unsigned long)(0x400253FC)) & 0xF0000000)
| 0x02000000 |
((((unsigned long)(0x400253FC)) & 0x000FFFFF) << 5)
| ((0) << 2))
)) = 1;
(type)
キャスト演算子は右から左に優先されるため、最後のキャストが適用さunsigned long
れ、ビット単位の演算に使用されます(これは正しく機能するはずです)。どこにも暗黙的なものはなく、floatからポインタへの変換、精度/範囲の変更はありません...左端のキャストは、右へのキャストを単に無効にする必要があります。
私の質問(ついに...)
- なぜと
(unsigned long)(0x400253FC)
同等ではないの(unsigned long)((*((volatile unsigned long *)0x400253FC)))
ですか? HWREGBITW
既存のマクロを機能させるにはどうすればよいですか?または、同じタスクを実行するが、既存のキャストで引数が与えられたときに失敗しないようにマクロを作成するにはどうすればよいですか?