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

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

RX64M、GR-KAEDEのSPI、SDカードインターフェースの罠

GR-KAEDEにはRSPIを使った、SDカードインターフェースがある。

ところが、非常に不安定で、動作しない事が多かった。
実装はRX24Tでも実績のあるコードで、RX24Tでは何の問題も無く動作
しているものだった・・・

MMC/SDCの使い方
SDカードをSPIモードにするには、「DAT0」端子をプルアップしておく
必要があるのだが、回路図を観ると、GR-KAEDEには、プルアップが無い
ようだ、そこで、10Kでプルアップした。
しかし、全く効果は無かった。

電源ノイズによるものなのかとも思い、10uFをマイクロSDソケットの端子
に接続したが効果は無かった。

ソフト的に色々考えられる事を試したが、成果は無かった・・・

症状としては、初期化の段階で、SDカードをSPIモードに切り替える段階で
エラーになり、SPIモードにならないものだった。

SDカードの相性問題があるのかもしれず、試したが違うようだ(マイクロSD
を二種類しか持っていない)
※そもそも電気回路に「相性」のような不確定性があるハズも無い。
※ごく稀に動作する事もあるが、何かの拍子にすぐに不良になる。

約2日悩んだが、どうやら原因が判った。

RX64Mのデータシートを観ていて、気が付いた、何と、GR-KAEDEで
は、DAT0はPC7に接続している、しかも、この端子はリセット時にブート
モードを切り替えるMD端子でもある。
よくよく回路図を見ると、モード切替のDIP-SW付近で、4.7Kオームで
プルダウンされている。

あーーー、これだ・・・・・


そこで、1Kオーム位ででプルアップしたいが、それだと、ブート出来ない。
そこで、1KオームでPC3と接続しておき、SDカードの初期化時にPC3を
出力にして「H」を出力する事で、プルアップした状態を作る事にした。

この改修を行い、PC3の制御を足したら、当たり前だが、SDカードがSPI
接続出来るようになった。

-----
また、DAT0のプルアップは、必要無いカードもあり、状況を複雑にしている。

GR-KAEDEでSDカードを使っている人はどのように回避しているのだろ
うか?

追記:
ネットを調べたら、普通に情報があった(良く調べるべきだった・・・)
GR-KAEDEでSDカードにアクセスする場合について

RX64M、GR-KAEDEを試用してみた

GR-KAEDEを試用する機会があったので、少し内容に触れてみたい。

同時に、「RENESAS E1」も借りたので、それについても述べておく。

ルネサス関係のマイコンを集中して扱っているが、E1エミュレーターは、持って
いない。
理由として:
・値段が高い
・基本的に普段は詳細なデバッグを必要としない事が多い
※この理由が大きい、ターミナルデバッグで通常は十分
・ルネサスのIDEを使わない(購入するには高価すぎる)
・KPIT はフリーで使えるが、やはり、IDE が好きでは無いし、自分的には刺さらな

など、色々な理由がある、今回は、デバッガーとしてではなく、FlashROM
の書き換え時に、「Renesas Flash Programmer」でのみ利用した。
通常は、シリアルポートを使って書き込んでいるので、それに比較すると、書き込
み速度が速く、重宝した。

GR-KAEDEは、ハードとしては悪くは無いが、高すぎるので興味は無い。
※サポートや、色々考えると、まぁしょうがないのは理解できるが納得はできない。
※バッテリーバックアップ用の電池フォルダーくらいは付けて欲しかった。
・初期からSDRAMが載っているのは好印象。

GR-KAEDEに用意されているプロジェクトに関して:
とりあえず、WEBコンパイラで、簡単なコードを動かしてみて、動作確認し、自分
のシステムに、必要な部分を移植(主にイーサーネット関係のスタック)する為、
プロジェクト一式のソースコードを取得した。
※何故か、ビルドして出来た、mot ファイルをフラッシュに直接書いても動作しない。
スケッチとしてロードすると機能した、「まぁ、そういうものなのだろう」として
詳細な理由は調べなかった。

