「電子工作な日々」カテゴリーアーカイブ

電子工作に関連するお話など・・

R8C RB2を使ったタイマー

R8C もようやくタイマー関係の定義が出来ました。

R8C には3つのタイマーモジュールが内臓されています。
それぞれ、RC、RJ、RB です。

AVRに比べると、複雑で、機能を使うには、マニュアルの意図を理解するのに時間がかかりますが、
高機能で、AVRと両方使って思うのは、ルネサス系のタイマーの方が、細かい部分が良くできている点です。
インプットキャプチャー機能などは、ダブルバッファになっていて、正確な値を取得できますし、PWM機能は、
多くの場面を想定していて、十分な使い方が出来ます。

この中で、比較的単純な構造なのはRBです。
単純と言っても、色々な仕組みがあるのですが、とりあえず、16ビットのタイマーとして使い、周期的に割り込みをかけるのに使う事にします。

タイマークラスでは、登録した関数を割り込み内から呼び出す仕組みを設けてありますが、通常「禁止」としています。
これを「有効」にすると、ライブラリー関数の静的変数を全てスタックへ退避するコードが追加される為、注意が必要です。
※そうしないと、メイン側で、あるライブラリー関数を実行していた場合、それを、割り込み側でも呼ぶと、問題が起こります。

周期的な割り込みを使うと、プログラム全体の時間管理が単純に行えるので便利です。
これは、同期式とも言います、ゲームなどに向いた方法で、画像の表示、書き換えを同期させ、常に一定の速度で全体を動作させます。
又、シングルタスクでありながら、マルチタスク的な並列動作を行うのに便利な方式です。
※厳密な意味での「並列」ではありませんが。

組み込みでも、「同期式」は、色々な面で、都合が良い場合が多くあります。

簡易的なマルチタスク的な動作が出来ます。

一つの例として、スイッチのチャタリング除去などが上げられます。
周期的な割り込みを行い、その周期で I/O ポートの値を読み込む事で、デジタルフィルター的な効果が付加され、結果的にチャタリングを除去
します。
この周期はスイッチの機械的特性によりますが、60Hz~100Hzくらいが適当です。
※スクリーンのリフレッシュレートが60Hzなので、その値が使われます。

当然ながら、1秒に60回以上のOn/Offを検出出来なくなりますが、通常は問題ありません。

また、個々の処理を時分割で動作するように実装して、それを周期的に呼び出す事で、並列動作が実現出来ます。

通常は、カーネルがタイムスライスを行い各スレッドを管理しますが、小さなシステムでは、マルチスレッドは複雑になりすぎる場合があり、
「同期式」でも十分な場合があります。

ゲームを作っている人には、常識的な実装ですが、初めて触れる人には新鮮で、判り難いかもしれませんが、馴れておくと良いと思います。
今まで、複雑で、難解な実装が、シンプルに出来る場合があり、モジュール的に他の処理と分離する事ができます。

ここで、今までに実装したR8C関係クラスなどをまとめておきます。

M120AN/
  m120an.ld     ---> リンカースクリプト
  system.hpp    ---> システム制御
  clock.hpp     ---> クロック発生回路
  port.hpp      ---> I/O ポート
  intr.hpp      ---> 割り込み
  uart.hpp      ---> シリアルインターフェース
  timer_rb.hpp  ---> タイマRB
  timer_rc.hpp  ---> タイマRC
  timer_rj.hpp  ---> タイマRJ

I/O制御関係では、以下のファイルがあります。

common/
  start.s        ---> R8C起動アセンブラソース
  vect.[hc]      ---> 割り込み、割り込みベクター関連
  init.c         ---> 初期化関連
  io_utils.hpp   ---> レジスター定義ユーティリティーテンプレート
  uart_io.hpp    ---> シリアルインターフェース制御クラス
  trb_io.[hc]pp  ---> タイマRB制御クラス

各デバイス毎にテストしたプロジェクトがあります。

R8C/
L_chika     ---> 基本の基本LED点滅(最小限の実装)
UART_test   ---> シリアルインターフェースのテスト(ポーリング、割り込み)
TIMER_test  ---> タイマーRBのテスト(ポーリング、割り込み)

これからも、随時追加していく予定です。

R8C UART の制御

凄い長い間、間が空いたけど、再びR8Cです。
※WR250Xを買ったせいで、休みは、出かける事も多く、体調を崩した事もあり、進んでませんでした・・

UARTですが、M120、M110には1チャネルのUARTが備わっています。
R8CではSCIと言わないのが、何となく系統の違いを感じますが、内部の機構や構成は、RXマイコンなどと殆ど同じです。
※良く調べたら、送信割り込みの機構はかなり違っていて、RXマイコンやSH用SCIのプログラムはそのままの構成では流用できませんでした。
※もしかしたら、これが「UART」と呼ぶ事なのかもしれません・・

クロックジェネレーターの構成により、あまり高いボーレートを使う場合は苦しいかもしれません。
※内部発振器は通常20MHzで発振しますが、調整機構があり、18.432MHzで発振させる事が出来るようで、ボーレートクロックに適しています。
※19.968MHzならもっと良かったのに・・

追加したファイルは、以下です。

