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

« aitendoの「あちゃんでいいの」を組み立てました | トップページ | Icigojamのファームウェアを1.2 beta 24にアップデートしました »

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の「あちゃんでいいの」を組み立てました | トップページ | Icigojamのファームウェアを1.2 beta 24にアップデートしました »

arduino」カテゴリの記事

IchigoJam」カテゴリの記事

表示器制御関連」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: IchigoJam用漢字フォントモジュールの製作 その2:

« aitendoの「あちゃんでいいの」を組み立てました | トップページ | Icigojamのファームウェアを1.2 beta 24にアップデートしました »