RaspberryPiPicoにmruby/cでプログラムする（Lチカ）

まだタイマーは実装できていない…
# 準備したもの
RaspberryPiPico
windows10のPC
USB-microUSBケーブル

# 開発環境の構築
[公式のドキュメント](https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf)を参照
私はwindowsだったので「9.2.Building on MS Windows」を参考にした。
・ARM GCC compiler
・CMake
・Build Tools for Visual Studio 2019
・Python 3.7
・Git
をインストールすればいいらしい。
特に問題は無いはずだが私がつまずいた点だけあげておく。

1. Visual Studio 2019のインストール時、チェックボックスが公式ドキュメントと異なる。<br>
日本語ですから…とりあえず↓のようにしておいた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195542/338badd1-d042-15bb-816c-ccd7c0bea3c4.png)
2. Gitのインストール時にvim以外を指定するようにドキュメントに書いてある。<br>
ドキュメント曰くNotepad++にするようにと画像で示されているが、Notepad++をインストールしていなかったのでインストールした。
3. [9.2.3. Building "Hello World" from the Command Line]にて<br>
Windows > Visual Studio2019 > Developer Command Prompを開くように言われているのに無視してそのままcmd.exeで作業していました。
気を付けましょう。cmakeとnmakeができないと思います。

# mruby/cを導入
[mruby/c](https://github.com/mrubyc/mrubyc)と[mrbc](https://www.s-itoc.jp/files/original/201904181318159501cbec95e.zip)をダウンロードします。(コマンドを使用しないでcode > DownlodeZipでコードを持ってくる男)
　→ それぞれ解凍しておく。
mruby/cのzipファイルを解凍すると中にsrcフォルダがあると思うので、そのsrcフォルダを`pico-examples/blink`へそのまま入れます。
ちなみに今回は`pico-examples/blink`を改造して使っていきます。
`pico-examples/blink`内にあるCMakeLists.txtを編集しなきゃならないですが、cmakeなんてはじめて触るので雑ですが↓のように編集しました。

```CMakeLists.txt
add_compile_options(-D MRBC_NO_TIMER)

add_executable(blink
	blink.c
	src/alloc.c
	src/c_array.c
	src/c_hash.c
	src/c_math.c
	src/c_numeric.c
	src/c_range.c
	src/c_string.c
	src/class.c
	src/console.c
	src/error.c
	src/global.c
	src/keyvalue.c
	src/load.c
	src/mrblib.c
	src/rrt0.c
	src/static.c
	src/symbol.c
	src/value.c
	src/vm.c
        )

# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(blink pico_stdlib)

# create map/bin/hex file etc.
pico_add_extra_outputs(blink)

# add url via pico_set_program_url
example_auto_set_url(blink)
```

`pico-examples/blink/src/vm_config.h`84行目にあるコメントアウトを外します。

```vm_config.h
/* 32it alignment
   If 32-bit alignment is required, enable the following line.
 */
#define MRBC_REQUIRE_32BIT_ALIGNMENT
```

`pico-examples/blink/src`内にある`hal_psoc5lp`フォルダを`hal`へリネームします。
そのhalフォルダにある`hal.h`を↓のように編集します。

```hal.h
#ifndef MRBC_SRC_HAL_H_
#define MRBC_SRC_HAL_H_

#ifdef __cplusplus
extern "C" {
#endif

/***** Feature test switches ************************************************/
/***** System headers *******************************************************/
#include "pico/stdlib.h"


/***** Local headers ********************************************************/
/***** Constant values ******************************************************/
/***** Macros ***************************************************************/
#if !defined(MRBC_TICK_UNIT)
#define MRBC_TICK_UNIT_1_MS   1
#define MRBC_TICK_UNIT_2_MS   2
#define MRBC_TICK_UNIT_4_MS   4
#define MRBC_TICK_UNIT_10_MS 10
// You may be able to reduce power consumption if you configure
// MRBC_TICK_UNIT_2_MS or larger.
#define MRBC_TICK_UNIT MRBC_TICK_UNIT_1_MS
// Substantial timeslice value (millisecond) will be
// MRBC_TICK_UNIT * MRBC_TIMESLICE_TICK_COUNT (+ Jitter).
// MRBC_TIMESLICE_TICK_COUNT must be natural number
// (recommended value is from 1 to 10).
#define MRBC_TIMESLICE_TICK_COUNT 10
#endif

#ifndef MRBC_NO_TIMER
# define hal_init()        ((void)0)
# define hal_enable_irq()  ((void)0)
# define hal_disable_irq() ((void)0)
# define hal_idle_cpu()    (sleep_ms(1), mrbc_tick())
#else // MRBC_NO_TIMER
# define hal_init()        ((void)0)
# define hal_enable_irq()  ((void)0)
# define hal_disable_irq() ((void)0)
# define hal_idle_cpu()    (sleep_ms(1), mrbc_tick())

#endif

/***** Typedefs *************************************************************/
/***** Global variables *****************************************************/
/***** Function prototypes **************************************************/
int hal_write(int fd, const void *buf, int nbytes);
int hal_flush(int fd);


/***** Inline functions *****************************************************/


#ifdef __cplusplus
}
#endif
#endif // ifndef MRBC_HAL_H_
```

(タイマーの実装はできてないので同じ内容をダミーとして入れておきました)


今回使用するRubyのプログラムを用意します。
保存場所はコンパイラのフォルダ内がいいと思います。`201904181318159501cbec95e/mruby-2.0.1-win`の下
Lチカしたいので、それらしいプログラムを書いておきます。
led1_writeによってオンボードLEDを制御することにします。
第一引数が1の時LEDがON、0の時OFFとなる予定です。
while文の無限ループ内にsleepも含めてプログラムします。１秒間隔でLEDが点滅する。

```sample1.rb
while true
    led1_write(1)
    sleep(1)
    led1_write(0)
    sleep(1)
end
```

sample1.rbを書き終えたらコマンドラインで`201904181318159501cbec95e/mruby-2.0.1-win`まで移動しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195542/ec33d0ea-061e-0b76-80e8-56134fb850c5.png)

