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

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

2016年4月の11件の記事

2016年4月30日 (土)

Arduino1台で複数のI2Cスレーブを実装する

ArduinoのI2CライブラリであるWireを使う場合、同時に複数のスレーブ(複数のアドレス)を
実装することが出来ません。

09

1つのI2Cアドレスを使って送信データで処理を振り分ければいいのですが、
現在取り組んでいる I2C EEPROMエミューレションの実装には必要な機能なのです。

エミュレションのターゲットは Microchip社の24LC1025(容量 128kバイト)ですが、
I2Cスレーブアドレスを2つもつデバイスです(内部的に 64kバイトEEPROMが二つある)。

08

仕様書ではスレーブアドレス部の2ビット目(B0)でバンク切り替えをしています。
(スレーブアドレス的には 0x50 と 0x54 となる ※ 7ビットアドレス指定の場合).

何とかならないかなぁと思い、Atmega328のデータシートを見ると、
複数のスレーブアドレスを同時実装することは可能であることが分かりました。

TWAMR (スレーブアドレスマスクレジスタ)を使えば良いと分かりました(下図)。

07

このレジスタをスレーブアドレス設定直後に、
   Wire.begin(0x50);
   TWAMR = B00001000;

  とすれば、スレーブアドレスの2ビット目が1でも0でもアドレスとして判定されます。
  結果としてスレーブアドレス 0x50と0x54が同時利用出来ます。

  ただし、これだけでは受信したデータがスレーブアドレス0x50宛てなのか0x54宛てなのか
  判定出来ません。

  マスターからアドレスを受け取った直後にTWDRレジスタを参照してアドレス値
  を取得する必要があります。
  この対応にはライブラリの修正が必要となりました。
  といっても、わずかな修正でマルチスレーブアドレス対応が出来ました。

  twi.c の修正
    ・受信スレーブアドレスの保存変数の追加

    static volatile uint8_t twi_adr;	// 2016/04/30 add by Tamakichi

    ・割り込み処理ハンドラ関数 ISR(TWI_vect)のアドレス受信後にスレーブアドレス取得
     するコードの追加

    // Slave Receiver
    case TW_SR_SLA_ACK:   // addressed, returned ack
    case TW_SR_GCALL_ACK: // addressed generally, returned ack
    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack
    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
  	  // save address 2016/04/30 by Tamakichi
  	  twi_adr = TWDR;

    ・保存したスレーブアドレス取得関数の追加、スレーブアドレスマスク設定関数の追加 

    uint8_t twi_get_address(void) {
	return twi_adr;
    }

    void twi_set_addressMask(uint8_t msk) {
	TWAMR = msk;
    }

  twi.hの修正
    ・追加した関数のプロトタイプ宣言の追加      

    uint8_t twi_get_address(void);	// 2016/04/30 add by Tamakitchi
    void twi_set_addressMask(uint8_t);// 2016/04/30 add by Tamakitchi

この修正で何とかいけそうです。
先日書いたスケッチで追加した関数を使って簡単な動作確認をしてみました。
下記はスケッチの抜粋(赤文字が追加部分)

// I2Cマスタからのデータ受信ハンドラ
void receiveEvent(int len) {
  uint16_t d1,d2;
  uint16_t slaveAdr;
  int n = 0;

 slaveAdr = twi_get_address(); // ターゲットスレーブアドレス
    
  // アドレス情報取得
  d1 = Wire.read();
  d2 = Wire.read(); 
  adr = (d1<<8) + d2;
  adr &= 0x3ff;

#if MYDEBUG == 1
  Serial.print("adr=");
  Serial.print(adr,HEX);
  Serial.write(' ');
  Serial.println(len,DEC);
#endif

  // 送信されたデータを受信(データがある場合) 
  while (Wire.available()){
    buf[adr++] = Wire.read();
    if (adr >= 1024) {
        adr= 0;
    }
  }
}

// セットアップ
void setup() {
    adr = 0;
    Serial.begin(115200);
    Wire.begin(DEVICE_ADDRESS) ;        // I2Cの初期化、自アドレスをA0とする
    twi_set_addressMask(B00001000);    // 複数アドレス対応 DEVICE_ADDRESS+0x04 も許可)
    Wire.onRequest(requestEvent) ;      // I2Cコマンド要求割込み関数の登録
    Wire.onReceive(receiveEvent) ;      // I2Cデータ受信割込み関数の登録
    Serial.println("start");
}

IchigoJamからも二つのスレーブアドレスでの保存が出来ています。
(100~163がスレーブアドレス0x50の領域、164~227がスレーブアドレス0x54の領域)

10

slaveAdr = twi_get_address() で取得した値を出力して見るとちゃんとターゲットの
スレーブアドレスが取得出来ています。

11

もうちょっと動作確認し、問題が無ければWireオブジェクトのメソッドとして組み込んで
使いやすくしてみます。

Arduino(あちゃんでいいの)でmicroSDカード利用の動作確認

「あちゃんでいいの」にmicro SDカードモジュールを繋げてmicroSDカードアクセスの
動作確認をしました。



