2018年11月12日月曜日

Nucleo(mbed)からI2Cで通信してArduinoでOLEDに表示させてみる(その2)

配線は前回と同じです。主にファームウェアを検討しました。


Nucleo DCOはNucleoF767ZIをコアとして開発していますが、(貧乏で何枚もF767ZIを買う余裕がないため)テストはNucleo F446REで行いました。

IC間通信 データーフォーマット

https://github.com/ryood/Nucleo_DCO/blob/master/Nucleo-Arduino_I2C_Test/Arduino/Nucleo_DCO_I2C_Slave_OLED_print_FullBuffer_Test/DataComFormat.h

I2Cではバイト単位の送受信を行うので、送受信するデータをまとめるために構造体を定義しました。
#pragma pack(1)
とすると構造体のアラインメントが1Byte単位になります。

I2Cマスター Nucleo F446RE(mbed)


https://github.com/ryood/Nucleo_DCO/tree/master/Nucleo-Arduino_I2C_Test/mbed/I2C_Master_Arduino_OLED_Test01


マスター側のNucleo(mbed)のプログラムは、ダミーデータを送信するものです。

ボードに付いている「User Button」を押すと、「display mode」が切り替わり、スレーブに送るデータが切り替わります。

I2C通信の仕方は、1Byte目に1Byteの「display mode」を送信し、それ以降のデータのフォーマットを識別できるようにしました。

困った点。


「void displayTitle()」は「プログラム名」、「コンパイル日付」、「コンパイル時刻」の3つの固定長文字列(32byte)を送信します。ここは、I2Cの流儀に従って、

[I2C Address][display mode(DM_TITLE)][プログラム名(32Byte)][コンパイル日付(32Byte)][コンパイル時刻(32Byte)][STOP]
と、まとめて送信したかったのですが、スレーブのArduinoから冒頭の「I2C Address」の時点でACKが返ってきません。

[I2C Address][display mode(DM_TITLE)][プログラム名(32Byte)][コンパイル日付(32Byte)][STOP]

と、文字列2個なら正常に通信できました。原因はわかりません。

しかたがないので、

[I2C Address][display mode(DM_TITLE_STR1)][プログラム名(32Byte)][STOP]
[I2C Address][display mode(DM_TITLE_STR2)][コンパイル日付(32Byte)][STOP]
[I2C Address][display mode(DM_TITLE_STR3)][コンパイル時刻(32Byte)][STOP]
wait_ms(1);
[I2C Address][display mode(DM_TITLE)][STOP]

と分離して送信するようにしました。また、途中に「wait_ms(1)」を入れないとかえって通信速度が遅くなります。Arduino側のI2Cのバッファサイズかなにかが影響しているのかもしれません。

I2Cスレーブ Arduino Pro mini 8MHz/3.3V 中華製

https://github.com/ryood/Nucleo_DCO/tree/master/Nucleo-Arduino_I2C_Test/Arduino/Nucleo_DCO_I2C_Slave_OLED_print_FullBuffer_Test

最終的にu8g2のフルバッファで表示できました。u8g2のページバッファは消費RAM量が少なくて済むのですが、OLEDの表示がダラダラした感じになるので見栄えのためにはフルバッファがいいと思います。

u8g2のフルバッファを使うとRAMを1024バイト消費するようです。ATMega328pのArduinoボードは2048バイトしか使えるRAMがなく、デバッグ用に使っているSerialでPCにUART通信する文字列の容量が大きく、「UART_TRACE」を有効にするとメモリーオーバーしてコンパイルできません。

Arduino IDEのメッセージは以下の通りです。

#define UART_TRACE (0)
最大30720バイトのフラッシュメモリのうち、スケッチが17392バイト(56%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が1866バイト(91%)を使っていて、ローカル変数で182バイト使うことができます。
スケッチが使用できるメモリが少なくなっています。動作が不安定になる可能性があります。
#define UART_TRACE (1)
最大30720バイトのフラッシュメモリのうち、スケッチが21210バイト(69%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が2689バイト(131%)を使っていて、ローカル変数で-641バイト使うことができます。
スケッチが使用するメモリが足りません。メモリを節約する方法については、以下のURLのページを参照してください。http://www.arduino.cc/en/Guide/Troubleshooting#size
ボードArduino Pro or Pro Miniに対するコンパイル時にエラーが発生しました。
スケッチで、
Serial.print("xxxx");
としているところを
Serial.print(F("xxxx"));
と「F()」マクロを使えば「"xxxx"」の文字列がRAMではなく、Flash Memoryに置かれてRAMの消費量が節約できるそうですが、試していません。

困った点というか助かった点。


Arduinoの「sprintf()」は浮動小数点が使えません。u8g2には「print()」メンバ関数が用意されていて、これを使えば「Serial.print()」と同じ様に
u8g2.print(<浮動小数点数>, <小数点以下の桁数>)
として浮動小数点数が表示できました。

タイミングの測定


ch1:Arduino(D2) ch2:I2C_SCL

ch1はArduinoのスケッチで、I2C割り込みがかかったとき(receiveEvent()が呼ばれる)、処理の最初と最後でH/Lしています。

これを見ると、I2C通信が終わったあとにI2C割り込みがかかっているようです。

やはりI2Cは難解です(T_T;

0 件のコメント:

コメントを投稿