フォト
2025年3月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
無料ブログはココログ

« 2015年3月 | トップページ | 2015年5月 »

2015年4月の12件の記事

2015年4月30日 (木)

書籍「挿すだけ!ARM32ビット・マイコンのはじめ方」を購入

最近マイブームのLPC810関連の書籍「挿すだけ!ARM32ビット・マイコンのはじめ方」を
購入しました。

Dscn3779

こちらの書籍の方が、ちょっと前に購入した「ボクのLPC810工作ノート」よりも
私向きでした。ライブラリとしてはCMSIS_COREのみの利用なので、LPC810の
「ハードウェアを自分で操る」というプリミティブな楽しみが味わえます。
こちらの方かLPC810の習得には向いていると思います。

「ボクのLPC810工作ノート」は工作事例集っといった感じです。
これはこれで、参考書的に使えます。

徐々に、Arduinoから徐々にARM+mbedと方向転換していきます。
ARM(というか32ビットCPU)の方が慣れると楽です。開発環境でデバッガが使える等、
大人(プロ)の環境です。

2015年4月28日 (火)

IchigoJamでシフトレジスタを利用してみる

以前、arduino用に製作した4桁 7セグスタティック表示ボードをIchigoJaimに
接続してみました。

仕組み的には、74HC595 という8ビット出力シフトレジスタを4連結して出力
32個のLEDをON/OFFをしています(1桁で8個のLED、4桁で32個のLED)。

IchigoJamとの接続はVCC、GND、OUT1、OUT2、OUT3の4線のみです。


Dscn3777

回路図的には、下記のようか感じです。



ボードのGND                 → IchigoJam のGND に接続
ボードの5V(実際は3.3V)  → IchigoJam のVCC に接続
ボードのclock        → IchigoJam のOUT1 に接続
ボードのlach                  → IchigoJam のOUT2 に接続
ボードのDATA               → IchigoJam のOUT3 に接続

若干、電力不足(1つのLEDにつき510Ωの抵抗を付けており、LED当たり2.8mAしか
流れませんが全点点灯すると、90mAとなりIchigoJamの3.3V三端子レギュレータの
50mAを超えてしまいます)ですが、実験ですのでよしとします。
プログラムは、こんな感じです。

100 ' OUT1: CLOCK, OUT2: LACH, OUT3: DATA
130 LET [0],`11111100,`01100000,`11011010,`11110010
140 OUT2,0 :'Lach :LOW
150 FOR N=0 TO 3
160 D=[N]:GOSUB 500
170 NEXT
180 OUT2,1:'Lach :HIGH
190 END
500 'FUNC D:data
510 FOR I=0 TO 7
520 OUT 1,0 :'clk :LOW
530 OUT 3, D>>I & 1: 'DATA out
540 OUT 1,1 :'clk :High
550 NEXT 
560 RETURN

手順
1)LachピンをLOW設定して、データ送信開始(140行)
2)クロックピンをLOWにした後、データピンにデータをセット(520行、530行)
3)データピンにデータセット後、クロックピンをHIGHにしてデータ確定(540行)
4) 2)3)を繰り返して、送信に必要なビットデータを送信(510行 FOR文~550行 NEXT文)

5)LachピンをHIGHに設定して、内部レジスタの値をパラレルポートからデータ出力(180行)

意外と簡単に、出力ピン増やせます。

2015年4月27日 (月)

Aliexpressでブレッドボード用電源を購入しました

Aliexpressでブレッドボード用に使えそうな電源(5V、3.3V用)を見つけて購入しました。

01

1個99円です。安いですね。2つ購入しました。

10日くらいで届きました。実物はこれです。

Dscn3768

ブレッドボードに乗せると、ちょうどいい感じの大きさです。
基板上にジャンパ・ピンが2つあり、ブレッドボードの両端のそれぞれの電源出力を
5V、3.3Vのいずれかに設定出来ます。

Dscn3770

まずは、USBで接続して3.3Vの出力を試しました。

Dscn3773

次にACアダプターでDC12Vを供給してみます。

Dscn3774

問題なく使えそうです。

5Vも試してみました。

Dscn3775

問題なさそうです。

006P(9V乾電池)でもいい感じに使えます。

Dscn3776

商品説明では、700mAまで対応しているとのことです。
送料込みで99円1個買いもOK、安すぎです。原価はいくらなんでしょう。


2015年4月26日 (日)

IchigoJamで疑似グラフィックを使った画像の表示

IchigoJamの画面表示解像度は、キャラクタ文字 横32文字×縦24行ですが、
次のキャラクタが用意されており、疑似的に64×48のグラフィック表示が出来ます。

01