micro SDカードモジュールは以前Aliexpressで5個で$2.83で買ったものを利用しました。(同じストアで追加購入しようと思ったら、品切れで買えず)

3.3Vで利用するタイプです。小型でブレッドボードでの利用に適しています。

Arduino IDE 1.6.8の メニューの [ファイル] - [スケッチの例] - [SD] - [ReadWrite]にて
サンプルスケッチを読み込んで動作確認しました。
サンプルスケッチのCSピンの設定のみ変更し書き込みを行い、問題なく動作しました。

スケッチのコンパイルと書き込み



IDEの出力メッセージを見るとメモリの使用量がちょっと多いです。

 最大32,256バイトのフラッシュメモリのうち、スケッチが12,898バイト(39%)を使っています。

 最大2,048バイトのRAMのうち、グローバル変数が1,006バイト(49%)を使っていて、ローカル変数で
 1,042バイト使うことができます。

  RAMを多く消費する他のライブラリ(TVoutなど)との併用は厳しそうです。

実行中のコンソール出力



microSDカードに作成されたファイル

日付は2000/01/01 1:00 固定のようです。

ファイルの中

書込みも問題なく出来ました。
これで、今着手しているEEPROMエミューレションもSDカードで実装出来そうです。
ただし、メモリ消費がちょっと心配です。

SD Libraryに関するドキュメント
  ・ SD Library(http://www.arduino.cc/en/Reference/SD)

2016年4月29日 (金)

Arduino(あちゃんでいいの)によるI2C EEPROMのエミュレーション

Arduino(あちゃんでいいの)によるI2C EEPROM エミュレーションをやってみました。

目的はIchigoJamとの連携です。
IchigoJamはプログラム保存デバイスとしてI2C EEPROMをサポートしています。
そのインタフェースを使って「通信をしてしまおう!」という目論見です。

05

IchigoJamからは容量 1kバイトの24系のI2C EEPROM として利用出来ます。
(実際はSRAM上に保存のため ROMではないですが.. 最終的にはSDカードに保存したい)

Arduino の I2Cライブラリ(Wire) のスレーブ実装機能が今一問題ありで苦労しましたが、
何とか出来ました。

接続はこんな感じ。ちなみにArduino として aitendo「あちゃんでいいの」を使っているのは、
3.3V 16MHz稼働で利用出来るからです。

Dscn5124

IchigoJamからはプログラム保存番号100として利用出来ます。
実際に動かしてみるとこんな感じです。

02

起動後、LOAD 0 命令で本体保存プログラムをロードし、SAVE 100 でエミュレーションした
プログラム保存番号100 に保存します。 認識されてちゃん動作しています。

次に FILES 100 命令でファイルリストの表示。100番もちゃんと表示出来ました。
ここでプログラムを消して、プログラム保存番号100 をロードします。

03

ちゃんとロードしました。内容も確認。

04

問題無くロード出来ています。

Arduino側でも保存状態を確認出来ます。

06

メニュー選択でプログラムを表示すると、同じものが保存されているのが分かります。

IchigoJam固有フォントで表示出来ない文字はダンプ表示で確認します。

07

容量1kバイトでは全然実用でないですが、SDカードに保存なんか出来るように
したいと思います。

Arduioのスケッチについて

プログラム的にはArduinoをI2CスレーブにしてEEPROMをエミュレーションしています。
利用しているI2Cライブラリ(Wire)をI2Cスレーブとして使う場合、微妙に機能不足で
若干問題ありです。かなりハマりました。

1)受信バッファの問題
まず、受信バッファが32バイトしかなくEEPROMのような一回のトランザクションで
大量のデータ通信を行うスレーブの実装は無理です。

IchigoJamでは一回のトランザクションで34バイトの通信を行うためギリギリでOUTでした。
仕方がなく、ライブラリのバッファサイズ指定部を32にから64に変更しました。
(2ヶ所修正、詳細はソースに記載)

汎用的なEEPROM機能をエミュレーション出来ず、1回あたり64バイトまでの転送という
制約が付きます。

2)スレーブ時のwrite()関数のマスター応答が取得できない問題
また、EEPROMでは可変長データリードをサポートするのですが、この機能を
Arduinoで実装するにあたり、マスターにデータを渡すのにwrite()関数を使うのですが、
この関数は渡した応答(ACK/NACK)を取得することが出来ません。
ちょっと困った仕様です。

下図はそのパケットの仕様でマスターが次のデータの受信が不要の場合、NACKで応答します。

08

この対応としては、write()関数で多めにデータを送信することで対処出来ることが分かりました。
ライブラリ内部ではマスターからNACKを受け取ると送信はそこで終了するようです。
(ロジックアナライザで確認にて確認)

09

プログラムではwrite()関数で常に64バイトを送信していますが、実際にはマスターが
NACKを返した時点で送信は終了します。ちょっと美しくないですね。

