フォト
2018年6月
          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
無料ブログはココログ

IchigoJam

2018年5月16日 (水)

ゲームボーイ(旧タイプ)のパーツ その2

前回からの続きです。
その後、ケースの他に液晶モジュールとそのカバーを追加注文し、部品が到着しました。
とりあえず、IchigoJamで稼働させてみる予定です。

到着したパーツ

Dscn7908

Dscn7910

追加注文したパーツ

・LCDモジュール
3.5インチ 4:3の画面だと選択枝がこれしかありませんでした。
Podofo 3.5" TFT LCD Display RGB LCD Display Module Kit

01

・LCD用のカバー
  プラスチックではなくガラス製です。
Glass For GameBoy Zero DMG-01 For Raspberry Pi Modify Glass Lens Protector

02


まずは、LCDディスプレイの動作チェック

LCD部とドライバーボードのセットです。NTSCビデオ入力で表示出来ます。
IchigoJamに接続して表示確認をしたところ、仕様では12V駆動ですが5Vで動作しました。
意外と視野角の広く、斜めからも良く見える液晶です。

Dscn7907

液晶パネルはLQ035NC111という、比較的入手しやすいパーツです。

さっそく、今回の試みで一番重要なLCDの組み込みをやってみました。
傷防止のマスキングテープを付けて、段差のある部分をカットします。
パネルカバーが載せられるように、若干フチを残します。

Dscn7912

マスキングテープで仮止めして、一旦組み立ててみます。

Dscn7914

基板も装着

Dscn7917

ふたを閉めて、表示の確認をします。
LCDモジュールからケーブルを引き出して電源供給とビデオ信号入力を行っています。

Dscn7921

とりあえず、見栄えも良くいい感じに仕上がりました。
LCDカバーは購入して正解でした。

次に裏の電池ボックスからの電源供給をどうするか考えてみます。
Ichigojamを中にどう入れるかも検討します。

Dscn7922

他にもコネクタ類(キーボード、シリアル通信、外部電源)も何とかしたいですね。


2017年12月 4日 (月)

ラズパイ版IchigoJamが公式サイトに掲載されています

IchigoJamのラズパイ版がラスパイ公式サイト ダウンロードに掲載されています。

https://www.raspberrypi.org/downloads/

01

早速、手持ちのラズパイ2で試してみました。
オリジナル版とは異なり、USBキーボードがサポートされています。
画面表示もHDMIに対応していますが、AV端子を使ってNTSCビデオ出力を試してみました。

02

config.txtファイルに sdtv_mode=1 を追加るつことでNTSCビデオ出力出来ます。

今回、ちょとハマったのがSDカードの相性問題です。
下記サイトにラズパイでのSDカードの相性についての記載があります。
https://elinux.org/RPi_SD_cards

手持ちのSanDisk製microSDカードではブートできませんでした。
手持ちのエレコム製microSDカードでは問題無く起動出来ました(写真)。

現時点では、オリジナル版の全ての機能はサポートされていません。
処理速度は、オリジナル版の50倍から100倍(利用するラズパイによる)くらい出ているようです。

移植は完成度は高く、素晴らしいのですが、
オリジナル版のインタープリタ実装方式が今一だった部分がそのまま移植されたため、
ラズパイ本来のパフォーマンス出せていないようで、ちょっと残念です。
(STM32F103C8T6の豊四季Tiny BASICよりも処理は遅いです^^)

このあたりは、改善を望みます。

2017/12/15 追記

現在ラズパイ版IchigoJamは、随時改良・更新が行われています。
描画処理がかなり改善されているようです。

2017年6月 3日 (土)

IchigoJamに関しての不満

FacebookのIchigoJam-FANにて、
開発者さんが「IchigoJamの拡張版にほしいもの大募集!」とのことで、

RENUMコマンドの不具合の対応をお願いしたのですが、
「ラベルを使え!」との回答。
この回答にはちょと「カチン」ときました。たま吉さん的には..
RENUMコマンドは、行番号の付け替えを行うコマンドで、
N-BASIC、MSX-BASIC等のBASIC言語では古くからあるコマンドです。
IchigoJamのコマンドでは、次のプログラムを

1 CLS
5 A=0
6 PRINT "Hello!"
10 A=A+1
20 IF A<10 GOTO 6
30 END

RENUMコマンドで
RENUM  100, 10

と実行して行番号の付け替えを行うと、
結果は
100 CLS
110 A=0
120 PRINT "Hello!"
130 A=A+1
140 IF A<10 GOTO 6
150 END

となり、GOTO文の飛び先が元のままのため、
プログラムを実行すると動かなくなります。
これは、明らかに問題(欠陥)なのです。

なぜ対応して頂け無いのかを質問すると、
「優先度が低い、実装方式が中間コードを使っていないため、難しい」との回答でした。
さらに、
「ラベルを使わない理由がなんかあるのか!」
とのなんか、角の立つような嫌な回答..
まあ、「つまらんことに突っ込むな」的な意味の回答なんだろうなぁ
不具合の対応よりも、機能拡張の方が優先度が高いらしい..

利用者、お金を払って企業が販売している製品を購入した私からすると、
中身の実装方法なんて全然関係ないし、
昔のBASICのGOTO文といったら、行番号指定が定番、
利用者としては当然、行番号を使おうが、ラベルを使おうが自由ななず..

なんか一気に使う気が無くなった。
荒探しをすると、色々とありそれ含めて見守ってきたですが、
今まで更新のたびに不具合等を見つけて連絡してきたがそれもやめよう..

もう一点、不満な点
IchigoJamはとにかく遅い。本来のLPC1114は、もっとパフォーマンスがもう少し良いはず。
STM32F103C8T6のTiny BASICと比べると1万回ループ、ライフゲームの1世代表示等
で比べると100分の1以下の性能。本来なら2~3分の1程度はでるはず。
この当たりは改善の余地があるので、根本的に実装を見直していただきたい。

2017年3月 9日 (木)

IchigoJam用画像コンバータを少々改良

以前作成した「IchigoJam用画像コンバータ」をちょっとだけ改良しました。

  Top

  ・過去の関連記事
    IchigoJamで疑似グラフィックを使った画像の表示
    IchigoJamでQRコードを表示してみる

改良点
・ドラック&ドロップ対応
・画像ファイルパスを直接入力出来るように修正
・Windows 10対応(動作確認)

GitHubにてこの改良プログラムの公開しました。
・Tamakichi/IchigoBmpConv  IchigoJam用画像コンバータ
   https://github.com/Tamakichi/IchigoBmpConv

動作確認にQRコード表示プログラムを作成しました。

09

前回はMS Wordの差し込み印刷機能を使ってブログURLをQRコードに変換したのですが、
Wordのバージョンアップのためか、イチゴジャムの画面解像度64x48ドットに収まるサイズの
画像が作成出来なくなってしまいました。

そこで、下記のサイトを利用させていただいてQRコードを作成しました。
・QRコードBlog
  http://www.qrcodeblog.com/date/qrcgi/

  誤り訂正レベル:Q(25%)
  バージョン:自動
  サイズ:1
を指定して作成しました。この指定で41x41ドットの画像が作成出来ました。
これを元にしてペイントツールで加工して64x48の変換用画像を作成しました。

02

これを作成したツールで変換し、プログラムソースをIchigoJamに転送します。
(転送はこれこれを使って出来ます)

転送したプログラムをIchigoJamで実行

10

スマートフォンでこのQRコードが読めました。

03


2016年11月19日 (土)

IchigoJam用 USBキーボード変換 Bluetooth・USBキーボードの両対応できました

現在取り組んでいる、USB Hostシールドを使った USB - PS/2変換、
Bluetooth版USB HID版が別スケッチだったのですが1つに統合して両対応にしました。

Dscn6165

Bluetoothドングル、有線・無線USBキーボードを自動認識して利用出来ます。
構成的には次のような感じです。

System

更にキーを押し続けた場合のキーリピート機能を追加しました。
これでほぼ完全にPS/2キーボードとして利用出来ます。

USBハブにも対応したのですが、現状は動かない場合がありおまけレベルです。

Arduino Uno環境では、BluetoothドングルとUSB HIDキーボード(有線・無線)が同時利用出来ました。
(同じ種類のデバイスの同時利用は出来ません。 例:USB HIDキーボード2台同時)

Dscn6162

Arduino pro miniではUSBの電流供給能力的に無理ですが..

スケッチ