キャラクタコード 0x80(IchigoJamでは #80と表記)~ 0x8Fの16文字が割り当てています。
これを使って、疑似的に64x48ドットの画像を表示してみます。

まずは、表示したい絵をペイントツールで作成します。画面いっぱいに表示する大きさの
64×48ドットで作成します。色はモノクロ(白、黒の2色)を指定します。

03

作成した画像を保存します(ファイル名はcat.bmp)。

次に、この画像からIcigoJamのキャラクターコードに変換します。
4ドットが1文字(0x80~0x8F)に対応する形で変換します。

手作業でやるのも大変なので、ツールを作成して変換しました。
ツールはこちらからダウンロード(ダウンロード後、IchigoBmpConv.zipを
マウス右ボタンでプロパティを開いてセキュリティブロックを外してから
解凍して下さい)できます。

Photo

作成した画像ファイルを指定し、[ソース出力]ボタンをして
IchigoJam BASICのソースを出力します。
Windows上で開くと意味不明の内容です。

Photo_2

これをIchigoJamに転送して実行します。

20150425001801

実行すると、画像が表示されます。340行で無限ループとなっているので
中断する場合は[ESC]キーを押します。

20150426083128

空き領域を調べると52バイトしかありません。
これだと他に何も出来ないですね。

そこでツールでバイナリ出力してEEPROMに格納して
IchigoJamのI2CRコマンドで表示出来るかを試してみました。

IchigoJamにI2CインタフェースのEEPROMを接続します。

Dscn3767

プログラム自体は6行だけです。

 10 FOR I=0 TO 4
 20 POKE #700,I*3,0
 30 R=I2CR(#50,#700,2,#900,768)
 40 WAIT 30
 50 NEXT
 60 GOTO 10

5枚の絵を切り替えて表示しています。WAIT命令を入れないといけないくらい
高速で表示出来ました。ちょっとしたアニメーション表示が可能ですね。

こプログラムの内容ですが、
  R=I2CR(#50,#700,2,#900,768)
でI2Cアドレスが#50のEEPROMに対して、一画面分の画像768バイトを取得し
IcihoJamの画面表示用のメモリ #900に書き込むことを行っています。

事前のPOKE #700,I*3,0でEEPROMの読出しアドレス2バイトをIcihoJamの
メモリアドレス #700 設定しています。
1画面分768バイトは16進数では#300ですので、Iの値に応じて
#300、#600、#900、・・・ と5枚分の画像の先頭アドレスを指定しています。

I2CRコマンドの使い方については、
 IchigoJam 情報サイト 「イチゴジャム レシピ」 http://15jamrecipe.jimdo.com/
BASIC コマンド一覧I2CRの解説が分かりやすいです。

IchigoJamでは、内部メモリの情報が公開されおり、
EEROMから読み取ったデータを直接変数領域に格納したりも出来ます。
配列に一気に格納とか、プログラム領域自体も変更できます。

以下は IchigoJamのメモリマップと演算子優先順位よりコピペの内容です。

仮想アドレス           機能
#000-#6FF   キャラクターパターン #00〜#DF (読み取り専用)
#700-#7FF   書換可能キャラクターパターン(PCG) #E0〜#FF
#800-#8FF   2byte符号付き整数の変数(配列0〜101、変数A〜Z)
#900-#BFF   画面キャラクターコード(VRAM) 32x24
#C00-#FFF          プログラム(行番号(2B)、サイズ(2B)、テキスト)

頑張れば ROM版 アドベンチャーゲームなんかが作れそうです。


2015年4月23日 (木)

arduinoでPS/2キーボードのエミュレーションを行う その2

前回の続きです。

全てのキーについて対応しました。

Windows上のキー入力を全てキャプチャーしてそのキーに対応する
スキャンコードを送信するアプリをVBで作成しました。



IchigoJamのスクリーンエディタでのカーソルキーやBackSpace、ファンクションキー、
等の利用が出来ます。

Windows上でキャプチャー画面を見ながら、windowsのキーボード操作で
IchigoJamの全ての操作が可能です。

20150423

キー入力キャプチャーはこんな感じです。フォーカスが無くてもWindows上の全ての
キーボード操作をキャプチャーし、キーボードに対応するスキャンコードを
arduinoに送信します。

01

arduinoは受信したスキャンコードをPS/2インタフェースにてIchigoJamに送信します。
IchigoJamは、キーボードが繋がっていると思い込んで、キー入力に対応する処理を
行います。

これは、結構よい感じです。ちょっと大がかりな感じがしますが...

入力キーに対応するスキャンコードの変換をWindows側で行うようにしたので、
arduinoのプログラムは前回よりもシンプルになりました。
#include "ps2dev.h"

PS2dev keyboard(3,2); 
int enabled =0; 
int code;

void ack() {
  while(keyboard.write(0xFA));
}

int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF:  ack();
    while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: // Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。その後キーボードはセルフテストを実行する。
    ack();
    break;
  case 0xF6: // set defaults: 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //disable data reporting: 起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //enable data reporting : キースキャンを開始する
    //FM
    enabled = 1;
    ack();
    break;
  case 0xF3: //set typematic rate/delay : 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xF2: //get device id : 
    ack();
    keyboard.write(0xAB);
    keyboard.write(0x83);
    break;
  case 0xF0: //set scan code set
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xEE: //echo :キーボードが接続されている場合、キーボードはパソコンへ応答(ECHO Responce)を返す。
    //ack();
    keyboard.write(0xEE);
    break;
  case 0xED: //set/reset LEDs :キーボードのLEDの点灯/消灯要求。これに続くオプションバイトでLEDを指定する。 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  }
}

void setup() {
  Serial.begin(115200);
  // send the keyboard start up
  while(keyboard.write(0xAA)!=0);
}

void loop() {
  unsigned char c;  // PCからの送信データ
  uint8_t inkey;    // シリアルポートからの取得文字コード

  if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  } else {
    if (Serial.available()>0 ) {
      inkey = Serial.read();
        keyboard.write(inkey);     
    }
  }
}

キー操作キャプチャーはちょっと危険(犯罪に利用できるという意味で)なので、
ソースは公開出来ません。

今回の実験で、
  「PS/2インタフェースの入力デバイスを簡単に製作できそうだ」
いう感覚をつかむことが出来ました。

関連記事

2015年4月22日 (水)

書籍「ボクのLPC810工作ノート」届きました

2015/04/30 追記
 本誌を購入するなら、株式会社 ラトルズでユーザー登録後、同HPで
  購入がお得です。ユーザー登録で500円分のポイントをもらった後に
 購入すれば、送料無料なので500円引きで購入出来ます。


amazonで注文していた書籍 「ボクのLPC810工作ノート」が届きました。

Dscn3760

かなりの良本です。写真や図解がいっぱいの丁寧な解説です。

Dscn3761

Dscn3763

PDF無料サービスですとな!

Dscn3762_2

PDF版のダウンロードには、ユーザー登録とレシートを撮影した画像を送信
する必要があります。

早速、ユーザー登録してamazonで購入した領収書の画像を送信して
申し込みました。

10分もしないうちにメールが送信されて、ダウンロードの案内が来ました。
早速ダウンロードしてPDF版をゲットしました。

02

この出版社 「株式会社 ラトルズ」、今回初めて知ったのですが好きになりました。
面白そうな書籍が結構あります。これもいいかも。

03

会社案内を見ると、大手ではない(弱小企業)ですが、いい仕事しています。

04

応援したいですね。

さて、CQ出版からもLPC810の書籍が4/25に発売されます。
「挿すだけ! ARM32ビット・マイコンのはじめ方」

ただし、こちらの書籍は見本をみると微妙かも。
トラ技のLPC810の記事のCD-ROM添付ソースも素人の私が見ても
欠陥ライブラリソース流用で問題点ありまくりだったので..

2015/04/26 追記
本誌、プログラムの実装においてはライブラリとしてLPCOpen(lpc_chip_8xx)を
使っています。そのため、プログラムサイズがちょっと大きくなってしまいます。
フラッシュメモリが4kバイトしかない状況で、これはちょっと辛いかも。

また、LPCOpenを使うのでLPC810のレジスタ構成や詳細機能を使い込む
勉強が出来ないのもちょっと残念。

arduinoでPS/2キーボードのエミュレーションを行う

IchigoJam用の仮想キーボードでも作ろうと思い、
まずはarduinoでPS/2キーボードのエミュレーションを行ってみました。

06

まずは、上の図の感じでパソコン上でIchigoJamのキーボードをパソコンで
完全操作できるようにしてみます。

arduinoでPS/2インタフェースのキーボードやマウスを実装は、
公開されている ps2dev というライブラリを利用することで比較的簡単に実現できます。
ps2devライブラリ PS2 mouse interface for Arduino

実装例を探してみると下記サイトでWiiのヌンチャクリモコンをarduinoに接続し、
パソコンでPS2/2キーボードとして利用する例がありました。
内容的は大変参考になりました。

また、PS/2インタフェース、JISキーボードのスキャンコード関連の情報として
下記の情報を参考にさせて頂きました。
  ・Sazanami Online PS/2 インターフェイスの研究
  ・PS/2キーボードインターフェース http://www.technoveins.co.jp/technical/keyboard/
  ・O-Family   JIS配列 PS/2 キーボード スキャンコード表

取りあえず、動作確認の試作として
TeraTermで入力した文字をシリアル通信経由でarduinoに送信し、
その文字に対応するキーコード(スキャンコード)をPS/2インタフェースで
IchigoJamに送信するプログラムを作ってみました。

結線はこんな感じです。IchigoJamoとの接続は3線(GND,KBD1,KBD2)です。
arduinoは3.3Vで稼働させています。

Dscn3758

KBD1、KBD2、GNDを接続

Dscn3759

実際に動かしてみると、簡単にエミュレーションできました。
取りあえず、半角英数記号と、バックスペース、Enterキー、ESCを使えるようにしました。
全てのキーには対応していませんが、いけそうです。

これならIchigoJam BASICのINKEY()にも対応できます。ゲームパッドも作成可能です。

20150422105156

ps2devライブラリを見ると、LPC810にも移植可能そうです。
最終的にはLPC810を使った小型モジュール化LPC810で動かしてみたいと思います。

ただし、TeraTermではALTキーなのど特殊キーのコードを拾うのは無理なので、
Windows上でキーイベントを拾ってシリアル通信でキーコードを送信する
アプリケーションの作成も必要になりますね。

ソースはこんな感じとなります。

#include "ps2dev.h"

#define TM_PRESS 2

// スキャンコード(A-Zのキー)
uint8_t kcode[]= {
  0x1c,0x32,0x21,0x23,0x24,0x2b,0x34,0x33,0x43,0x3b,
  0x42,0x4b,0x3a,0x31,0x44,0x4d,0x15,0x2d,0x1b,0x2c,
  0x3c,0x2a,0x1d,0x22,0x35,0x1a
};

// スキャンコード(0-9のキー or '!'-')'の文字)
uint8_t kcode_num[]= {
  0x45,0x16,0x1e,0x26,0x25,0x2e,0x36,0x3d,0x3e,0x46
};

PS2dev keyboard(3,2); 
int enabled =0; 
int code;

void ack() {
  while(keyboard.write(0xFA));
}

int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF:  ack();
    while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: // Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。その後キーボードはセルフテストを実行する。
    ack();
    break;
  case 0xF6: // set defaults: 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //disable data reporting: 起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //enable data reporting : キースキャンを開始する
    //FM
    enabled = 1;
    ack();
    break;
  case 0xF3: //set typematic rate/delay : 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xF2: //get device id : 
    ack();
    keyboard.write(0xAB);
    keyboard.write(0x83);
    break;
  case 0xF0: //set scan code set
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xEE: //echo :キーボードが接続されている場合、キーボードはパソコンへ応答(ECHO Responce)を返す。
    //ack();
    keyboard.write(0xEE);
    break;
  case 0xED: //set/reset LEDs :キーボードのLEDの点灯/消灯要求。これに続くオプションバイトでLEDを指定する。 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  }
}