移動したらコマンドを打ちます`mrbc.exe -E -Bsample1 sample1.rb`
すると同じフォルダ内にsample1.cができると思います。↓　sample1[]の中身をコピーしておきましょう。

```sample1.c
/* dumped in big endian order.
   use `mrbc -e` option for better performance on little endian CPU. */
#include <stdint.h>
extern const uint8_t sample1[];
const uint8_t
#if defined __GNUC__
__attribute__((aligned(4)))
#elif defined _MSC_VER
__declspec(align(4))
#endif
sample1[] = {
0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x36,0xd1,0x25,0x00,0x00,0x00,0x83,0x4d,0x41,
0x54,0x5a,0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0x65,0x30,0x30,
0x30,0x32,0x00,0x00,0x00,0xe7,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x2e,
0x21,0x00,0x23,0x10,0x01,0x07,0x02,0x2e,0x01,0x00,0x01,0x10,0x01,0x07,0x02,0x2e,
0x01,0x01,0x01,0x10,0x01,0x06,0x02,0x2e,0x01,0x00,0x01,0x10,0x01,0x07,0x02,0x2e,
0x01,0x01,0x01,0x11,0x01,0x22,0x01,0x00,0x03,0x0f,0x01,0x37,0x01,0x67,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x0a,0x6c,0x65,0x64,0x31,0x5f,0x77,0x72,0x69,
0x74,0x65,0x00,0x00,0x05,0x73,0x6c,0x65,0x65,0x70,0x00,0x45,0x4e,0x44,0x00,0x00,
0x00,0x00,0x08,
};
```