次のような感じです。まだまだこれから修正を予定しています。
  ダウンロード USBKBD2PS2_v2.zip (5.4K)

最新版はgithubにて公開しています。
       https://github.com/Tamakichi/Arduino_USBToPS2
//
// USBKBD2PS2_v2 USBキーボード PS/2キーボード変換 for IchigoJam v2
// 作成者 たま吉さん
// 作成日 2016/11/11 , 最終修正日 2016/11/18
// 修正 2016/11/18 Bluetooth HIDとUSB HIDのスケッチの統合,キーリピート機能対応
//
// このスケッチの利用には以下のハードウェア(シールド)が必要です.
//  ・USB Host Shield
// 
// このスケッチのコンパイルには以下のライブラリが必要です.
//  ・PS/2デバイス ps2dev(ps2dev.zip) - an interface library for ps2 host 
//    PS2 mouse interface for Arduino(http://playground.arduino.cc/ComponentLib/Ps2mouse)
//  ・USB_Host_Shield_2.0 (https://github.com/felis/USB_Host_Shield_2.0)
//  ・MsTimer2 (http://playground.arduino.cc/Main/MsTimer2)
//

//******* 用途により、下記の定義を設定して下さい ***************************
#define MYDEBUG      0  // 0:デバッグ情報出力なし 1:デバッグ情報出力あり 
#define KB_CLK      A4  // PS/2 CLK  IchigoJamのKBD1に接続
#define KB_DATA     A5  // PS/2 DATA IchigoJamのKBD2に接続
//**************************************************************************

#include <ps2dev.h>
#include <BTHID.h>
#include <hidboot.h>
#include <usbhub.h>
#include <MsTimer2.h>

#define LOBYTE(x) ((char*)(&(x)))[0]
#define HIBYTE(x) ((char*)(&(x)))[1]

// キーリピートの定義
#define REPEATTIME      5   // キーを押し続けて、REP_INTERVALxREPEATTIMEmsec後にリピート開始
#define EMPTY           0   // リピート管理テーブルが空状態
#define MAXKEYENTRY     6   // リピート管理テーブルサイズ
#define REP_INTERVAL    100 // リピート間隔 150msec

#define MS_SIKIICHI     10

uint8_t keyentry[MAXKEYENTRY];    // リピート管理テーブル
uint8_t repeatWait[MAXKEYENTRY];  // リピート開始待ち管理テーブル
uint8_t enabled =0;               // PS/2 ホスト送信可能状態
PS2dev keyboard(KB_CLK, KB_DATA); // PS/2デバイス

//
// HIDキーボード レポートパーサークラスの定義
//
class KbdRptParser : public KeyboardReportParser {
  protected:
    virtual uint8_t HandleLockingKeys(USBHID *hid, uint8_t key);
    virtual void OnControlKeysChanged(uint8_t before, uint8_t after);
    virtual void OnKeyDown(uint8_t mod, uint8_t key);
    virtual void OnKeyUp(uint8_t mod, uint8_t key);
    virtual void OnKeyPressed(uint8_t key) {};
};

// HIDマウス レポートパーサークラスの定義
/*
class MouseRptParser : public MouseReportParser {
  protected:
    virtual void OnMouseMove(MOUSEINFO *mi) {};
    virtual void OnLeftButtonUp(MOUSEINFO *mi){};
    virtual void OnLeftButtonDown(MOUSEINFO *mi){};
    virtual void OnRightButtonUp(MOUSEINFO *mi) {};
    virtual void OnRightButtonDown(MOUSEINFO *mi){};
    virtual void OnMiddleButtonUp(MOUSEINFO *mi){};
    virtual void OnMiddleButtonDown(MOUSEINFO *mi){};
};
*/

class MouseRptParser : public MouseReportParser {
  protected:
    void OnMouseMove(MOUSEINFO *mi);
    void OnLeftButtonUp(MOUSEINFO *mi);
    void OnLeftButtonDown(MOUSEINFO *mi);
    void OnRightButtonUp(MOUSEINFO *mi);
    void OnRightButtonDown(MOUSEINFO *mi);
    void OnMiddleButtonUp(MOUSEINFO *mi);
    void OnMiddleButtonDown(MOUSEINFO *mi);
};

void MouseRptParser::OnMouseMove(MOUSEINFO *mi){
/*  
  Serial.print("dx=");
  Serial.print(mi->dX, DEC);
  Serial.print(" dy=");
  Serial.println(mi->dY, DEC);
*/
  if (mi->dX > MS_SIKIICHI) {
    keyboard.write(0xE0);
    keyboard.write(0x74);
    delay(50); 
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x74);
  } else if (mi->dX < -MS_SIKIICHI) {
    keyboard.write(0xE0);
    keyboard.write(0x6B);    
    delay(50); 
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x6B);    
  }
  if (mi->dY > MS_SIKIICHI) {
    keyboard.write(0xE0);
    keyboard.write(0x72);        
    delay(50); 
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x72);        
  } else if (mi->dY < -MS_SIKIICHI) {
    keyboard.write(0xE0);
    keyboard.write(0x75);        
    delay(50); 
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x75);        
  }
}

void MouseRptParser::OnLeftButtonUp  (MOUSEINFO *mi){
  Serial.println("L Butt Up");
}

void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi){
  Serial.println("L Butt Dn");
}

void MouseRptParser::OnRightButtonUp  (MOUSEINFO *mi){
  Serial.println("R Butt Up");
}

void MouseRptParser::OnRightButtonDown  (MOUSEINFO *mi){
  Serial.println("R Butt Dn");
}

void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi){
  Serial.println("M Butt Up");
}

void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi){
  Serial.println("M Butt Dn");
}

USB      Usb;
USBHub  Hub1(&Usb);
USBHub  Hub2(&Usb);
USBHub  Hub3(&Usb);
USBHub  Hub4(&Usb);

BTD     Btd(&Usb);
BTHID   bthid(&Btd, PAIR, "0000");
BTHID   hid(&Btd);

KbdRptParser keyboardPrs;
MouseRptParser mousePrs;

HIDBoot<USB_HID_PROTOCOL_KEYBOARD>    HidKeyboard(&Usb);
HIDBoot<USB_HID_PROTOCOL_MOUSE>    HidMouse(&Usb);

uint8_t classType = 0;      
uint8_t subClassType = 0;
uint32_t next_time;

// HID Usage ID (0x04 - 0x67) => PS/2 スキャンコード 変換テーブル
const uint8_t keytable1[] PROGMEM = {
  0x1C,0, 0x32,0, 0x21,0, 0x23,0, 0x24,0, 0x2B,0, 0x34,0, 0x33,0, // 0x04 - 0x0B
  0x43,0, 0x3B,0, 0x42,0, 0x4B,0, 0x3A,0, 0x31,0, 0x44,0, 0x4D,0, // 0x0C - 0x13
  0x15,0, 0x2D,0, 0x1B,0, 0x2C,0, 0x3C,0, 0x2A,0, 0x1D,0, 0x22,0, // 0x14 - 0x1B
  0x35,0, 0x1A,0, 0x16,0, 0x1E,0, 0x26,0, 0x25,0, 0x2E,0, 0x36,0, // 0x1C - 0x23
  0x3D,0, 0x3E,0, 0x46,0, 0x45,0, 0x5A,0, 0x76,0, 0x66,0, 0x0D,0, // 0x24 - 0x2B
  0x29,0, 0x4E,0, 0x55,0, 0x54,0, 0x5B,0, 0x5D,0, 0x5D,0, 0x4C,0, // 0x2C - 0x33
  0x52,0, 0x0E,0, 0x41,0, 0x49,0, 0x4A,0, 0x58,0, 0x05,0, 0x06,0, // 0x34 - 0x3B
  0x04,0, 0x0C,0, 0x03,0, 0x0B,0, 0x83,0, 0x0A,0, 0x01,0, 0x09,0, // 0x3C - 0x43
  0x78,0, 0x07,0, 0x00,2, 0x7E,0, 0x00,3, 0x70,1 ,0x6C,1, 0x7D,1, // 0x44 - 0x4B
  0x71,1, 0x69,1, 0x7A,1, 0x74,1, 0x6B,1, 0x72,1 ,0x75,1, 0x77,0, // 0x4C - 0x53
  0x4A,1, 0x7C,0, 0x7B,0, 0x79,0, 0x5A,1, 0x69,0, 0x72,0, 0x7A,0, // 0x54 - 0x5B
  0x6B,0, 0x73,0, 0x74,0, 0x6C,0, 0x75,0, 0x7D,0, 0x70,0, 0x71,0, // 0x5C - 0x63
  0x61,0, 0x2F,1, 0x37,1, 0x0F,0,                                 // 0x64 - 0x67
};