void setup() {
  Serial.begin(115200);
  // send the keyboard start up
  while(keyboard.write(0xAA)!=0);
}

void loop() {

  unsigned char c;  // PCからの送信データ
  uint8_t inkey;    // シリアルポートからの取得文字コード
  uint8_t code;     // シーケンスコード 
  uint8_t shifton;  // シフトキーの状態

  if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
    while(keyboard.read(&c)) ;
    Serial.println(c,HEX);
    keyboardcommand(c);
  } else {
    if (Serial.available()>0 ) {
      code = 0;
      inkey = Serial.read();
      Serial.write(inkey);
      Serial.write(':');      
      Serial.println(inkey,HEX);
    if ( inkey >='a' && inkey <='z') {
        // a-zの文字
        shifton = 0;
        code = kcode[inkey - 'a'];
      } else if (inkey >='A' && inkey <='Z') {
        // A-Zの文字
        shifton = 1;
        code = kcode[inkey - 'A'];        
      } else if (inkey >='0' && inkey <='9') {
        // 0-9の文字
        shifton = 0;
        code = kcode_num[inkey - '0'];
      } else if (inkey >='!' && inkey <=')') {
        // '!'-')'の文字
        shifton = 1;
        code = kcode_num[inkey - '!'+1];
      } else {
        code = 0;
        shifton = 0;
        switch(inkey) {
          case 0x2d: code = 0x4e; break; // -
          case 0x5e: code = 0x55; break; // ^
          case 0x5c: code = 0x6a; break; // \
          case 0x40: code = 0x54; break; // @
          case 0x5b: code = 0x5b; break; // [
          case 0x3b: code = 0x4c; break; // ;
          case 0x3a: code = 0x52; break; // :
          case 0x5d: code = 0x5d; break; // ]          
          case 0x2c: code = 0x41; break; // ]
          case 0x2e: code = 0x49; break; // ` 
          case 0x2f: code = 0x4a; break; // /
          //case 0x5c: code = 0x51; break; // \ '
          case 0x20: code = 0x29; break; // \ ' 
          case 0x08: code = 0x66; break; // Bksp
          case 0x0d: code = 0x5a; break; // enter
          case 0x1b: code = 0x76; break; // ESC
        }
        if (!code) {
          shifton = 1;
          switch(inkey) {
          case 0x3d: code = 0x4e; break; // =
          case 0x7e: code = 0x55; break; // ~
          case 0x7c: code = 0x6a; break; // |
          case 0x60: code = 0x54; break; // `
          case 0x7b: code = 0x5b; break; // {
          case 0x2b: code = 0x4c; break; // +
          case 0x2a: code = 0x52; break; // *
          case 0x7d: code = 0x5d; break; // ]
          case 0x3c: code = 0x41; break; // } 
          case 0x3e: code = 0x49; break; // <
          case 0x3f: code = 0x4a; break; // >
          case 0x5f: code = 0x51; break; // _
         }
      }
    } 
      // PCに押したキーのシーケンスコードを送信
      if (code) {
        if (shifton) {
          keyboard.write(0x12);  // シフトキーを押した
        } else {
          keyboard.write(0xF0);  // シフトキーを離した 
          keyboard.write(0x12);  
        }          
        keyboard.write(code);    // キーを押した
        delay(TM_PRESS);
        keyboard.write(0xF0);    // キーを離した 
        keyboard.write(code);        
      }
    }
  }
}

