SPRESENSEでthreadを使ってみる


###SPRESENSE購入しました！
ARMのコアを6つも搭載しているということで、折角ならコア数を活かしたいと思い、SPRESENSE SDKを使って開発しています。

今回はマルチスレッドを試してみました。
この記事を見るだけで、プロジェクト作成、ソースコード作成、書き込み、実行までの一連の流れを追えるようになっています。

この記事では、

- pthreadの使い方
- Spresenseに搭載している4つのLEDの点滅

を説明しています。

## 前提

- SPRESENSE SDK `tag v1.1.1`
- [Spresense SDKの使い方](https://developer.sony.com/ja/develop/spresense/developer-tools/get-started-using-nuttx/set-up-the-nuttx-environment#_spresense_sdk_%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E6%A7%8B%E7%AF%89) の`1.5. シリアルターミナル上での動作確認`まで動作確認しています。



## プロジェクト作成
### フォルダ作成
sdkフォルダ内で下記コマンドを実行します。

```terminal
$ tools/mkappsdir.py test
```

`spresense`フォルダに`test`というフォルダが作成されます。

次に、アプリを追加します。sdkフォルダで以下を実行します。

```terminal
$ tools/mkcmd.py -d test test_app "My test application"
```

testフォルダ以下にtest_appフォルダが作られます。
その中の`test_app_main.c`を修正していきますが、まずはこのままspresenseに書き込んでみます。

### Build
```terminal 
$ make clean
$ tools/config.py -k release
$ tools/config.py -m
```

`test`を選択し、` [] My test application.`で`Y`を押し、登録する。


```terminal
$ make buildkernel
$ make
```

登録した`test_app`がビルドされます。

```terminal
(略)
$ make[1]: Entering directory '(SPRESENSE_PATH)/spresense/test'
$ make[2]: Entering directory '(SPRESENSE_PATH)/spresense/test/test_app'
$ Register: test_app
$ make[2]: Leaving directory '(SPRESENSE_PATH)/spresense/test/test_app'
$ make[1]: Leaving directory '(SPRESENSE_PATH)/spresense/test'
(略)
```
※(SPRESENSE_PATH)はSpresenseSDKをcloneしたフォルダ

### 書き込み

```
$ tools/flash.sh nuttx.spk
```

プロジェクト作成から書き込みまでの一連の流れを実行しました。
次は肝心のプログラムです。

## スレッドを使ってみる
今回作るプログラムは、

- スレッドA: 1秒ごとにLED0を点滅
- スレッドB: 2秒ごとにLED1を点滅

を実装します。なお、SPRESENSEにはLEDが4個搭載されています。

```test_app_main.c

#include <sdk/config.h>
#include <stdio.h>
#include <arch/board/board.h>
#include <arch/chip/pin.h>

#define PIN_LED0  PIN_I2S1_BCK
#define PIN_LED1  PIN_I2S1_LRCK
#define PIN_LED2  PIN_I2S1_DATA_IN
#define PIN_LED3  PIN_I2S1_DATA_OUT

const int led_pin[4] = {
  PIN_LED0,
  PIN_LED1,
  PIN_LED2,
  PIN_LED3
};

void toggle_led(uint32_t pin){
  board_gpio_write(pin, board_gpio_read(pin) == 0 ? 1 : 0);
}

void* task_A(void *arg)
{
  for(int i = 0; i < 10; i++)
  {
    toggle_led(led_pin[0]);
    sleep(1);
  }
  return NULL;
}


void* task_B(void *arg)
{
  for(int i = 0; i < 10; i++)
  {
    toggle_led(led_pin[1]);
    sleep(2);
  }
  return NULL;
}

#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int test_app_main(int argc, char *argv[])
#endif
{
  printf("thread test.\n");
  for(int i = 0; i < 4; i++){
    board_gpio_config(led_pin[i], 0, true, true, PIN_FLOAT); // GPIOの設定
  }
  pthread_t thread_A, thread_B;
  
  pthread_create(&thread_A, NULL, task_A, NULL);
  pthread_create(&thread_B, NULL, task_B, NULL);

  pthread_join(thread_A, NULL);
  pthread_join(thread_B, NULL);
  
  return 0;
}

```
nuttxではPOSIX環境で使われた関数がそのまま使えるため、`POSIX thread`などで調べるとたくさん使用例が出てきます！


`board_gpio_write`などのGPIOに関する関数は、
[Spresense SDK Library Documentation](https://developer.sony.com/develop/spresense/developer-tools/api-reference/api-references-spresense-sdk/)
の右上の検索に`gpio`と入力すると使い方を調べられます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/322966/103c1452-652f-f012-6b86-b56276064e78.png)

LEDのピン名は、
[Spresense SDK 開発ガイド 11.2.3. Pin specification](https://developer.sony.com/ja/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_pin_list)
のリストに定義の記述があります。
あるいは、上記ページにも書かれていますが、`(SPRESENSE_PATH)/spresense/sdk/bsp/include/arch/chip/pin.h`に定義されています。

> Pin Name: sdk/bsp/include/arch/chip/pin.h に、PIN_XXX という形式で定義されています



## 実行
`sdk`フォルダで

```terminal
$ make
$ tools/flash.sh nuttx.spk
$ minicom
```

```terminal
$ minicom -s
```
で、minicomのポート名を`/dev/ttyUSB0`(Spresenseが接続されているポート名)、ボーレートを115200にしておくと、`minicom`と入力するだけで接続できます。

NuttShellが起動したら、

```
test_app
```
と入力すると、プログラムが再生されます。

- LED0:1 → 0 → 1 → 0 → 1 → 0 →・・・
- LED1:1 → 1 → 0 → 0 → 1 → 1 →・・・

のように1秒ずつ点滅すればOK！

[次回](https://qiita.com/fururu/items/c5499c1fa1559044488f)はセマフォについてまとめます。