続いて`pico-examples/blink/blink.c`を編集していきます。
led1_writeという関数をRubyのプログラムで使えるように追加しておきます。
sample1[]には先ほどRubyプログラムをコンパイルしてできた配列を入れます。

```blink.c
#include "pico/stdlib.h"
#include "src/mrubyc.h"
#define MEMORY_SIZE (1024*20)

uint8_t sample1[] = {
0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x36,0xd1,0x25,0x00,0x00,0x00,0x83,0x4d,0x41,
0x54,0x5a,0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0x65,0x30,0x30,
0x30,0x32,0x00,0x00,0x00,0xe7,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x2e,
0x21,0x00,0x23,0x10,0x01,0x07,0x02,0x2e,0x01,0x00,0x01,0x10,0x01,0x07,0x02,0x2e,
0x01,0x01,0x01,0x10,0x01,0x06,0x02,0x2e,0x01,0x00,0x01,0x10,0x01,0x07,0x02,0x2e,
0x01,0x01,0x01,0x11,0x01,0x22,0x01,0x00,0x03,0x0f,0x01,0x37,0x01,0x67,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x0a,0x6c,0x65,0x64,0x31,0x5f,0x77,0x72,0x69,
0x74,0x65,0x00,0x00,0x05,0x73,0x6c,0x65,0x65,0x70,0x00,0x45,0x4e,0x44,0x00,0x00,
0x00,0x00,0x08,
};
static uint8_t memory_pool[MEMORY_SIZE];

static void c_led1_write(mrb_vm *vm, mrb_value *v, int argc) {
    int set_value = GET_INT_ARG(1);
    gpio_put(25,set_value);
}

int hal_write(int fd, const void *buf, int nbytes) {
    return 0;
}
int hal_flush(int fd) {
    return 0;
}

int main() {
    gpio_init(25);
    gpio_set_dir(25, GPIO_OUT);
    mrbc_init(memory_pool, MEMORY_SIZE);
    mrbc_define_method(0, mrbc_class_object, "led1_write", c_led1_write);
    mrbc_create_task(sample1, 0);
    mrbc_run();
    return 1;
}
```

# プログラムの書き込み
`Developer Command Promp`を使って`pico-examples/build`へ移動します。
`nmake`コマンドを実行。↓のようにビルドがはじまります。

```
Scanning dependencies of target blink
[  0%] Building C object blink/CMakeFiles/blink.dir/blink.c.obj
[  0%] Building C object blink/CMakeFiles/blink.dir/src/alloc.c.obj
[  0%] Building C object blink/CMakeFiles/blink.dir/src/c_array.c.obj
[  0%] Building C object blink/CMakeFiles/blink.dir/src/c_hash.c.obj
[  0%] Building C object blink/CMakeFiles/blink.dir/src/c_math.c.obj
[  0%] Building C object blink/CMakeFiles/blink.dir/src/c_numeric.c.obj
............
```

エクスプローラーで`pico-examples/build/blink`を開きます↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195542/e05182c8-253e-4a5f-fb84-c83d7e854fd5.png)
ラズパイpicoをパソコンへ接続します。
すると勝手にエクスプローラが起動します。(一度書き込んだ後はBOOTSELボタンを押しながらパソコンへ接続)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195542/e7747661-d8e0-34fe-3682-47dc59cb9ceb.png)
`pico-examples/build/blink`にある`blink.uf2`をラズパイpicoのディレクトリにドラッグアンドドロップすれば書き込み完了です。
Lチカが始まります。
動画：<a href="https://t.co/D87VRTHXlr">pic.twitter.com/D87VRTHXlr</a>

# まとめ(感想)
環境構築だけで数時間かかった(´;ω;｀)こんなに手のかかったマイコンははじめてです。
現在はタイマーやスリープを実装したいのでドキュメントとにらめっこしています(*´Д｀)
スリープのサンプルはあった。
https://github.com/raspberrypi/pico-playground