関連記事

2015年4月20日 (月)

Nexx WT3020FをOpenWrt化しました

Aliexpressで購入したNexx WT3020FOpenWrt化しました。

Dscn3743

本製品はCPUとしては、MediaTek社製のMT7620n(580Mhz)を搭載しています。
このサイズとしては、パワフルなCPUを積んでいます。
その他のスペックはRAM 64MB、フラッシュメモリ8MB、有線LAN 100Mbps x 2、
無線LAN (802.11N MiMo 2x2、USB 2.0ポートx1)といった感じです。

ちなみに、上海問屋で同OEM製品(技適OK)が製品が販売されています。

管理画面

02

SSHで接続

03

TL-WR703Nと比べると、サクサク動きます。

名機TL-WR703Nとの大きさの比較

Dscn3745

ただ、本機を含めMediaTek社製 CPU MT7620が乗っている OpenWrtはまだ
開発途中のようです。まだUSB用のドライバがあまり用意されていませんでした。
USBメモリやUSB-Serialが使えません。現状は何もできないですね。

自分で開発環境を用意して移植するしかないです。

TL-WR703Nだと、下記のように豊富にあります。

01

USB-SerialドライバもCH341、CP210x、ftdi、pl2303と使えます。

元のファームウェアに戻して、小型NASとして使った方が良さそうです。
元のファームウェアがどこにもない。

とりあえず、このまま使うか。




2015年4月16日 (木)

Aliexpressで注文した商品が40日経っても出荷されない

Aliexpressで小型のUSB-UART変換モジュールを注文したのですが、
40日経っても出荷されず、時間切れで返金となりました。

02

売り手に、何回も在庫があるのに遅れている理由や出荷予定を問い合わせたのですが
回答なしの無言状態でした。

01

最後には、こちらも怒りが爆発です。

03

既に100回近くAliexpressで買い物をしていますが、こんな業者は初めてですね。
時間切れはキャンセル扱いとなり、売り手の評価をつけられないんですよねぇ。

