AVR Studio リテラル文字列取扱注意 Part 2
前回の日記で扱ったリテラル文字列の処理は不完全でした。
http://ameblo.jp/elementor/entry-10192030215.html (←前回の日記)
ポイント1
リテラル文字列容易のROM配置指定のマクロがありました
『PSTR』
ポイント2
読込みにもprogram(ROM)領域を意識する必要があります
ポイント3
昨日の疑問なぜRAMにリテラルを配置するか分りました。
AVRではROM(program)領域とRAM(data)領域はアドレス空間自体が異なっています。
そのため通常変数として扱う場合はdata領域に配置していなければなりません。
program領域に配置した変数は特別な操作(*)をしないとデータを読み込めません。
CPUの構造による制約だったわけです。
*:LPM
そういうわけでコードを書き直すと次のようになります。
~定義部~
#include <avr/pgmspace.h>
#define ERRMSG_BAD_COMMAND PSTR("E1")
#define ERRMSG_BAD_PARAMETER PSTR("E2")
~関数内~
SendMsg_P(ERRMSG_BAD_COMMAND);
/* SendMsg実装 */
void SendMsg_P(PGM_P buf){
char c;
while((c = pgm_read_byte(buf)) != (char)0)
{
UART_write(c);
buf++;
}
UART_write('\r'); /* 改行コード */
UART_write('\n'); /* 改行コード */
}
/*----ここまで----*/
PSTRを使ったことで幾分シンプルになりましたね。
AVR Studio リテラル文字列取扱注意
例えば
~定義部~
#define ERRMSG_BAD_COMMAND "E1"
#define ERRMSG_BAD_PARAMETER "E2"
~関数内~
SendMsg(ERRMSG_BAD_ COMMAND);
とした場合
文字列"E1"はdata(RAM)領域に配置されます。
ATTINY2313ではRAMが非常に小さく128バイトしかないなめリテラル文字列をRAMには配置させたくありません。
この対策にはAVR Studio固有の定義PROGMEMという定義を使います
使い方
~定義部~
#include
#define ERRMSG_BAD_COMMAND "E1"
#define ERRMSG_BAD_PARAMETER "E2"
const char Errmsg_Bad_Command[] PROGMEM = ERRMSG_BAD_COMMAND;
const char Errmsg_Bad_Parameter[] PROGMEM = ERRMSG_BAD_PARAMETER;
~関数内~
SendMsg(Errmsg_Bad_ Command);
シミュレータやマップファイルで確認するとちゃんとprogram (ROM)領域に配置されたことを確認できます
複数モジュール(ファイル)で共通のリテラルを使用する場合はPROGMEM変数は1つのモジュール(ファイル)で実体を定義し、定義部にはextern宣言で使用すると良いと思う(未確認)
SPLINTを使用する場合PROGMEMはSPLINTで解釈出来ないので無視する様に設定する必要があります。
それにしてもどうしてこんな仕様にしてるんだろう?
ソフトバンク通信モジュール
auからも同様のモジュールがあったのは知ってましたが、ソフトバンクからもでてたんですね。
NI-01S(ネットインデックス社製)
あまり聞いたこと無い会社ですね
FOMAモジュールとの違いは、音声通話、SMSにも対応しているところ
FOMAの場合は専用線かmoperaへ接続する利用法だがソフトバンクの場合はどうなんだろ、ソフトバンクだけに通信コストが安そうなイメージがあるので時間の有るときに詳しく調べたい。
単価も気になります。