Spresenseのマルチコア

# Spresenseのマルチコアを試す
Sonyの[Spresenseボード](https://www.sony-semicon.co.jp/products/smart-sensing/spresense/)は、ARM Cortex M4Fを6個搭載している。ここでは、マルチコアプログラミングを試してみる。

## 環境
Arduino IDE利用。サンプルコードは下記にあるものを参考に作成。
![スクリーンショット 2021-07-18 16.58.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/a5250dd7-c596-ea62-1261-b13c7a5d3f5c.png)

また、[こちら](https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_multicore)に、マルチコアプログラミングについて詳しい説明あり。

## サンプル
MaincoreとSubcore（ここでは2番目）とがメッセージの送受信を行い、受信時にLEDを点灯させるもの。

## ソースコード
### Maincore
```c++:Main.ino
#ifdef SUBCORE  // ①
#error "Core selection is wrong!!"
#endif

#include <MP.h>

int subcore = 2; /* Communication with SubCore2 */  // ② 

void setup()
{
  int ret = 0;

  Serial.begin(115200);
  while (!Serial);

  /* Launch SubCore2 */
  ret = MP.begin(subcore);  // ③
  if (ret < 0) {
    printf("MP.begin error = %d\n", ret);
  }

  randomSeed(millis());
}

void loop()
{
  int      ret;
  uint32_t snddata;
  uint32_t rcvdata;
  static int8_t   sndid = 0;
  int8_t   rcvid;

  snddata = random(32767);

  ret = MP.Send(sndid, snddata, subcore);  // ④
  printf("MainCore Send: id=%d data=0x%08x\n", sndid, snddata);
  sndid = (sndid != 127)? (sndid+1): 0;
  if (ret < 0) {
    printf("MP.Send error = %d\n", ret);
  }

  MP.RecvTimeout(3000); // Timeout 3000 msec

  ret = MP.Recv(&rcvid, &rcvdata, subcore);  // ⑤
  ledOn(LED0);  // ⑥
  delay(500);
  ledOff(LED0);
  if (ret < 0) {
    printf("MP.Recv error = %d\n", ret);
  }

  printf("MainCore Recv: id=%d data=0x%08x : %s\n\n", rcvid, rcvdata,
         (snddata == rcvdata) ? "Success" : "Fail");

  delay(1000);
}
```

- ①：Subcore指定時にはエラー
- ②：Subcore2の指定
- ③：Subcore2を指定してマルチコア起動
- ④：Subcore2へメッセージ（ランダム数値）送信
- ⑤：Subcore2からメッセージ受信
- ⑥：LED0点灯

### Subcore
```c++:Sub2.ino
#if (SUBCORE != 2)  // ⑦ 
#error "Core selection is wrong!!"
#endif

#include <MP.h>

void setup()
{
  int ret = 0;

  Serial.begin(115200);
  while (!Serial);

  ret = MP.begin();  // ⑧
  if (ret < 0) {
    printf("MP.begin error = %d\n", ret);
  }
}

void loop()
{
  int      ret;
  int8_t msgid;
  uint32_t msgdata;

  /* Echo back */

  ret = MP.Recv(&msgid, &msgdata);  // ⑨
  if (ret < 0) {
    printf("MP.Recv error = %d\n", ret);
  }

  delay(100);
  printf("SubCore2 Recv: id=%d data=0x%08x\n", msgid, msgdata);
  ledOn(LED2);  // ⑩
  delay(2000);
  ledOff(LED2);

  ret = MP.Send(msgid, msgdata);  // ⑪
  if (ret < 0) {
    printf("MP.Send error = %d\n", ret);
  }
}
```

- ⑦：Subcore2の指定（それ以外はエラー）
- ⑧；マルチコア起動
- ⑨：Maincoreからメッセージ受信
- ⑩：LED2点灯
- ⑪：Maincoreへメッセージ送信（ループバック）

## Build
Build時に対象となるCoreを指定する必要がある。間違えるとBuildエラーとなる。（ソースコードの①、⑦参照。）

### Maincore
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/741573ef-d3a5-cdcd-c3b2-9d63d3091612.png)

### Subcore2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/fe280123-786a-bb1a-7615-03d17dc18684.png)


## 実験
シリアルコンソール表示。
![Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/91955020-e5e3-26f2-f3be-87ff3021c925.png)

MaincoreのLED点灯。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/1e3b268e-f494-a3ca-cde3-3a08ac37d36c.png", width=60%>

Subcore2のLED点灯。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/d5f154b2-5e39-f892-303e-b26f59cbc421.png", width=60%>

成功。