取扱い商品数が多いように見せかけてるんですかね。

2015年4月15日 (水)

LPC810を使ったUART-I2Cブリッジがやっと出来ました

ゼロからのLPC810の利用だったため、学ぶことが多くちょっと時間がかかりましたが、
とりあえずプログラムは完成です。

まだ未熟ですがソースを置いておきます(2015/04/18 ソースを更新しました)。
開発環境は LPCXpresso v7.6.2+CMSIS_CORE_LPC8xxです。
  ダウンロード UART2I2C_050418.zip (226.9K)

コマンドマニュアル(PDF形式) 2016/07/16 追加
ダウンロード UART-I2C_DOCV1L3PDF.zip (279.3K)

以後、下記で修正版等を公開します。
https://github.com/Tamakichi/LPC810-UART-I2C-Bridge

シリアル通信でコマンドを流してI2Cバス接続のデバイスの操作ができるようになりました。
さすがにATtiny13Aよりは処理が早いです。

Dscn3729

上の写真の表示をするには、次のようなコマンドをシリアル通信で送り込みます。
@cA000@h01380c
@cA080@sHello!World!
@cA000@hc0
@cA080@sThis is LPC810!

01

実行すると応答を返します(返さないように指定も可能)。

I2Cモジュールを気軽に調査できます。
シリアルからコマンド送信でユーザーフォント登録をやってみました。

Dscn3731

デバイスの機能調査、テストがノープログラミングでできるのは意外と良いです。

IchigoJamにも接続してみました。(2015/04/18 追記)

Dscn3736

ちゃんと表示出来ました。

Dscn3735

IchigoJamのプログラムと実行はこんな感じです。
単純にプリント命令(?は PRINTの短縮)で出力してシリアル出力をしています。

01

"wait 10" で10ミリ秒の待ちを入れないと正常に動作しませんでしたが、
まあ、よいでしょう。

コマンドとしては次のようなものが使えます。(2016/07/14 追記)

  一括データ送信           @w[I2Cアドレス][送信データ指定部][改行]
  一括データ送受信        @r[I2Cアドレス][受信データ長][送信データ指定部][改行]
  一括データ受信           @g[I2Cアドレス][受信データ長][改行]
  1バイト単位データ送信 @c[I2Cアドレス][制御データ][送信データ指定部][改行]
                                   送信データ指定部のデータを1バイトづづ制御データを付加
                                   して個別のトランザクションにて送信します。下記と等価です。
                                              @w[I2Cアドレス][制御データ][送信データ指定部1バイト目] [改行]
                                              @w[I2Cアドレス][制御データ][送信データ指定部2バイト目] [改行]
                                              @w[I2Cアドレス][制御データ][送信データ指定部3バイト目] [改行]
                                                                                   ・・・・

また、送信データは次のような感じで指定します。
   16進数可変データ  @h[2桁16進文字列][2桁16進文字列][2桁16進文字列] …
   可変文字列データ  @s[文字列]

   16進数可変データと可変文字列データは連結して利用することも出来ます。
      @h0102ABabffCCcc@sHello!World@h1234

さらに、デバッグ用、受信データの形式指定、ウェイト時間指定、エラー情報指定を
行うコマンドがあります。

詳細については、別途記載する予定です。

さて、LPC810を使った感想ですが、
組み込み用 32ビットマイコンは意外と使いやすいですね。
もう、同じ8ピンのATtiny13Aを使う気にはなれません。

SRAMが1kバイトあるとデータ処理が楽できます。
ATtiny13Aの64バイトSRAMからすると1kバイトは広大な空間です。

ただし、ライブラリやドキュメントをもう少しなんとかしてほしいです。
LPCXpressoのlpc800_driver_libがダメすぎで、結局データシートを見て
UART、I2C回りの処理はほぼ自作になってしまいました(その分勉強になりましたが)。
UART、I2Cは割り込みを使わないで実装しました。

「ARM® Cortex™マイクロコントローラ ソフトウェア インタフェース規格(CMSIS)」
って何だったんでしょうかね。期待しすぎました。

また、ARM系のCPUはコードの生成効率が良いと聞きましたが、
結構ソースを書いた割にはプログラムサイズは3kバイト弱程度のサイズでした。
AVRよりも効率が良い感じです。

今後はLPC810を積極的に使っていきたいと思います。

回路図はこんな感じで、単純なものです。プログラムの作成に時間がかかりました。

02
スイッチマトリックスの3番ピン、4番ピンにI2CのSCL、SDAを割り当てています。
UART用に2番ピン、8番ピンにTXD、RXDを割り当てています。

Dscn3730

手持ちのEEPROMへのデータの読み書き、リアルタイムクロックの設定、参照も
問題なく出来ました。

次の目標として基板実装して、石鹸(Nexx WT3020F)につなげてみたいと思います。

Dscn3732

2015/04/19 追記
基板実装しました(不足気味、ブレッドボード2枚回収)。

Dscn3742

裏は、段ボールをねじ止め

Dscn3741


一応、今回は実装前に配線図をEXCELで作成しました。

02
IchigoJamに接続

Dscn3737

問題なく動作しました。

2015/05/17 追記
エラーコードと補助コマンドについて追記します。

エラーコード

00 正常終了
01 タイムアウト
02 スレーブからNACKを受信
03 I2Cアドレス送信エラー(NACK)
04 スレーブにデータ送信でNACKを受信
05 データ受信失敗
0A コマンドエラー
0B 16進数文字異常
0C パラメタエラー
0D 未定義コマンド
0E 補助コマンドのみ指定
0F コマンドのデータがない

