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

/*
* Nucleo DCO IC間通信 データーフォーマット
*
* 2018.11.11
*
*/
#ifndef _DATA_COM_FORMAT_H_
#define _DATA_COM_FORMAT_H_
#define OSC_NUM (3)
// display mode
enum {
DM_TITLE = 0,
DM_NORMAL = 1,
DM_FREQUENCY = 2,
DM_AMPLITUDE = 3,
DM_PULSE_WIDTH = 4,
DM_TITLE_STR1 = 128,
DM_TITLE_STR2 = 129,
DM_TITLE_STR3 = 130,
DM_DISPLAY_OFF = 255
};
// I2C通信用構造体
// DM_NORMAL
#pragma pack(1)
struct normalData {
uint8_t waveShape[OSC_NUM];
uint8_t frequencyRange[OSC_NUM];
uint16_t fps;
uint8_t batteryVoltage;
bool adcAvailable;
};
// DM_FREQUENCY
#pragma pack(1)
struct frequencyData {
uint16_t rate[OSC_NUM];
int16_t detune[OSC_NUM];
};
// DM_AMPLITUDE
#pragma pack(1)
struct amplitudeData {
int16_t amplitude[OSC_NUM];
int16_t masterAmplitude;
uint8_t clip;
};
// DM_PULSE_WIDTH
#pragma pack(1)
struct pulseWidthData {
int16_t pulseWidth[OSC_NUM];
};
#endif //_DATA_COM_FORMAT_H_
view raw DataComFormat.h hosted with ❤ by GitHub
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 DCO I2C Slave / OLED Module Test.
*
* 2018.11.05
*
*/
#include "mbed.h"
#include "DataComFormat.h"
#define UART_TRACE (0)
#define I2C_CLOCK (400000)
#define I2C_ARDUINO_ADDR (0x08 << 1) // 8bit address
#define TITLE_STR1 ("I2C OLED Test")
#define TITLE_STR2 (__DATE__)
#define TITLE_STR3 (__TIME__)
#define DEBOUNCE_DELAY (50000) // usec
int displayMode = DM_TITLE;
I2C I2cArduino(PB_9, PB_8); // SDA, SCL
InterruptIn UserButton(PC_13);
DigitalOut CheckPin1(PA_10);
Timeout debouncer;
#if (UART_TRACE)
Serial pc(USBTX, USBRX);
#endif
// parameter
volatile int waveShape[OSC_NUM];
volatile int frequencyRange[OSC_NUM];
volatile int fps;
volatile int batteryVoltage;
volatile bool adcAvailable;
volatile double drate[OSC_NUM];
volatile double detune[OSC_NUM];
volatile float amplitude[OSC_NUM];
volatile float masterAmplitude;
volatile bool isClip;
volatile int pulseWidth[OSC_NUM];
volatile bool isDirty = true;
int x = 0;
//-------------------------------------------------------------------------------------------------
// I2C 通信
//
void displayTitle()
{
#if (UART_TRACE)
pc.printf("displayTitle()\r\n");
#endif
const int len = 32;
char strBuffer[len];
// Title文字列を送信
strncpy(strBuffer, TITLE_STR1, len);
printf("%s %d %d\r\n", strBuffer, len, strlen(strBuffer));
uint8_t mode = DM_TITLE_STR1;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, strBuffer, len, false) != 0) {
printf("%d I2C failure: TitleStr1\r\n", x);
}
strncpy(strBuffer, TITLE_STR2, len);
printf("%s %d %d\r\n", strBuffer, len, strlen(strBuffer));
mode = DM_TITLE_STR2;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, strBuffer, len, false) != 0) {
printf("%d I2C failure: TitleStr2\r\n", x);
}
strncpy(strBuffer, TITLE_STR3, len);
printf("%s %d %d\r\n", strBuffer, len, strlen(strBuffer));
mode = DM_TITLE_STR3;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, strBuffer, len, false) != 0) {
printf("%d I2C failure: TitleStr3\r\n", x);
}
wait_ms(1);
// Title表示指示を送信
mode = DM_TITLE;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, false) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
}
void displayNormal()
{
#if (UART_TRACE)
pc.printf("displayNormal()\r\n");
#endif
struct normalData d;
d.waveShape[0] = waveShape[0];
d.waveShape[1] = waveShape[1];
d.waveShape[2] = waveShape[2];
d.frequencyRange[0] = frequencyRange[0];
d.frequencyRange[1] = frequencyRange[1];
d.frequencyRange[2] = frequencyRange[2];
d.fps = fps;
d.batteryVoltage = batteryVoltage;
d.adcAvailable = adcAvailable;
#if (UART_TRACE)
pc.printf("WaveShape1: %d\r\n", d.waveShape[0]);
pc.printf("WaveShape2: %d\r\n", d.waveShape[1]);
pc.printf("WaveShape3: %d\r\n", d.waveShape[2]);
pc.printf("FreqRange1: %d\r\n", d.frequencyRange[0]);
pc.printf("FreqRange2: %d\r\n", d.frequencyRange[1]);
pc.printf("FreqRange3: %d\r\n", d.frequencyRange[2]);
pc.printf("FPS: %d\r\n", d.fps);
pc.printf("BattVoltage: %d\r\n", d.batteryVoltage);
pc.printf("ADCAvailable: %d\r\n", d.adcAvailable);
#endif
uint8_t mode = DM_NORMAL;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&d, sizeof(d), false) != 0) {
printf("%d I2C failure: normalData\r\n", x);
}
}
void displayFrequency()
{
#if (UART_TRACE)
pc.printf("displayFrequency()\r\n");
#endif
struct frequencyData d;
d.rate[0] = drate[0] * 10;
d.rate[1] = drate[1] * 10;
d.rate[2] = drate[2] * 10;
d.detune[0] = detune[0] * 1000;
d.detune[1] = detune[1] * 1000;
d.detune[2] = detune[2] * 1000;
#if (UART_TRACE)
pc.printf("Rate1: %d\r\n", d.rate[0]);
pc.printf("Rate2: %d\r\n", d.rate[1]);
pc.printf("Rate3: %d\r\n", d.rate[2]);
pc.printf("Detune1: %d\r\n", d.detune[0]);
pc.printf("Detune2: %d\r\n", d.detune[1]);
pc.printf("Detune3: %d\r\n", d.detune[2]);
#endif
uint8_t mode = DM_FREQUENCY;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&d, sizeof(d), false) != 0) {
printf("%d I2C failure: frequencyData\r\n", x);
}
}
void displayAmplitude()
{
#if (UART_TRACE)
pc.printf("displayAmplitude()\r\n");
#endif
struct amplitudeData d;
d.amplitude[0] = amplitude[0] * 1000;
d.amplitude[1] = amplitude[1] * 1000;
d.amplitude[2] = amplitude[2] * 1000;
d.masterAmplitude = masterAmplitude * 1000;
d.clip = isClip;
#if (UART_TRACE)
pc.printf("Amplitude1: %d\r\n", d.amplitude[0]);
pc.printf("Amplitude2: %d\r\n", d.amplitude[1]);
pc.printf("Amplitude3: %d\r\n", d.amplitude[2]);
pc.printf("MasterAmplitude: %d\r\n", d.masterAmplitude);
pc.printf("Clip: %d\r\n", d.clip);
#endif
uint8_t mode = DM_AMPLITUDE;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&d, sizeof(d), false) != 0) {
printf("%d I2C failure: amplitudeData\r\n", x);
}
}
void displayPulseWidth()
{
#if (UART_TRACE)
pc.printf("displayPulseWidth()\r\n");
#endif
struct pulseWidthData d;
d.pulseWidth[0] = ((float)pulseWidth[0] / UINT16_MAX) * 1000;
d.pulseWidth[1] = ((float)pulseWidth[1] / UINT16_MAX) * 1000;
d.pulseWidth[2] = ((float)pulseWidth[2] / UINT16_MAX) * 1000;
#if (UART_TRACE)
pc.printf("PulseWidth1: %d\r\n", d.pulseWidth[0]);
pc.printf("PulseWidth2: %d\r\n", d.pulseWidth[1]);
pc.printf("PulseWidth2: %d\r\n", d.pulseWidth[2]);
#endif
uint8_t mode = DM_PULSE_WIDTH;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&d, sizeof(d), false) != 0) {
printf("%d I2C failure: pulseWidthData\r\n", x);
}
}
void displayOff()
{
#if (UART_TRACE)
pc.printf("displayOff()\r\n");
#endif
uint8_t mode = DM_DISPLAY_OFF;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&mode, 1, true) != 0) {
printf("%d I2C failure: mode %d\r\n", x, mode);
}
uint8_t message = false;
if (I2cArduino.write(I2C_ARDUINO_ADDR, (char *)&message, 1, false) != 0) {
printf("%d I2C failure: displayOff message\r\n", x);
}
}
//-------------------------------------------------------------------------------------------------
// 入力処理
//
void changeDisplayMode()
{
if (UserButton.read() == 0) {
displayMode++;
if (displayMode > DM_DISPLAY_OFF) {
displayMode = 0;
}
else if (displayMode > DM_PULSE_WIDTH) {
displayMode = DM_DISPLAY_OFF;
}
isDirty = true;
}
}
void debounce()
{
debouncer.attach_us(&changeDisplayMode, DEBOUNCE_DELAY);
}
//-------------------------------------------------------------------------------------------------
// Main loop
//
int main()
{
#if (UART_TRACE)
pc.baud(115200);
pc.printf("\r\n%s\r\n", TITLE_STR1);
pc.printf("%s\r\n", TITLE_STR2);
pc.printf("%s\r\n", TITLE_STR3);
wait(1.0);
#endif
I2cArduino.frequency(I2C_CLOCK);
UserButton.fall(&debounce);
// initialize parameter (dummy)
waveShape[0] = 1;
waveShape[1] = 2;
waveShape[2] = 3;
frequencyRange[0] = 4;
frequencyRange[1] = 5;
frequencyRange[2] = 6;
fps = 600; // 60.0fps
batteryVoltage = 90; // 9.0V
adcAvailable = true;
drate[0] = 440.1;
drate[1] = 880.2;
drate[2] = 1320.3;
detune[0] = 0.0;
detune[1] = -0.543;
detune[2] = 0.543;
amplitude[0] = 0.123f;
amplitude[1] = 0.456f;
amplitude[2] = 0.567f;
masterAmplitude = 1.000f;
isClip = true;
pulseWidth[0] = 0;
pulseWidth[1] = 32768;
pulseWidth[2] = 65536;
while(1) {
if (isDirty) {
CheckPin1.write(1);
switch (displayMode) {
case DM_TITLE:
displayTitle();
break;
case DM_NORMAL:
displayNormal();
break;
case DM_FREQUENCY:
displayFrequency();
break;
case DM_AMPLITUDE:
displayAmplitude();
break;
case DM_PULSE_WIDTH:
displayPulseWidth();
break;
case DM_DISPLAY_OFF:
displayOff();
break;
}
//isDirty = false;
wait_ms(1);
CheckPin1.write(0);
x++;
}
}
}
view raw main.cpp hosted with ❤ by GitHub

