ESP-WROOM-02でrtcメモリやflashメモリにデータを読み書きする場合、読み書きに使うメモリのアドレスを32bit境界に合わせなければなりません。その方法を調べたのでメモします。
要約
変数宣言に __attribute__((aligned(4)))
を付ければよい。
uint8 data __attribute__((aligned(4)));
alignが必要な場面
例えば、rtcメモリを読む関数 system_rtc_mem_read の定義は次のようになっています。
bool system_rtc_mem_read(uint32 src_addr, void *des_addr, uint32 load_size);
第2引数のdes_addr
は32ビット境界のアドレスでなければなりません。つまり、16進数で表した場合下1桁が 0, 4, 8, C のいずれかでなければなりません。
alignを指定しないでプログラムを書いた例(その1)
グローバル変装としてuint8 dataBuffer[8];
を宣言しているプログラム書いた場合、アドレスがどうなっているか試してみましょう。
uint8 dataBuffer[8];
void setup() {
Serial.begin(115200);
delay(10); // macのserial consoleが文字化けしないためのおまじない
Serial.println("");
Serial.println("--- setup() ---");
}
void loop() {
Serial.println("--- loop() ---");
printAddress("dataBuffer=", (uint32)dataBuffer);
Serial.println("Wait for 10 seconds");
delay(10*1000);
}
void printAddress(char *name, uint32 address) {
Serial.print(name);
Serial.println(address, HEX);
}
このプログラムをmac上のArduino IDEでコンパイルしてESP-WROOM-02で実行してみると次のような結果が得られます。
--- setup() ---
--- loop() ---
dataBuffer=3FFEE298
Wait for 10 seconds
アドレスの下1桁が 8
なのでこれでOKです。
alignを指定しないでプログラムを書いた例(その2)
では、先ほどのプログラムにグローバル変数 uint8 aaa;
を追加してみましょう。
uint8 dataBuffer[8];
uint8 aaa;
void setup() {
Serial.begin(115200);
delay(10); // macのserial consoleが文字化けしないためのおまじない
Serial.println("");
Serial.println("--- setup() ---");
}
void loop() {
Serial.println("--- loop() ---");
printAddress("dataBuffer=", (uint32)dataBuffer);
printAddress("aaa =", (uint32)&aaa);
Serial.println("Wait for 10 seconds");
delay(10*1000);
}
void printAddress(char *name, uint32 address) {
Serial.print(name);
Serial.println(address, HEX);
}
このプログラムを実行してみるとこういう結果が得られます。
--- setup() ---
--- loop() ---
dataBuffer=3FFEE299
aaa =3FFEE298
Wait for 10 seconds
dataBufferのアドレスの下1桁が 9
になっています。これではいけません。
変数を色々宣言していると、そのアドレスが何になるかはコンパイラ任せなので、32bit境界になるかどうかは運任せになります。
alignを指定したプログラム
「この変数は32bit境界に配置してね!」とコンパイラにお願いすることができます。お願いの方法はコンパイラによってまちまちです。ESP-WROOM-02用のプログラムをArduino IDEで記述する場合は、変数宣言に __attribute__((aligned(4)))
を付ければ良いことがわかりました。
先ほどのプログラムにこれを付けてみるとこうなります。
uint8 dataBuffer[8] __attribute__((aligned(4)));
uint8 aaa;
void setup() {
Serial.begin(115200);
delay(10); // macのserial consoleが文字化けしないためのおまじない
Serial.println("");
Serial.println("--- setup() ---");
}
void loop() {
Serial.println("--- loop() ---");
printAddress("dataBuffer=", (uint32)dataBuffer);
printAddress("aaa =", (uint32)&aaa);
Serial.println("Wait for 10 seconds");
delay(10*1000);
}
void printAddress(char *name, uint32 address) {
Serial.print(name);
Serial.println(address, HEX);
}
このプログラムを実行するとこういう結果が得られます。
--- setup() ---
--- loop() ---
dataBuffer=3FFEE29C
aaa =3FFEE298
Wait for 10 seconds
dataBufferのアドレスの下1桁が C
になっているので、32bit境界なのでOKです。
TODO
Macでしか動作を確かめていないので、Windowsでもやってみる必要があります。