R8C/M120AN/uart.hpp
R8C/common/uart_io.hpp
R8C/UART_test/*

現在のところ、ポーリングによる動作しか実装していませんが、そのうち割り込み動作も追加するつもりです。
R8Cは、RAMのリソースに余裕が無い為、割り込みベクターをROM側に置いておく必要があり、その為のしくみを考え中です。

M120以外のR8Cでも流用が出来るように、UART0だけに特化していません。
※今のところ、M120以外のR8Cを使う予定はありませんが・・

以前にRXマイコン用に作った、sci_io.hpp をR8C/UART 用に焼きなおしただけで、基本的な構成は似ています。

・テンプレート関数内 static 宣言
テンプレートクラスで static クラスを宣言すると、実態が必要なので、uart_io.hpp の最後の方で実体を宣言してあります。
※以前、この宣言方法が判らなくて、少し苦労しました・・

template<class UART, uint16_t recv_size, uint16_t send_size>
	utils::fifo<recv_size> uart_io<UART, recv_size, send_size>::recv_;
template<class UART, uint16_t recv_size, uint16_t send_size>
	utils::fifo<send_size> uart_io<UART, recv_size, send_size>::send_;

何故、static にする必要があるかと言えば、割り込みが関係しています。
割り込みが発生した場合、テンプレートクラスのリソースにアクセスする為には、テンプレートクラスの実体のアドレスが必要ですが、
通常の方法では、簡単に得られません(クロックを消費します)、そこで、static 変数にしておく事で、コンパイル時にアドレスが決定される為、
割り込み関数から、容易にアクセスできるのです。
static にしてありますが、テンプレート引数に依存しているので、UART チャネルが違う場合は、別のリソースとして割り当てられます。

・最適化の功名
main 関数内で、UART にボーレートを設定している関数がありますが、内部でボーレートジェネレーターに設定する値などを計算しています、
しかしこれは定数を指定している為、コンパイル時に最適化によって計算部分が最適化され、ダイレクトに定数がレジスターに設定されるような
アセンブリコードが出力されます。
※機能としてボーレートを変更できるような仕様だと、省く事が出来ない為、計算するコードが含まれる事になります。

・基本的な使い方
UART0を使うには、モジュールを有効にして、I/Oのマッピングを設定する必要があります。

    MSTCR.MSTUART = 0;  // モジュールスタンバイ制御
    PMH1E.P14SEL2 = 0;
    PMH1.P14SEL = 1;
    PMH1E.P15SEL2 = 0;
    PMH1.P15SEL = 1;

※M120の場合、I/Oポートの方向レジスターの設定は不要のようです。

M120のシリアルフラッシュライターでは、TXDのポートは、本来のTXD0とは違うポートを使っている為、フラッシュライターのハード
を使って、シリアル入力のテストを行うには、P1:B6とP1:B5をブリッジする必要があります、今回は適当な抵抗でブリッジしています。

※使い方は、main.cpp を参考にして下さい。

いつものように GitHub にプッシュしてあります。

追記:
割り込みにも対応するべく、色々やっていました。
色々なバグなども見つけて、安定度なども向上しつつあります。

リンカースクリプトに記述してあるスタックのアドレスを間違ってました・・

それを修正して、割り込みベクターの設定ハード用のテンプレートを実装したら、受信割り込みは簡単に動いたのだけど、
送信割り込みがーー、R8Cでは、送信割り込みハードの実装が微妙で、スマートな方法が使えないのです。

普通、送信割り込みはバッファが「空」になったら発生するので、ソフトとの連携も楽なのですが、R8Cではそうなっておらず、
少し苦労しましたが、何とか方法を考えて実装しました、以外と簡単な対処ですが、ロジックに誤りがあれば、普段は良くても、何か違う状況
の場合などに微妙に正しく動作しない可能性があります。
※バッファに送信データが残るとか、送られないデータが出るとか・・
割り込みを含んだロジックは、隠れて見えない部分が多いものなので、しばらく注意して観ておく必要があります。

送信割り込みで運用したロジックは以下のような物です。
・リングバッファが空で、UARTのレジスタも空なら、送る物が何も無い状態なので、直接送信レジスターにデータを書く。
・リングバッファが空では無いか、UARTのレジスタが埋まっていれば、送信中なので、リングバッファにデータをいれる。
・送信割り込みでは、リングバッファが空なら、送る物が無いので、何もしないで終了とする。
・送信割り込みでは、リングバッファに何かデータがあれば、それをUARTのレジスターに書いて終了する。

R8Cスタートアップの手順と、Lチカ

さて、R8C用 gcc が出来たのでー、早速、最初の一歩、スタートアップルーチンの実装です~

RX マイコン用 gcc で色々学習したので、今回はかなり楽です。
ただ、R8C のアセンブラは初めてなので、少し苦労しそう・・・

全体の構成としてー

・start.s ---> CPU リセット時に開始するルーチン
・init.c ---> 初期化関係
・vect.c ---> ベクターアドレス関係
・xxx.ld ---> リンカースクリプト

この4つの構成になります。


「start.s」

	.text
	.global _reset_start
_reset_start:
	.global	_start
_start:
	/* 割り込みスタック設定 */
	.extern _isp_init
	ldc #_isp_init,isp

	/* ユーザースタック設定 */
	.extern _usp_init
	fset u
	ldc #_usp_init,sp

	/* 割り込み許可 */
	fset i

	.extern _init
	jmp.w _init

	.global _exit
_exit:
	jmp.w	_exit

・「_reset_strat」、「_start」は同一アドレスに向けておきます。
※リンク時、「-nostartfiles」を指定しても、「_start」のシンボルは必要なようです。
・「_isp_init」、「_usp_init」はリンカースクリプトで指定してあります。
※それぞれ、割り込み用スタック、ユーザースタックです、プログラムの性質に合わせて、少ないメモリーのどこにどれくらい配置するか考える必要があります。


「init.c」

int main(int argc, char**argv);

extern short _datainternal;
extern short _datastart;
extern short _dataend;

extern short _bssstart;
extern short _bssend;

extern short _preinit_array_start;
extern short _preinit_array_end;
extern short _init_array_start;
extern short _init_array_end;

int init(void)
{
	// R/W-data セクションのコピー
	{
		short *src = &_datainternal;
		short *dst = &_datastart;
		while(dst < &_dataend) {
			*dst++ = *src++;
		}
	}

	// bss セクションのクリア
	{
		short *dst = &_bssstart;
		while(dst < &_bssend) {
			*dst++ = 0;
		}
	}

	// 静的コンストラクターの実行(C++ )
	{
		short *p = &_preinit_array_start;
		while(p < &_preinit_array_end) {
			void (*prog)(void) = (void *)*p++;
			(*prog)();
		}
	}
	{
		short *p = &_init_array_start;
		while(p < &_init_array_end) {
			void (*prog)(void) = (void *)*p++;
			(*prog)();
		}
	}

	// main の起動
	static int argc = 0;
	static char **argv = 0;
	int ret = main(argc, argv);

	return ret;
}

void __dso_handle(void)
{
}

初期化ルーチンでは、一連の準備をする必要があります。
・メモリーのクリア(通常、bss セクション)
・初期値が設定してあるメモリーにROMエリアからコピー
・静的コンストラクターの実行(C++ の場合のみ必要)
・最後に「main」関数の起動


「vect.c」

#include <stdlib.h>

#define INTERRUPT_FUNC __attribute__ ((interrupt))

extern void reset_start(void);

// 未定義命令
INTERRUPT_FUNC void undef_inst_(void)
{
}

// null interrupt TASK
INTERRUPT_FUNC void null_task_(void)
{
}

// R8C M110AN, M120AN の場合、ポインターは2バイト、ベクターテーブルは4バイト単位のアドレスを想定
const void* fixed_vectors_[] __attribute__ ((section (".vec"))) = {
// 0xFFD8  予約領域 (with OSF2)
	(const void*)0xffff, (const void*)0xffff,
// 0xFFDC  未定義命令 (with ID1)
    undef_inst_, (const void*)0xff00,
// 0xFFE0  オーバーフロー (with ID2)
	null_task_,  (const void*)0xff00,
// 0xFFE4  BRK 命令
	null_task_,  (const void*)0xff00,
// 0xFFE8  アドレス一致 (with ID3)
	null_task_,  (const void*)0xff00,
// 0xFFEC  シングルステップ (with ID4)
	null_task_,  (const void*)0xff00,
// 0xFFF0  ウオッチドッグタイマ、発振停止検出、電圧監視1 (with ID5)  
	null_task_,  (const void*)0xff00,
// 0xFFF4  予約 (with ID6)
	(const void*)0xffff,  (const void*)0xffff,
// 0xFFF8  予約 (with ID7)
	(const void*)0xffff,  (const void*)0xffff,
// 0xFFFC  リセット (with OFS)
	reset_start, (const void*)0xff00,
};