今まで、GR系のソースコードには触れていなかったのだが、開発期間が短いので、
色々調べたが、やはり既にある程度枯れているソースを再利用する事にした。

第一印象:
・CとC++のコードがあるが、どれも、品質がとても低い。
※ボードの価格に値しない、ソースコードの品質
・コーディング規約はほとんど守られていない。
※多分、会社内でコードレビューを行った事が無いのだろうな・・・
・関数名、クラス名、変数名のつけ方に一貫性がないのでわかり難い。
・C++のクラスがいくつかあるが、これはC++とは言えない(C+-だろうな)
※典型的な、C++を少しだけかじったCのプログラマーのコード
・色々なところに細かく罠とも思える実装依存が含まれている
※動作させるまでに、時間がかかった・・・
・設計が悪すぎで、典型的なスパゲッティーコードになっている。

そんなこんなで、動作させるまでに非常に時間がかかってしまったが、色々改修し
ながらコツコツを進めている・・・

R8C(M120AN)を使ったUSB、電流、電圧チェッカー(その2)

液晶のDPIが高い為、いつも使っている12×6ピクセルのフォントでは
小さすぎて見にくい(最近、視力が極端に落ちてる事も影響・・・)

とりあえず、24ピクセルのフォントを用意するまでの繋ぎで、縦横二倍
にして表示する事で、解像度を生かせないが、それなりの大きさになった。

※余ったスペースで、電力変化をグラフ表示した。

ケースに液晶の穴を開けたが、液晶への配線が邪魔で、蓋が閉まらないが、
何とか工夫すれば、閉まる感じではある。

単独で、電力のグラフ表示も追加した。

マイコンのアナログ入力はまだ余っているので、USBの差動信号電圧を測
定する機能も追加した。

まだ、ソフトを見直す余地はあるが、とりあえず完成とする。

-----
今後の改修予定:
・電力のグラフ表示のインターバル設定
・電圧、電流変化時のフィルター

などなど

R8C(M120AN)を使ったUSB、電流、電圧チェッカー(その1)

R8C(100円マイコン)では、多分始めてとなる実用的なサンプルだ。
※液晶の事故により、第二段となった・・

マイコンは100円だけど、ハイサイトの電流検出に210円のICを使っているのが
痛い・・・
まぁそれはそれとして、多少豪華な仕様(128×32グラフィックス液晶)にしてあ
る。

また見た目も重要なので、タカチ電機工業のケース(CS75N)に収まるように
製作した。

表示切替などを行う、スイッチも設けた。

問題となったのは、「クイックチャージ」をどうするかだ、この仕様では、最大20V
の電圧に対応する必要がある。
電源電圧が5~20Vも変化するとなると、部品の選定や回路設計が難しくなる。
自分は、そのようなデバイスを持っていないが、折角だから「対応」を視野に入れて製
作した。

・マイコンは3.3Vで動作させる。
※グラフィックス液晶が3.3V動作なのと、M120ANのA/D変換の基準電圧は
VCCと同等なので、電源電圧が正確である必要がある。
※5V~20Vから3.3Vを出力する事ができるレギュレーターを入れる。
・ハイサイト電流検出のIC、「LT6106CS5」は、都合の良い事に、最大36
VまでOKなので、これをそのまま使う。

-----

さて、製作してる過程で、配線を修正したり、オペアンプを追加したりしてたら、液晶
に余計な力がかかり、フレキが「ポロリ」ととれてしまいご臨終となった。

しばらくの間、その衝撃で、製作意欲が吹き飛んでいたのだが、秋月で、新たな液晶を
購入、入れ替えた・・・

この液晶、以前のより解像度が高いのだけど、表示面積は少し小さい、またバックライ
トも無いが、コントラストは良好なようだ。
解像度は、128×48ピクセルあり、フレームバッファを用意すると、768バイト
必要となる為、少ないRAMしかないM120ANでは、半分のフレームバッファを
用意して、二回に分けてレンダリングし、半分づつLCDに転送する事で、何とかやり
くりしている。

-----