// HID Usage ID (0x87 - 0x94) => PS/2 スキャンコード 変換テーブル
const uint8_t keytable2[] PROGMEM = {
  0x51,0, 0x13,0, 0x6A,0, 0x64,0, 0x67,0, 0x27,0, 0x00,0, 0x00,0, // 0x87 - 0x8E
  0x00,0, 0xF2,0, 0xF1,0, 0x63,0, 0x62,0, 0x5F,0,                 // 0x8F - 0x94
};

// PS/2 ホストにack送信
void ack() {
  while(keyboard.write(0xFA));
}

// PS/2 ホストから送信されるコマンドの処理
int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF:  ack();// Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。
    //while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: // 再送要求
    ack();
    break;
  case 0xF6: // 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //キースキャンを開始する
    //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 claerKeyEntry() {
 for (uint8_t i=0; i <MAXKEYENTRY; i++)
    keyentry[i] = EMPTY;
}

// リピート管理テーブルにキーを追加
void addKey(uint8_t key) {
 for (uint8_t i=0; i <MAXKEYENTRY; i++) {
  if (keyentry[i] == EMPTY) {
    keyentry[i] = key;  
    repeatWait[i] = REPEATTIME;
    break;
  }
 }
}

// リピート管理テーブルからキーを削除
void delKey(uint8_t key) {
 for (uint8_t i=0; i <MAXKEYENTRY; i++) {
  if (keyentry[i] == key) {
    keyentry[i] = EMPTY;
    break;
  }
 }  
}

//
// PS/2 makeコード送信
// 引数 key(IN) HID Usage ID
//
uint8_t sendKeyMake(uint8_t key) {
  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre = 0xff;

  if (key >= 0x04 && key <= 0x67) {
    code = pgm_read_byte(keytable1 + (key - 0x04)*2);
    pre = pgm_read_byte(keytable1 + (key - 0x04)*2 + 1);
  } else if (key >= 0x87 && key <= 0x94) {
    code = pgm_read_byte(keytable2 + (key - 0x87)*2);    
    pre = pgm_read_byte(keytable2 + (key - 0x87)*2 + 1);    
  }

  // PS/2キーの発行
  if (pre == 0) {
    keyboard.write(code);
    return 1;
  } else if (pre == 1) {
    keyboard.write(0xE0);
    keyboard.write(code);    
  } else if (pre == 2) { // PrintScreenキー
    keyboard.write(0xE0);
    keyboard.write(0x12);
    keyboard.write(0xE0);
    keyboard.write(0x7C);
  } else if (pre == 3) { // Pauseキー
    keyboard.write(0xE1);
    keyboard.write(0x14);
    keyboard.write(0x77);
    keyboard.write(0xE1);
    keyboard.write(0xF0);    
    keyboard.write(0x14);
    keyboard.write(0xF0);    
    keyboard.write(0x77);
  }
  return code;
}

//
// PS/2 breakコード送信
// 引数 key(IN) HID Usage ID
//
uint8_t sendKeyBreak(uint8_t key) {
  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre = 0xff;
 
  if (key >= 0x04 && key <= 0x67) {
    code = pgm_read_byte(keytable1 + (key - 0x04)*2);
    pre = pgm_read_byte(keytable1 + (key - 0x04)*2 + 1);
  } else if (key >= 0x87 && key <= 0x94) {
    code = pgm_read_byte(keytable2 + (key - 0x87)*2);    
    pre = pgm_read_byte(keytable2 + (key - 0x87)*2 + 1);    
  }

  // PS/2キーの発行
  if (pre == 0) {
    keyboard.write(0xF0);
    keyboard.write(code);    
  } else if (pre == 1) {
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(code);    
  } else if (pre == 2) {
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x7C);
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x12);
  }
  return code;
}

// リピート処理(タイマー割り込み処理から呼ばれる)
void sendRepeat() {
  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre, key;
  
  for (uint8_t i=0; i < MAXKEYENTRY; i++) {
    if (keyentry[i] != EMPTY) {
      key = keyentry[i]; 
      if (repeatWait[i] == 0) {
        sendKeyMake(key);
    } else {
        repeatWait[i]--;          
      }
    }
  }
}

//
// ロックキー(NumLock/CAPSLock/ScrollLock)ハンドラ
//

uint8_t KbdRptParser::HandleLockingKeys(USBHID *hid, uint8_t key) {
  if (classType == USB_CLASS_WIRELESS_CTRL) {
    uint8_t old_keys = kbdLockingKeys.bLeds;  
    switch (key) {
      case UHS_HID_BOOT_KEY_NUM_LOCK:
        kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
        break;
      case UHS_HID_BOOT_KEY_CAPS_LOCK:
        kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
        break;
      case UHS_HID_BOOT_KEY_SCROLL_LOCK:
        kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
        break;
    }
    if (old_keys != kbdLockingKeys.bLeds && hid) {
      BTHID *pBTHID = reinterpret_cast<BTHID *> (hid); // A cast the other way around is done in BTHID.cpp
      pBTHID->setLeds(kbdLockingKeys.bLeds); // Update the LEDs on the keyboard
    }
  } else {
    return KeyboardReportParser::HandleLockingKeys(hid, key);   
  }
  return 0;
}


//
// キー押しハンドラ
// 引数
//  mod : コントロールキー状態
//  key : HID Usage ID 
//
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) {
  MsTimer2::stop();
#if MYDEBUG==1
  Serial.print(F("DN ["));  Serial.print(F("mod="));  Serial.print(mod,HEX);
  Serial.print(F(" key="));  Serial.print(key,HEX);  Serial.println(F("]"));
#endif
  if (sendKeyMake(key))
    addKey(key);
  MsTimer2::start();
}

//
// コントロールキー変更ハンドラ
// SHIFT、CTRL、ALT、GUI(Win)キーの処理を行う
// 引数 before : 変化前のコード USB Keyboard Reportの1バイト目
//      after  : 変化後のコード USB Keyboard Reportの1バイト目
//
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
  MODIFIERKEYS beforeMod;
  *((uint8_t*)&beforeMod) = before;

  MODIFIERKEYS afterMod;
  *((uint8_t*)&afterMod) = after;

  // 左Ctrlキー
  if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
    if (afterMod.bmLeftCtrl) {
      keyboard.write(0x14);  // 左Ctrlキーを押した
    } else {
      keyboard.write(0xF0);  // 左Ctrltキーを離した       
      keyboard.write(0x14);
    } 
  }

  // 左Shiftキー
  if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
    if (afterMod.bmLeftShift) {
      keyboard.write(0x12);  // 左Shiftキーを押した
    } else {
      keyboard.write(0xF0);  // 左Shiftキーを離した       
      keyboard.write(0x12);  // 
    }
  }

  // 左Altキー
  if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
    if (afterMod.bmLeftAlt) {
      keyboard.write(0x11);  // 左Altキーを押した
    } else {
      keyboard.write(0xF0);  // 左Altキーを離した       
      keyboard.write(0x11);  // 
    }
  }

  // 左GUIキー(Winキー)
  if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
    if (afterMod.bmLeftGUI) {
      keyboard.write(0xE0);  // 左GUIキーを押した
      keyboard.write(0x1F);
    } else {
      keyboard.write(0xE0);  // 左GUIキーを離した       
      keyboard.write(0xF0); 
      keyboard.write(0x1F); 
    }
  }

  // 右Ctrlキー
  if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
    if (afterMod.bmRightCtrl) {
      keyboard.write(0xE0);  // 右Ctrlキーを押した
      keyboard.write(0x14);  
    } else {
      keyboard.write(0xE0);  // 右Ctrlキーを離した 
      keyboard.write(0xF0);       
      keyboard.write(0x14);
    }
  }

  // 右Shiftキー
  if (beforeMod.bmRightShift != afterMod.bmRightShift) {
    if (afterMod.bmRightShift) {
      keyboard.write(0x59);  // 右Shiftキーを押した
    } else {
      keyboard.write(0xF0);  // 右Shiftキーを離した       
      keyboard.write(0x59); 
    }
  }

  // 右Altキー
  if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
    if (afterMod.bmRightAlt) {
      keyboard.write(0xE0);  // 右Altキーを押した
      keyboard.write(0x11); 
    } else {
      keyboard.write(0xE0);  // 右Altキーを離した       
      keyboard.write(0xF0);
      keyboard.write(0x11); 
    };
  }

  // 右GUIキー
  if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
    if (afterMod.bmRightGUI) {
      keyboard.write(0xE0);  // 右GUIキーを押した
      keyboard.write(0x27);
    } else {
      keyboard.write(0xE0);  // 右GUIキーを離した       
      keyboard.write(0xF0); 
      keyboard.write(0x27); 
    }
  }
}