※R8C/M110AN、R8C/M120AN では、ポインターは2バイトです、ですが、ハードウェアーベクターは4バイト構成になっています。
※また、R8Cのアーキテクチャー的には、最大1Mバイトの空間までアクセス出来るので、ベクターは3バイトあれば十分です、最上位バイトは、別の機能(「IDコードチェック機能」、「オプション機能選択」などのレジスター)として使われています、通常0xFFにしておけば良いようです。
※間違って書き換えてしまうと、フラッシュの書き換えが出来なくなる場合があるようなので、注意が必要です


「リンカースクリプト」(抜粋)


MEMORY {
	RAM (w) : ORIGIN = 0x0300, LENGTH = 0x0480
	ROM (r) : ORIGIN = 0x8000, LENGTH = 0x7FD8
	VEC (r) : ORIGIN = 0xFFD8, LENGTH = 40
}
SECTIONS
{
        _usp_init = 0x07E0 - 2;
        _isp_init = 0x0800 - 2;

...

  .rodata : {
    . = ALIGN(2);
    *(.plt)
    KEEP (*(.init))
    KEEP (*(.fini))
    *(.rodata .rodata.* .gnu.linkonce.r.*)
    *(.rodata1)
    *(.eh_frame_hdr)
    KEEP (*(.eh_frame))
    KEEP (*(.gcc_except_table)) *(.gcc_except_table.*)
    . = ALIGN(2);
    PROVIDE(__romdatastart = .); /* IF_ROROM */
  } > ROM

  PROVIDE( __datainternal = ABSOLUTE(LOADADDR(.data)));

...

  .vec : {
    *(.vec)
  } > VEC

...

・リンカースクリプトは、通常 gcc のバージョンによって構造が異なります、今回 gcc-4.7.4 ベースの M32C-elf をビルドしましたが、
m32c-elf/m32c-elf/lib/r8c.ld に基本になるリンカースクリプトがありますので、これを修正して使っています。
※正しい書き方や、意味を完全に理解している訳では無いので、カットアンドトライ的ですが、とりあえず、現状のスクリプトで大丈夫と思います。


「main.cpp」Lチカのプログラムです。

#include "port.hpp"

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

	PD1.B0 = 1;

	while(1) {
		for(int i = 0; i < 1000; ++i) P1.B0 = 0;
		for(int i = 0; i < 1000; ++i) P1.B0 = 1;
	}
}

・初期状態の内臓発振器を想定したソフトループとなっています。
・port.hpp がポートのテンプレートクラス定義です。
・Makefile により、自動で、ファイルの従属規則を生成しています。

IMG_0712
IMG_0713

とりあえず、ソースコードは、GitHub にプッシュしてありますので参考にして下さい。
※定義は I/O ポートの部分しか無いので、ちょくちょく更新、及び追加すると思います。

R8Cマイコン用 gcc (m32c-elf) の構築

さてー、M110AN、M120ANが、もの凄く使えるやつだって判ったのでー

まず、お決まりの gcc ビルドです。
色々調べると、R8Cは、M32Cマイコンのサブセットのようです、そこで、M32Cマイコン用 gcc をビルドします。
M110AN、M120AN は R8C の中でも(Tiny)と呼ばれる縮小セット版のようです。
※コンパイルオプションとして「-mcpu=r8c」などとします。

毎回、gcc のビルドは苦労します。

Windows7 MSYS(MinGW) の場合:
※ MSYS に、gcc ビルドに必要な、「gmp、mpfr、mpc」がインストールしてある事を前提とします。

・gmp-5.1.3
・mpfr-3.1.2
・mpc-1.0.1

OS-X の場合:
・mac brew を使ってするのが楽です。
※他に、「MacPorts」が同じようなシステムですが、こちらは、メインツリー以外のバージョンをインストールする
場合など、全く融通が利かないので、mac brew を推します。
※mac brew のインストールについては、詳しいサイトが沢山あるので、そちらを参照下さい。
OS-X では、標準コンパイラは clang で、gcc コマンドがオーバーライドされています、gcc をインストールしておき、シンボリックリンクを貼り直しておきます。

brew install gcc
sudo ln -sf /usr/local/bin/gcc-4.9 /usr/local/bin/gcc
sudo ln -sf /usr/local/bin/g++-4.9 /usr/local/bin/g++
brew install gmp
brew install mpfr
brew install mpc

※確認

gcc --version
gcc (Homebrew gcc 4.9.2_1) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

まず、binutils-2.24 のビルド

binutils-2.24 のソースを展開したら、
※gcc-4.9 では途中でビルドを失敗するので、binutils-2.25 を使います。

cd binutils-2.24
# 直でビルドしないで、専用のディレクトリーで作業するのが普通です、失敗したらディレクトリーを削除してやり直せる。
mkdir m32c_build
cd m32c_build
../configure --target=m32c-elf --prefix=/usr/local/m32c-elf --disable-nls
make
make install

アセンブラのパスを通して、パスを有効にする為コンソールを開きなおします、そして、最初のCコンパイラをビルドします。
※この段階では、C コンパイラのみビルドします、C++ は、後でビルドします。
gcc-4.7.4 のソースを展開したら、(とりあえず、C++11 完全対応の gcc4.8 系を使わずに枯れたバージョンで試します。)
※ gcc は 4.8 系でかなり大きく構造が変わったようで、メンテナンスがされていない CPU の場合、4.8 系ソースでは、コンパイルに失敗する事が多い為です。
※C++11 完全対応ではありませんが、C++0x オプションがありますから、ほぼ遜色無く C++11 の機能を使えます。

cd gcc-4.7.4
mkdir m32c_build
cd m32c_build
../configure --prefix=/usr/local/m32c-elf --target=m32c-elf --enable-languages=c --disable-libssp --with-newlib --disable-nls
make

windows:
make install

OS-X:
sudo make install

次に newlib をビルドします。

newlib-2.1.0 のソースを展開したら

cd newlib-2.1.0
mkdir m32c_build
cd m32c_build
../configure --target=m32c-elf --prefix=/usr/local/m32c-elf
make

windows:
make install

OS-X:
sudo make install

最後に C++ をビルドします。

cd gcc-4.7.4
cd m32c_build
../configure --prefix=/usr/local/m32c-elf --target=m32c-elf --enable-languages=c,c++ --disable-libssp --with-newlib --disable-nls --disable-libstdcxx-pch
make

windows:
make install

OS-X:
sudo make install