ケースは、少し小さすぎで、色々削って、何とか入る余地を設けたが、もう少し大きい
方が良さそうだった・・・

基板に、フラッシュプログラムの切り替えや、シリアルコネクターを設ける余裕が無か
ったので、インライン6ピンの専用ラインを設けて、外部でフラッシュプログラム時の
切り替えやリセットなどを行うようにした。

※この段階では液晶の窓は、開けていない・・・

表示に使うフォントなど作り直す必要もあり、色々修正中ではあるけど、とりあえず、
電圧表示と、電流表示、経過時間表示などできたので、回路図を含めて、Gitに上げた。

USB チェッカー

R8C(M110AN)を使ったRCサーボテスター

100円マイコンR8Cには、14ピンの小型パッケージ(M110AN)が
ある。

今まで、ほぼ、20ピンの120ANを多用してきた為、あまり使う理由が無
かったので、今回、RCサーボテスターを作成し、小さいケースに収める事で、
14ピンパッケージの利便性を役立てた。

以前に、サンプルとして、2チャネルのRCサーボを制御する為のコードを実
装したが、これは、それを少しだけ修正して、シングルチャネルで動作させる
だけのものだ。
※ボリュームの角度により点滅速度を変化させるLEDインジケーターを追加
した。

タカチのケースに収める為、余分なスペースが無いので、6ピンのフラッシュ・
プログラム用コネクターを設けている。

インジケーターは、ケースに穴を開けて、グルーガンで塞ぎ、硬化したら、表
面の凸部分をカッターで削って平面にする。
最近良く使う手法で、こうする事で、かなり自由にLEDを基板に取り付けら
れる。
また、グルーガンのスティックが半透明なので、淡い発光で見栄えも良い。

RCサーボテスター回路図:

現状では、サーボのPWMパルスの仕様は、JRサーボ用にしてある。
※ソースコードの先頭で、フタバ用に切り替える事ができる。

// どちらか片方を有効にする
#define JR_TYPE_SERVO
// #define FUTABA_TYPE_SERVO

ソースコードと、KiCADのプロジェクトは、GitHub にプッシュ済み。

M705マウスの修理

最近、どうもボタンの調子が悪い、いわゆる「チャタリング」を起こす感じで、具合が
悪い。

このマウス、保障期間は3年と長いのだが、保障期間は過ぎている。
かと言って、買いなおすのももったいない。

ネットで調べると、同じような症状に悩んでいる人も多いようで、スイッチに使ってい
るマイクロスイッチを単体で入手する事が出来るので、自分も修理する事にした。

分解する場合に、この+ドライバーが、ピッタリだった。

ある程度値段のするマウスは、分解する事を前提に作られているためか、比較的容易に
分解できる構造になっている。

(1)まず、5箇所のネジを外して、上ケースを分離する、側面にあるスイッチ用のコ
ネクターを抜く(そこそこ硬いので注意)
※パッドの下に2本隠れているので、パッドを剥がす(両面テープで貼ってある)

(2)スクロールホイールを固定してあるピンを抜く。

(3)スクロールホイールを外して、ネジを4箇所外すと基板が取れる。
※電源コネクターを抜く(そこそこ硬いので注意)
※スクロールホイールボタン用の小さいバネがあるので、無くさないように!

(4)問題のスイッチを取り除く。

※十分溶かして、吸引機で吸い取る、ピンを左右に揺らした感触で、フリーになってい
るか、まだハンダが残っているか判断できる。
※サーマルリリーフがあってもパターンの面積が広いと、熱が拡散されて、ハンダが十
分に溶けないので、大きな容量のコテが必要。(自分は、アンテックスの60Wを使っ
た)
※80Wの温度調整機能付のコテでは、最大温度でもハンダがうまく溶けなかった。

(5)新品のスイッチを取り付けて完了。
・購入したスイッチと、古いスイッチ

・GNDはサーマルリリーフになっているので、コテの熱量が足りないとハンダ付けしにくい。

・右ボタン、左ボタンで向きが違うので注意

(6)各部品を元に戻して終了。

当たり前だが、チャタリングも収まって、調子が戻った~