//
// キー離し ハンドラ
// 引数
//  mod : コントロールキー状態
//  key : HID Usage ID 
//
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) {
  MsTimer2::stop();
#if MYDEBUG==1
  Serial.print(F("UP ["));  Serial.print(F("mod="));  Serial.print(mod,HEX);
  Serial.print(F(" key="));  Serial.print(key,HEX);  Serial.println(F("]"));
#endif
  if (sendKeyBreak(key)) // HID Usage ID から PS/2 スキャンコード に変換  
    delKey(key);  
  MsTimer2::start();
}

//
// インターフェースクラスの取得
//
uint8_t getIntClass(byte& intclass, byte& intSubClass ) {
  uint8_t buf[ 256 ];
  uint8_t* buf_ptr = buf;
  byte rcode;
  byte descr_length;
  byte descr_type;
  unsigned int total_length;

  uint8_t flgFound = 0;
  
  //デスクプリタトータルサイズの取得
  rcode = Usb.getConfDescr( 1, 0, 4, 0, buf );
  LOBYTE( total_length ) = buf[ 2 ]; HIBYTE( total_length ) = buf[ 3 ];
  if ( total_length > 256 ) {
    total_length = 256;
  }
  
  rcode = Usb.getConfDescr( 1, 0, total_length, 0, buf ); 
  while ( buf_ptr < buf + total_length ) { 
    descr_length = *( buf_ptr );
    descr_type = *( buf_ptr + 1 );

    if (descr_type == USB_DESCRIPTOR_INTERFACE) {
      // 最初のインタフェースの取得
      USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )buf_ptr;  
      intclass = intf_ptr->bInterfaceClass;
      intSubClass = intf_ptr->bInterfaceSubClass;
      flgFound = 1;
      break;
    }
    buf_ptr = ( buf_ptr + descr_length );    //advance buffer pointer
  }
  return ( flgFound );
}

void setup() {
  Serial.begin( 115200 );
  while(keyboard.write(0xAA)!=0);
  if (Usb.Init() == -1) {
    Serial.println(F("OSC did not start."));
    while (1); // Halt    
  }
  
  next_time = millis() + 5000;

  bthid.SetReportParser(KEYBOARD_PARSER_ID, &keyboardPrs);
  bthid.SetReportParser(MOUSE_PARSER_ID, &mousePrs);
  bthid.setProtocolMode(USB_HID_BOOT_PROTOCOL); // Boot Protocol Mode
  bthid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode
  //HidKeyboard.SetReportParser(0, &Prs);
  HidKeyboard.SetReportParser(0, &keyboardPrs);
  HidMouse.SetReportParser(0, &mousePrs);

  claerKeyEntry();
  MsTimer2::set(REP_INTERVAL, sendRepeat); 
  MsTimer2::start();
    
  Serial.println(F("Start."));
}

void loop() {
  unsigned char c;  // ホストからの送信データ
  if( (digitalRead(KB_CLK)==LOW) || (digitalRead(KB_DATA) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  }  
  Usb.Task();
  if ( (classType == 0) && (Usb.getUsbTaskState() == USB_STATE_RUNNING) )  {  
    // デバイスクラス情報の取得
    getIntClass(classType, subClassType) ;
#if MYDEBUG == 1  
    Serial.print(F("class="));  Serial.println(classType, HEX);
    Serial.print(F("subclass="));  Serial.println(subClassType, HEX);
#endif
  }
  
#if MYDEBUG == 1  
  static uint8_t prevSts = 0xFF;
  if (Usb.getUsbTaskState() != prevSts) {
    prevSts = Usb.getUsbTaskState();
    Serial.print(F("sts="));
    Serial.println(prevSts, HEX);
  }
  if (Serial.available()) {
    Serial.read();
    for (uint8_t i=-0; i < MAXKEYENTRY; i++) {
      Serial.print(F("keyentry["));
      Serial.print(i,DEC);
      Serial.print(F("]="));
      Serial.println(keyentry[i],HEX);
    }
  }
#endif
}

現状、試行錯誤中の中途半端なマウス対応のコードを含んでいます。
削除してゲームパッド対応を予定しています。

2016年11月16日 (水)

IchigoJamでLogicool製ワイヤレスキーボードを利用する(USB・PS/2変換) その2

前回からの続きです。

ケースを製作しました。
aitendoのUSBケースは結局、小さすぎて使えませんでした。
事前に作成していたダサいケースを加工して利用することにしました。

とりあえず、表面を平らにして表面に何か貼ろうと構想。

Dscn6138


ホームセンターで購入したコルクシールを貼ることにしました。
はさみで切って貼ることが出来ます。

Dscn6157

貼り付けると、いい感じになりました。
適当なサイズに切って、貼った後にはさみではみ出た部分をカットしました。
中が発泡スチロールボードとはもう分かりません。

Dscn6151

中に入れるモジュール

IchigoJamのUSBポート経由でVCC、GND、KBD1、KBD2を接続します。
電源はUSB 5V(VCC)はArduino pro mini のRAW端子に接続することで3.3Vに変換して
利用しています。

USBケーブルは百円ショップのUSB延長ケーブルを利用しました。
最初太いケーブルをチョイスしたのですが、固くて曲げにくいため細いケーブルに変更しました。

Dscn6150

ケースの中に入れるとこんな感じです。
いい感じ! 上出来です。

Dscn6152


IchogoJamに接続の様子

ケースに使った発泡スチロールボードが5mmと厚いため、一回り大きくなりましたが、
良しとします。

Dscn6156

IchigoJam周辺

邪魔にならず、IchigoJamの全ての端子が利用出来るのでこの形態で正解でした。

Dscn6154


最後に

ケースに収納すると可搬性も良くなり実用性が増しますね。
発泡スチロールボードを使ったケース作成も意外といいです。
カッターナイフでお手軽に作成できます。

IchigoJamのケースも作ってみような?

2016年11月13日 (日)

IchigoJamでLogicool製ワイヤレスキーボードを利用する(USB・PS/2変換)

前回のポケモンキーボードのスケッチを修正して一般的なUSBキーボードに対応しました。
USBワイヤレスキーボードをPS/2インターフェースに変換します。


利用したキーボードはLogicool  K270です。
以前 amazonで1,290円で購入したのですが、今は値上がりしてますね。

  Dscn6124

IchigoJamはaitendoのai.Jam(ファームウェア V1.2.1)を使っています。
純正品IchigoJam Tと互換性があります。

IchigoJamとの接続はArduino pro miniのGND、VCCの他、
A4、A5ピンをPS/2用の通信に利用し、IchigoJamのKBD1、KBD2に接続しています。

Arduino pro miniではA4、A5端子がボード上の変なところにあります。
これはこれで、場合によっては接続しやすいです。

  Dscn6121

動いている様子

 

システム構成的な図

Photo

USB HIDに対応しています。有線キーボードも利用出来ます。

処理としては、図のようなハードウェア&ソフトウェア構成となっています。
USB HIDのキーボード入力データをPS/2キーボードデータと信号に変換して
IchigoJamのPS/2キーボードとして利用出来るようにしています。


利用しているハードウェア

1)Arduino pro mini 3.3V 8MHz版(上)とUSB Hostシールド

  Dscn6127

VCCに3.3Vを供給するのであれば、5V 16MHz版のArduino pro mini も利用出来ます。

私は最終的にIchigoJamのUSBコネクタに繋げる予定で、5V=>3.3Vの電圧変換が出来る
3.3V版を利用しています。

制約事項
・USBポートからの電源供給は3.3Vで電流もあまり流せません。
 動かないキーボードもあると思います。
・現状、マルチメディアキーには対応していません。
・起動直後、なぜか、IchigoJamに"@"文字が送られていまいます。
  IchigoJamとのPS/2キーボード接続のイニシャル処理でIchigoJamがコマンドではなく
  文字として認識しているようです。
 接続完了の目印になるので、これは放置しておきます。
 