ここでwrite()関数が実際に送信したバイト数を返してくれればよいのですが64が帰って
きます。関数のソースを見ると引数の送信バイト数をそのまま復帰値として返すと
いう手抜きをやってくれていました。

何処にもそんな仕様が書かれていないようですし.. まあ、この対処で良しとしましょう。

スケッチ ダウンロード Ichigoepprom.zip (2.0K)

//
// I2C EEPROMエミュレーション調査
// 2016/04/26,4/30 Tamakichi
//
// 注意:このスケッチの動作にはWireライブラリの修正が必要
//  修正箇所 
//   \libraries\Wire\utility\twi.h #define TWI_BUFFER_LENGTH 32 => #define TWI_BUFFER_LENGTH 64
//   \libraries\Wire\Wire.h        #define BUFFER_LENGTH 32 => #define BUFFER_LENGTH 64
//

#include <Wire.h>

#define DEVICE_ADDRESS 0x50  // AT24C1024B I2Cデバイスアドレス 
#define MYDEBUG 0            // 0:デバッグ表示on(=1)/off(=0)
 
 uint8_t buf[1088]; // プログラム保存領域 
 uint16_t adr;      // EEPROM アクセスアドレス

// I2Cマスタからのデータ受信ハンドラ
void receiveEvent(int len) {
  uint16_t d1,d2;
  int n = 0;
  
  // アドレス情報取得
  d1 = Wire.read();
  d2 = Wire.read(); 
  adr = (d1<<8) + d2;
  adr &= 0x3ff;

#if MYDEBUG == 1
  Serial.print("adr=");
  Serial.print(adr,HEX);
  Serial.write(' ');
  Serial.println(len,DEC);
#endif

  // 送信されたデータを受信(データがある場合) 
  while (Wire.available()){
    buf[adr++] = Wire.read();
    if (adr >= 1024) {
        adr= 0;
    }
  }
}

// I2Cマスタからの要求の処理
void requestEvent() {
  uint16_t n;
  uint8_t  sts;
  uint8_t  i;
  
#if MYDEBUG  == 1
  Serial.print("req ");
  Serial.println(adr,HEX);
#endif
  Wire.write(&buf[adr], 64);
}

//
// 保存プログラムのダンプ表示
//
void disp_prog() {
  uint16_t ptr = 0;  // 参照位置
  uint16_t nm,n1,n2; // 行番号
  uint8_t sz;        // 行サイズ
   Serial.println("Ichigojam program list");
  while (1) {
    n1 = buf[ptr++];
    n2 = buf[ptr++];
    nm = n1 + (n2<<8);
    if (!nm)
      break;
    sz = buf[ptr]; ptr++;
    Serial.print(nm,DEC); Serial.write(' ');
    for (uint8_t i= 0; i < sz; i++) 
      Serial.write(buf[ptr++]);
    Serial.println();
    ptr++;  
  }  
}

//
// 書込みデータのダンプリスト
// dt(in) : データ格納先頭アドレス
// n(in)  : 表示データ数
void dump(byte *dt, int n) {
  unsigned long sz;
  char buf[64];
  int clm = 0;
  byte data;
  byte sum;
  byte vsum[16];
  byte total =0;
  int saddr =0;
  int eaddr =n-1;
  sz = eaddr - saddr;
  
  Serial.println(F("----------------------------------------------------------"));
  for (int i=0;i<16;i++) vsum[i]=0;  
  for (unsigned long addr = saddr; addr <= eaddr; addr++) {
    data = dt[addr];
    if (clm == 0) {
      sum =0;
      sprintf(buf,"%05lx: ",addr);
      Serial.print(buf);
    }

    sum+=data;
    vsum[addr % 16]+=data;  
    sprintf(buf,"%02x ",data);
    Serial.print(buf);
    clm++;
    if (clm == 16) {
      sprintf(buf,"|%02x ",sum);
      Serial.print(buf);      
      Serial.println("");
      clm = 0;
    }    
  }
  Serial.println(F("----------------------------------------------------------"));
  Serial.print("       ");
  for (int i=0; i<16;i++) {
    total+=vsum[i];
    sprintf(buf,"%02x ",vsum[i]);
    Serial.print(buf);
  }
  sprintf(buf,"|%02x ",total);
  Serial.print(buf);      
  Serial.println("");
  Serial.println("");
}

// セットアップ
void setup() {
    adr = 0;
    Serial.begin(115200);
    Wire.begin(DEVICE_ADDRESS) ;        // I2Cの初期化、自アドレスをA0とする
    Wire.onRequest(requestEvent) ;    // I2Cコマンド要求割込み関数の登録
    Wire.onReceive(receiveEvent) ;      // I2Cデータ受信割込み関数の登録
    Serial.println("start");
}

// メイン処理
void loop() {
  byte c;
  Serial.print(F("Menu(1:disp 2:dump 3:init) ="));
  while ( !Serial.available() );
   c = Serial.read();
   if (c == '1') {
     Serial.println();
     disp_prog();
   } else if (c == '2') {
     Serial.println();
     dump(buf, 1024);
   } else if (c == '3') {
     Serial.println();
     adr = 0;
     for (uint16_t i = 0; i < 1088; i++)
       buf[i] =0;
   } else {
     Serial.println();
   } 
}