scanfに対応するC++のクラスを作ってみる~

可変引数は「危険」なので、C++では「printf」を使わない文化がある。
それは、以前に説明した、しかしながら、printf のコンビニエンス性は捨てがたい、
そこで、boost::format に習って、組み込み向け utils::format クラスを提供した。


それでは、入力はどうしたものか・・・
一般的には、scanf を使って文字列中の数字を変換する。
しかし、scanf は C の API で、可変引数も使う、なので、format クラスに対応する
入力クラスも実装する必要性が大きい、そこで、input クラスを実装してみた。
※良くある、数字の変換に付き物の機能も追加した。

以下のように使う。

    int a;
    uint32_t b;

    int n = (utils::input("%d[, ]%x", "-99 100") % a % b).num();
    std::cout << a << ", " << b << std::endl;
    std::cout << "N: " << n << std::endl;

結果:

-99, 256
N: 2

上のサンプルでは、「%d」、「%x」の仕切りとして、「,」又は「 」(スペース)を
使う事ができる。
これは、正規表現に似た書式を簡略化したものだが、機能的には最低限の物しか無い。
※豊富な機能を盛り込むとコードが肥大化するし、たぶん実際には、それ程高機能で
無くても困らないと思えるからだ。

また、取り込んだ数は、「num()」を使って取得する事ができる。

input クラスの書式は以下のようになっている。

//-----------------------------------------------------------------//
/*!
    @brief  コンストラクター
    @param[in]  form    入力形式
    @param[in]  inp     変換文字列(nullptrの場合、sci_getch で取得)
*/
//-----------------------------------------------------------------//
basic_input(const char* form, const char* inp = nullptr);

basic_input クラス・テンプレートは、以下のように typedef されている。

typedef basic_input<def_chainp> input

ここで、「def_chainp」クラスは以下のようになっている。
自前の特殊クラスを作って食わせる事ができる。

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  標準入力ファンクタ
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
class def_chainp {
    const char* str_;
    char        last_;
    bool        unget_;
public:
    def_chainp(const char* str = nullptr) : str_(str), last_(0), unget_(false) { }

    void unget() {
        unget_ = true;
    }

    char operator() () {
        if(unget_) {
            unget_ = false;
        } else {
            if(str_ == nullptr) {
                last_ = sci_getch();
            } else {
                last_ = *str_;
                if(last_ != 0) { ++str_; }
            }
        }
        return last_;
    }
};

※「unget()」は、一文字を書き戻す。

input.hpp のプロジェクト

RXマイコン用、FatFsとシステムコール

データロガーの実装を進めるに中って、boost を使うようになった。
そうすると、どうしても「システムコール」を実装しなくてはならない状況にな
った。
これは、boost の動作で、ファイルを操作したり、標準出力を使っている為なの
だと思うが、リンク時一連のシステムコールがリンクできずににエラーを起こす。
※boost の内部設定を変更して、それらを使わないように「魔改造」する事も考
えられるが、それはそれで、大変と思うので、とりあえず、標準的な設定で何と
かなるよにしたい。

以前にSH2Aで、LCDの描画などを行った時にも、同じような事があり、実
装したので、どうすれば良いか、簡単に説明しておこうと思う。

まず、最低限必要なのが、標準入出力のしくみなどだ。

以下の関数を最低限実装する必要があるようだ、何か足りなければ、リンクエラ
ーが出るので、その都度追加すればよい。

int open(const char *path, int flags, ...);
int fstat(int file, struct stat *st);
int read(int file, void *ptr, int len);
int write(int file, const void *ptr, int len);
int lseek(int file, int offset, int dir);
int close(int file);
int isatty(int file);
void kill(int n, int m);
int getpid(int n);
void exit(int n);

また、固定のファイルディスクリプタとして以下がある:

stdin  : 0
stdout : 1
stderr : 2

これらは、オープンもクローズもできない、また、シークも必要ない。