補助コマンド

補助コマンドについて
送受信コマンドに付加して利用します。
@iN :IchigoJamモード N:1 有効、0:無効 エラー通知等を REM(')文付きで帰す
@eN :エラー通知設定 N:0or1 0:通知なし(デフォルト) 1:通知あり
@oN :受信データ出力モード設定 N: 0:HEX(デフォルト) 1:バイナリ 2:16進ダンプ表示
@DN :デバッグ情報表示 N: 0:OFF 1:ON
@tCC :データ送信(1バイトづつ)のウエイト時間(msec)指定 CC: 00 ~FF
@TCC :即時ウェイト実行 時間(msec)指定 CC: 00 ~FF
@v :バージョン表示


2016/07/16 追記 コマンドマニュアル(PDF)より抜粋

Command

Error

関連記事
LPC810を使ったUART-I2Cブリッジの改良版が出来ました (16/07/21)
LPC810を使ったUART-I2Cブリッジの機能拡張の検討中 (16/07/13)
UART-I2Cブリッジの使い方 - リアルタイムクロックの調査 (15/05/17)
Wiiヌンチャクの動作確認しました (15/05/17)
LPC810を使ったUART-I2Cブリッジがやっと出来ました (15/04/15) [この記事です]
ATtiny13AでUART-I2Cブリッジを試作したが微妙 (15/03/29)
ATtiny13AでUART-I2Cブリッジの製作 - まずその準備3 (15/03/26)
ATtiny13AでUART-I2Cブリッジの製作 - まずその準備2 (15/03/25)
ATtiny13AでUART-I2Cブリッジの製作 - まずその準備 (15/03/24)

公開・ダウンロードサイト
GitHub - LPC810 UART-I2Cブリッジモジュール

2015年4月 8日 (水)

IchigoJamにプログラムをアップロード/ダウンロードするGUIツールを作成しました

** 2015/05/24 更新 ****** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 
   公開プログラムを更新しました。修正内容は下記の通りです。
    ・IchigoJamの特殊キャラクタのダウンロード時に発生する不具合の対応を行いました。
    ・ファイルの読み書き、シリアル通信異常時のエラー処理を追加しました。
**** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** *

IchigoJamにプログラムをアップロード/ダウンロードするツールの
GUI環境版を作成しました。Windows環境で利用できます。
以前のコマンド版よりは使い勝手が良くなったと思います。

画面はこんな感じです。

040801

ダウンロード完了時は、メモ帳で開くことが出来ます。

040802
まだ、異常系のテスト不十分なところもありますが、公開いたします。
自由にご使用下さい。

下記のリンクからダウンロードできます。
  https://nuneno.cocolog-nifty.com/download/Ichigotool_vb3.zip

インストーラーは用意していません。
環境によっては別途、ランタイムモジュールのインストールが必要に
なるかもしれません。
圧縮ファイル Ichigotool_vb.zipを解凍後、Ichigotool.exeをを起動してください。
ダウンロード時に、ブラウザによっては警告が表示される場合がありますが、
継続等を指定してダウンロードして下さい。
また、Ichigotool.exeにセキュリティブロックがかかる場合があります。
プロパティを開いて、ブロック解除を行ってください。

使い方は、添付のREADME.TEXをお読み下さい。
読まなくても画面のボタンを見れば(触れば)わかると思います。

なんか、初めからGUI版を作ればよかった気がしますね。

関連記事
エクスプローラの「送る」でIchigoJamにプログラムをアップロードする

2015年4月 5日 (日)

LPC810でI2Cでフリーズする

ここ数日、8ピンDIP マイコン LPC810を使って試行錯誤しています。

作業効率を上げるため、実験するボードを作成しました。
まあ、秋月電子のLPC810の商品情報の
「ボクのLPC810工作ノート発売決定!(株式会社ラトルズ)」の実験ボートを
まねて作っただけですけどね(この書籍は早速、予約注文しました)。

Dscn3713

開発は、LPCXpresso v7.6.2 を使っています。
トラ技2014年2月号と、開発ツールのサンプルライブラリソースを利用して
タイマー、Lチカ、シリアル通信(UART)、I2Cとなんとか理解して動かせるようになりました。

ただし、I2Cの振舞が今一納得がいかず悩んでいました。
LPC810でI2Cでフリーズする
って問題にぶち当たりました。

正常にデバイスが動作している場合は問題ないのですが、
バス上に指定したアドレスのデバイスがなかったり、デバイスの調子が悪く
ACKを返さない場合、フリーズするようです。

LPCXpressoのサンプルライブリを使って発生しました。

トラ技2014年2月号のLPC810でI2Cのサンプルソースを
使っても同じ症状が発生しました。

まあ、正常時は問題ないのですが、
さすがに、バス上に存在しないアドレスを指定するとフリーズするのは
無視できないですね。

色々と調べて、次の記事に答えを見つけました。
LPC812 i2c freezes http://www.lpcware.com/content/forum/lpc812-i2c-freezes

問題発生の原因は、
From what I can see, the I2C_MstSend function doesn't look for NACKs.
It checks for errors and then attempts retransmits, but for NACKs it loops busily,
and will never exit. Here's some code that might help you to understand how
nacks are detected in the I2C.


LPCXpressoのI2CサンプルライブリのMstSendがNACKを見ていないとのこと。
エラーは検出して再送信を繰り返しているようですが、NACKの場合のは
処理を終了する必要があります。

このため、存在しないデバイスのI2Cアドレスを指定すると
無限ループになってしまうようです。

とりあえず、この記事内容の対応方法を参考にしてソースを修正しました。

//void I2C_MstSend( LPC_I2C_TypeDef *I2Cx, uint32_t addr, uint8_t *tx, uint32_t Length )
int I2C_MstSend( LPC_I2C_TypeDef *I2Cx, uint32_t addr, uint8_t *tx, uint32_t Length )
{
  uint32_t i;

  I2Cx->MSTDAT = addr;
  I2Cx->MSTCTL = CTL_MSTSTART;

  // <<-- 2015/04/05 add by Tamakichi,
  // 参考:http://www.lpcware.com/content/forum/lpc812-i2c-freezes
  while(!(I2Cx->STAT & STAT_MSTPEND)); // wait for master pending
  if((I2Cx->STAT & MASTER_STATE_MASK) == STAT_MSTNACKADDR) // check for nack on address
	  return -1; // slave nacked address
  // -->>

同じように3か所修正しました。
また、上記のほかに、I2C_MstReceive、I2C_MstSendRcvも修正しました。

これで試してみると、フリーズが発生しなくなりました。


2015/04/15 追記
作成した実験ボートですが、重大な欠陥がありました。
FlashMagicでの書き込みで自動リセットを行うためにUARTのDTR,RTSの信号を
使っているのですが、マイコンでシリアル通信を使う機能を実装し、
TeraTermでテストを行おうとすると、TeraTermでのデータの送受信が出来ません。
TeraTermがDTR,RTSの処理をちゃんとしていないようで、マイコンがリセット状態
のままになってしまいます。

この現象、当初は自作したUARTライブラリのミスと思ってちょっとはまりました。

利用したライブラリのlpc800_driver_libですが、
I2Cライブラリはフリーズする問題を含め、エラー発生時に無限ループ箇所があり、
また再送信で再起呼び出し等でスタックを消費する等、色々と問題がありそうなので、
使うのは辞めました。
自分が理解できる範囲で大幅修正(ほぼ自作)しちゃいました。

lpc800_driver_libのI2Cライブラリでは、割り込み処理で状態をチェックしている作りですが、
直接レジスタ見てループして待つようにしました。

また、アイドル処理や、タイムアウト処理が今一わからないので、
自分が分かる単純なものに置き換えました。

こんな感じに大幅修正(ほぼ自作)です。

#include "LPC8xx.h"
#include "i2c.h"
#include "uart.h"
#include "mrt.h"
#include "lpc_types.h"

// I2C送受信レディ待ち
// 500msecでタイムアウト
bool i2c_waitReady() {
	uint32_t cnt = mrt_read_counter()+500;
	while(!(LPC_I2C->STAT & STAT_MSTPEND)) {
		if (mrt_read_counter() > cnt) {
			return false;
		}
	}
	return true;
}

// I2Cアドレス送信
int i2c_write_address(uint32_t addr) {
  // レディ待ち
  if (i2c_waitReady() == false) {
	  return I2C_ERR_TIMEOUT;
  }

  // START + I2Cアドレス送信
  LPC_I2C->MSTDAT = addr;
  LPC_I2C->MSTCTL = CTL_MSTSTART;
  if (i2c_waitReady() == false) {
	  // タイムアウト(処理を終了する)
	  LPC_I2C->MSTCTL = CTL_MSTSTOP;
	  return I2C_ERR_TIMEOUT;
  }

  // スレーブからのアドレス送信 ACK/NACKのチェック
  if((LPC_I2C->STAT & MASTER_STATE_MASK) == STAT_MSTNACKADDR) {
	  return I2C_ERR_ADDRSND; // (CTL_MSTSTOPは自動送信される)
  }
  return 0;
}

// 1バイト送信
int i2c_write_byte(uint8_t b) {

	// 送信可能か?
	if(!(LPC_I2C->STAT & STAT_MSTTX)) {
			LPC_I2C->MSTCTL = CTL_MSTSTOP;
			return I2C_ERR_DATASND;
	 }

	// 1バイト送信
	LPC_I2C->MSTDAT = b;
	LPC_I2C->MSTCTL = CTL_MSTCONTINUE; // 処理を継続

	if (i2c_waitReady() == false) {
	  // タイムアウト(処理を終了する)
	  LPC_I2C->MSTCTL = CTL_MSTSTOP;
	  return I2C_ERR_TIMEOUT;
	}

	// スレーブからのデータ送信ACK/NACKのチェック
	if((LPC_I2C->STAT & MASTER_STATE_MASK) == STAT_MSTNACKTX)
		return I2C_ERR_DATASND; // (CTL_MSTSTOPは自動送信される)

	return 0;
}

// 1バイト受信
int i2c_read_byte(bool flgrpt) {
	int rc;

	// データ受信済チェック
	if (i2c_waitReady() == false) {
	  // タイムアウト(処理を終了する)
	  LPC_I2C->MSTCTL = CTL_MSTSTOP;
	  return I2C_ERR_TIMEOUT;
	}

	// データ受信可能?
	if(!(LPC_I2C->STAT & STAT_MSTRX)) {
		LPC_I2C->MSTCTL = CTL_MSTSTOP;
		return I2C_ERR_DATARCV;
	}

	// データ受信
	rc = LPC_I2C->MSTDAT;

	// 継続受信?
	if (flgrpt) {
		LPC_I2C->MSTCTL = CTL_MSTCONTINUE;
		if (i2c_waitReady() == false) {
		  LPC_I2C->MSTCTL = CTL_MSTSTOP;
		  return I2C_ERR_TIMEOUT;
		}
	}
	return rc;
}

//
// I2Cマルチバイトデータ送信
//   addr  : i2cスレーブアドレス(8ビット)
//   tx    : 送信データ格納アドレス
//   Length: 送信データサイズ
// 戻り値   0:正常終了   0以外:異常終了
//
int i2c_msend(uint32_t addr, uint8_t *tx, uint32_t Length ) {
  uint32_t i;
  int rc;

  // アドレス送信(START+I2Cスレーブアドレス送信、ACK/NACK受信、タイムアウト)
  if ( (rc = i2c_write_address(addr)) )
	  return rc;

  // データ送信(データ送信、ACK/NACK受信、タイムアウト)
  for ( i = 0; i < Length; i++ ) {
	  if ( (rc = i2c_write_byte(tx[i])) ) {
		  return rc;
	  }
  }

  // 処理の終了(ストップコンディション)
  LPC_I2C->MSTCTL = CTL_MSTSTOP;
  if (i2c_waitReady() == false) {
	  return I2C_ERR_TIMEOUT;
  }
  return 0;
}

// コマンド送信(2バイトデータ送信)
uint8_t i2c_send(uint8_t i2c_addr, uint8_t ctrl , uint8_t data ) {
	uint8_t sndbuf[2];
	sndbuf[0] = ctrl;
	sndbuf[1] = data;
	return i2c_msend(i2c_addr, sndbuf, 2 );
}

//
// I2Cマルチバイトデータ受信
//  addr : i2cスレーブアドレス
//  rx   : 受信データ格納アドレス
// Length: 受信データ長さ
// 戻り値   0:正常終了   0以外:異常終了
// 補足 アドレスにはR/Wビットをつけないこと。関数内部で設定する
//
int i2c_mreceive(uint32_t addr, uint8_t *rx, uint32_t rxlen ) {
  uint32_t i;
  int rc;

  // アドレス送信(START+I2Cスレーブアドレス送信、ACK/NACK受信、タイムアウト)
  if ( (rc = i2c_write_address(addr|RD_BIT)) )
	  return rc;

  // データ受信(受信、ACK/NACK送信)
  for ( i = 0; i < rxlen; i++ ) {
	  if ( (rc = i2c_read_byte(i != rxlen -1)) < 0 )
		  return rc;
	  *rx++ = (uint8_t)rc;
  }

  // 処理の終了(ストップコンディション)
  LPC_I2C->MSTCTL = CTL_MSTSTOP;
  if (i2c_waitReady() == false) {
	  return I2C_ERR_TIMEOUT;
  }

  return 0;
}

//
// I2Cマルチバイトデー送受信
//  addr : i2cスレーブアドレス
//  tx   : 送信データ格納アドレス
//  txlen : 送信データサイズ
//  rx   : 受信データ格納アドレス
//  rxlen: 受信データ長さ
// 戻り値   0:正常終了   0以外:異常終了
// 補足 アドレスにはR/Wビットをつけないこと。関数内部で設定する
//
int i2c_msendRcv(uint32_t addr, uint8_t *tx, uint32_t txlen, uint8_t *rx, uint32_t rxlen ) {

  uint32_t i;
  int rc;

  // アドレス送信(START+I2Cスレーブアドレス送信、ACK/NACK受信、タイムアウト)
  if ( (rc = i2c_write_address(addr)) )
	  return rc;

  // データ送信(データ送信、ACK/NACK受信、タイムアウト)
  for ( i = 0; i < txlen; i++ ) {
	  if ( (rc = i2c_write_byte(tx[i])) ) {
		  return rc;
	  }
  }

  // アドレス送信(START+I2Cスレーブアドレス送信、ACK/NACK受信、タイムアウト)
  if ( (rc = i2c_write_address(addr|RD_BIT)) )
	  return rc;

  // データ受信(受信、ACK/NACK送信)
  for ( i = 0; i < rxlen; i++ ) {
	  if ( (rc = i2c_read_byte(i != rxlen -1)) < 0 )
		  return rc;
	  *rx++ = (uint8_t)rc;
  }

  // 処理の終了(ストップコンディション)
  LPC_I2C->MSTCTL = CTL_MSTSTOP;
  if (i2c_waitReady() == false) {
	  return I2C_ERR_TIMEOUT;
  }
  return 0;
}

//
// I2C初期化
//  LPC810用(呼び出し前に スイッチマトリックスで PIN02:SDA , PIN03:SCLとすること)
//  通信速度 100kbps,割り込みは利用していない
//
void i2c_init() {
	// オープンドレイン設定(LPC810のPIN2,PIN3をI2Cに設定)
	LPC_IOCON->PIO0_2 |= (0x1<<10);
	LPC_IOCON->PIO0_3 |= (0x1<<10);

	// クロック供給開始
	LPC_SYSCON->SYSAHBCLKCTRL |= (1<<5);

	// I2Cリセット
	LPC_SYSCON->PRESETCTRL &= ~(0x1<<6);
	LPC_SYSCON->PRESETCTRL |= (0x1<<6);

	// 条件設定(割り込みは使わない)
	LPC_I2C->DIV = I2C_SMODE_PRE_DIV;
	LPC_I2C->CFG &= ~(CFG_MSTENA);
	LPC_I2C->MSTTIME = TIM_MSTSCLLOW(0x00) | TIM_MSTSCLHIGH(0x00);
	NVIC_DisableIRQ(I2C_IRQn);
	LPC_I2C->CFG |= CFG_MSTENA;
}

« 2015年3月 | トップページ | 2015年5月 »