2016年4月26日 (火)

IchigoJamの新しいファームウェア 1.2 リリースのようです

IchigoJamの1.2系ファームウェアが正式にリリースされました。


こどもIoTを実現する、こどもパソコン『IchigoJam』ver 1.2 リリース

01

さっそくファームウェアを1.2.0にアップデートしました。
IchigoJam ファームウェア 入手サイト http://ichigojam.net/farm.html

02

ファームウェア 1.2.0では文字列が利用出来るようになりました。
また、いくつかの点が改良・改善されています。


2016年4月24日 (日)

「IchigoJam」の新製品が出るっぽい

開発者 福野さんのブログによるとIchigoJamの新製品が出るようです。 

福野泰介の一日一創 -
  自分で作って学べるコンピューター「IchigoJam」の新プリント基板、小型CPU「LPC1114FDH28」にも対応予定




現行のmicroUSBコネクタは疲労で取れやすい、PS/2キーボードコネクタは、
USB - PS/2変換コネクタを使って接続する必要がありかさばる問題があったのですが、
今回の基板では改善されているようです。

キーボードI/Fは一見USB対応っぽいですが、そうではなくPS/2仕様のキーボードのみ対応
です。現状、流通しているUSBキーボードはUSBコネクタ接続が殆どです。
しかも、PS/2仕様で利用できるものが大半でわざわざ USB - PS/2変換コネクタ無しでも
PS/2仕様で利用できます。
ただし、ワイヤレスキーボードはPS/2対応していないですね。

2016年4月23日 (土)

Ichigojamのプログラム保存領域 その1

Ichigojamのプログラム保存をSDカードでやってしまおうと構想しており、
まずはIchigoJamのプログラム保存に関してのちょっと確認とまとめをしてみました。

Ichigojamのプログラム保存機能の確認

Ichigojamでは作成したプログラムを本体のフラッシュメモリ領域に4本まで保存することが出来ます。

  □作成したプログラムを保存する
     SAVE n  (nは0~3を指定、省略時は0とみなす)

   01

先頭行にコメントでプログラムの説明を記載するのがIchigojam的作法です。

次に本体のフラッシュメモリに何が保存されているかを調べる場合は、FILES命令を使います。

  □保存されているプログラムリストの表示
     FILES n,m  (n,mは表示する範囲 省略時は 0,3指定と同じ)

  02_2

このコマンドでは、保存されている各プログラムの先頭行をリスト表示します。
ですので、先頭行にコメントや作成日を付けると良いですね。
上記リストのプログラム 1,3 は何のプログラムだか分かりませんね。

保存したプログラムのロードはLOAD命令を使います。

  □保存されているプログラムをメモリにロードする
      LOAD n  (nは0~3を指定、省略時は0とみなす)

  04

電源を入れた直後にFILESコマンドでリストを表示して確認、LOADコマンドで
プログラムをロードってな感じで使います。

ここで、若干注意が必要です。現在プログラムを実行していて別のプログラムを
LOADコマンドでロードした場合、プログラム領域はロードしたプログラムに置き換わる
のですが、変数領域、キャラクタ定義領域等は初期化されず、前のプログラムで利用した
ままの状態になっています。

初期化するにめ明示的にコマンドの実行が必要です。
  □ 変数領域の初期化        CLV
  □ キャラクタ定義領域の初期化    CLP
  □ タイマーカウンタの初期化        CLT
  □ キーバッファーの初期化          CLK
  □ 画面表示の初期化                 CLS
   
ここまでが基本的な機能ですが、ほかに起動後にプログラムをロードして実行する
機能もあります。

□起動後に保存プログラム番号0 をロードして自動起動する
    Ichigojam本体のボタンを押しながら電源を入れる、
   または BTNピンをGNDに接続して電源を入れる、
   または SOUNDピンをプルダウン
接続して電源を入れる(20kΩ程度)
   とプログラム番号0を自動起動する。

 
参考文献:福野泰介の一日一創  - IchigoJamのピン配置解説、IchigoJamを自動起動させてマイコン的に使う新方式 ver 1.2β1

  Dscn5090

    この場合の起動では、起動時のバージョン等の表示は行われません。
    この機能は、Icihojamをロボットカーなんかに組み込んで使う場合に便利です。
    キーボード無しでプログラムに実行が出来ますね。

また、プログラムから別のプログラムをロードして実行する機能があります。

  □指定したプログラムをロードして実行する
     LRUN n,m (nはプログラム番号、mはプログラム内の行番号,省略時は直前ロードしたプログラム番号)

     05

     上記のプログラムは実行したいプログラム番号を入力して実行するというものです。
     0を指定して、保存したプログラム番号0が実行されます。

     LRUNもLOADと同様、変数領域等は直前のプログラムで利用した状態のままです。

     06

     実行後、元に戻る場合はLRUNを使います。

     07

    行番号の指定も可能なでの、プログラム間のでのジャンプが出来ます。    

     08   

    LRUN 3,40 にて プログラム番号3の40行にジャンプして実行した結果です。

    プログラム間を渡り歩いても変数領域等は継承されるので上手く利用すれば
    大きなプログラムが作成出来ます。

