SubCoreでGPIOを制御する@SDK

#今回用意したもの

[**SPRESENSEメインボード[CXD5602PWBMAIN1]**
https://www.switch-science.com/catalog/3900/](https://www.switch-science.com/catalog/3900/)
<img src="https://d2air1d4eqhwg2.cloudfront.net/images/3900/500x500/42ccd153-3e89-4f7c-921c-775bc7de996d.jpg" width="200">

[**B-stem PDA01 SPRESENSE用機能拡張ボード**
https://www.switch-science.com/catalog/5687/](https://www.switch-science.com/catalog/3900/)
<img src="https://d2air1d4eqhwg2.cloudfront.net/images/5687/500x500/0a013974-3601-4d76-9228-a4bbbde7b45b.jpeg" width="300">

今回は、単純にスイッチが欲しかっただけで、何でも良かったんだけど、
この基板は、スイッチが付いていたので、これを使いました。

#ブログ（元ネタ）
この記事は、以下のブログに過去に投稿したもののまとめです。

[SubCoreでGPIOを制御する@SDK　その1
http://spresense.livedoor.blog/archives/24401112.html](http://spresense.livedoor.blog/archives/24401112.html)


[SubCoreでGPIOを制御する@SDK　その2
http://spresense.livedoor.blog/archives/24409556.html](
http://spresense.livedoor.blog/archives/24409556.html)


[SubCoreでGPIOを制御する@SDK　その3
http://spresense.livedoor.blog/archives/24417303.html](
http://spresense.livedoor.blog/archives/24417303.html)

#はじめに

他のアプリケーションを実行している中、ある信号線が立ち上がったら、8us以内にある信号線を落とさなければいけなかったので、SubCoreでのGPIO制御をしてみることにしました。

SubCore側のコードで、スイッチの押下を検知し、LEDを点灯させることポーリングで行えば、
8us以内にGPIOのINからOUTへの反応が可能になります。

#サンプルプログラム
SubCoreを使うということで、Spresense SDKの中のサンプル

[**examples/asmp**](https://github.com/sonydevworld/spresense/tree/master/examples/asmp)

をいじって、スイッチの検知&LED点灯を行います。

#スイッチのGPIO
**PDA01**の回路図を見ると、
https://p-art.net/wp2/wp-content/uploads/2019/11/PDA01_kairozu.pdf


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526253/eb87bbe0-7435-cc62-0df0-68c7c4c13db5.png)

スイッチ5番が SPR_PWM3 につながっています。

ちなみに、Spresenseの拡張ボードのGPIOをみてみると
https://developer.sony.com/develop/spresense/docs/introduction_ja.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526253/e2c541ec-fe1d-a2e8-8667-9fea97851549.png)

**D03**につながっていることがわかります。

#LEDのGPIO

worker側にはLEDのユーティリティーもないので、LEDとGPIOの関係から調査します。
**Spresense** の **Mainボードの回路図** を見ると、
https://github.com/sonydevworld/spresense-hw-design-files/raw/master/CXD5602PWBMAIN1/schematics/CXD5602PWBMAIN1_schematics.pdf

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526253/bca961be-9f55-afcc-d463-97e109eda26b.png)

どれでも良かったんですが、

**SPR_I2S1_LRCK**

につながっているので、取り急ぎ、これを叩くことにします。

#GPIOの叩き方
現時点で、workerからGPIOを叩くユーティリティーもないので、ここは、コードを読み解いて実装します。

GPIOの制御は、
https://developer.sony.com/develop/spresense/docs/sdk_tutorials_ja.html#_system_gpiotool

こちらを読むとわかります。

**board_gpio_config**
で、pinの設定をして、

**board_gpio_read**
**board_gpio_write**
で、RWします。

MainCoreでの普通の使い方は、チュートリアルでわかります。

今回はこの中身を見て、レジスタアクセスの仕方を調べます。

spresense/nuttx/arch/arm/src/cxd56xx/cxd56_gpioif.c

の中を見ていくと、

**cxd56_gpio_write** と **cxd56_gpio_read**

によって、Read/Write がされており、その中の

**regaddr** と **regval** とが、レジスタアドレスと生値だとわかります。

#WokerでのGPIOの叩き方
workerでは、アドレスに直接アクセスするしかないので、
**SPR_PWM3** と **SPR_I2S1_LRCK** へのアドレスが必要です。

spresense/nuttx/arch/arm/src/cxd56xx/hardware/cxd5602_topreg.h

をみると、

```c:cxd5602_topreg.h
#define CXD56_TOPREG_GP_PWM3                    (CXD56_TOPREG_BASE + 0x20c0)
#define CXD56_TOPREG_GP_I2S1_LRCK               (CXD56_TOPREG_BASE + 0x216c)
```

だとわかります。

またこのレジスタの叩き方は、下記のLSIのユーザマニュアルに書いてあります。
https://sony-semicon.co.jp/products/smart-sensing/spresense/assets/images/CXD5602_user_manual.pdf

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526253/fb5352ba-e349-54dc-f936-e544770b23c4.png)

読み出すときは、**最下位ビット** を、書き込むときは、**下位から9ビット目** を叩くことがわかりました。

GPIOの叩き方が分かったと同時に、アドレス空間を見る限り、どのコアでも同一にIOを制御できそうだということが分かったので、SubCoreでの制御が可能だと言ことがわかります。

#MainCoreプログラム

上記で書いたように

[**examples/asmp**](https://github.com/sonydevworld/spresense/tree/master/examples/asmp)

を使って確認します。このサンプルは、特にチュートリアルはないようなので、
Readmeを参考に動作させてみます。
https://github.com/sonydevworld/spresense/tree/master/examples/asmp/


このサンプルの詳しい説明は、今回の目的から外れるのでしないのですが、

***> ./tools/config.py examples/asmp***

でconfigでbuildすると、SubCoreのバイナリも**Romdisk**になって読み込めます。
その後、ロードして実行すると、MultiCore間で、
message queue、mutexのテストをして終了するサンプルです。

今回、これらの通信テストをせずに、**スイッチ5**を叩くと**LED2**が点灯するコードをSubCoreに書いて実行できればOKです。


まず、**pin**の**Configration**を**MainCore**で行います。

[examples/asmp/asmp_main.c](https://github.com/sonydevworld/spresense/blob/master/examples/asmp/asmp_main.c) ※Master側のMain Loop

に、**pin制御**をするための**include**をします。

```c:asmp_main.c
#include <arch/board/board.h>
#include <arch/chip/pins.h>
```

また、

```c:asmp_main.c
int main(int argc, FAR char *argv[])
```

の中の 310行目

```c:asmp_main.c
  (void) run_worker(fullpath);
```

の前に、inputとoutputのpinを設定します。
今回は、inputをPIN_PWM3、outputをPIN_I2S1_LRCKとしたので、

```c:asmp_main.c
  board_gpio_config(PIN_PWM3, 0, true, false, PIN_PULLUP);
  board_gpio_config(PIN_I2S1_LRCK, 0, false, false, PIN_FLOAT);

  (void) run_worker(fullpath);
```

を追加します。
これで、**pin**の**config**ができました。

※PDA01のスイッチは、開放が1、押下が0なので、pullupにしています。

※こちらを参考にしました。
https://developer.sony.com/develop/spresense/docs/sdk_tutorials_ja.html#_%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0

#SubCoreプログラム

次にSubCore側で、inputされたら、直ちにoutputするコードを書きます。

[examples/asmp/worker/hello/hello.c](https://github.com/sonydevworld/spresense/blob/master/examples/asmp/worker/hello/hello.c) ※SubCore側のMain Loop

このファイルの

```c:hello.c
int main(void)
```
の前に、

レジスタ定義を追記します。

```c:hello.c
#define CXD56_SYS_MIRROR                   0x04000000
#define CXD56_TOPREG_BASE                  (CXD56_SYS_MIRROR + 0x00100000)
#define CXD56_TOPREG_GP_PWM3               (CXD56_TOPREG_BASE + 0x20c0)
#define CXD56_TOPREG_GP_I2S1_LRCK          (CXD56_TOPREG_BASE + 0x216c)
```

※諸々includeパスが通ってない場所なので、定義を直接書いてしまっています。

これで、Mapped IO のレジスタアドレスが定義できたので、

```c:hello.c
int main(void)
```

の先頭に、

```c:hello.c
  volatile uint32_t* iadr = (uint32_t*)CXD56_TOPREG_GP_PWM3;
  volatile uint32_t* oadr = (uint32_t*)CXD56_TOPREG_GP_I2S1_LRCK;

  while(1){
    if( (*iadr & 0x01) == 0){
      break;
    }
  }
  *oadr = 0x100; 
  while(1);  /* exit代わり */
```
を記述することで、SubCore側で、スイッチ5の検出をするとLEDが点灯を点灯させるコードになりました。

#動作結果
動かすとこんな感じになります。オシロで見ても8us以内に反応できています！
※動画無くしちゃった…。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526253/f6f102dc-e86f-1e13-7216-a185a19d4766.png)