「write」、「read」の中で、「file」が0、1、2の場合に、シリアル入出力へ
繋げば良いと思う。
「isatty」は、ファイルディスクリプターが端末を参照しているかをチェックす
る機能なので、これも実装しておく。
※そうすれば、「printf」は使えるようになる。(ただ、C++ ではあくまでも、
iostream が基本なのと、自分の実装では、format があるので必要無い、又、
iostream を使うようなコードを書くと、単純にメモリーが足りなくて、リンク
時にエラーを起こすだけではある)
※とりあえず、この程度なら、RL78やR8Cでも利用可能と思う。

//-----------------------------------------------------------------//
/*!
    @brief      ファイル記述子で指定されたファイルから指定バイトを読む
    @param[in]  file    ファイル記述子
    @param[in]  ptr     読み込み先
    @param[in]  len     読み込みバイト数
    @return     読み込みバイト数
*/
//-----------------------------------------------------------------//
int read(int file, void *ptr, int len)
{
    int l = 0;
    if(file >= 0 && file <= 2) {
        // stdin
        if(file == 0) {
            char *p = ptr;
            for(int i = 0; i < len; ++i) {
                *p++ = sci_getch();
            }
            errno = 0;
            l = len;
        }
    }
    return l;
}

//-----------------------------------------------------------------//
/*!
    @brief      ファイル記述子で指定されたファイルから指定バイトを書く
    @param[in]  file    ファイル記述子
    @param[in]  ptr     書き込み元
    @param[in]  len     書き込みバイト数
    @return     書き込みバイト数
*/
//-----------------------------------------------------------------//
int write(int file, const void *ptr, int len)
{
    int l = -1;
    if(file >= 0 && file <= 2) {
        if(file == 1 || file == 2) {
            const char *p = ptr;
            for(int i = 0; i < len; ++i) {
                char ch = *p++;
                sci_putch(ch);
            }
            l = len;
            errno = 0;
        }
    }
    return l;
}

//-----------------------------------------------------------------//
/*!
    @brief      ファイルディスクリプタが端末を参照しているかをチェックする
    @param[in]  file    ファイル記述子
    @return     端末を参照するオープンされたファイルディスクリプタ @n
                であれば 1 を返す。@n
                そうでなければ 0 を返し、 errno にエラーを示す値を設定する。
*/
//-----------------------------------------------------------------//
int isatty(int file)
{
    if(file >= 0 && file <= 2) {
        errno = 0;
        return 1;
    } else if(file < OPEN_MAX_) {
        errno = ENOTTY;
        return 0;
    }
    errno = EINVAL;
    return 0;
}

--------

FatFs を使って、SDカードにアクセスする場合は、GitHub の syscalls.cを参照してほしい。
RX24Tの場合、RAMは16Kしか無いので、記憶割り当てを実装するのは、
少しキビシイ、そこで、FatFsの設定では、「記憶割り当て」を使わない設
定にしている、そうすると、1個のファイルを開くのに必要なメモリーは、そこ
そこ大きく、最大オープン数を多く取るとスタテックにメモリーを消費する。
ファイルの先頭で、「OPEN_MAX_」を「4」と定義してある。
最大4つまでファイルを開く事ができる、通常これくらいあれば十分と思うが、
アプリにより最適な値を調整する必要があるかもしれない。
又、FatFSを使わない場合には、「FAT_FS」をコメントアウトして、
無効にする。

ファイルをオープンするパスは、UTF-8を使う、内部でShift_JIS
に変換されて、FatFSに渡される。

FatFsを使う場合、内部で「sdc_io」クラスと連携しているので、SDカード
の自動マウントなどを見守る必要がある。

RX24Tを使ったデータロガー(その1)

以前にATMegaを使ってデータロガーを作成したが、需要が無かったのと、
大きくて、使いかってが悪いなどで使わなくなっていた。
IMG_0904sIMG_0905sIMG_0906s

最近、需要が、少しではあるがありそうなので、最新のRX24Tで作り直す
事にした。
ソースは、ATMegaの物をなるべく利用するが、元はCで書かれているの
と、AVR用に特化している部分もあるので、C++で作り直す。