スケッチ

  スケッチを公開します。
  ダウンロード USBKBD2PS2.zip (3.2K) (2016/11/19 バグがあり差し換えました)

  ※ 2016/11/18 追記 最新版はgithubにて公開しています。
       https://github.com/Tamakichi/Arduino_USBToPS2

コンパイルはArduino IDE 1.6.12を利用しています。

本スケッチの他に別途、下記のライブラリが必要です。

  ・PS2 mouse interface for  Arduino
     http://playground.arduino.cc/ComponentLib/Ps2mouse
  ・USB_Host_Shield_2.0
     https://github.com/felis/USB_Host_Shield_2.0

スケッチの全ソース
//
// USBKBD2PS2 USBキーボード PS/2キーボード変換 for IchigoJam
// 作成者 たま吉さん
// 作成日 2016/11/11
// 修正日 2016/11/19 OnKeyUp()のバグ修正 
//
// このスケッチの利用には以下のハードウェア(シールド)が必要です.
//  ・USB Host Shield
// 
// このスケッチのコンパイルには以下のライブラリが必要です.
//  ・PS/2デバイス ps2dev(ps2dev.zip) - an interface library for ps2 host 
//    PS2 mouse interface for Arduino(http://playground.arduino.cc/ComponentLib/Ps2mouse)
//  ・USB_Host_Shield_2.0 (https://github.com/felis/USB_Host_Shield_2.0)
//

#include <ps2dev.h>
#include <hidboot.h>
#include <usbhub.h>

#define KB_CLK    A4  // IchigoJamのKBD1に接続
#define KB_DATA   A5  // IchigoJamのKBD2に接続

PS2dev keyboard(KB_CLK, KB_DATA);   // PS/2デバイス

// HID Usage ID (0x04 - 0x67) => PS/2 スキャンコード 変換テーブル
const uint8_t keytable1[] PROGMEM = {
  0x1C,0, 0x32,0, 0x21,0, 0x23,0, 0x24,0, 0x2B,0, 0x34,0, 0x33,0, // 0x04 - 0x0B
  0x43,0, 0x3B,0, 0x42,0, 0x4B,0, 0x3A,0, 0x31,0, 0x44,0, 0x4D,0, // 0x0C - 0x13
  0x15,0, 0x2D,0, 0x1B,0, 0x2C,0, 0x3C,0, 0x2A,0, 0x1D,0, 0x22,0, // 0x14 - 0x1B
  0x35,0, 0x1A,0, 0x16,0, 0x1E,0, 0x26,0, 0x25,0, 0x2E,0, 0x36,0, // 0x1C - 0x23
  0x3D,0, 0x3E,0, 0x46,0, 0x45,0, 0x5A,0, 0x76,0, 0x66,0, 0x0D,0, // 0x24 - 0x2B
  0x29,0, 0x4E,0, 0x55,0, 0x54,0, 0x5B,0, 0x5D,0, 0x5D,0, 0x4C,0, // 0x2C - 0x33
  0x52,0, 0x0E,0, 0x41,0, 0x49,0, 0x4A,0, 0x58,0, 0x05,0, 0x06,0, // 0x34 - 0x3B
  0x04,0, 0x0C,0, 0x03,0, 0x0B,0, 0x83,0, 0x0A,0, 0x01,0, 0x09,0, // 0x3C - 0x43
  0x78,0, 0x07,0, 0x00,2, 0x7E,0, 0x00,3, 0x70,1 ,0x6C,1, 0x7D,1, // 0x44 - 0x4B
  0x71,1, 0x69,1, 0x7A,1, 0x74,1, 0x6B,1, 0x72,1 ,0x75,1, 0x77,0, // 0x4C - 0x53
  0x4A,1, 0x7C,0, 0x7B,0, 0x79,0, 0x5A,1, 0x69,0, 0x72,0, 0x7A,0, // 0x54 - 0x5B
  0x6B,0, 0x73,0, 0x74,0, 0x6C,0, 0x75,0, 0x7D,0, 0x70,0, 0x71,0, // 0x5C - 0x63
  0x61,0, 0x2F,1, 0x37,1, 0x0F,0,                                 // 0x64 - 0x67
};

// HID Usage ID (0x87 - 0x94) => PS/2 スキャンコード 変換テーブル
const uint8_t keytable2[] PROGMEM = {
  0x51,0, 0x13,0, 0x6A,0, 0x64,0, 0x67,0, 0x27,0, 0x00,0, 0x00,0, // 0x87 - 0x8E
  0x00,0, 0xF2,0, 0xF1,0, 0x63,0, 0x62,0, 0x5F,0,                 // 0x8F - 0x94
};

//
// HIDキーボード レポートパーサークラスの定義
//
class KbdRptParser : public KeyboardReportParser {
  protected:
    virtual void OnControlKeysChanged(uint8_t before, uint8_t after);
    virtual void OnKeyDown(uint8_t mod, uint8_t key);
    virtual void OnKeyUp(uint8_t mod, uint8_t key);
    virtual void OnKeyPressed(uint8_t key) {};
};

//
// キー押しハンドラ
// 引数
//  mod : コントロールキー状態
//  key : HID Usage ID 
//
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) {

  Serial.print(F("DN ["));  Serial.print(F("mod="));  Serial.print(mod,HEX);
  Serial.print(F(" key="));  Serial.print(key,HEX);  Serial.println(F("]"));

  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre;
 
  if (key >= 0x04 && key <= 0x67) {
    code = pgm_read_byte(keytable1 + (key - 0x04)*2);
    pre = pgm_read_byte(keytable1 + (key - 0x04)*2 + 1);
  } else if (key >= 0x87 && key <= 0x94) {
    code = pgm_read_byte(keytable2 + (key - 0x87)*2);    
    pre = pgm_read_byte(keytable2 + (key - 0x87)*2 + 1);    
  }

  //Serial.print(F("PS2 ["));  Serial.print(F("code="));  Serial.print(code,HEX);
  //Serial.print(F(" pre="));  Serial.print(pre,DEC);  Serial.println(F("]"));
  
  // PS/2キーの発行
  if (pre == 0) {
    keyboard.write(code);    
  } else if (pre == 1) {
    keyboard.write(0xE0);
    keyboard.write(code);    
  } else if (pre == 2) { // Breakキー
    keyboard.write(0xE0);
    keyboard.write(0x12);
    keyboard.write(0xE0);
    keyboard.write(0x7C);
  } else if (pre == 3) { // Pauseキー
    keyboard.write(0xE1);
    keyboard.write(0x14);
    keyboard.write(0x77);
    keyboard.write(0xE1);
    keyboard.write(0xF0);    
    keyboard.write(0x14);
    keyboard.write(0xF0);    
    keyboard.write(0x77);
  }
}

//
// コントロールキー変更ハンドラ
// SHIFT、CTRL、ALT、GUI(Win)キーの処理を行う
// 引数 before : 変化前のコード USB Keyboard Reportの1バイト目
//      after  : 変化後のコード USB Keyboard Reportの1バイト目
//
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
  MODIFIERKEYS beforeMod;
  *((uint8_t*)&beforeMod) = before;

  MODIFIERKEYS afterMod;
  *((uint8_t*)&afterMod) = after;

  // 左Ctrlキー
  if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
    if (afterMod.bmLeftCtrl) {
      keyboard.write(0x14);  // 左Ctrlキーを押した
    } else {
      keyboard.write(0xF0);  // 左Ctrltキーを離した       
      keyboard.write(0x14);
    } 
  }

  // 左Shiftキー
  if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
    if (afterMod.bmLeftShift) {
      keyboard.write(0x12);  // 左Shiftキーを押した
    } else {
      keyboard.write(0xF0);  // 左Shiftキーを離した       
      keyboard.write(0x12);  // 
    }
  }

  // 左Altキー
  if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
    if (afterMod.bmLeftAlt) {
      keyboard.write(0x11);  // 左Altキーを押した
    } else {
      keyboard.write(0xF0);  // 左Altキーを離した       
      keyboard.write(0x11);  // 
    }
  }

  // 左GUIキー(Winキー)
  if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
    if (afterMod.bmLeftGUI) {
      keyboard.write(0xE0);  // 左GUIキーを押した
      keyboard.write(0x1F);
    } else {
      keyboard.write(0xE0);  // 左GUIキーを離した       
      keyboard.write(0xF0); 
      keyboard.write(0x1F); 
    }
  }

  // 右Ctrlキー
  if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
    if (afterMod.bmRightCtrl) {
      keyboard.write(0xE0);  // 右Ctrlキーを押した
      keyboard.write(0x14);  
    } else {
      keyboard.write(0xE0);  // 右Ctrlキーを離した 
      keyboard.write(0xF0);       
      keyboard.write(0x14);
    }
  }

  // 右Shiftキー
  if (beforeMod.bmRightShift != afterMod.bmRightShift) {
    if (afterMod.bmRightShift) {
      keyboard.write(0x59);  // 右Shiftキーを押した
    } else {
      keyboard.write(0xF0);  // 右Shiftキーを離した       
      keyboard.write(0x59); 
    }
  }

  // 右Altキー
  if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
    if (afterMod.bmRightAlt) {
      keyboard.write(0xE0);  // 右Altキーを押した
      keyboard.write(0x11); 
    } else {
      keyboard.write(0xE0);  // 右Altキーを離した       
      keyboard.write(0xF0);
      keyboard.write(0x11); 
    };
  }

  // 右GUIキー
  if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
    if (afterMod.bmRightGUI) {
      keyboard.write(0xE0);  // 右GUIキーを押した
      keyboard.write(0x27);
    } else {
      keyboard.write(0xE0);  // 右GUIキーを離した       
      keyboard.write(0xF0); 
      keyboard.write(0x27); 
    }
  }
}