とりあえず、C++ のビルド中、怪しい動作がありましたが、最後まで到達しました。(Windows)
簡単なテストは、とりあえずOKで、詳細なテストはこれからです。

スタートアップルーチンは、デバイスに合わせて書く事になる為、しばらくは、ハードウェアーマニュアル、ソフトウェアーマニュアルと「にらめっこ」です・・
また、R8C のアセンブラもある程度理解する必要があります・・

-cpu=r8c でR8C を選択した場合、「int」のサイズは16ビットのようです。
※この CPU によって int のサイズを16にしたり32にしたりする慣わしって誰が始めたのか知らないけど、ホントクズ仕様だよなぁー・・・
なので、int32_t、とかがあるんだけど、short があるんだから、int は32ビットで良くない!?

gcc のビルドは、手間もそうですが、時間もそれなりにかかるので、「めんどぃ」って人は、
今回ビルドしたバイナリーを以下のリンクに置いておきますので活用下さい~
MSYS(MinGW)版 M32C-gcc-elf
※通常は、「/usr/local/」で、アーカイブを解凍すれば、
「/usr/local/m32c-elf」が出来ますので、「/usr/local/m32c-elf/bin」にパスを通します。
これで、

m32c-elf-gcc
m32c-elf-g++

などが利用可能です。

R8C/M11A、M12Aの秘密

M11A、M12Aについて~

低価格なマイコンと言えば、AVRですが、ルネサスにも、CPの高いマイコンがあります。
それは、R8Cマイコンで、R8C/M12A/M11Aです。
「@100円、確かに安いけど、AVRもあるし、PICもあるしで、そんなにインパクト無いけどーー」と言いたくなるかもしれませんが・・
このマイコン、裏事情があって、表向きは
・プログラムメモリ(フラッシュ):2KB
・RAM:256バイト
となっていますが、実際には、
・プログラムメモリ(フラッシュ):32KB
・RAM:1280バイト
時代に逆行するアセンブラ屋さんの調査による。

これが、現在出回っているデバイスでも有効に出来るのなら、今までの常識が一遍しそうです。

AVRのATTiny2313は、安くて使いやすいマイコンですが、A/Dコンバーターが無いのが痛いとこです。
最近秋月の価格を観ると@150になっていますね・・

M12Aの場合は:
・最大20MHz動作(2.7V以上)
・1.8V~5.5V動作
・入出力ポート:17本 (LED駆動用ポート含む)
・外部割り込み入力:8本
・16ビット多機能タイマ(タイマRJ2):1
・8ビットプリスケーラ付8ビット多機能タイマ(タイマRB2):1
・16ビットインプットキャプチャ/アウトプットコンペアタイマ(タイマRC):1
・UART/クロック同期形シリアルインタフェース:1チャネル
・10ビットA/Dコンバータ:6チャネル
・コンパレータ:2回路
・ウォッチドッグタイマ
・クロック発生回路:XINクロック発振回路、オンチップオシレータ(高速/低速)
この充実ぶりです・・

この機能と、プログラムエリア32Kバイト、RAMエリア1280バイトとなると、かなりの用途にマッチします。


フラッシュの書き込みボードの作成

・配線は、ハードウェアーマニュアルに詳しく書かれていますので参考にして下さい。
・フラッシュ書き込みモードで電源投入後、FDTとの接続が時間内に無いと、接続出来なくなるので、「リセットスイッチ」は必要です。
・フラッシュの書き込みは、3.3Vでも行えるようです。
このDIPタイプは、シリアルインターフェースで接続出来る為、非常に手軽に書き込みが行えます。
IMG_0705

購入したデバイス
デバイスの表記では(下に書かれているのはロット番号と思います)


 M120AN
0432N01

 M110AN
0432N01

となっていました。


書き込みソフトのインストールと設定ファイルの修正

書き込みソフトは、FDT4.09 を使います。
インストール後、以下の設定ファイルを書き換えます。(Windows7 64 ビットの環境です)

/c/Program Files (x86)/Renesas/FDT4.09/kernels/ProtD/R5F2M110A/Renesas/1_0_00/R5F2M110A.fcf
/c/Program Files (x86)/Renesas/FDT4.09/kernels/ProtD/R5F2M120A/Renesas/1_0_00/R5F2M120A.fcf

「R5F2M110A.fcf」の修正箇所

[Header]
Description = Flash Development Toolkit Configuration File
File Type = 2.1

[Device Info]
EVB Name = R5F2M110A
EVB Kernel Suffix = R5F2M110A

...

FLASH ROM Size = 32768

...

Secret Flash Memory = 
Erase Block Count = 10
Memory Area Count = 2
Reserved Area Count = 0

...

[Erase Block 2]
Block Name = EB8
Start Address = 32768
Start (Hex) = 0x00008000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 3]
Block Name = EB7
Start Address = 36864
Start (Hex) = 0x00009000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 4]
Block Name = EB6
Start Address = 40960
Start (Hex) = 0x0000A000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 5]
Block Name = EB5
Start Address = 45056
Start (Hex) = 0x0000B000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 6]
Block Name = EB4
Start Address = 49152
Start (Hex) = 0x0000C000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 7]
Block Name = EB3
Start Address = 53248
Start (Hex) = 0x0000D000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 8]
Block Name = EB2
Start Address = 57344
Start (Hex) = 0x0000E000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Erase Block 9]
Block Name = EB1
Start Address = 61440
Start (Hex) = 0x0000F000
Block Size = 4096
Size (Hex) = 0x00001000
EBR0 = 0
EBR1 = 0
EBR2 = 0
Overlay = 0
Lockable = False

[Memory Area 0]
Block Name = UA0
Start Address = 32768
Start (Hex) = 0x00008000
Block Size = 32768
Size (Hex) = 0x00008000
Area Type = User Flash
Overlay = 0

...

「R5F2M120A.fcf」の修正箇所

[Header]
Description = Flash Development Toolkit Configuration File
File Type = 2.1

[Device Info]
EVB Name = R5F2M120A
EVB Kernel Suffix = R5F2M120A

...
 
FLASH ROM Size = 32768

...

Secret Flash Memory = 
Erase Block Count = 10
Memory Area Count = 2
Reserved Area Count = 0

...

[Erase Block 2]
 Block Name = EB8
 Start Address = 32768
 Start (Hex) = 0x00008000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

 [Erase Block 3]
 Block Name = EB7
 Start Address = 36864
 Start (Hex) = 0x00009000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