今度は利便性を第一に考えて、小型に作る。
とりあえず、タカチのケース(CS115N)に入るようにして、基板を起こす
予定でいる。
※最近は、基板を小ロット作成するのにかかるコストは凄く少なくなっている。
IMG_0907s

スペックや仕様は以下の通り:
・100Hzサンプリング
・ラップタイム入力
・G.P.S.入力
・加速度、ジャイロセンサー(MPU6050)
・速度(パルス)入力、2チャンネル
・回転(パルス)入力、1チャネル(エンジン回転用)
・アナログ4チャンネル
・SDカード対応
・128×64、液晶表示
・720mAリチウムポリマー電池と充電、3.3VDC/DC
・USB充電

RX24Tデータロガーリソース

RX24Tで内臓データフラッシュの読み書き

RX24Tの内臓データフラッシュの読み書きが出来たので、関係クラスと
サンプルを追加した。

RX24Tでは、内臓データフラッシュは8Kバイトあり、1Kバイト毎の
ブロックに分かれている。
※消去は、1Kバイト単位で行う。

以前、RL78では、内臓データフラッシュへのアクセスは、情報が公開さ
れておらず、使う事が出来なかった。
※操作ラブラリーだけが公開されており(gcc 版は無い)ソースコードや、
関係レジスターの説明等は未公開となっている為、実装をあきらめた。
※「公開できない」理由について、色々考えたりもしたが、それが、トリガー
となって、RL78からは疎遠になってしまった。

RXマイコンでは、アクセスが多少面倒ではあるものの、内蔵データフラッ
シュを使う事が出来る。(常識でもある)
また、ROMフラッシュ領域も、書き込みなどが行えるものの、操作が面倒
なのと、当面必要では無いので、実装していない。

データフラッシュは、消去が1バイト単位で出来ない(1Kバイト毎)ので、
汎用的なメモリーとして扱うようにするには、巧妙なマネージメントを必要
とする、これは、フラッシュの書き換え可能回数制限や、ブロック・イレー
スに、時間が多少必要など、フラッシュメモリーの特性が起因している。

データフラッシュの扱いは、RXマイコンで共通なら、問題は無いが、デバ
イスによって異なるようだ・・
今回、RX24T専用となったので、

RX24T/flash.hpp
RX24T/flash_io.hpp

専用のクラスを用意した。

ただ、データフラッシュに対する操作は同じ仕様とする。

//-----------------------------------------------------------------//
/*!
    @brief    開始
*/
//-----------------------------------------------------------------//
void start() const;

//-----------------------------------------------------------------//
/*!
    @brief  読み出し
    @param[in]   org   開始アドレス
    @return データ
*/
//-----------------------------------------------------------------//
uint8_t read(uint16_t org) const;

//-----------------------------------------------------------------//
/*!
    @brief  読み出し
    @param[in]  org     開始アドレス
    @param[in]  len     バイト数
    @param[out] dst     先
*/
//-----------------------------------------------------------------//
void read(uint16_t org, uint16_t len, void* dst) const;

//-----------------------------------------------------------------//
/*!
    @brief  消去チェック
    @param[in]  bank    バンク
    @return エラーがあれば「false」
*/
//-----------------------------------------------------------------//
bool erase_check(data_area bank) const;

//-----------------------------------------------------------------//
/*!
    @brief  消去
    @param[in]  bank     バンク
    @return エラーがあれば「false」
*/
//-----------------------------------------------------------------//
bool erase(data_area bank) const;

//-----------------------------------------------------------------//
/*!
    @brief  書き込み
    @param[in]  src     ソース
    @param[in]  org     開始オフセット
    @param[in]  len     バイト数
    @return エラーがあれば「false」
*/
//-----------------------------------------------------------------//
bool write(const void* src, uint16_t org, uint16_t len) const;

//-----------------------------------------------------------------//
/*!
    @brief  書き込み
    @param[in]	org	開始オフセット
    @param[in]	data	書き込みデータ
    @return エラーがあれば「false」
*/
//-----------------------------------------------------------------//
bool write(uint16_t org, uint8_t data) const;

データ・フラッシュ・サンプル