マルチコアプログラミングの初めでつまづいた話

Qiita Advent calendar2021の記事です。

:::note
Spresenseの関係会社に勤務していますが、業務外の個人活動の紹介です。
当記事は会社と関係ありません。
:::

こちらの記事を試して動くことを確認した後で、プログラムを少し変更したときの話です。
https://qiita.com/mk-takahashi/items/9f068eabc999dee16243

オリジナル
シリアルモニタの入力と待機はMainが行い、Sub1 ~ Sub4にLEDの点滅を指示する。

変更
シリアルモニタの入力と待機はSub5が行う。
Sub5がLED番号と点滅間隔の2つの入力値をMainに送り、
そしてMainがSub1 ~ Sub4にLEDの点滅を指示する。

<details><summary> Sub5 </summary><div>

```
// 参考 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

```

</div></details>


2つの変数を送るため、msgidを2つ使うことにします。


<details><summary> Sub1-4, Main </summary><div>

```
// 参考 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

```

</div></details>

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の戻り値の挙動に気づくまで起き上がれなかった話でした。

ファームが古いせいかもしれないし、マルチコアの使い方のお作法を分かってないせいかもしれないです。