以上のプログラム保存機能は外部接続EEPROMでも利用出来ます。
Ichigojamは外部記憶装置的にI2C接続のEEPROMにプログラムの保存が出来ます。
本体保存領域への保存と異なるのはプログラム番号が100以降となるだけです。

   参考文献
     福野泰介の一日一創 - 外部記憶装置とROMカセットに対応!こどもパソコンIchigoJam
     イチゴジャムレシピ - 外部記憶装置 EEPROM

      
外部接続EEPROMについては次回とします。
取りあえずArduino(あちゃんでいいの)でI2C EEPROMをエミュレートしてSDカードに
読書きしようと考えています。 出来そうな感じなのですが、まだ調査段階です。

2016年4月20日 (水)

Icigojamのファームウェアを1.2 beta 24にアップデートしました

Ichigojamのファームウェアを1.2 beta 24にアップデートしました。

02

IchigoJam のファームウェア1.2系が頻繁にアップデートされています。
近々1.2系の正式版が公開されるようです。

昔作成した「処理が遅いなぁ」と思っていたプログラム(ファームウェアバージョン 0.9.3時)を
このバージョンで動かしてみると、かなり高速化されているのが分かります。

Ichigojam ファームウェア 1.2 beta 22 b24 の動作の様子


Ichigojam ファームウェア 0.9.3 の動作の様子


次元の異なるレベルで改善されています。

試したプログラムソース

10 CLS
30 [0]=31599:[1]=4681:[2]=29671:[3]=29647:[4]=23497
40 [5]=31183:[6]=31215:[7]=29257:[8]=31727:[9]=31695
50 [10]=1040:[11]=0:[20]=32:[21]=1
100 N=0:P=0:Q=0
210 X=P:Y=Q:GOSUB 500
220 N=N+1:IF N=10 N=0
230 P=P+4:IF P>31 P=0:Q=Q+6:IF Q >20 ?:END
240 GOTO 210
500 B=12
510 D=[N]>>B&7:GOSUB 600:IF B>=0 GOTO 510
520 RETURN
600 LC X,Y:?CHR$([20+(D&4>0)]);CHR$([20+(D&2>0)]);CHR$([20+(D&1>0)]);
610 Y=Y+1:B=B-3
620 RETURN

注)0.9.3版と比べると画面表示の横が36文字から32文字に変更となったため
     横の表示文字数だけプログラムを変更しています。

このプログラムも1.2系の命令を使うともうちょっと短く出来ます。
また、0.9.3ではFOR文が利用出来ないために繰り返し処理にGOTO文を
使っておりちょっとスパゲッティなプログラムになっています。

2016年4月12日 (火)

IchigoJam用漢字フォントモジュールの製作 その2

ちょっと間が空きましたが前回の続きです。

当初LPC810にて実装をするつもりでしたがメモリーとI/Oピンの制約が厳しいので
ATmega328でやろうと思いつつ、aitendoの あちゃんでいいの(AKIT-ADINO) で取りあえず
実装することにしました。

まあ、こんなことする意味もないのですが、取りあえず情報量と実績の多いArduinoの
資産をIchigoJamにて利用出来たらよいなぁと思い、連携方法について試していきます^^。

回路的には前回のArduinoによる実装を あちゃんでいいの への置き換えです。
動作も前回と同じですが、Ichigojam側のプログラムをちょっと修正しました。

Dscn5068

接続図

01_2

あちゃんでいいの およびブレッドボード用の電源はIchigojamからの供給としています。
非公式ですが、3.3V 16MHzで利用出来るので接続性が良いです。

IchigoJamとあちゃんでいいのはI2Cバスにて接続しています。

処理イメージ

02_2

今回の実装では上記の図の表示用メモリの転送をI2Cバスにて行っています。
IchigoJamからの命令で漢字文字列をあいちゃんでいいのに送信し、SPI接続の
漢字ROMを使ってイメージを作成し、IchigoJamの表示用メモリに転送しています。

この仕組みを使えば、漢字の他に図形描画も出来ますね。
さらに別の領域のキャラクタ定義、変数領域も同様なことをやるともっと面白いことが
出来そうです。

IchigoJamのプログラム
ファームウェア1.2系で実装しました。文字列とラベルジャンプを使っています。
文字列が使えるので前回よりもスッキリしました。