Overlay = 0
Lockable = False

 [Erase Block 4]
 Block Name = EB6
 Start Address = 40960
 Start (Hex) = 0x0000A000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

 [Erase Block 5]
 Block Name = EB5
 Start Address = 45056
 Start (Hex) = 0x0000B000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

 [Erase Block 6]
 Block Name = EB4
 Start Address = 49152
 Start (Hex) = 0x0000C000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

 [Erase Block 7]
 Block Name = EB3
 Start Address = 53248
 Start (Hex) = 0x0000D000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

 [Erase Block 8]
 Block Name = EB2
 Start Address = 57344
 Start (Hex) = 0x0000E000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

 [Erase Block 9]
 Block Name = EB1
 Start Address = 61440
 Start (Hex) = 0x0000F000
 Block Size = 4096
 Size (Hex) = 0x00001000
 EBR0 = 0
 EBR1 = 0
 EBR2 = 0
 Overlay = 0
 Lockable = False

[Memory Area 0]
 Block Name = UA0
 Start Address = 32768
 Start (Hex) = 0x00008000
 Block Size = 32768
 Size (Hex) = 0x00008000
 Area Type = User Flash
 Overlay = 0

書き込みプロジェクトの設定

・デバイスを指定する際、チェックサムが合わない為、警告が出ますが、そのまま進みます。
・とりあえずこの修正で、32Kまでプログラムメモリーが使えると思います。
※MSYS のコンソールから、emacs でファイルを直接編集したのですが、パーミッションの関係で、実際には更新されない事が判りました。
エクスプローラーなどで、編集後のファイルを上書き保存する必要があります。(その際、警告のダイアログが出ます)


謝辞

・「時代に逆行するアセンブラ屋」さんの「toida」さんには、設定内容などお世話になりました。

・M110AN 設定ファイル
・M120AN 設定ファイル

ウィンカーの LED 化(その1)

前から改造してみたかった、ウインカーのLED化を行っている。

まず、電球をLED化する、球切れの心配が無くなり、消費電力が減る。
それとLEDは、点灯、消灯がハッキリしていて視認性も良くなるのではと思う。

改造したバイクはヤマハのWR250Xモタードで、標準的には10Wの電球が付いていた。
IMG_0679s
ポジションは無く、1灯式バルブ。
※LED化する事でウィンカーリレーも自作するので、ポジションランプ機能も加えようと思う。

口金は「BA15s」と言うタイプで、ピンが水平に出ている。
※千石電商で購入

自作する場合に考えなくてはならない事は、以下のような点・・
・頑丈で、振動などで、点灯不良にならない構造。(接着剤での接着などを極力避ける)
・最低でも4個は必要なので、作りやすさ、同じ物が作れる(再現性の確保)事。
・売っているLEDバルブには無い機能と性能など。

以上のような点だろうか・・

最初に問題となるのは、口金にLEDをどのように固定するか?
そこで、以前に自動車の車内を照らすシーリングライトをLED化した時の手法を応用した。
まず、口金にユニバーサル基板をピッタリサイズで切り出し差し込む、この時、スルホールが、口金の金属と近くなるようにする。
基板には、垂直に基板を固定する為のボスを作っておく。
IMG_0676s

基板を中に入れて、スルホールにハンダを流し、口金の金属部分にもハンダを流して固定する。
※それなりにハンダを流し込めば、ある程度の強度は確保出来ると思う。
IMG_0678s

蓋をするように基板を切り出す、大体円になるように基板を削る、中心も、先ほどの基板のボスが入るようにリューターで削る。
※10Wの電球は外形19mmくらいなので、それ以下の大きさにする。
IMG_0680s

IMG_0681s

さて、LEDはどのような物を選ぶのが良いか?、何個くらいを並列にするか?

LEDの性能は、日進月歩で、日増しに効率が高くなっている為、「使いたい時にまとめて買う!」のが良いと思う。
今回選択したのは、このLED「OSWX4EZ4E1P」リンクは秋月のものだが、適当なLED屋さんでまとめて買った方が安いと思う(自分は千石の手前のLED専門ショップで50個1000円で買った)

このLEDは、3個の白色LEDが直列になっていて、90mAまで電流が流せる、その場合30ルーメンと言う明るさ。
LEDは、 全ての範囲で電流と明るさが比例するわけではなく、効率の良い電流値があるものだ、その電流なら、発熱も少ない。
今回は実験して、10Wの電球との明るさの違いなどを調べ、1個辺り、約20mA~30mA程度にし、全部で9個を使う(大体全体で200ルーメン程度だと思う)のが丁度良いと思った。
※LEDを並列にして使うので、特性が揃っている必要がある為、同じロットの物を選ぶ必要がある。
※それでも10Wの電球よりかなり明るい。
※ある程度数を多くして分散させた方が、光が集中しないで電球と同じように拡散させる事が出来る。

IMG_0683s
実験用として作ったLEDアレイ

LEDに流れる電流の制限抵抗は、以下のように計算した。

・電源の電圧を13Vとする。
※LED保護と汎用性を考えて、ショットキーダイオードによるブリッジを組む、こうすると、極性が事実上無くなるので、扱いが楽になる。
・ショットキーダイオードの順方向電圧降下を0.4Vとする。
・LEDのVFを3.1Vとする。

25mAの電流を流すには?

13-0.4×2-3.1×3 / (25mA×9) = 13オーム

※適当な抵抗が無かったので47オームを4本並列とした。

まず、下の列、5個を直線で繋ぎ~
IMG_0684s

適当に曲げて五角形にする。
IMG_0685s

それを、口金のベースに並べて端子をハンダ付け。
IMG_0686s

最後に正面用アレイ:
まず、2個のLED、サイドを斜めに削って、斜めに密着させる。
IMG_0687s

それを2組作り、やはりサイドを斜めに削り、密着させて4個のアレイにする。

それを、上に載せて隙間からハンダを流して接続、出来上がり~
IMG_0689s
※順番を考えながら、ショートに注意して組み立てる、失敗すると修正が大変なので注意。
※4隅の角を少し削って19mmの直径に収まるようにする。

やっと1個出来た・・・、あと3個、とりあえず今日はここまで。

俺俺 RX マイコンボードを作ろう!(その1)

最近は、フルタイムで仕事をしている関係で、趣味の時間が凄く制限されていたのだが、仕事もだいぶ安定してきて、趣味の時間を持てるようになってきた。
それと、「この暑さ」、休みの多くは、ファミレスにノートを持ち込んで、主にソフトの制作などを行っていた。
最近、少し暑さも和らいだので、ハードの作業もしようかと思案していたら、秋月で良い物を見つけた。

128Mbits SDRAM 133MHz
まぁ、別にそんな珍しい物でも無いけど、デバイスを単体で扱っているのは珍しい、数個単位で買えるのはありがたい。
※多分、秋月で、SDRAMが乗ったマイコンボードでも出るのだと思う。

そして、マルツパーツで 176ピン、フラットパッケージ版 RX63N が単体で買える事が判ったのが最後の一押しとなった。

