Help us understand the problem. What is going on with this article?

ESP-WROOM-02プログラムでalignを指定する方法

More than 3 years have passed since last update.

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];を宣言しているプログラム書いた場合、アドレスがどうなっているか試してみましょう。

program1-no-align.ino
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; を追加してみましょう。

program2-no-align.ino
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))) を付ければ良いことがわかりました。

先ほどのプログラムにこれを付けてみるとこうなります。

program3-with-align.ino
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でもやってみる必要があります。

iotlt
IoT縛りの勉強会です。 毎月イベントを実施しているので是非遊びに来てください! 登壇者を中心にQiitaでも情報発信していきます。 https://iotlt.connpass.com
https://iotlt.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away