10 'Kanji3
20 [0]="ついに漢字フォント搭載!"
30 [1]="大きな文字で日本語が表示"
40 [2]="が出来るぞ!でも文字が大"
50 [3]="き過ぎて用途が無いかも?"
60 @LOOP:CLS
70 POKE #700,1
80 FOR P=0 TO 3
90 R=I2CW(#10,#700,1,[P],24)
100 FOR I=0 to 23
110 POKE #700,i
120 R=I2CR(#10,#700,1,#900+i*32,32)
130 NEXT
140 WAIT 100
150 NEXT
160 WAIT 200
170 GOTO @LOOP

Ichigojam上では当然漢字の入力が出来ないためプログラムはWindows上にて
サクラエディタにて書いています。
また漢字部分のコードがシフトJISである必要があるため、エンコードはシフトJISを指定
しています。

これをIchigojamに転送して実行させます。
プログラム的には、20~50行の文字列をI2Cにてあちゃんでいいのに送信し、
あちゃんでいいのにて1画面分のデータを作成したのち、IchigojamからI2Cの要求にて
データを受信しています。

受信したデータはダイレクトに表示用領域に書き込んでいるのでその内容がそのまま
画面に表示されます。

あちゃんでいいの(Arduino)のスケッチ

#include <SPI.h>
#include <Wire.h>
#include <string.h>

#define CS_PIN   10      // CSピン
#define ASC8x16S 255968  // 8x16 ASCII 粗体字符(半角)
#define ASC8x16N 257504  // 8x16 ASCII 日文假名(半角)
#define CHR_BNK  0x80    // 疑似グラフィックフォント先頭コード
#define TWI_STX   4

extern "C" {
  uint8_t get_twi_state();
}
  
byte screen[32*24];        // IchigoJam用スクリーンデータ
byte rcv[32];              // I2C受信データ
byte str_len;              // 格納文字数

//
// シフトJISコードからJISコード変換
// 引  数: s_code シフトJIS文字コード
// 戻り値: JISコード文字コード
//
uint16_t sjis2jis(uint16_t s_code){
  byte c1 = s_code >>8;
  byte c2 = s_code & 0xff;
  uint16_t j_code;
  uint16_t adjust = c2 < 159;
  uint16_t rowOffset = c1 < 160 ? 112 : 176;
  uint16_t cellOffset = adjust ? (c2 > 127 ? 32 : 31) : 126;

  j_code  = ((c1 - rowOffset) << 1) - adjust;
  j_code <<=8;
  j_code += c2- cellOffset;
  return j_code;
}

// 
// 漢字ROM  GT20L16J1Y用
// 全角JISコードからフォント格納先頭アドレスを求める
//   GT20L16J1Y データシート VER 4.0 2013-3のサンプルを参照した
//   (サンプルでは区点コードからの変換であることに注意)
// 引  数 : jiscode JIS文字コード
// 戻り値 : 該当フォントデータ格納アドレス
//
uint32_t calcAddr(uint16_t jiscode) {
  uint32_t MSB;   
  uint32_t LSB;
  uint32_t Address;
  char buf[32];

  // 上位、下位を区点コードに変換
  MSB = (jiscode >> 8) - 0x20;
  LSB = (jiscode & 0xff) -0x20;
  
  // データ格納アドレスを求める
  if(MSB >=1 && MSB <= 15 && LSB >=1 && LSB <= 94)
    Address =( (MSB - 1) * 94 + (LSB - 01))*32;
  else if(MSB >=16 && MSB <= 47 && LSB >=1 && LSB <= 94)
    Address =( (MSB - 16) * 94 + (LSB - 1))*32+43584;
  else if(MSB >=48 && MSB <=84 && LSB >=1 && LSB <= 94)
    Address = ((MSB - 48) * 94 + (LSB - 1))*32+ 138464;
  else if(MSB ==85 && LSB >=0x01 && LSB <= 94)
    Address = ((MSB - 85) * 94 + (LSB - 1))*32+ 246944;
  else if(MSB >=88 && MSB <=89 && LSB >=1 && LSB <= 94)
    Address = ((MSB - 88) * 94 + (LSB - 1))*32+ 249952;
  
  return Address;
}

//
// 漢字ROM  GT20L16J1Y用
// 漢字ROMフォントを表示用形式に変換する
// 引数 :fnt(out)    変換したデータの格納アドレス
//      :rdata(in)   変換元データの格納アドレス
//
void rowtofont(uint16_t* fnt, byte* rdata) {
  for (byte i=0; i <16; i++)
    fnt[i]=0;
  
  for (byte i=0;i<8;i++)
    for (byte j=0; j<16; j++) { 
       fnt[7-i] |= (rdata[j] & 0x1<<i ? 0x8000: 0) >>j;
       fnt[15-i] |= (rdata[j+16] & 0x1<<i ? 0x8000: 0) >>j;
    }   
}

//
// 漢字ROM  GT20L16J1Y用
// シフトJIS漢字コートに対応するフォントデータの取得
// 引数  :fnt(out)   フォントデータ格納アドレス
//       :code(in)   シフトJIS文字コード
//
void loadfontdata(uint16_t* fnt, uint16_t sjis_code) {
   byte rdata[32]; // 16x16データ
   getCharData(rdata, sjis2jis(sjis_code)); // 生フォントデータの取得
   rowtofont(fnt, rdata);                   // 表示用にデータ変換
}

//
// 漢字ROM  GT20L16J1Y用
// SPI接続 漢字ROMからJISコードに対応するフォントデータを得る
// 引数 :rdata(out) フォントデータ格納アドレス
//      : code(in)  JIS文字コード
//
void getCharData(byte* rdata, uint16_t code) {
    byte data;
    uint32_t addr=0;
    byte n;
 
    if (code > 0xFF) {
      // 全角
      addr =calcAddr(code);
      n = 32;
    } else {
      // 半角
      addr = ASC8x16N + (code*16);
      n = 16;
    }
    
    digitalWrite(10, HIGH);
    delayMicroseconds(10);   
    digitalWrite(10, LOW);
    SPI.transfer(0x03);
    SPI.transfer((addr>>16) & 0xff);
    SPI.transfer((addr>>8) & 0xff);
    SPI.transfer(addr & 0xff);
    SPI.setBitOrder(LSBFIRST);
    
    for(byte i = 0; i< n; i++)  {
      rdata[i] = SPI.transfer(0x00);
      delay(10);
    }
    SPI.setBitOrder(MSBFIRST);
    digitalWrite(10, HIGH);
}

//
// 1文字分フォントデータをIchigojam疑似グラフィックデータに変換し
// 指定位置に配置する
// 引数 sc : IchigoJam用表示データ
//      fd : 1文字分16x16フォントデータ
//        x: 横位置 0~23
//        y: 縦位置 0~15
//
void setFontToScreen(byte* sc, uint16_t* fd, byte x, byte y) {  
  byte   i,j;
  int    s_pos = x + y * 32;
  byte   d;
  uint16_t w1,w2,*pt;
  pt = fd;
 
  //疑似グラフィック 8x8キャラデータ変換
  for (i = 0; i < 16; i += 2) { // 縦  
    w1 = *pt++;   // 上行16ドット分
    w2 = *pt++;   // 下行16ドット分
 
    for (j = 0; j < 8; j++) { // 横
       d = ( w1 >> (14-j*2) ) & 3;  // 上2ドット取得
       sc[s_pos] =  (d>>1 | (d&1)<<1)  + CHR_BNK; 
       d = ( w2 >> (14-j*2) ) & 3;  // 下2ドット取得
       sc[s_pos] |= ((d>>1) | ((d&1)<<1)) <<2; 
       s_pos++;
    }
    s_pos += 24;
  }  
}

// 文字列を疑似グラフィックデータに変換する
// 引数 :sc  スクリーンバッファ
//      :dt  文字列データ
//      :len 文字列長
//
void convToScreen(byte* sc, byte *dt, byte len) {
  uint16_t fd[16];  // ビットマップフォントデータ
  int y = 0,x = 0;  // バッファ内表示位置
  uint16_t code;    // シフトJIS文字コード
  str_len = len;    // 文字列長
  
  for (int i = 1; i <24; i+=2) {
    code = dt[i]; code<<=8; code+= dt[i+1]; 
    loadfontdata(fd, code);         // 文字コードに該当するフォントデータの取得
    setFontToScreen(sc, fd, x, y);  // スクリーンにフォントを書き込み 
    x += 8;
    if (x > 31) {
      x = 0;
      y = y + 8;
    }
  }
}

// I2C マスターからのデータ受信
//  グローバル変数rc[]に受信データを格納する
//  最大データ長:24バイト
void receiveEvent(int howMany) {
  byte d;
  byte len = 0;
  for (int i=0; i < howMany; i++) {
      d = Wire.read()  ;
      if (len < 25) {
        rcv[len++] = d;
      }      
  }
  
  if (len > 0) {
    // 受信データのチェック
    if (rcv[0] == 0) {
      convToScreen(screen, rcv, len);
    }
  }  
}
  
// I2Cマスタからの要求の処理
void requestEvent() {
  if (str_len > 0)
      Wire.write(&screen[rcv[0]*32], 32);  
}

// セットアップ
void setup() {
    pinMode(CS_PIN,OUTPUT);            // SPI_CDピン
    SPI.begin();                      // SPIの利用開始
    Wire.begin(0x10) ;                // I2Cの初期化、自アドレスを8とする
    Wire.onRequest(requestEvent) ;    // I2Cコマンド要求割込み関数の登録
    Wire.onReceive(receiveEvent) ;    // I2Cデータ受信割込み関数の登録
}

void loop() {
}

プログラム的にはI2Cを使ってIcigojamからはI2Cデバイスとして振る舞います。
I2Cのwireライブラリをスレーブとして使う場合、ちょっと問題があるようなので
ライブラリをちょっと修正してます。

    ライブラリの修正については下記を参照
      IchigoJamとArduinoでI2Cバス通信を試してみる

プログラムがちょっと突貫工事なので、もう少し2者間の通信インターフェスを詰めた
方がよさそうです。

aitendoの「あちゃんでいいの」を組み立てました

aitendoの あちゃんでいいの(AKIT-ADINO)を組み立てました。

01

Atmega328は別途購入する必要がありますが、166円と安いです。
3.3V 16MHz動作のArduino環境が欲しいと考え、組み立てました。

Dscn5056

袋の中はこんな感じです。真ん中の白いのはチップコンデンサとチップ抵抗です。

Dscn5057

チップ抵抗とコンデンサがちょっとはんだ付けが面倒ですが、
取りあえず苦も無く組み立て終了。

  今調べると半実装済バージョンがあるようです。
  最初から、チップ抵抗とチップコンデンサが実装されているようです。
  基板のパターンが全然違いますね。縦の長さが50mmから44.43と5mm短くなってます。
  こっちの方が良かったなぁ。電解コンデンサとセラコンがチップコンデンサに置き換わって
  いて、LEDが1つ追加されています。


    02

完成はこんな感じです。

Dscn5060

次に動作確認です。まずはプログラマとしてUSBtinyISPを使っての接続。

Dscn5061

まずは、ブートローダ無しでの書込みでLチカしてみます。
メニュー のツール/.書込装置でUSBtinyISPを選択し、通常の書き込みではなく
「書込装置を使って書き込む」で書き込みます。問題無く書き込めました。

03

次にブートローダを書き込みます。

04

ブートローダも問題なく書き込めました。
さらにブートローダ経由での書き込みの動作確認をします。

USB-UARTモジュール経由でスケッチを書き込みます。

Dscn5062

スケッチの例にてASCIItableスケッチを選択し、
Arduino IDEの(⇒)ボタン(マイコンボードに書き込む)にて書込みます。

この時、供給電源はUSB-UARTの3.3Vを利用します。

05

書込みは問題なく完了。
スケッチも3.3V 16Mhzにて正常に動作しました。

06

この あちゃんでいいの はとりあえずIchigojamの上か下に取り付けての電源供給で
稼働させて、I2Cスレーブ接続にて色々やらせたいと思っています。

大きさ的にも、いい感じです。

Dscn5065

構想としてはこんな感じ
  ・arduino経由でSDカードの利用
  ・arduinoで数値演算支援(浮動小数演算)
  ・arduinoでグラフィック表示支援(以前やった漢字表示+円や直線の描画支援)
  ・arduinoで赤外線リモコン -> PS2キーボード変換 -> Ichigojam PS/2端子

2016年4月 8日 (金)

AliexpressでHDMIセレクタを購入、不良品のため全額返金

AliexpressでHDMIセレクタを購入(下の画像の製品)し、

01

到着した製品を使ってみると動作せず(下の画像がその製品)
微妙に製品が見本画像と異なります。電源コネクタの位置が違う、ラベルが違う。

Dscn5054

製品的には400円でリモコン付き、3入力のセレクタ、送料無料は格安です。

売り方に不良の旨を連絡しても回答が無いので、紛争を起こすことにしました。

数日たって、回答が来て全額返金、返品無しの要求に応じてくれました。

下記は紛争の際のメッセージと添付画像、売り方の回答です。

02

評価として☆を4つ以上付けてくれと要求していますが、対応としては良好なので
☆4つとすます。

過去の紛争履歴が見れるので、調べると6回起こしていました。
今のところ、全てこちらの希望通りの要求を売り方が受け入れて解決しています。

2016/04/09 追記
評価☆5つとしました。

03

この製品、評価を見ると"Full Refund"(全額返金済)が若干多い気がします。
ただし、それでも高評価で☆4、5個です。
不良品に対して、売り手の対応が良好なのでしょう。

売り手も粗悪品を高値で売りつけるってわけでもなく、不良品率を販売価格に上乗せして
売っている程度で格安販売している良好な状況です。
平均評価も4.7と高いです。

ただし、フィードバックによる評価で☆1つが7件あります。
"Full Refund"の表記も無しです。
☆1つの評価理由は、”商品が来ない”、”品質が悪い”のようですが、
これは返金要求もせず、受け入れているので買い手がおバカさんとも言えます。
☆1の評価者、ランクがA1、A2が大半なので、システムを理解していないのかもしれません。


2016/04/24 追記


修理したら使える? ダメ元で基板を取り出してチェック。
電源コネクタがグラグラ、一ヶ所はんだ付けされていませんでした。

そこをはんだ付けし、他の甘い箇所を数点はんだ付けして動作確認すると
電源ランプが点灯し、リモコン・手動にて映像切り替えが出来ました。

04

背面の何点かをはんだ付けし直した状態

05

付かなかったLEDが点灯、映像も正常に切り替えて表示可能に

06

これはラッキーでした。

2016年4月 1日 (金)

2個で$0.67のUSBコネクタ、微妙に写真と異なる製品到着

AliexpressでUSBコネクタを購入。4個買いましたが到着した製品が写真と微妙に異なります。

注文した商品

01

届いた商品

Dscn5028

色と形状が微妙に異なります。固定用のねじ穴が4つから2つです。
写真のピンヘッダも付いてませんでした。

まあ、これは許せる範囲なので紛争はおこしませんでした。
評価を辛めに★3つにしました。


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