5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

spresenseAdvent Calendar 2021

Day 6

SubCoreでGPIOを制御する@SDK

Last updated at Posted at 2021-12-07

#今回用意したもの

SPRESENSEメインボード[CXD5602PWBMAIN1]
https://www.switch-science.com/catalog/3900/

B-stem PDA01 SPRESENSE用機能拡張ボード
https://www.switch-science.com/catalog/5687/

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

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

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

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

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

#はじめに

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

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

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

examples/asmp

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

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

image.png

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

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

image.png

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

#LEDのGPIO

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

image.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_writecxd56_gpio_read

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

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

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

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

をみると、

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

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

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

#MainCoreプログラム

上記で書いたように

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です。

まず、pinConfigrationMainCoreで行います。

examples/asmp/asmp_main.c ※Master側のMain Loop

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

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

また、

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

の中の 310行目

asmp_main.c
  (void) run_worker(fullpath);

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

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);

を追加します。
これで、pinconfigができました。

※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 ※SubCore側のMain Loop

このファイルの

hello.c
int main(void)

の前に、

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

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 のレジスタアドレスが定義できたので、

hello.c
int main(void)

の先頭に、

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

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?