最強の１００円マイコンＲ８Ｃ／Ｍ１２Ａ、Ｍ１１Ａ

![M12A11A.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/d0b813f4-9fb6-6359-998a-f7a98223d9a3.jpeg)

## 何故最強と言えるのか？

１００円で買える史上最強のマイコンと言えば↑コレです。

でもー、ＲＯＭが２キロバイト、ＲＡＭが２５６バイトではなぁー・・・

とお嘆きの方々、コッソリ秘密を教えますｗ

カタログスペックでは、ＲＯＭサイズ２Ｋバイト、ＲＡＭサイズ２５６バイトとなっていますが、実際は・・

**ＲＯＭサイズ６４Ｋバイト、ＲＡＭサイズ１３６６バイトが存在し、実際に使えます。**

これだけのスペックなら、何か小物を作る際には、ほとんど困る事も無く、パッケージがＤＩＰなのもあって、気軽に利用できます。
製造中止品なので、在庫が無くなればそれでお終いですが、この事実があまり公になっていないのと、Arduino のような環境でプログラム出来ないので、イマイチ人気が無く、入手性も問題無いようです。

内蔵のペリフェラルもそこそこ充実していて、主な特徴をあげると・・

- 2.7V ～ 5.5V の電源電圧で動作
- 最大 20MHz 動作
- オンチップオシレータ
- 1K バイト x2 のデータフラッシュ
- ６チャネル１０ビット A/D コンバーター内蔵（サンプルホールドあり）
- ２チャネルのコンパレーター
- ３チャネルのタイマー（RJ2、RB2、RC）
- UART（シリアルインターフェース）

これだけあれば応用次第で、かなり色々なアプリケーションにマッチします。

※I2C のインターフェースがありませんが、ソフトウェアー I2C ドライバーを使う事で、I2C デバイスを扱う事が出来ます。

## 開発環境

この R8C は、M32C のサブセット版で、gcc/M32C で開発が可能です。
※C++14 での実装を行っているので、ルネサス純正 C/C++ コンパイラではコンパイル出来ません。

今回、専用の C++ フレームワークを公開して、C++ でプログラミングが出来るようにしています。

また、ルネサス社純正のプログラマー（Renesas Flash Programmer Vx）では、カタログスペックを超えてプログラムを書き込む事が出来ない為、専用のプログラミングツールも公開しています。

詳しくは、GitHub のリンクを参照して下さい。

https://github.com/hirakuni45/R8C

## プログラムの書き込み方法

R8C/Mxx シリーズは、シリアルインターフェースを使ってプログラムを書き込む事が出来ます。

詳細は、github を参照して下さい。

安価な、USBシリアルなどを使って、簡単に書き込む事が出来ます。

マルチプラットホーム対応の R8C/Mxx フラッシュプログラマー r8c_prog を公開しています。

```
Uranus-W10./d/Git/R8C/PLUSE_INP_sample % r8c_prog
Renesas R8C Series Programmer Version 0.82b
Copyright (C) 2015, Hiramatsu Kunihito (hira@rvf-rc45.net)
usage:
r8c_prog[options] [mot file] ...

Options :
-d, --device=DEVICE             Specify device name
-e, --erase                     Perform a device erase to a minimum
    --erase-all, --erase-chip   Perform rom and data flash erase
    --erase-rom                 Perform rom flash erase
    --erase-data                Perform data flash erase
-i, --id=xx:xx:xx:xx:xx:xx:xx   Specify protect ID
-P, --port=PORT                 Specify serial port
-a, --area=ORG,END              Specify read area
-r, --read                      Perform data read
-s, --speed=SPEED               Specify serial speed
-v, --verify                    Perform data verify
    --device-list               Display device list
-V, --verbose                   Verbose output
-w, --write                     Perform data write
    --progress                  display Progress output
-h, --help                      Display this
```

![IMG_0135s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/17bed8e9-8dc3-70f5-8adc-00637b6c3a20.jpeg)

![R8C_Writer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/92bbbf3a-e7a2-e4fa-121b-1d63e59219c2.png)

上記回路のように 2 回路の SW を設ける事で、通常（RUN 側）動作時は、UART との通信として利用し、FLASH 書き込み時は（WRITE 側）にして、プログラムを書き込みます。
※ WRITE 時は「MODE」端子を LOW レベルにしています。
※回路図では、USB シリアルとの接続は、１０ピンコネクタになっていますが、写真のボードでは、６ピンコネクタとしています。
※スイッチを切り替えたら、「RESET」を押して、モードを切り替えてから、プログラムします。

```
Uranus-W10./d/Git/R8C/FIRST_sample % make run
r8c_prog -d R5F2M120 --progress -e -w -v first_sample.mot
Erase:  #####################################
Write:  #####################################
Verify: #####################################
```

## サンプルプログラム

このマイコン用にサンプルをいくつか用意していますので参考にして下さい。

