Qiita Advent calendar2021の記事です。
Spresenseの関係会社に勤務していますが、業務外の個人活動の紹介です。
当記事は会社と関係ありません。
こちらの記事を試して動くことを確認した後で、プログラムを少し変更したときの話です。
https://qiita.com/mk-takahashi/items/9f068eabc999dee16243
オリジナル
シリアルモニタの入力と待機はMainが行い、Sub1 ~ Sub4にLEDの点滅を指示する。
変更
シリアルモニタの入力と待機はSub5が行う。
Sub5がLED番号と点滅間隔の2つの入力値をMainに送り、
そしてMainがSub1 ~ Sub4にLEDの点滅を指示する。
Sub5
// 参考 https://qiita.com/mk-takahashi/items/9f068eabc999dee16243
// 参考にあるmain coreとほぼ同じ 出力が混じらないようdelayを入れたくらい
#include <MP.h>
// #if SUBCORE
#if (SUBCORE == 5)
byte interval;
void setup()
{
MP.begin();
MP.RecvTimeout(MP_RECV_POLLING);
MP.EnableConsole(); // https://developer.sony.com/develop/spresense/docs/arduino_developer_guide_ja.html#_mp_library
MPLog("start 1\n");
Serial.begin(115200);
}
void loop()
{
byte ledid = 0;
byte interval = 0;
int8_t msgid1 = 1;
int8_t msgid2 = 2;
int len = 0;
int ret, ret2;
Serial.print("LED NUMBER[1-4]:");
while(Serial.available() <= 0);
ledid = Serial.read()-48;
if((ledid >= 1) and (ledid <= 4))
{
Serial.println(ledid);
delay(5);
MPLog("Send led id : %d\n", ledid);
ret = MP.Send(msgid1, ledid);
delay(5);
}
Serial.print("Lighting interval[10ms]:");
while(Serial.available() <= 0);
len = Serial.available();
while(len)
{
interval = interval*10 + Serial.read()-48;
len--;
}
Serial.println(interval);
MPLog("Send freq id : %d\n", interval);
ret2 = MP.Send(msgid2, interval);
delay(5);
delay(10);
}
#endif
2つの変数を送るため、msgidを2つ使うことにします。
Sub1-4, Main
// 参考 https://qiita.com/mk-takahashi/items/9f068eabc999dee16243
// subcoreの中身はほとんど参考と同じ
#include <MP.h>
#ifdef SUBCORE
#if (SUBCORE == 1)
#define LED LED0
#elif (SUBCORE == 2)
#define LED LED1
#elif (SUBCORE == 3)
#define LED LED2
#elif (SUBCORE == 4)
#define LED LED3
#endif
void setup()
{
MP.begin();
MP.RecvTimeout(MP_RECV_POLLING);
MPLog("start");
}
int interval;
byte data0;
void loop()
{
int ret;
int8_t msgid;
ret = MP.Recv(&msgid, &data0);
// 待っている間、retはゼロ以外というより-11だった
if (ret != -11)
{
interval = data0 * 10;
MPLog("Recieve: ret=%3d msgid=%d, data0=%0d \n", ret, msgid, data0);
}
ledOn(LED);
delay(interval);
ledOff(LED);
delay(interval);
}
#else /* MAINCORE */
int status1 = 0;
int status2 = 0;
void setup()
{
int ret = 0;
int subid;
Serial.begin(115200);
while (!Serial);
/* Boot SubCore */
for (subid = 1; subid <= 5; subid++) {
ret = MP.begin(subid);
if (ret < 0) {
MPLog("MP.begin(%d) error = %d\n", subid, ret);
}
}
/* Polling */
MP.RecvTimeout(MP_RECV_POLLING);
MP.DisableConsole(); // https://developer.sony.com/develop/spresense/docs/arduino_developer_guide_ja.html#_mp_library
MPLog("start\n");
}
byte subcore = -1;
void loop()
{
byte rec1;
int ret;
int8_t msgid;
int8_t msgid1 = 1;
int8_t msgid2 = 2;
byte interval0;
ret = MP.Recv(&msgid, &rec1, 5);
// MP.Recvの戻り値はmsgidだった
if(ret == msgid1)
{
subcore = rec1;
status1 = 1;
MPLog("Recieved led id : %d, status1: %d, status2: %d\n", rec1, status1, status2);
}
if(ret == msgid2)
{
interval0 = rec1;
status2 = 1;
MPLog("Recieved frequency : %d, status1: %d, status2: %d\n", rec1, status1, status2);
}
if((status1 == 1) and (status2 == 1))
{
MP.Send(5, interval0, subcore);
status1 = 0;
status2 = 0;
MPLog("Send LEDid: %d, frequency : %d, status1: %d, status2: %d\n", subcore, interval0, status1, status2);
}
;
}
#endif
MainはmsgidによってLED番号と点滅間隔を切り替え受け取ります。
ここでつまづいたのはMP.Recvの戻り値でした。
Spresense Arduino 開発ガイドを読むと、MP.Recvの戻り値は「成功した場合は 0、エラーの場合は 0 以外の値が返ってきます。」とありましたが、実験すると成功した場合はmsgidが返ってきました。
https://developer.sony.com/develop/spresense/docs/arduino_developer_guide_ja.html#_mp_library
msgidを使い分ける例の紹介が見つからなかったこともあり、MP.Recvの戻り値の挙動に気づくまで起き上がれなかった話でした。
ファームが古いせいかもしれないし、マルチコアの使い方のお作法を分かってないせいかもしれないです。