マスター側の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

/*
* Nucleo DCO I2C Slave / OLED Module Test.
* use u8g2::print()
*
* 2018.11.11
*
*/
#include <Wire.h>
#include <U8g2lib.h>
#include "DataComFormat.h"
#define UART_TRACE (0) // UART_TRACEを有効化(1)にすると、メモリーオーバーのためコンパイルできません。
#define TITLE_STR1 ("I2C Slave Test")
#define TITLE_STR2 ("20181111")
#define I2C_ADDR (0x08)
#define I2C_CLOCK (400000)
#define MASTER_TITLE_STR_LEN (32)
//U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
const int CheckPin1 = 2;
// Const strings
const char* waveShapeName[] = {
"SIN",
"TRI",
"SWU",
"SWD",
"SQR",
"NOS",
"XXX"
};
const char* frequencyRangeName[] = {
"A-1",
" A0",
" A1",
" A2",
" A3",
" A4",
" A5",
" A6",
" A7",
" A8"
};
char masterTitleStr1[MASTER_TITLE_STR_LEN] = "TitleStr1";
char masterTitleStr2[MASTER_TITLE_STR_LEN] = "TitleStr2";
char masterTitleStr3[MASTER_TITLE_STR_LEN] = "TitleStr3";
volatile int displayMode = DM_TITLE;
volatile struct normalData normalData;
volatile struct frequencyData frequencyData;
volatile struct amplitudeData amplitudeData;
volatile struct pulseWidthData pulseWidthData;
volatile bool displayOffMessage;
volatile bool isDirty = true;
void setup()
{
#if (UART_TRACE)
Serial.begin(9600); // start serial for output
Serial.println();
Serial.println(TITLE_STR1);
Serial.println(TITLE_STR2);
#endif
pinMode(CheckPin1, OUTPUT);
// OLED
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_8x13_tf);
u8g2.setCursor(0, 10);
u8g2.print(TITLE_STR1);
u8g2.setCursor(0, 25);
u8g2.print(TITLE_STR2);
u8g2.sendBuffer();
// I2C
Wire.begin(I2C_ADDR); // join i2c bus with address #8
pinMode(A4, INPUT); // disable pullup
pinMode(A5, INPUT); // disable pullup
Wire.setClock(I2C_CLOCK);
Wire.onReceive(receiveEvent); // register event
delay(2000);
}
//-------------------------------------------------------------------------------------------------
// OLED Display
//
void displayTitle()
{
#if (UART_TRACE)
Serial.println("displayTitle()");
#endif
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_10x20_mf);
u8g2.setCursor(0, 16);
u8g2.print(masterTitleStr1);
u8g2.setCursor(0, 32);
u8g2.print(masterTitleStr2);
u8g2.setCursor(0, 48);
u8g2.print(masterTitleStr3);
u8g2.sendBuffer();
}
void displayNormal()
{
#if (UART_TRACE)
Serial.println("displayNormal()");
#endif
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_10x20_mf);
u8g2.setCursor(4, 16);
u8g2.print(waveShapeName[normalData.waveShape[0]]);
u8g2.print(' ');
u8g2.print(waveShapeName[normalData.waveShape[1]]);
u8g2.print(' ');
u8g2.print(waveShapeName[normalData.waveShape[2]]);
u8g2.setCursor(4, 32);
u8g2.print(frequencyRangeName[normalData.frequencyRange[0]]);
u8g2.print(' ');
u8g2.print(frequencyRangeName[normalData.frequencyRange[1]]);
u8g2.print(' ');
u8g2.print(frequencyRangeName[normalData.frequencyRange[2]]);
u8g2.setCursor(4, 48);
u8g2.print("FPS:");
u8g2.print((float)normalData.fps/10, 1);
u8g2.setCursor(4, 64);
u8g2.print("BAT:");
u8g2.print((float)normalData.batteryVoltage/10, 1);
u8g2.print("V ");
u8g2.print(normalData.adcAvailable ? "xx" : "AD");
u8g2.sendBuffer();
}
void displayFrequency()
{
#if (UART_TRACE)
Serial.println("displayFrequency()");
#endif
u8g2.clearBuffer();
u8g2.setCursor(0, 16);
u8g2.print("F1:");
u8g2.print((float)frequencyData.rate[0]/10, 1);
u8g2.print(" Hz");
u8g2.setCursor(0, 32);
u8g2.print("F2:");
u8g2.print((float)frequencyData.rate[1]/10, 1);
u8g2.print(" Hz");
u8g2.setCursor(0, 48);
u8g2.print("F3:");
u8g2.print((float)frequencyData.rate[2]/10, 1);
u8g2.print(" Hz");
u8g2.setCursor(0, 64);
u8g2.print((float)frequencyData.detune[1]/1000, 3);
u8g2.print(' ');
u8g2.print((float)frequencyData.detune[2]/1000, 3);
u8g2.sendBuffer();
}
void displayAmplitude()
{
#if (UART_TRACE)
Serial.println("displayAmplitude()");
#endif
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_10x20_mf);
u8g2.setCursor(0, 16);
u8g2.print("AMP1: ");
u8g2.print((float)amplitudeData.amplitude[0]/1000, 3);
u8g2.setCursor(0, 32);
u8g2.print("AMP2: ");
u8g2.print((float)amplitudeData.amplitude[1]/1000, 3);
u8g2.setCursor(0, 48);
u8g2.print("AMP3: ");
u8g2.print((float)amplitudeData.amplitude[2]/1000, 3);
u8g2.setCursor(0, 64);
u8g2.print("MAMP: ");
u8g2.print((float)amplitudeData.masterAmplitude/1000, 3);
u8g2.sendBuffer();
}
void displayPulseWidth()
{
#if (UART_TRACE)
Serial.println("displayPulseWidth()");
#endif
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_10x20_mf);
u8g2.setCursor(0, 16);
u8g2.print("PW1: ");
u8g2.print((float)pulseWidthData.pulseWidth[0]/1000, 3);
u8g2.setCursor(0, 32);
u8g2.print("PW2: ");
u8g2.print((float)pulseWidthData.pulseWidth[1]/1000, 3);
u8g2.setCursor(0, 48);
u8g2.print("PW3: ");
u8g2.print((float)pulseWidthData.pulseWidth[2]/1000, 3);
u8g2.sendBuffer();
}
void displayOff()
{
#if (UART_TRACE)
Serial.println("displayOff()");
#endif
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_10x20_mf);
u8g2.setCursor(4, 24);
u8g2.print("DISPLAY OFF");
u8g2.sendBuffer();
}
//-------------------------------------------------------------------------------------------------
// Main loop
//
void loop()
{
if (isDirty) {
isDirty = false;
switch (displayMode) {
case DM_TITLE:
displayTitle();
break;
case DM_NORMAL:
displayNormal();
break;
case DM_FREQUENCY:
displayFrequency();
break;
case DM_AMPLITUDE:
displayAmplitude();
break;
case DM_PULSE_WIDTH:
displayPulseWidth();
break;
case DM_DISPLAY_OFF:
displayOff();
break;
}
}
#if (UART_TRACE)
switch (displayMode) {
case DM_TITLE:
Serial.println("******* Display Title *********");
Serial.println(masterTitleStr1);
Serial.println(masterTitleStr2);
Serial.println(masterTitleStr3);
Serial.println("*******************************");
break;
case DM_NORMAL:
Serial.println("*********** Normal ************");
Serial.print("WaveShpe1: "); Serial.println(normalData.waveShape[0]);
Serial.print("WaveShpe2: "); Serial.println(normalData.waveShape[1]);
Serial.print("WaveShpe3: "); Serial.println(normalData.waveShape[2]);
Serial.print("FreqRange1: "); Serial.println(normalData.frequencyRange[0]);
Serial.print("FreqRange2: "); Serial.println(normalData.frequencyRange[1]);
Serial.print("FreqRange3: "); Serial.println(normalData.frequencyRange[2]);
Serial.print("Fps: "); Serial.println(normalData.fps);
Serial.print("Fps: "); Serial.print(normalData.fps/10); Serial.print("."); Serial.println(normalData.fps%10);
Serial.print("BattVoltage: "); Serial.println(normalData.batteryVoltage);
Serial.print("BattVoltage: "); Serial.print(normalData.batteryVoltage/10); Serial.print("."); Serial.println(normalData.batteryVoltage%10);
Serial.print("ADCAvilable: "); Serial.println(normalData.adcAvailable);
Serial.println("*******************************");
break;
case DM_FREQUENCY:
Serial.println("********** Frequency **********");
Serial.print("Rate1: "); Serial.println(frequencyData.rate[0]);
Serial.print("Rate1: "); Serial.print(frequencyData.rate[0]/10); Serial.print("."); Serial.println(frequencyData.rate[0]%10);
Serial.print("Rate2: "); Serial.println(frequencyData.rate[1]);
Serial.print("Rate2: "); Serial.print(frequencyData.rate[1]/10); Serial.print("."); Serial.println(frequencyData.rate[1]%10);
Serial.print("Rate3: "); Serial.println(frequencyData.rate[2]);
Serial.print("Rate3: "); Serial.print(frequencyData.rate[2]/10); Serial.print("."); Serial.println(frequencyData.rate[2]%10);
Serial.print("Detune1: "); Serial.println(frequencyData.detune[0]);
Serial.print("Detune1: "); Serial.print(frequencyData.detune[0]/1000); Serial.print("."); Serial.println(frequencyData.detune[0]%1000);
Serial.print("Detune2: "); Serial.println(frequencyData.detune[1]);
//Serial.print("Detune2: "); Serial.print(frequencyData.detune[1]/1000); Serial.print("."); Serial.println(frequencyData.detune[1]%1000);
Serial.print("Detune2: "); Serial.println((float)(frequencyData.detune[1])/1000.0f, 3);
Serial.print("Detune3: "); Serial.println(frequencyData.detune[2]);
Serial.print("Detune3: "); Serial.print(frequencyData.detune[2]/1000); Serial.print("."); Serial.println(frequencyData.detune[2]%1000);
Serial.println("*******************************");
break;
case DM_AMPLITUDE:
Serial.println("********** Amplitude **********");
Serial.print("Amplitude1: "); Serial.println(amplitudeData.amplitude[0]);
Serial.print("Amplitude1: "); Serial.println((float)(amplitudeData.amplitude[0])/1000.0f, 3);
Serial.print("Amplitude2: "); Serial.println(amplitudeData.amplitude[1]);
Serial.print("Amplitude2: "); Serial.println((float)(amplitudeData.amplitude[1])/1000.0f, 3);
Serial.print("Amplitude3: "); Serial.println(amplitudeData.amplitude[2]);
Serial.print("Amplitude3: "); Serial.println((float)(amplitudeData.amplitude[2])/1000.0f, 3);
Serial.print("MasterAmplitude: "); Serial.println(amplitudeData.masterAmplitude);
Serial.print("MasterAmplitude: "); Serial.println((float)(amplitudeData.masterAmplitude)/1000.0f, 3);
Serial.print("Clip: "); Serial.println(amplitudeData.clip);
Serial.println("*******************************");
break;
case DM_PULSE_WIDTH:
Serial.println("********* Pulse Width *********");
Serial.print("PulseWidth1: "); Serial.println(pulseWidthData.pulseWidth[0]);
Serial.print("PulseWidth1: "); Serial.println((float)(pulseWidthData.pulseWidth[0])/1000.0f, 3);
Serial.print("PulseWidth2: "); Serial.println(pulseWidthData.pulseWidth[1]);
Serial.print("PulseWidth2: "); Serial.println((float)(pulseWidthData.pulseWidth[1])/1000.0f, 3);
Serial.print("PulseWidth3: "); Serial.println(pulseWidthData.pulseWidth[2]);
Serial.print("PulseWidth3: "); Serial.println((float)(pulseWidthData.pulseWidth[2])/1000.0f, 3);
Serial.println("*******************************");
break;
case DM_DISPLAY_OFF:
Serial.println("********* Display Off *********");
Serial.print("DisplayOffMessage: "); Serial.println(displayOffMessage);
Serial.println("*******************************");
}
delay(1000);
#endif
}
//-------------------------------------------------------------------------------------------------
// I2C Event
//
void receiveEvent(int byteN)
{
#if (UART_TRACE)
Serial.println("receiveEvent()");
#endif
displayMode = Wire.read();
#if (UART_TRACE)
Serial.print("displayMode: ");
Serial.println(displayMode);
#endif
digitalWrite(CheckPin1, HIGH);
uint8_t* p;
switch (displayMode) {
case DM_TITLE:
break;
case DM_TITLE_STR1:
for (int i = 0; i < MASTER_TITLE_STR_LEN; i++) {
masterTitleStr1[i] = Wire.read();
}
break;
case DM_TITLE_STR2:
for (int i = 0; i < MASTER_TITLE_STR_LEN; i++) {
masterTitleStr2[i] = Wire.read();
}
break;
case DM_TITLE_STR3:
for (int i = 0; i < MASTER_TITLE_STR_LEN; i++) {
masterTitleStr3[i] = Wire.read();
}
break;
case DM_NORMAL:
p = (uint8_t *)&normalData;
for (int i = 0; i < sizeof(struct normalData); i++) {
p[i] = Wire.read();
}
case DM_FREQUENCY:
p = (uint8_t *)&frequencyData;
for (int i = 0; i < sizeof(struct frequencyData); i++) {
p[i] = Wire.read();
}
break;
case DM_AMPLITUDE:
p = (uint8_t *)&amplitudeData;
for (int i = 0; i < sizeof(struct amplitudeData); i++) {
p[i] = Wire.read();
}
break;
case DM_PULSE_WIDTH:
p = (uint8_t *)&pulseWidthData;
for (int i = 0; i < sizeof(struct pulseWidthData); i++) {
p[i] = Wire.read();
}
break;
case DM_DISPLAY_OFF:
displayOffMessage = Wire.read();
break;
}
isDirty = true;
digitalWrite(CheckPin1, LOW);
}
最終的に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 件のコメント:

コメントを投稿