|プロジェクト|概要|
|-----------|---|
|FIRST_sample|ＬＥＤ点滅サンプル|
|UART_sample|シリアルインターフェースの送信、受信サンプル|
|TIMER_sample|タイマーＲＢのサンプル（インターバルタイマー）|
|ADC_sample|Ａ／Ｄ変換のサンプル|
|DATA_FLASH_sample|データフラッシュの初期化、リード、ライト|
|PWM_sample|タイマーＲＣのサンプル（ＰＷＭ出力）|
|RC_SERVO_sample|ラジコン用サーボの動作テスト（ＰＷＭ、２出力）|
|COMP_sample|コンパレーターのサンプル|
|DS1371_sample|I2C RTC デバイスのサンプル（DS1371）|
|DS3231_sample|I2C RTC デバイスのサンプル（DS3231）|
|EEPROM_sample|I2C EEPROM デバイスのテスト|
|VL53L0X_sample|I2C VL53K0X レーザー距離センサのサンプル|
|SWITCH_sample|スイッチ入力テスト（チャタリング除去とトリガー判定）|
|TOUCH_sample|タッチスイッチのテスト|
|ENCODER_sample|エンコーダー入力テスト|
|PLUSE_OUT_sample|タイマーＲＪを使ったパルス出力テスト|
|PLUSE_INP_sample|タイマーＲＪを使った周波数計測テスト|
|PLUSE_OUT_LCD|タイマーＲＪ、ＬＣＤ、エンコーダ|
|ARITH_sample|文字列による計算式、評価サンプル|
|MPU6050_sample|MPU6050 加速度、ジャイロ、センサー、サンプル|
|BMP180_sample|Bosh BMP180 温度、標高、センサー、サンプル|
|MAX7219_sample|LED ディスプレイ・ドライバー、サンプル|
|MAX6675_sample|SPI 接続、ｋ熱電対温度センサー、サンプル|
|THERMISTOR_sample|サーミスターを使った温度検出、サンプル|
|LCD_DOT_sample|128x32 mono color graphics のテスト|
|SD_sample|pFatFS を使った、SD カードのテスト|
|RC_SERVO_tester|ラジコン用サーボのテスター（ＪＲ、又はフタバＰＷＭ出力、１チャネル用）|
|USB_CHECKER|USB 電流、電圧チェッカー|
|AD9833_sample|DDS デバイスのサンプル（AD9833）|

## FIRST_sample を観てみる（LED 点滅）

コンパイル：

- C++14 でコンパイルしています。
- プロジェクトに含まれる Makefile は、独自の工夫がしてあり、「make」と入力するだけで、完全な従属規則生成など、自動化されています。
- この Makefile は IDE におけるプロジェクトファイルに相当するものです。

```
Uranus-W10./d/Git/R8C/FIRST_sample % make
mkdir -p release/; \
m32c-elf-g++ -MM -DDEPEND_ESCAPE  -std=c++14 -Wall -Werror -Wno-unused-variable -fno-exceptions -Os -mcpu=r8c -DF_CLK=20000000 -I. -I../ -I../M120AN main.cpp \
| sed 's/main\.o:/release\/main.o release\/main.d:/' > release/main.d ; \
[ -s release/main.d ] || rm -f release/main.d
mkdir -p release/common/; \
m32c-elf-gcc -MM -DDEPEND_ESCAPE  -std=gnu99 -Wall -Werror -Wno-unused-variable -fno-exceptions -Os -mcpu=r8c -DF_CLK=20000000 -I. -I../ -I../M120AN ../common/init.c \
| sed 's/init\.o:/release\/common\/init.o release\/common\/init.d:/' > release/common/init.d ; \
[ -s release/common/init.d ] || rm -f release/common/init.d
mkdir -p release/common/; \
m32c-elf-gcc -MM -DDEPEND_ESCAPE  -std=gnu99 -Wall -Werror -Wno-unused-variable -fno-exceptions -Os -mcpu=r8c -DF_CLK=20000000 -I. -I../ -I../M120AN ../common/vect.c \
| sed 's/vect\.o:/release\/common\/vect.o release\/common\/vect.d:/' > release/common/vect.d ; \
[ -s release/common/vect.d ] || rm -f release/common/vect.d
mkdir -p release/common/; \
m32c-elf-as -c    -I. -I../ -I../M120AN -o release/common/start.o ../common/start.s
mkdir -p release/common/; \
m32c-elf-gcc -c  -std=gnu99 -Wall -Werror -Wno-unused-variable -fno-exceptions -Os -mcpu=r8c -DF_CLK=20000000  -I. -I../ -I../M120AN  -o release/common/vect.o ../common/vect.c
mkdir -p release/common/; \
m32c-elf-gcc -c  -std=gnu99 -Wall -Werror -Wno-unused-variable -fno-exceptions -Os -mcpu=r8c -DF_CLK=20000000  -I. -I../ -I../M120AN  -o release/common/init.o ../common/init.c
mkdir -p release/; \
m32c-elf-g++ -c  -std=c++14 -Wall -Werror -Wno-unused-variable -fno-exceptions -Os -mcpu=r8c -DF_CLK=20000000  -I. -I../ -I../M120AN  -o release/main.o main.cpp
m32c-elf-gcc -mcpu=r8c -nostartfiles -Wl,-Map,first_sample.map -T ../M120AN/m120an.ld  -o first_sample.elf release/common/start.o release/common/vect.o release/common/init.o release/main.o -lstdc++
m32c-elf-size first_sample.elf
   text    data     bss     dec     hex filename
    380     168       0     548     224 first_sample.elf
m32c-elf-objcopy --srec-forceS3 --srec-len 32 -O srec first_sample.elf first_sample.mot
m32c-elf-objdump -h -S first_sample.elf > first_sample.lst
```