//
// キー離し ハンドラ
// 引数
//  mod : コントロールキー状態
//  key : HID Usage ID 
//
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) {
  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre = 0;
 
  if (key >= 0x04 && key <= 0x67) {
    code = pgm_read_byte(keytable1 + (key - 0x04)*2);
    pre = pgm_read_byte(keytable1 + (key - 0x04)*2 + 1);
  } else if (key >= 0x87 && key <= 0x94) {
    code = pgm_read_byte(keytable2 + (key - 0x87)*2);    
    pre = pgm_read_byte(keytable2 + (key - 0x87)*2 + 1);    
  }

  // PS/2キーの発行
  if (pre == 0) {
    keyboard.write(0xF0);
    keyboard.write(code);    
  } else if (pre == 1) {
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(code);    
  } else if (pre == 2) {
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x7C);
    keyboard.write(0xE0);
    keyboard.write(0xF0);
    keyboard.write(0x12);
  }
}

int enabled =0; 

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

// ホストから送信されるコマンドの処理
int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF:  ack();// Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。
    while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: // 再送要求
    ack();
    break;
  case 0xF6: // 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //キースキャンを開始する
    //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;
  }
}

USB     Usb;
//USBHub     Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD>    HidKeyboard(&Usb);
uint32_t next_time;
KbdRptParser Prs;

void setup() {
  Serial.begin( 115200 );
  while(keyboard.write(0xAA)!=0);
  
  if (Usb.Init() == -1)
    Serial.println(F("OSC did not start."));

  // USBデバイス情報の取得
  delay(200);

  while(1) {
  Usb.Task();
    if ( Usb.getUsbTaskState() == USB_STATE_RUNNING )  {
      USB_DEVICE_DESCRIPTOR buf;
      byte rcode;
      rcode = Usb.getDevDescr( 1 , 0, 0x12, ( uint8_t *)&buf );
      if (rcode) {
        Serial.println(F("USB Devide Error."));
      } else {
        Serial.print(F("class:")); Serial.println(buf.bDeviceClass, HEX);
        Serial.print(F("sub class:")); Serial.println(buf.bDeviceSubClass, HEX);
      }
      break;
    }
  }
  //delay( 200 );
  next_time = millis() + 5000;
  HidKeyboard.SetReportParser(0, &Prs);
  Serial.println(F("Start."));
}

void loop() {
  unsigned char c;  // ホストからの送信データ
  if( (digitalRead(KB_CLK)==LOW) || (digitalRead(KB_DATA) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  }  
  Usb.Task();
}

スケッチ的には実は大したことやってないです。ライブラリが大半の処理をやってくれます。
2つのプロトコル(USB HIDとPS/2)を繋げただけです。
USB HIDインターフェスのキー入力情報(HID Usage ID)をPS/2のキー入力に変換する
部分が本スケッチのかなめです。

この変換にはテーブル(keytable1[]、keytable2[])を用いて行っています。
ただし、CTRL、Shift、ALT、GUIキーはHID Usage IDではなくビット(ON/OFF)情報での
取得となるので、KbdRptParser::OnControlKeysChanged()で別処理を行っています。

スケッチはBluetooth版と類似点が多いです。なんとか統合したいと思います。
最終的にはケースに収納して、USBコネクタに接続して使いたいのですが..

とりあえず、手持ちの発泡スチロールボードで作って見たけど...
厚さが5mmあるのでデカくなった.. ダサい.. Otz  3Dプリンター欲しいですね。

Dscn6129

aitendoの「プラケースwith基板 [2P-E44.5]」が使えるかもしれないので注文しました。
(厚さがダメかも...)

Photo_2



スケッチはArduino UNO+USB HOSTシールドでも動くことを確認しました。
IchigoJamの入力端子KBD1、KBD2には5Vが入力されますが、IchigoJam(LPC1114)は、
5Vトレラントなので問題なしです。

比べるとArduino UNOだとデカいですね。

Dscn6132


2016年11月10日 (木)

IchigoJamでポケモンキーボードを使ってみる(Bluetooth・PS/2変換)

前回調査したArduino pro mini+USB Hostシールドを使って、
IchigoJamで「ポケモンキーボード(Bluetoothキーボード)」を利用出来るようにしました。

IchigoJamからはPS/2キーボードと認識されて利用出来ます。
ポケモンキーボードの全てのキーが利用出来ます。

Dscn6077

IchigoJamから電源供給しています。
キーボードからの入力情報はPS/2キーボード用の端子 KBD1、KBD2に接続しています。
arduino      IchigoJam
  D2     =>     KBD2
  D3     =>     KBD1
  VCC   =>    VCC
  GND   =>    GND

Dscn6084

Dscn6078

動作の様子


システム構成的な図

If
                          ※図のGND => VCCは記載ミスです GND => GND が正しいです

処理としては、図のようなハードウェア&ソフトウェア構成となっています。
Bluetooth HIDのキーボード入力データをPS/2キーボードデータと信号に変換して
IchigoJamのPS/2キーボードとして利用出来るようにしています。

起動後のキーボードのキーを押しまくっているとペアリングが行われます。

利用しているハードウェア

1)Arduino pro mini 3.3V版(上)とUSB Hostシールド

  Dscn6030

 純正品は高いので2つともクローン製品を使っています。
  合計で1000円くらいです。

2)USB Bluetoothドングル
   BT-MicroEDR2X
   Bluetooth Ver.2.1+EDR対応 Micro サイズ USBアダプタ (Class2/10m)

   Dscn6080

   かなり前に買って放置していたものです。

   これ以外にElecom製のLBT-UAN05C2でも動作しました。   

   Dscn6081

スケッチ

スケッチを公開します。
   スケッチのダウンロード btkbd2ps2.zip (3.2K)

   ※ 2016/11/18 追記 最新版はgithubにて公開しています。
       https://github.com/Tamakichi/Arduino_USBToPS2

コンパイルはArduino IDE 1.6.12を利用しています。

本スケッチの他に別途、下記のライブラリが必要です。

  ・PS2 mouse interface for  Arduino
     http://playground.arduino.cc/ComponentLib/Ps2mouse
  ・USB_Host_Shield_2.0
     https://github.com/felis/USB_Host_Shield_2.0

スケッチの全ソース
//
// btkbd2ps2 Bluetoothキーボード PS/2キーボード変換 for IchigoJam
// 作成者 たま吉さん
// 作成日 2016/11/09
//
// このスケッチの利用には以下のハードウェア(シールド)が必要です.
//  ・USB Host Shield
// 
// このスケッチのコンパイルには以下のライブラリが必要です.
//  ・PS/2デバイス ps2dev(ps2dev.zip) - an interface library for ps2 host 
//    PS2 mouse interface for Arduino(http://playground.arduino.cc/ComponentLib/Ps2mouse)
//  ・USB_Host_Shield_2.0 (https://github.com/felis/USB_Host_Shield_2.0)
//

#include <ps2dev.h>
#include <BTHID.h>
#include <usbhub.h>

PS2dev keyboard(3,2);   // PS/2デバイス