「176ピン、フラットパッケージ」は重要。
・0.5mm ピッチなので、ギリギリ、手ハンダができる。
・32ビットバスでSDRAMを接続出来る。(フルスピードで動かしても、性能があまり落ちない)
・内蔵 RTC のバックアップが出来る。
・外部バスを使っても、残りの空いたピンはかなり潤沢で、色々活用出来る。

そして、前から、RX マイコンの大容量メモリーを積んだボードが欲しかった。
・開発の効率などを考えると、プログラムをRAMに転送して実行したい。
・RX マイコン用の LLVM を作ってみたい、それには、ある程度メモリーが潤沢に使えるボードが必要。
・組み込み機器でも、メモリーが潤沢に使える環境が欲しい。
※大容量メモリーが無いと、画像ファイルなどを扱うのが難しい。
・PC 用フレームワークのソースコードをそのまま利用したい。
・安いボードじゃないと、色々な物に使う気になれない。
※「なひたふ」さんとこで、究極の RX62N ボードを扱っているのだけど、値段が高くて手が出せない。
※構成的には、同じようなものになってしまうのだけど・・・

他にも色々な動機がある〜

もうそろそろ、RX64M シリーズが流通しそうな感じなのだが、KiCAD を使ってボードも作ってみたかったので、汎用的で、応用が効く俺俺ボードを自分で作ってみる事にした。