ソースコード：

```cpp
//=====================================================================//
/*!	@file
	@brief	R8C LED 点滅 @n
			LED は、P1_0(20)、P1_1(19)に接続（吸い込み点灯）@n
			※M120AN(20)
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2021 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/R8C/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"

namespace {

	// LED は '0' で点灯、'1' で消灯するように接続するので、LED クラスの論理を反転して定義する
	typedef device::PORT<device::PORT1, device::bitpos::B0, false> LED0;
	typedef device::PORT<device::PORT1, device::bitpos::B1, false> LED1;

}

int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);  // >=30us(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	// LED 設定
	{
		LED0::DIR = 1;
		LED1::DIR = 1;
	}

	// LED 点滅メイン
	while(1) {
		LED0::P = 0;
		LED1::P = 1;
		// 250ms (0.25s)
		utils::delay::milli_second(250);
		LED0::P = 1;
		LED1::P = 0;
		// 250ms (0.25s)
		utils::delay::milli_second(250);
	}
}
```

C++ フレームワークのおかげで、判りやすく直観的な操作で、プログラムを実装する事が出来ます。

### クロック周波数のブースト

R8C/Mxx では、起動時、低い周波数で起動します。
以下の手順で、最高速度（20MHz）までブーストします。

```cpp
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);  // >=30us(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;
```

### LED ポートの定義と動作

```cpp
typedef device::PORT<device::PORT1, device::bitpos::B0, false> LED0;
typedef device::PORT<device::PORT1, device::bitpos::B1, false> LED1;
```
- 点滅に利用する LED を定義します。

「device::PORT」テンプレートクラスは、ポート、ビット位置のパラメーターを使って、１つのポートオブジェクトを定義しています。
３番目のパラメーターに「false」を渡す事で、反転入出力とする事が出来ます。
ポートに LED を吸い込みで点灯するように接続しても、「１」で LED が点灯、「０」で消灯するようにプログラム出来ます。
実際の出力は反転されて、1--->0、0--->1 となります。

- ポートを出力にするには

```cpp
    LED::DIR = 1;
```

- ポート出力を設定するには

```cpp
    LED::P = 1;    // LED 点灯
    LED::P = 0;    // LED 消灯
```

- 今回は出力としていますが、ポートの入力状態を取得する場合は

```cpp
    auto n = LED::P();
```

などとします。

※Arduino のポート操作 API と異なり、PORT テンプレートクラスでは最適化が十分行われる為、以下のように、無駄なコードが殆ど出現しません。

```asm
    80f8:	7e 9f 48 05 	bset:g 0,0xa9    // LED0::DIR = 1;
    80fc:	7e 9f 49 05 	bset:g 1,0xa9    // LED1::DIR = 1;
    8100:	7e 9f 78 05 	bset:g 0,0xaf    // LED0::P = 0;
    8104:	7e 8f 79 05 	bclr:g 1,0xaf    // LED1::P = 1;
```

### ソフトウェアー遅延

あまり正確では無いですが、ソフトウェアーによる遅延 API を用意してあります。
※20MHz で動作する前提でループファクターが調整されています。
※以下の場合は２５０ミリ秒（０．２５秒）です。

```cpp
	// LED 点滅メイン
	while(1) {
		LED0::P = 0;
		LED1::P = 1;
		// 250ms (0.25s)
		utils::delay::milli_second(250);
		LED0::P = 1;
		LED1::P = 0;
		// 250ms (0.25s)
		utils::delay::milli_second(250);
	}
```

---

R8C/C++ フレームワークでは、デバイスの操作は、ハードウェアーマニュアルに沿った正確な名称を使っています。

## VSC を使った開発

開発環境は、VSC が便利です！

![vscode_scs.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/30b315b6-a76f-169c-b65e-2e0578106f5c.jpeg)

GitHub の R8C のルートを開くようなショートカットを用意してプロジェクトを開始できるように、R8C/.vscode 以下に専用の設定ファイルを置いてあります。

![vsc_sc_propaty.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58667/38677c49-f551-4b6d-ff6d-cdc0c6a6ff26.png)


## むすび

現実には、もっと安いマイコンは数多くありますが、通常、プログラム容量とコストは比例するものです。

それと、内蔵しているペリフェラルもかなり充実している事から、かなり色々なガジェットに応用が出来るものと思います。

C/C++ でプログラム開発が出来て、入門用教材としても優れています。
※手持ちの USB シリアルがあれば、100 円で、ガジェットを作成可能です！