// HID Usage ID (0x04 - 0x43) => PS/2 スキャンコード 変換テーブル
const uint8_t keytable1[64] PROGMEM = {
  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,0x16,0x1E,0x26,0x25,0x2E,0x36,
  0x3D,0x3E,0x46,0x45,0x5A,0x76,0x66,0x0D,0x29,0x4E,0x55,0x54,0x5B,0x5D,0x5D,0x4C,
  0x52,0x0E,0x41,0x49,0x4A,0x58,0x05,0x06,0x04,0x0C,0x03,0x0B,0x83,0x0A,0x01,0x09,
};

// HID Usage ID (0x4A - 0x52) => PS/2 スキャンコード 変換テーブル
const uint8_t keytable2[9] PROGMEM = {
  0x6C,0x7D,0x71,0x69,0x7A,0x74,0x6B,0x72,0x75,
};

//
// HIDキーボード レポートパーサークラスの定義
//
class KbdRptParser : public KeyboardReportParser {
  protected:
    virtual uint8_t HandleLockingKeys(USBHID *hid, uint8_t key);
    virtual void OnControlKeysChanged(uint8_t before, uint8_t after);
    virtual void OnKeyDown(uint8_t mod, uint8_t key);
    virtual void OnKeyUp(uint8_t mod, uint8_t key);
    virtual void OnKeyPressed(uint8_t key) {};
};

uint8_t KbdRptParser::HandleLockingKeys(USBHID *hid, uint8_t key) {
  uint8_t old_keys = kbdLockingKeys.bLeds;
  
  switch (key) {
    case UHS_HID_BOOT_KEY_NUM_LOCK:
      kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
      break;
    case UHS_HID_BOOT_KEY_CAPS_LOCK:
      kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
      break;
    case UHS_HID_BOOT_KEY_SCROLL_LOCK:
      kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
      break;
  }
  if (old_keys != kbdLockingKeys.bLeds && hid) {
    BTHID *pBTHID = reinterpret_cast<BTHID *> (hid); // A cast the other way around is done in BTHID.cpp
    pBTHID->setLeds(kbdLockingKeys.bLeds); // Update the LEDs on the keyboard
  }
  return 0;
}

//
// キー押しハンドラ
// 引数
//  mod : コントロールキー状態
//  key : HID Usage ID 
//
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) {
/*  
  Serial.print(F("DN ["));  Serial.print(F("mod="));  Serial.print(mod,HEX);
  Serial.print("F( key="));  Serial.print(key,HEX);  Serial.println(F("]"));
*/
  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre = 0;
  if (key >= 0x04 && key <= 0x43) {
    code = pgm_read_byte(keytable1 + key - 0x04);
  } else if (key >= 0x4A && key <= 0x52) {
    code = pgm_read_byte(keytable2 + key - 0x4A);    
    pre = 0xE0;
  } else if (key == 0x87) {
    code = 0x51;    
  } else if (key == 0x89) {
    code = 0x6A;    
  }

  // PS/2キーの発行
  if (pre) keyboard.write(pre);
  keyboard.write(code);
}

//
// コントロールキー変更ハンドラ
// SHIFT、CTRL、ALT、GUI(Win)キーの処理を行う
// 引数 before : 変化前のコード USB Keyboard Reportの1バイト目
//      after  : 変化後のコード USB Keyboard Reportの1バイト目
//
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
  MODIFIERKEYS beforeMod;
  *((uint8_t*)&beforeMod) = before;

  MODIFIERKEYS afterMod;
  *((uint8_t*)&afterMod) = after;

  // 左Ctrlキー
  if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
    if (afterMod.bmLeftCtrl) {
      keyboard.write(0x14);  // 左Ctrlキーを押した
    } else {
      keyboard.write(0xF0);  // 左Ctrltキーを離した       
      keyboard.write(0x14);
    } 
  }

  // 左Shiftキー
  if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
    if (afterMod.bmLeftShift) {
      keyboard.write(0x12);  // 左Shiftキーを押した
    } else {
      keyboard.write(0xF0);  // 左Shiftキーを離した       
      keyboard.write(0x12);  // 
    }
  }

  // 左Altキー
  if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
    if (afterMod.bmLeftAlt) {
      keyboard.write(0x11);  // 左Altキーを押した
    } else {
      keyboard.write(0xF0);  // 左Altキーを離した       
      keyboard.write(0x11);  // 
    }
  }

  // 左GUIキー(Winキー)
  if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
    if (afterMod.bmLeftGUI) {
      keyboard.write(0xE0);  // 左GUIキーを押した
      keyboard.write(0x1F);
    } else {
      keyboard.write(0xE0);  // 左GUIキーを離した       
      keyboard.write(0xF0); 
      keyboard.write(0x1F); 
    }
  }

  // 右Ctrlキー
  if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
    if (afterMod.bmRightCtrl) {
      keyboard.write(0xE0);  // 右Ctrlキーを押した
      keyboard.write(0x14);  
    } else {
      keyboard.write(0xE0);  // 右Ctrlキーを離した 
      keyboard.write(0xF0);       
      keyboard.write(0x14);
    }
  }

  // 右Shiftキー
  if (beforeMod.bmRightShift != afterMod.bmRightShift) {
    if (afterMod.bmRightShift) {
      keyboard.write(0x59);  // 右Shiftキーを押した
    } else {
      keyboard.write(0xF0);  // 右Shiftキーを離した       
      keyboard.write(0x59); 
    }
  }

  // 右Altキー
  if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
    if (afterMod.bmRightAlt) {
      keyboard.write(0xE0);  // 右Altキーを押した
      keyboard.write(0x11); 
    } else {
      keyboard.write(0xE0);  // 右Altキーを離した       
      keyboard.write(0xF0);
      keyboard.write(0x11); 
    }
  }

  // 右GUIキー
  if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
    if (afterMod.bmRightGUI) {
      keyboard.write(0xE0);  // 右GUIキーを押した
      keyboard.write(0x27);
    } else {
      keyboard.write(0xE0);  // 右GUIキーを離した       
      keyboard.write(0xF0); 
      keyboard.write(0x27); 
    }
  }
};

//
// キー離し ハンドラ
// 引数
//  mod : コントロールキー状態
//  key : HID Usage ID 
//
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) {
  // HID Usage ID から PS/2 スキャンコード に変換
  uint8_t code = 0;
  uint8_t pre = 0;
  if (key >= 0x04 && key <= 0x43) { // keytable1を使った変換
    code = pgm_read_byte(keytable1 + key - 0x04);
  } else if (key >= 0x4A && key <= 0x52) { // keytable2を使った変換
    code = pgm_read_byte(keytable2 + key - 0x4A);    
    pre = 0xE0;
  } else if (key == 0x87) {
    code = 0x51;    
  } else if (key == 0x89) {
    code = 0x6A;    
  }

  // PS/2キーの発行
  if (pre) keyboard.write(pre);
  keyboard.write(0xF0);  
  keyboard.write(code);
};

// HIDマウス レポートパーサークラスの定義
class MouseRptParser : public MouseReportParser {
  protected:
    virtual void OnMouseMove(MOUSEINFO *mi) {};
    virtual void OnLeftButtonUp(MOUSEINFO *mi){};
    virtual void OnLeftButtonDown(MOUSEINFO *mi){};
    virtual void OnRightButtonUp(MOUSEINFO *mi) {};
    virtual void OnRightButtonDown(MOUSEINFO *mi){};
    virtual void OnMiddleButtonUp(MOUSEINFO *mi){};
    virtual void OnMiddleButtonDown(MOUSEINFO *mi){};
};

USB   Usb;
BTD   Btd(&Usb);
BTHID bthid(&Btd, PAIR, "0000");
BTHID hid(&Btd);

KbdRptParser keyboardPrs;
MouseRptParser mousePrs;
int enabled =0; 

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

// ホストから送信されるコマンドの処理
int keyboardcommand(int command) {
  unsigned char val;
  switch (command) {
  case 0xFF:  ack();// Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。
    while(keyboard.write(0xAA)!=0);
    break;
  case 0xFE: // 再送要求
    ack();
    break;
  case 0xF6: // 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //キースキャンを開始する
    //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);
  while(keyboard.write(0xAA)!=0);
  
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1); // Halt
  }

  bthid.SetReportParser(KEYBOARD_PARSER_ID, &keyboardPrs);
  bthid.SetReportParser(MOUSE_PARSER_ID, &mousePrs);
  bthid.setProtocolMode(USB_HID_BOOT_PROTOCOL); // Boot Protocol Mode
  bthid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode
  Serial.println(F("Start."));
}

