2020年10月
2020年10月18日 02:02
状態によって再生する音楽を変更するとしたら、一番簡単なのは複数のプレイリストを持って切り替えるのが良いだろうということで、今日は複数のプレイリストを生成して、それを切り替えることができるか?を確認してみます。
もともとは、
と1つのインスタンスを生成しているところを
もともとは、
Playlist thePlaylist("TRACK_DB.CSV");
と1つのインスタンスを生成しているところを
Playlist thePlaylist0("TRACK_DB0.CSV");
Playlist thePlaylist1("TRACK_DB1.CSV");
Playlist thePlaylist2("TRACK_DB2.CSV");
Playlist* thePlaylist = &thePlaylist0;
というように3つのインスタンスを生成するようにし、
の中の
thePlaylist.
を
thePlaylist->
に変更。
の中の
thePlaylist.
を
というように3つのインスタンスを生成するようにし、
static void list()
static bool next()
static bool prev()
の中の
thePlaylist.
を
thePlaylist->
に変更。
void setup()
の中の
thePlaylist.
を
thePlaylist0.
thePlaylist1.
thePlaylist2.
の3つに、
例えば、initだったら、
を
success = thePlaylist0.init(playlist_dirname); success = thePlaylist1.init(playlist_dirname);
thePlaylist1.
thePlaylist2.
の3つに、
例えば、initだったら、
success = thePlaylist.init(playlist_dirname);
を
success = thePlaylist0.init(playlist_dirname);
success = thePlaylist2.init(playlist_dirname);
※エラーチェックはちゃんとやったほうがいい。苦笑。
のように、すべての初期化と設定は、3つのインスタンスに行う。
※presetの値を3つ持たせて、それぞれで設定したほうがいいだろうが今はしない。
void loop()
の中の
thePlaylist.
は、
thePlaylist->
に変更し、
switch/caseに、x/y/z でプレイリストを切り替えるコードを追加。
このコードをコンパイル&実行すると、x/y/z できりかえられるコードができた。
のように、すべての初期化と設定は、3つのインスタンスに行う。
※presetの値を3つ持たせて、それぞれで設定したほうがいいだろうが今はしない。
void loop()
の中の
thePlaylist.
は、
thePlaylist->
に変更し、
switch/caseに、x/y/z でプレイリストを切り替えるコードを追加。
case 'x': // change list
if (s_state == Active) {
stop();
s_state = Ready;
}
thePlaylist = &thePlaylist1;
break;
case 'y': // change list
if (s_state == Active) {
stop();
s_state = Ready;
}
thePlaylist = &thePlaylist2;
break;
case 'z': // change list
if (s_state == Active) {
stop();
s_state = Ready;
}
thePlaylist = &thePlaylist0;
break;
このコードをコンパイル&実行すると、x/y/z できりかえられるコードができた。
2020年10月16日 14:29
おいおい、ダイエットウォークマンどうなってんだよ~!
と言われそうだけど、ちょっと、気分を変えてサンプラーっぽいものを作ってみようかなと思い始めました。
というのも、Spresense のサンプルの中に、文字を打つとすぐに音を鳴らせるサンプルを発見したため。
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_%E4%BD%8E%E9%81%85%E5%BB%B6%E5%86%8D%E7%94%9F%E3%81%99%E3%82%8B
これを使うと、シリアル入力した文字に合わせて、遅延なく音を出せそうなので、
このシリアル入力を以前買ったキーパッド
https://www.switch-science.com/catalog/5535/
に置き換えるだけで、サンプラーっぽいものができるな~と思ったんです。
で、早速、
https://github.com/sonydevworld/spresense-arduino-compatible/tree/master/Arduino15/packages/SPRESENSE/hardware/spresense/1.0.0/libraries/Audio/examples/application/rendering_objif/rendering_objif.ino
を改変。
まず、キーパッドが使えるように、以下をinclude。
次に、setupの中の "Serial.begin(115200);"の後で、で、初期化を呼ぶ。
これで、簡単に、ボタンを押すと効果音が鳴るようになりました!
と言われそうだけど、ちょっと、気分を変えてサンプラーっぽいものを作ってみようかなと思い始めました。
というのも、Spresense のサンプルの中に、文字を打つとすぐに音を鳴らせるサンプルを発見したため。
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_%E4%BD%8E%E9%81%85%E5%BB%B6%E5%86%8D%E7%94%9F%E3%81%99%E3%82%8B
これを使うと、シリアル入力した文字に合わせて、遅延なく音を出せそうなので、
このシリアル入力を以前買ったキーパッド
https://www.switch-science.com/catalog/5535/
に置き換えるだけで、サンプラーっぽいものができるな~と思ったんです。
で、早速、
https://github.com/sonydevworld/spresense-arduino-compatible/tree/master/Arduino15/packages/SPRESENSE/hardware/spresense/1.0.0/libraries/Audio/examples/application/rendering_objif/rendering_objif.ino
を改変。
まず、キーパッドが使えるように、以下をinclude。
#include <Wire.h>
#include "SparkFun_Qwiic_Keypad_Arduino_Library.h"
KEYPAD keypad1; //Create instance of this object
次に、setupの中の "Serial.begin(115200);"の後で、で、初期化を呼ぶ。
if (keypad1.begin() == false) // Note, using begin() like this will use default I2C address, 0x4B.
// You can pass begin() a different address like so: keypad1.begin(Wire, 0x4A).
{
Serial.println("Keypad does not appear to be connected. Please check wiring. Freezing...");
while (1);
}
で、文字をscanしている部分を、キーパッド入力に変える。
で、文字をscanしている部分を、キーパッド入力に変える。
keypad1.updateFIFO(); // necessary for keypad to pull button from stack to readable register
char button = keypad1.getButton();
while (button == -1)
{
Serial.println("No keypad detected");
delay(1000);
}
if (button != 0)
{
switch (button) {
case '1': // play
playno = start_event(playno,0);
break;
case '2': // play
playno = start_event(playno,1);
break;
case '3': // play
playno = start_event(playno,2);
break;
case '#': // stop
if (s_state == Active)
{
stop();
}
s_state = Stopping;
break;
default:
break;
}
}
これで、簡単に、ボタンを押すと効果音が鳴るようになりました!
2020年10月10日 22:57
次に音楽再生部分を組み込みます。
折角なので、自分の聞きたい曲のリストを聞けるように、player_playlist.ino を組み込みます。
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_%E3%83%97%E3%83%AC%E3%82%A4%E3%83%AA%E3%82%B9%E3%83%88%E5%86%8D%E7%94%9F
ここは、地道にマージ。
同時に、Playlistと、聞きたい音楽ファイルをSDカードにそれぞれ、
折角なので、自分の聞きたい曲のリストを聞けるように、player_playlist.ino を組み込みます。
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_%E3%83%97%E3%83%AC%E3%82%A4%E3%83%AA%E3%82%B9%E3%83%88%E5%86%8D%E7%94%9F
ここは、地道にマージ。
同時に、Playlistと、聞きたい音楽ファイルをSDカードにそれぞれ、
AUDIO/ ディレクトリに、プレイリストで再生する音楽コンテンツファイルをコピーします。
PLAYLIST/ ディレクトリに、プレイリストファイル ( TRACK_DB.CSV ) をコピーします。
いよいよ、体重が前人未到の領域(自分の中で)に踏み込んできました。
やばいです。
なので、やろうやろうと思っててサボってた、ダイエット用ウォークマンを作ってみようかなと。
HWは、お得意(苦笑)のPDA01を使います。
※小さく音楽再生できるし、加速度がついているので!
https://p-art.net/pda01-2
まずは、StepCounterのサンプルを確認すると、BoschのBMI160ベースになっているので、
KX122に物理センサを変更します。
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_step_counter_%E3%81%AE%E7%89%A9%E7%90%86%E3%82%BB%E3%83%B3%E3%82%B5%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B
変更の仕方はドキュメントがあるので、わかりやすい!
簡単に、変更してStepCounterというより、走ってる、歩いてる、止まってるの行動認識ができた。
これで、行動認識部分はすんなりOK。
次は、音楽再生を組み込もう。
やばいです。
なので、やろうやろうと思っててサボってた、ダイエット用ウォークマンを作ってみようかなと。
HWは、お得意(苦笑)のPDA01を使います。
※小さく音楽再生できるし、加速度がついているので!
https://p-art.net/pda01-2
まずは、StepCounterのサンプルを確認すると、BoschのBMI160ベースになっているので、
KX122に物理センサを変更します。
https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_step_counter_%E3%81%AE%E7%89%A9%E7%90%86%E3%82%BB%E3%83%B3%E3%82%B5%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B
変更の仕方はドキュメントがあるので、わかりやすい!
簡単に、変更してStepCounterというより、走ってる、歩いてる、止まってるの行動認識ができた。
これで、行動認識部分はすんなりOK。
次は、音楽再生を組み込もう。
2020年10月07日 23:53
GPIOの叩き方が分かったと同時に、アドレス空間を見る限り、どのコアでも同一にIOを制御できそうだということが分かったので、実際に、SubCoreでたたいてみることにします。
マルチコアのサンプルをベースにするために、
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を叩くとLEDが点灯するコードをSubCoreに書いて実行できればOKです。
まず、pinのConfigrationをMainCoreで行います。
examples/asmp/asmp_main.c ※Master側のMain Loop
に、pin制御をするためのincludeをします。
#include <arch/board/board.h>
#include <arch/chip/pins.h>
また、
の中の 310行目
の前に、inputとoutputのpinを設定します。
今回は、inputをPIN_PWM3、outputをPIN_I2S1_LRCKとしたので、
を追加します。
これで、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側で、inputされたら、直ちにoutputするコードを書きます。
examples/asmp/worker/hello/hello.c ※SubCore側のMain Loop
このファイルの
int main(void)
レジスタ定義を追記します。
※諸々includeパスが通ってない場所なので、定義を書いてしまっています。
これで、Mapped IO のレジスタアドレスが定義できたので、
の先頭に、
volatile uint32_t* iadr = (uint32_t*)CXD56_TOPREG_GP_PWM3;
実際に、これらGPIOアクセスのHWドライバ層ををworker側から
呼べるようにしようと思ったのですが、きれいに構成をし直す必要があるので諦めました。
誰かやってくれる勇者はいないかなあ…。
マルチコアのサンプルをベースにするために、
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を叩くとLEDが点灯するコードをSubCoreに書いて実行できればOKです。
まず、pinのConfigrationをMainCoreで行います。
examples/asmp/asmp_main.c ※Master側のMain Loop
に、pin制御をするためのincludeをします。
#include <arch/board/board.h>
#include <arch/chip/pins.h>
また、
int main(int argc, FAR char *argv[])
の中の 310行目
(void) run_worker(fullpath);
今回は、inputをPIN_PWM3、outputをPIN_I2S1_LRCKとしたので、
board_gpio_config(PIN_PWM3, 0, true, false, PIN_PULLUP);
board_gpio_config(PIN_I2S1_LRCK, 0, false, false, PIN_FLOAT);
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側で、inputされたら、直ちにoutputするコードを書きます。
examples/asmp/worker/hello/hello.c ※SubCore側のMain Loop
このファイルの
int main(void)
の前に、
レジスタ定義を追記します。
#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 のレジスタアドレスが定義できたので、
int main(void)
の先頭に、
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が点灯を点灯させるコードになりました。if( (*iadr & 0x01) == 0){
break;
}
}
*oadr = 0x100;
while(1); /* exit代わり */
実際に、これらGPIOアクセスのHWドライバ層ををworker側から
呼べるようにしようと思ったのですが、きれいに構成をし直す必要があるので諦めました。
誰かやってくれる勇者はいないかなあ…。
昨日の続きが、また、夜中になってしまった。orz
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
の
regaddr と regvalとが、レジスタアドレスと生値になります。
ここから、GPIO(SPR_PWM3/SPR_I2S1_LRCK)アクセスは、
spresense/nuttx/arch/arm/src/cxd56xx/hardware/cxd5602_topreg.h
にある、
#define CXD56_TOPREG_GP_PWM3 (CXD56_TOPREG_BASE + 0x20c0)
#define CXD56_TOPREG_GP_I2S1_LRCK (CXD56_TOPREG_BASE + 0x216c)
だとわかります。
読み出すときは、最下位ビットを、書き込むときは、下位から9ビット目を叩くことがわかりました。
[補足]
と、実は、レジマップを発見!
こっちのページのここに載っていました。
https://sony-semicon.co.jp/products/smart-sensing/spresense/assets/images/CXD5602_user_manual.pdf
こちらの P89 を見ても、上記の認識があってたことがわかります。
スタート遅れたので、今日もここまで。
2020年10月06日 04:45
ず~っと、サボってたのですが、久しぶりに記事書きます…。
とある事情で、MainCoreの処理を邪魔したくなかった上に、ある信号線が立ち上がったら、8us以内にある信号線を落とさなければいけなかったので、SubCoreでのGPIO制御をどうしてもしたくなりました。
そこで、サンプル使ってSubCoreでのGPIOアクセスに関して実験しました。
examples/asmp
を使います。
ボードは簡単に試すために、手持ちのPDA01を使って実験しました。
※スイッチが付いていたので…。
https://p-art.net/pda01-2
こちらの回路図を見ると、
https://p-art.net/wp/wp-content/uploads/2019/06/PDA01_kairozu.pdf
スイッチ5番が SPR_PWM3 につながっているので、これを押したら、
LED が付くコードをSubCoreに実装して動作することを確認します。
LEDは、
https://github.com/sonydevworld/spresense-hw-design-files/raw/master/CXD5602PWBMAIN1/schematics/CXD5602PWBMAIN1_schematics.pdf
を見ると、
SPR_I2S1_LRCK
につながっているので、取り急ぎ、これを叩くことにします。
ただし、Spresense内部のレジスタマップが見つからなかったので、コードを読み解くことにしました。
眠いので、今日はここまで…。
つづく。
とある事情で、MainCoreの処理を邪魔したくなかった上に、ある信号線が立ち上がったら、8us以内にある信号線を落とさなければいけなかったので、SubCoreでのGPIO制御をどうしてもしたくなりました。
そこで、サンプル使ってSubCoreでのGPIOアクセスに関して実験しました。
examples/asmp
を使います。
ボードは簡単に試すために、手持ちのPDA01を使って実験しました。
※スイッチが付いていたので…。
https://p-art.net/pda01-2
こちらの回路図を見ると、
https://p-art.net/wp/wp-content/uploads/2019/06/PDA01_kairozu.pdf
スイッチ5番が SPR_PWM3 につながっているので、これを押したら、
LED が付くコードをSubCoreに実装して動作することを確認します。
LEDは、
https://github.com/sonydevworld/spresense-hw-design-files/raw/master/CXD5602PWBMAIN1/schematics/CXD5602PWBMAIN1_schematics.pdf
を見ると、
SPR_I2S1_LRCK
につながっているので、取り急ぎ、これを叩くことにします。
ただし、Spresense内部のレジスタマップが見つからなかったので、コードを読み解くことにしました。
眠いので、今日はここまで…。
つづく。