とりあえず、構成はこんな感じにする予定〜
・RX63N(R5F563NEDDFC#V0)176 ピンパッケージ(内蔵、256K RAM、2048K Flash)
・内蔵 RTC 用外部バッテリーバックアップ
・128M ビット SDRAM x 2、32ビットバス接続(32Mバイト)
・10/100 インサーネット(PHY層: LAN8720AI)※別モジュールにするかも・・
・マイクロSDカードインターフェース
・リチウムイオン/ポリマー、充電コントローラーと DC/DC コンバーター
・A/D 入力用バッファアンプと電圧リファレンスなど
・オーディオインターフェース(VS1053B)
・USB インターフェース(2チャンネル分)
・未使用ポート用ピンヘッダー
・J-TAGコネクター
ちょっと盛り過ぎな感じもするのだが、使わない物は載せなければ良いと思うので・・・
※完成したら、ボード単体で販売する予定(時価)だが、欲しい人は少ないかもしれないねwww
※SDRAM は、@300なので、2個載せても600円、しかも32Mバイトの空間を使えるのは便利

そもそも、R-PiやBBBが5千円くらいで買える現実を考えると、0.1GHz程度のマイコンなんてと思うのだが、OSが無く、電源投入で、いきなりアプリを動かせ、電源をいきなり切れるような、組み込みの用途は必要だと感じているし、0.1GHzで十分な用途はけっこう多い。
またLinuxベースで、ハードウェアーに依存した細かい制御を書くのは、面倒でもあるし、リアルタイム的な制御が難しい場合もある。
※内蔵カウンターを使ったタイマーや、PWM 出力、割り込み制御など。

別の動機として、販売されている組み込み用ワンボードマイコンが高価過ぎるのも問題と思う。
趣味では無く、会社の形態として販売する場合、あのような値段になる事は理解出来るので、自分で作るしか無い。
イニシャルコストはかかるのだが、3枚、同じボードを使う事を考えたら、作った方が安い事になる。
※この場合、制作に関わる人件費を計上してないのだけどwww

まず、マルツパーツで、R5F563NEDDFC#V0(RX63N, Flash: 2MB, RAM: 128K) を注文した、1912円もしたけど、数個単位で買えるのはありがたい。
数日で、物は届いたのだが、梱包が微妙、足が曲がっている感じがする・・・
とりあえず、交換の手配をメールで問い合わせたのだが、写真を送って欲しいとある。
0.5mm ピッチだと、ルーペで拡大しても、何とも言えないのだが、梱包のやり方に難があるように思う。

IMG_0658s

導電スポンジにチップを載せた状態で、ラップして内部の空気を抜いてあるのだが、空気を抜く事でスポンジが縮み、ピンにストレスがかかっていて、反っているじゃないかと思う。
ラップを破れば、空気が入って、反りは戻るかもしれないが、微妙に反った状態になるかもしれず、非常に微妙・・・
普通は、もっと安全確実な方法で梱包すると思うのだが、デリケートな品物だけに、強引すぎると思う。
※以前に RX63T を注文した時は、こんな強引な梱包をしてこなかった。

「ピンが曲がっていたら交換してくれる」と言う事なので、意を決して、パッケージを開けてみたー
ピンが曲がっていたと思えたのは、ピンが導電スポンジにめり込んでいる為だったようで、購入した3個、全て問題無かった。
でも、もっと「やんわり」梱包する方法はあるハズで、そこは改善して欲しいとこ。

早速、変換基板にハンダ付けしてみた。
※変換基板は、今まではダイセン製を好んで使っていたが、秋月で良さそうな物を売っていたので購入してみた、値段は安いけど、品質は満足のいく代物。
やっぱ、0.5mmピッチは厳しいなぁー、176ピンもあるので大変、それと、ハンダコテの温度設定が低くなってて、難儀した。
ハンダ吸い取り線による、ブリッジの除去も、温度が低かったせいか、難儀した・・・

IMG_0664s

ルーペで拡大して、念入りに確認したので、まぁ、大体大丈夫と思う、多少怪しい部分もあるのだけど・・・

追記:(2014年9月21日)
この変換基板、重大な問題がある事が判りましたー、まぁ176ピンの変換基板を使う人は限られると思いますが・・

IMG_0665s

↑写真で判るように、縦と横のピンヘッダー取り付け部分のグリッドが 2.54mm ピッチでは無く、そのままでは、一般的な
蛇の目基板に取り付け出来ません・・・

※twitterでツイートしたら沢山の方にリツイートしてもらいました・・・
※秋月には、報告しません、どうせしても無駄だから・・・、以前にSDカードモジュールの結線ミスに気がついて、報告しましたが、
何の返信もありませんし、商品のQ&Aに情報が共有される事もなく無視されました、なので、今回は何もしません。
秋月は、商品の価格が安く、それゆえ、自作をするものにはメリットが大きいし、利用している人は多いのですが、
アフターケアに関しては、全く駄目なように思います、それを判った上で最大限利用するしかありません。
※現在は、ピッチがズレている事が明記されているようです。

※以前に秋月にメールした全文

お疲れ様です。

K-05818「SDカードスロットDIP化モジュール」について
参考資料で、CD(Card Detect)となっている信号は、ライトプロテクト信号のようです。
この商品に使われているソケットは、「Card Detect」用の端子がありますが、(4番)、GND(5番)とショートされており、使う事が出来ない仕様となっています。
カッターなどで、パターンを切って、(4番)を引き出すと、「Card Detect」として使う事ができました。
Q&A等に、情報として記入する事をお勧めしたいです。

それでは宜しくお願いします。

-----
普通は、いきなり基板を設計するかもしれないが、個人制作なので、とりあえず、ユニバーサル基板で、試作してみる事にする。
まぁ時間はかかるけど、作って動かしてみないと判らない事も多くあるのではと思う。

C 言語よりお得な C++ その10

以前に、std::iostream に代わる小規模なクラスの紹介をしました。
その中で、std::iostream に馴染めなくて、printf 形式が忘れられない人の為に、「boost::format.hpp」を紹介しました。
しかしながら、「boost::format.hpp」は、std::iostream に依存している為、そのままでは、結局リソースを大量に消費してしまい、小規模な組み込みマイコンでは使えません。
そこで、機能を絞った簡易的な format クラスに相当する物を実装してみましたので紹介します。
※機能が足りなければ、自分で拡張する事も出来ると思います。
※本家では、エラーの場合は、例外がスローされますが、それでは使いにくいと思い、エラー関数クラスでハンドリングするようにしています。
※「例外」をスローさせたい場合は、エラー関数から、例外を投げれば良いと思います。
※組み込みマイコン向けに、A/D 変換などの値(整数)を、10進表示する場合に小数点位置を指定して、それを簡単に表示できるようなフォーマットも用意しました。

このように使います。

    int x = 1095;
    int y = 123;
    utils::format<output>("Pos: %d, %d\n") % x % y;

Pos: 1095, 123

    int adv = 257;
    utils::format<output>("A/D Ch0: %2.4:8y\n") % adv;

/// 2.4 ---> 実数2桁、小数4桁。
/// :8 ---> 小数点以下8ビットとして扱う。

A/D Ch0:  1.0039

ここで「output」は、文字の出力クラスで、以下のような定義を行います。
struct output {
    void operator() (char ch) {
        serial_out_(ch);  ///< ターミナルへ文字出力
    }
};
「operator()」を定義する事で、以下のように関数オブジェクトとして使えます。
    output o;
    o('a');    ///< 'a' を出力
    o('\n');   ///< 改行を出力
※「operator()」を「public」にする為、あえて、「struct」としています。

さて、実際の実装ですが、まず format の設計方針を決めます。
・名前空間を「utils」とします。
・float の表示は、基本的に行わない事とします。(今後コンパイルオプションで切り替える)
・整数計算のみを使い、巨大にならないよう配慮する。
・クラッシュは論外としても、きめ細かいエラーのハンドリングは省略する。(必要なら追加する事も可能)
・printf のフォーマットに近い仕様を網羅する。
・2進、8進、16進表示を行う。
・ゼロサプレスの制御
・有効表示数の制御
・オートフォーマットは未サポートとする。

format の中

・フォーマット文字列をスキャンして「%」以下の書式を読み取る。
    void next_() {
        if(form_ == 0) {
            err_(error_case::NULL_PTR);
            return;
        }
        char ch;
        bool fm = false;
        bool point = false;
        bool ppos = false;
        uint8_t n = 0;
        while((ch = *form_++) != 0) {
            if(fm) {
                if(ch == '+') {
                    sign_ = true;  // 符号付きの場合
                } else if(ch >= '0' && ch <= '9') {
                    if(n == 0 && ch == '0') {
                        zerosupp_ = true;  // 最初の数字が「0」なら、0サプレスしない。
                    } else if(point || ppos) {
                        if(point) {
                            decimal_ *= 10;
                            decimal_ += static_cast(ch - '0');
                        } else {
                            ppos_ *= 10;
                            ppos_ += static_cast(ch - '0');
                        }
                    } else {
                        real_ *= 10;
                        real_ += static_cast(ch - '0');
                    }
                    ++n;
                } else if(ch == '.') {
                    ppos = false;
                    point = true;
                } else if(ch == ':') {
                    ppos = true;
                    point = false;
                } else if(ch == 's') {
                    mode_ = mode::STR;
                    return;
                } else if(ch == 'c') {
                    mode_ = mode::CHA;
                    return;
                } else if(ch == 'b') {
                    mode_ = mode::BINARY;
                    return;
#ifdef WITH_OCTAL_FORMAT
                } else if(ch == 'o') {
                    mode_ = mode::OCTAL;
                    return;
#endif
                } else if(ch == 'd') {
                    mode_ = mode::DECIMAL;
                    return;
                } else if(ch == 'u') {
                    mode_ = mode::U_DECIMAL;
                    return;
                } else if(ch == 'x') {
                    mode_ = mode::HEX;
                    return;
                } else if(ch == 'X') {
                    mode_ = mode::HEX_CAPS;
                    return;
                } else if(ch == 'y') {
                    mode_ = mode::FIXED_REAL;
                    return;
#if defined(WITH_FLOAT_FORMAT) | defined(WITH_DOUBLE_FORMAT)
                } else if(ch == 'f' || ch == 'F') {
                    mode_ = mode::REAL;
                    return;
                } else if(ch == 'e' || ch == 'E') {
                    mode_ = mode::EXPONENT;
                    return;
                } else if(ch == 'g' || ch == 'G') {
                    mode_ = mode::REAL_AUTO;
                    return;
#endif
                } else if(ch == '%') {
                    out_(ch);
                    fm = false;
                } else {
                    err_(error_case::UNKNOWN_TYPE);
                    return;
                }
            } else if(ch == '%') {
                fm = true;  // フォーマットの開始を検出!
            } else {
                out_(ch);  // フォーマットに関係しない文字は、そのまま出力
            }
        }
    }
・オペレーター「%」を定義する
//  この定義では、int 型の値が代入された場合の挙動を記述します。
//  事前に format 文字列の中をスキャン(next_() 関数)して、「%」を見つけ、それに続く「型」を「mode_」に格納しておきます。
    format& operator % (int val) {
        if(mode_ == mode::BINARY) {
            out_bin_(val);
        } else if(mode_ == mode::OCTAL) {
            out_oct_(val);
        } else if(mode_ == mode::DECIMAL) {
            out_dec_(val);
        } else if(mode_ == mode::HEX) {
            out_hex_(static_cast(val), 'a');
        } else if(mode_ == mode::HEX_CAPS) {
            out_hex_(static_cast(val), 'A');
        } else if(mode_ == mode::FIXED_REAL) {
            if(decimal_ == 0) decimal_ = 3;
            out_fixed_point_(val, ppos_);
        } else {
            err_(error_case::DIFFERENT_TYPE);
        }
        reset_();  // 変数をリセット
        next_();  // 「%」のスキャンを再始動
        return *this;
    }

※これらはソースの一部です。
「%」オペレーターでは、「int」型、「unsigned int」型、「const char*」型など、色々な型を定義してあり、コンパイラが適合する型を選択して呼び出してくれます。

組み込みマイコンでは、A/D 変換した値(大抵、電圧や電流値)を、小数点以下まで表示させたい場合があります、そこで、「y」フォーマットを用意しておきました、これは、整数値を固定小数として扱い、小数点以下も変換して表示します、小数点の位置は「:x」として自由に設定できます。(最大28ビット)
※浮動小数点が扱えない場合などに重宝します。
たとえば、12ビットのA/Dコンバーターで、基準電圧を2.5V(4096)の場合で、A/D入力に1/5の電圧が分圧される場合は、以下のようになります。


    uint32_t adv = get_adc();
    utils::format<output>("A/D Chanel: %2.3:13y\n") % (adv * 25);  // 2.5 * 5 * 2 
//  2.5 * 5 ---> 12.5 なので、さらに倍にして、小数点以下を12に1を加えて13ビットとする。

※8進数は、あまり使わないと思うので、コンパイルオプションとしました。(リソースの節約)
※逆に、2進数表示は大抵必要なので、「%b」フォーマットを追加してあります。
※浮動小数点は、実装中です、仕様が複雑なので、今後の対応、課題とします。

最終的なソースコードは、format.hpp ここにあります。
※いつもの github

MinGW でビルドする RX マイコン用 gcc

開発環境を MinGW に移行して、懸案だった RX マイコン用 gcc の構築を行った。

以前の cygwin 環境では、途中で、gcc が止まったり、妙なエラーが出て、上手くコンパイル出来ない状態だった・・
これは、適切なオプションを選択する事で回避出来るようだが、情報が無いし、試行錯誤に疲れて棚上げ状態だった。

MinGW 環境では、何とも普通にコンパイル出来るので、逆に不思議でさえ思ったが、これが普通なんだろうね・・・

コンパイルの詳細は、「Interface 2014年2月号」に詳しく載っているようだが、ネットにあるクロスコンパイラの構築などを参考にしても良いだろう。

手順が複雑で、扱うパッケージのバージョンとの相性などがある為、上手くいかない場合があると思う。

-----

RX マイコン用では、gcc-4.7.3 が良いようだ、C++11 を本格利用は出来ないが、C++0x は使えるので、問題無いと思う、gcc-4.8.x は失敗するようだ。

RX-gcc-4.7.3-ELF パッケージ
※コンパイル済みバイナリーを置いておく。(107MB)
※gcc-4.8.1 で構築した。

MicroChip RN-52 Bluetooth モジュールを使ったオーディオ再生

Bluetooth オーディオで、音楽を飛ばす場合(A2DP)は、圧縮フォーマットの関係で、良い音で聞くのが物理的に困難だった。
しかし、最近になって、新しい高音質プロファイル(APT-X/AAC)などに対応する機器が出始めた。

丁度、Microchip 社が、↑のプロファイルに対応した Bluetooth モジュールの販売を始めたので、使ってみる事にした。
RN-52
※Microchip 社のオンラインストアでも、1個から購入可能、モジュールが20ドル、送料が10ドル程かかる(発送には2週間程度かかるようだ)

このモジュールの特徴は:
・APT-X/AAC プロファイルに対応
・デジタル出力を出せる
※設定を行う必要がある。
・比較的安価
・外付け部品が殆どいらない
・Bluetooth のオーディオ系のプロファイル(AVRCP など)を全てサポートしている
・認証:FCC、IC、CE、Bluetooth SIG
・言うまでも無く、手軽に、自分だけの Bluetooth 機器を作れる

バッテリー内臓で、持ち運びが出来る、小さいラジカセのような物が欲しかったので、丁度良い感じ~

昨日、モジュールが届いたので、早速、簡単な動作確認をしてみた。

最初のハードルは、モジュールに出ているピンの間隔が 1.2mm と狭い為、工夫しないと、ユニバーサル基板に乗せられない。
自分は、適当な基板に絶縁用の板(フォーレックス)を乗せ、その上にモジュールを置いて、ワイヤーをハンダ付けした。
RN-52 Board

モジュールを自力で何とかするのが厳しい人は、SparkFun のブレークアウトを利用すれば良いだろう~(44.95ドル)

しかし、1.2mm 間隔のハンダ付けは、そんなに厳しいものでは無いので、根気だけだと思うな。

モジュールが出来たら、必要な配線をして、ペアリングをしてみよう~

・POWEN(21) ---> パワースイッチ
・VDD(22) ---> 3.3V(電流は動作中は少ないけど、ピークで30mA くらいは流れるみたいだ・・)
・GND(1,18,27,44,45,46,47,48,49,50) ---> GND(接地)
・LED1(32) ---> LED 赤色(470)
・LED0(33) ---> LED 青色(47)
・AGND(39) ---> AGND(アナログ接地)
・SPKR_R-(40) ---> 右SP-
・SPKR_L-(41) ---> 左SP-
・SPKR_R+(42) ---> 右SP+
・SPKR_L+(43) ---> 左SP-
※L-、R- は独立した出力なので、共通にする事は出来ない、又、インピーダンスの低い負荷(直でスピーカー)をドライブする事も難しいと思う。
※一般的なステレオイヤホン(ステレオプラグなど、接地が共通の場合)などを繋ぐ場合には、アンプを入れる必要があると思う、ドキュメントの回路図などが参考になる。
※電源には1uF程度のパスコンを念のため入れておく。

とりあえず、これだけ接続して、パワースイッチを押せば電源が入る。
長押しすれば、赤、青の LED が交互に光って、ペアリング待ちになる。

------
以前に USB のデジタルオーディオインターフェースを作った時に、バーブラウンの 24 ビット DAC などを買ったので、それを接続しようと思う~
S/PDIF 出力を行うには、RXD、TXD にターミナルを接続して、コマンドで設定が必要みたいだ。

IMG_0575s

APT-X/AAC などに対応した、USB アダプターは、最近ようやく入手出来るようになってきた。
※ドライバーがカスで、使えないやつもあるみたいなので注意!、MM-BTUD44 は、問題無く使えている。

アイデア次第で、自分だけのオーディオ機器を気軽に自作できて、これは流行りそうだなー

IMG_0577s
ラジオデパートの4階で、1個200円で売っていたスピーカー(F70A21-5)と、アンプを繋いで鳴らしてみた、このスピーカー、200円とは思えないwww、これは、ちゃんと箱に入れれば、普通に使えそうだなー

☆Bluetooth AUDIO としては、ポケットに入れて持ち運べるタイプも欲しい、そこで、ヘッドホンでの音を確認する為、ヘッドホンアンプとしては最強との呼び声の TI の TPA6120A2を繋いで視聴してみたー
RN-52 内臓の D/A コンバーターもそんなに悪く無い感じだ。
※TPA6120A2 は、+-両電源が必要なので、DC/DC(MAU106) コンバーターを使っている。
※一般に売っているタイプはスティックタイプで、凄く小さいけど、電池はあまり長持ちしないし、あそこまで小さい必要は感じないので、パワフルなアンプを入れてガッツリ作りたい。
やっぱりボリュームが欲しいなぁー
IMG_0579s