void loop() {
  unsigned char c;  // ホストからの送信データ
  if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  }  
  Usb.Task();
}

ポケモンキーボード以外のBluetoothキーボードも利用出来ると思います。
ただし、現状はポケモンキーボードに無いキーは未対応です。
カタカナ/ひらがなキー、無変換、変換キー、テンキーは未対応です。

サイズ的に中央に配置出来そうです。
最終的にはこの形態で利用出来るよう、やってみます。

Dscn6083

2016/11/10 追記

取りあえず、ブレッドボードを付かない形態に変更しました。
ちょっと使いやすくなりました。

Dscn6093

参考文献

・USB HID to PS/2 Scan Code Translation Table
  http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
・USBキーボードのキーコード
http://www2d.biglobe.ne.jp/~msyk/keyboard/layout/usbkeycode.html
・Device Class Definition for Human Interface Devices (HID)
  http://www.usb.org/developers/hidpage/HID1_11.pdf
・HID Usage Tables
  http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
・NXP USB and PS/2 Multimedia Keyboard Interface
 http://www.nxp.com/files/microcontrollers/doc/ref_manual/DRM014.pdf

・Sazanami Online PS/2 インターフェイスの研究
  http://hp.vector.co.jp/authors/VA037406/html/ps2interface.htm
・PS/2キーボードインターフェース
  http://www.technoveins.co.jp/technical/keyboard/
・O-Family JIS配列 PS/2 キーボード スキャンコード表
  http://www.ne.jp/asahi/shared/o-family/ElecRoom/AVRMCOM/PS2_RS232C/KeyCordList.pdf


関連記事
IchigoJamでポケモンキーボードを使ってみる (16/11/10) この記事
arduinoでPS/2キーボードのエミュレーションを行う その2 (15/04/23)
arduinoでPS/2キーボードのエミュレーションを行う (15/04/22) 

2016年11月 7日 (月)

Arduino Pro mini Pro Mini用USB HOSTシールドの調査

Arduino pro mini用のUSB Hostシールドを見つけ、入手し動作確認しました。

購入時は$5.78でしたが、現時点では$7.60に値上がりしています。

Mini USB Host Shield Support Google ADK Android For Arduino UNO MEGA Duemilanove
Aliexpress


実際の製品


Arduino Pro mini が上(下でもよかも?)に乗っかるサイズです。
この製品はクローン製品です。オリジナルはCircuits製です。

Dscn6030

オリジナル製品は、本家サイト関連の情報Circuits@Homeを見ると下図のような感じです。

Board
(画像はCircuits@Homeより拝借しています)

オリジナル製品は左上部の5V供給対応のためのジャンパーがありますが、
クローン製品にはそれがありません。

オリジナル、クローン製品とも3.3V稼働がデフォルトです。
5V対応するには、ジャンパーの設定を行い、5V電源をVBUSに別途供給する配線が
必要となります。クローン製品にはそれが出来ないことに注意です。


USBの規格的には、VBASの電圧は4.4V以上との規定があります。
なんで、こんな仕様にしているんですかね。

ですので、このモジュールを使うには3.3Vで稼働するUSB機器に限定します。
ちょっと厳しい条件ですね。


このオリジナル製品に関する情報
  ・Circuits@Home
  ・felis/USB_Host_Shield_2.0 (GitHub)
  ・TKJ Electronics
  ・USB Host Shield 2.0


まずはArduino Unoで利用してみる


Arduino pro miniにはんだ付けして使う前にArduino Unoにて動作確認しました。

上にArduino pro miniを乗せられるようにしつつ、ブレッドボードにてArduino Unoにて
利用できるよう、ピンヘッダを付けました。

Dscn6039

BlueThoothキーボードを使ってみる

pqi製のBluetootドングルを使ってみます。
秋葉原で購入した安価キーボードとペアリングして使ってみます。

Dscn6040

ライブラリをfelis/USB_Host_Shield_2.0から入手し、そのライブラリのサンプルスケッチを
そのまま利用して動作確認を行います。
利用したスケッチは"BTHID"です。

取りあえず、動作しました。

Terminal

本命のArduino pro mini 3.3Vで利用してみる

ピンがハの字に沿っていたおかげて(ははんだ付け精度が悪いのが幸いして)、
がっちりはまり、はんだ付け無しで利用出来ました(これは良い♪)。

Dscn6048

以前作成したPS/2エミュレーションを利用して、IchigoJamのPS/2キーボードとしての
利用を試みます。

Dscn6063

一部のキーは動作しませんが、動作しました。

念のためUSBポートの電圧を測ると、昇圧されることなく3.3Vです。
これだと、規定外なので"動いてラッキー"ですね。
でも、手持ちの無線キーボード、有線キーボードを試すと3.3Vでも結構動きます。
(当然、動かないものもありました。特に古い製品)。

Dscn6065

動いている様子(動画)


取りあえず動きましたが、3.3Vという条件ですのでかなり相性的な問題があると思います。


2016年11月 4日 (金)

ArduinoによるI2C EEPROMのエミュレーション (6)

(2016/12/23 更新・追記)

以前作成したIchigoJam用のEEPROMエミュレーションの小型化を検討し、OpenLogが
使えるのではないかと思い、OpenLogのクローン製品を購入してチャレンジしました。

Aliexpressでは$6.80位で購入できます。

Aliexpress

そして、届いた製品はこんな感じです。

Dscn5974

Dscn5975

基板の片面にAtmega328と水晶発振子 16MHz等が搭載、その裏はmicroSDカードスロットです。

このOpenLogは名称の通りmicroSDカードにシリアル通信経由のログを記録することに
特化したモジュールです。
全ての端子の利用は出来ず、microSDカードスロットの他にシリアル通信、SPI通信しか利用出来ません。
I2Cが利用出来ないのはちょっと残念ですね。

一応、Arduinoのブートローダーが乗っており、スペック的にはArduino Pro miniのように
スケッチの書込みが可能なはずです。


私が目的とするEEPROMエミュレーションにはI2Cが必要なのですがこのままでは
利用出来ませんので強引に信号を取り出します。

Dscn5977

実はこの結線間違てます。詳細は後ほど説明します。 ^^


ユニバーサル基板上のレイアウトを決め、早速実装にかかります。

Photo

出来上がりはこんな感じです。

Dscn5983

IchigoJamに乗せるとこんな感じです。いい感じ!

Dscn5981

スケッチの書込みにはブートローダの書込みが必要

さて、シリアル通信経由でスケッチを書込みましょう。
やってみると、書き込みエラーが発生して書き込みできず。

デフォルトで乗っているOpenLogのプログラムでのシリアル通信は出来ているので、
シリアル接続には問題ないと判断し、ブートローダーが怪しいと思い、
Arduino IDE 1.6.9環境にてブートローダーを書き換えたところ、問題なくスケッチ書き込みhが出来るようになりました。

デフォルトのブートローダーが古かったようです。
ブートローダーの書込みはシリアル経由では出来ないので、SPI接続にて行います。
ラベルの無いSPI端子は次のような割り付けになっています。

MISOの穴はmicroSDカードスロットの樹脂が被さっており、ピンセットとカッターで
樹脂部を削って穴を確保しました。

Spi

書込みのために一時的にSPI端子を仮はんだ付けして端子を確保しました。
書込み機器としてUSBtynyISPを使いました。

Dscn5993

これで、ArduinoPro miniとしてスケッチ書き込みが出来るようになりました。

Ide

早速接続して、動作確認。

Dscn5986

プログラムを保存しようとするとエラーが発生して保存できません。

Ioerror

デバッグ機能にてSDカードは認識しているがI2C通信が出来ていない模様。
調べると、I2Cの信号取り出しの結線が1ピンずれてました(下図が正しいピンです)。

I2c

半田付けを取り除いて、修正を試みましたが無理でした。
ここで諦めるのもなんなので、OpenLogクローンを別に買うことにしました。

この失敗作はシリアル通信、SPI通信、ANA4(SDA)は使えるのでSPIを使う表示機器の
制御実験にても使うことにします。

作業は注文したOpenLogクローンが届くまで中断です。

(2016/12/23 追記)

再チャレンジにて完成しました。
問題なく動作しました。

Dscn6285

Dscn6283


より以前の記事一覧