LSI Jiu-Jitsu

半導体とブラジリアン柔術

第6回東日本柔術選手権

6月23日に墨田区体育館で行われた

JBJJF - 第6回東日本柔術選手権

に参加して参りました。

東日本選手権は第3回、第4回と出場したのですが、昨年の第5回は都合により参加できませんでしたので2年ぶりの参戦です。
過去2回はワンマッチだったのですが、今年は4人トーナメントなので優勝までは2試合の山となりました。

23日の土曜日が紫・茶・黒帯の試合で、24日の日曜日が白・青帯の試合となっています。
道場からは多数の選手が出場するので、なんとしても優勝して気分良く24日の応援に繋げたいところです。

1試合目は開始早々に引き込んで早い時間にスイープが成功しました。
しかし、抑え込めず直ぐに立ち上がられました。
スタンドから再度引き込んで下から攻めますが、強烈なパスアタックで1つアドバンテージを取られてしまいました。
その後はなんとか凌いでP2-0、AD0-1で勝つことができました。
正直、アドバンテージを取られた時はパスされたと思いましたが、諦めずに動いたことでアドバン止まりで耐えれたような気がします。

勝戦の相手選手は下から攻めてくるタイプの選手と思ったのですが、意外とワタクシに下と取らせてくれました。
スイープを狙うもベースが強くて崩せません。
パスアタック vs. ガードの攻防が5分間続きました。
お互い、ポイント、アドバンテージ無しでレフリー判定となりました。
残り20秒で強引にスイープアタックを仕掛けましたが、どちらかと言うと相手選手のパスアタックの時間の方が長かった気がします。
負けたな・・。
と、思ったのですが、手が上がったのはワタクシでした。
ちょっとビックリ(笑)

2試合ともギリギリの勝利で優勝となりましたが、たくさんの反省点が残る結果となりました。
次回までに修正してまた頑張りたいと思います。

でも、まぁ、ちょっと自分へのご褒美として帰りにヨドバシカメラでSwitch版のマインクラフトを買いました(笑)
最初は何をしていいのかわからず戸惑いましたが、慣れてきたら楽しくなってきました。

OLED 0.96インチで遊ぶ ~その7~

Amazonで1.3インチのOLEDを見かけたので買ってみました。

www.amazon.co.jp

レビューを見るとインターフェース(SPI or I2C)と色(白 or 青)は届くまでわからないとのこと(笑)
確かに注文時に選択する箇所が無いので、I2Cが届くことを願いながら注文しました。

結果・・

届いたのは7ピンのSPIでした(笑)

0.96インチと並べると大きさは一目瞭然です。

調べてみると裏の抵抗の位置を変えればI2Cで動かすことができるらしいのですが、せっかくなのでSPIのまま動かしてみることにしました。
また、コントローラーもSSD1306では無く、SH1106と言う型番のようでレジスタ形態が若干違うようです。
データシートは検索したら直ぐに入手できました。

ベースとなる回路とプログラムは前回作った馬のアニメーションgifです。
PICのSSP1はそのままI2CでEEPROMを接続し、SSP2をSPIにしてOLEDと接続しました。

f:id:mohran:20180704001102p:plain

OLEDのピンは左から
  GND
  VCC
  SCK(SPIクロック)
  SDI(SPI入力データ)
  RES(リセット)
  DC(データ/コマンド)
  CS(チップセレクト)
の並び順になっています。

DCとCSが存在しているので、4線式のSPIであることが伺えます。
SH1106のデータシートにタイミングチャートが載っていました。

f:id:mohran:20180704001108j:plain

A0がDCに相当しており、Lowでコマンド、Highでデータとなっています。

PICとの接続は下記のようにしました。
  RC4 : SCK
  RC5 : SDI(SDO)
  RA2 : RES
  RC2 : DC
SPIデバイスはOLEDのみなので、CSはLow固定にしています。

SPIクロックは最速の1Mにしました。
SPI通信はI2C通信と同様にPICのレジスタを操作することでPICが自動で行いますが、DCはRC2を直接操作して設定しています。

コマンドはほぼSSD1306と同じでしたが、アドレッシングモードはPageモードのみのようで、カラムには2のオフセットを付けて指定する必要があるようです。
(値2で位置0になる)
また、チャージポンプの設定は不要でした。

その他、表示On(0xaf)もSSD1306と同じなのでさほど苦労せずに動かせました。
しかし、せっかく1MHzのSPIクロックで送信しているのに表示はそれほど速くなった感じがしません。
おそらく400KHzのI2CクロックでEEPROMから表示データをリードしているのがボトルネックになっていると予想されます。
そこで、EEPROMも高速版(最大1MHz)の24FC512を使用してSPI、I2C共に1MHzで動かしてみることにしました。
24FC512は秋月電子で140円でした。

8MHzのメインクロックから、I2Cクロック1MHzを作るにはデータシートの式からSSP1ADDには値1を設定しなければいけません。

f:id:mohran:20180705001230j:plain

しかし、注釈のようにSSP1ADDはI2C使用時は3以上では無いといけないようなので、逆算するとメインクロックは最低でも16MHzが必要になります。
また、SSP1STATのビット7 のSMPにも1をセットしないと1MHzで通信できないようでした。

f:id:mohran:20180705233947j:plain

これに気がつかず3時間ほどハマってしまいました(笑)
(ステータスレジスタなのに設定項目があったとは・・)

このように色々と変更を加えたプログラムはこちらになります。

前回のI2C 400KHzよりもかなり高速に表示できました。
そして、1.3インチも見やすくていい感じです。

OLED 0.96インチで遊ぶ ~その6~

前回の ~その5~ に続いて今回もPICから表示を行ってみます。

表示する画像データは予め外部のEEPROMに格納しておき、I2Cバスを通してリードを行いOLEDへ送信するようにしました。

EEPROMは24LC256を使用しました。
秋月電子で100円でした。
1枚の画像データのサイズは128x64=8,192bit(1,024Byte)なので、32KByteの24LC256には最大32枚セットしておくことができます。

今回、画像データはフリー素材の馬が走っているアニメーションgifから作りました。
アニメーションgifをこちらのサイトで1枚づつに分解しておきます。

ysklog.net

分解した画像を ~その3~ で使用したgimpで128x64にリサイズしてpbmファイルに変換します。

そして、EEPROMへ書き込むにはHEXフォーマットにしておく必要があるので、スクリプトを通してpbmファイルをHEXファイルに変換します。


引数にpbmファイルとEEPROMへ格納するアドレスを16進数で指定します。
1枚当たり1,023Byteなので、0x400番地単位でピッタリ収まります。
使用したアニメーションgifは8枚で構成されていました。

$ ./pbm2hex.pl horse0.pbm 0000 >  eeprom.hex
$ ./pbm2hex.pl horse1.pbm 0400 >> eeprom.hex
$ ./pbm2hex.pl horse2.pbm 0800 >> eeprom.hex
$ ./pbm2hex.pl horse3.pbm 0c00 >> eeprom.hex
$ ./pbm2hex.pl horse4.pbm 1000 >> eeprom.hex
$ ./pbm2hex.pl horse5.pbm 1400 >> eeprom.hex
$ ./pbm2hex.pl horse6.pbm 1800 >> eeprom.hex
$ ./pbm2hex.pl horse7.pbm 1c00 >> eeprom.hex

HEXファイルをFTPからWindowsに移してAKI-PICプログラマー Ver.4を使って24LC256へ書き込みました。

f:id:mohran:20180611212709j:plain
f:id:mohran:20180611213250j:plain


本当はPICKit3を使ってMPLAB IPEからオンボードで書き込みたかったのですが、どうやら24LC256は対応していないようでした。
24LC256を選択できるのに転送できない。
赤丸は非対応と言う意味を理解するのに2時間ほどかかりました(笑)

f:id:mohran:20180611214549j:plain

そこで、旧版のPICKit3プログラマーを使おうとしたらPICKit3のファームウェアを書き換えないと使えないようでした。
しかしそのファームウェアはPIC16F18326には非対応なので、IPEを使うにはまたファームウェアを書き換えてと・・。
あまりにも面倒なので諦めてAKI-PICプログラマーを使うことにしたのです(笑)

回路とプログラムはこのようにしました。

f:id:mohran:20180611215031p:plain


1画面分の画像データをEEPROMからリードして内部変数に保持しておきOLEDへ送信します。
送信後は次の画面へと繰り返します。
I2Cバスのスピードは400KHzで毎フレーム全画素を書き換えていますが、モタつくことも無くスムーズに表示されました。

動画はこちらです。

OLED 0.96インチで遊ぶ ~その5~

今回はPICから表示を行ってみます。

PICは秋月電子で購入したPIC16F18326を使用しました。
プログラム領域が多くて高機能、それでいて低価格(130円)という大変素晴らしいデバイスです。

部品はブレッドボードに実装しました。
RC0とRC1をI2Cバスとして使用してOLEDに接続しています。
I2Cのプルアップ抵抗は1KΩにしました。

回路図はこちらです。

f:id:mohran:20180606232928p:plain


続いてプログラムです。
クロックは内部発振の8MHzにして、I2Cクロックは20分周してSSD1306が動作できる最速の400KHzにしています。

#include <pic.h>
#include <htc.h>
#include <pic16f18326.h>

// クロックサイクル
#define _XTAL_FREQ  8000000

// I2Cデバイスアドレス
#define DEV_OLED_W  0x78  // 0111_1000

// ========================================
//  Config 1 ~ 4
// ========================================
#pragma config  FCMEN    = OFF     // クロックモニタ
#pragma config  CSWEN    = ON      // クロック切り替え(NOSC & NDIV有効)
#pragma config  CLKOUTEN = OFF     // クロック出力
#pragma config  RSTOSC   = HFINT1  // クロック選択(HFINTOSC(1MHz))
#pragma config  FEXTOSC  = OFF     // 外部発振
#pragma config  DEBUG    = OFF     // デバッグモード
#pragma config  STVREN   = OFF     // スタック異常リセット
#pragma config  PPS1WAY  = OFF     // PPSロック
#pragma config  BORV     = HIGH    // Brown-out Reset電圧設定
#pragma config  BOREN    = OFF     // Brown-out Resetイネーブル
#pragma config  LPBOREN  = OFF     // Low-Power Brown-out Resetイネーブル
#pragma config  WDTE     = OFF     // ウオッチドッグタイマ イネーブル
#pragma config  PWRTE    = ON      // Power-up Timer イネーブル(電源ONから64ms後にプログラムを開始)
#pragma config  MCLRE    = OFF     // Master Clear イネーブル
#pragma config  LVP      = OFF     // 低電圧プログラム
#pragma config  WRT      = OFF     // プログラムメモリ プロテクト
#pragma config  CPD      = OFF     // EEPROM プロテクト
#pragma config  CP       = OFF     // コード プロテクト


// ========================================
//  関数プロトタイプ
// ========================================
void i2c_idle(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_send(unsigned char);
unsigned char i2c_recv(void);
void i2c_sack(void);
void i2c_snack(void);

void oled_init(void);
void oled_display(unsigned char);


// ========================================
//  プログラム メイン
// ========================================
void main(void){
  OSCCON1 = 0b01100000;  // NOSC=HFINTOSC(1MHz),NDIV=1
  OSCFRQ  = 0b00000100;  // HFFRQ=8MHz

  TRISA   = 0b00000000;
  TRISC   = 0b00000011;  // RC 0(SCL1),1(SDA1)
  PORTA   = 0b00000000;
  PORTC   = 0b00000000;
  LATA    = 0b00000000;
  LATC    = 0b00000011;
  ANSELA  = 0b00000000;
  ANSELC  = 0b00000000;

  SSP1CLKPPS = 0x10;  // RC0 - 入力先 = SCL1
  SSP1DATPPS = 0x11;  // RC1 - 入力先 = SDA1
  RC0PPS     = 0x18;  // RC0 - 出力源 = SCL1
  RC1PPS     = 0x19;  // RC1 - 出力源 = SDA1

  // I2C設定
  SSP1ADD  = 0b00000100;
  SSP1CON1 = 0b00101000;  // [7] WCOL   = 0    : ライト衝突無し
                          // [6] SSPOV  = 0    : 受信オーバーフロー無し
                          // [5] SSPEN  = 1    : SDA, SCL有効
                          // [4] CKP    = 0    : クロック極性(未使用)
                          // [3:0] SSPM = 1000 : I2Cマスターモード クロック=FOSC/(4*(SSP1ADD+1))
                          //                                                8MHz / (4*(4+1)) = 400KHz

  SSP1STAT = 0x00;
  INTCON   = 0x00;  // 割り込み無効

  __delay_ms(100);

  oled_init();

  while(1){
    oled_display(0x01);
    oled_display(0x02);
    oled_display(0x04);
    oled_display(0x08);
    oled_display(0x10);
    oled_display(0x20);
    oled_display(0x40);
    oled_display(0x80);
  }
}


// ========================================
//  I2C IDLE
// ========================================
void i2c_idle(void){
  while(SSP1CON2bits.SEN   |
        SSP1CON2bits.PEN   |
        SSP1CON2bits.RCEN  |
        SSP1CON2bits.ACKEN |
        SSP1STATbits.R_nW){}
}

// ========================================
//  I2C スタート送信
// ========================================
void i2c_start(void){
  i2c_idle();
  SSP1CON2bits.SEN = 1;      // スタート出力
  while(SSP1CON2bits.SEN){}  // スタート終了待ち
}

// ========================================
//  I2C ストップ送信
// ========================================
void i2c_stop(void){
  SSP1CON2bits.PEN = 1;      // ストップ出力
  while(SSP1CON2bits.PEN){}  // ストップ終了待ち
  i2c_idle();
}

// ========================================
//  I2C データ送信
// ========================================
void i2c_send(unsigned char data){
  SSP1BUF = data;                // データセット送信開始
  while(SSP1STATbits.BF){}       // 送信終了待ち
  while(SSP1CON2bits.ACKSTAT){}  // ACK返信待ち
  i2c_idle();                    // アイドル待ち
}

// ========================================
//  I2C データ受信
// ========================================
unsigned char i2c_recv(void){
  SSP1CON2bits.RCEN = 1;
  while(SSP1CON2bits.RCEN){}
  return(SSP1BUF);
}

// ========================================
//  I2C Ack送信
// ========================================
void i2c_sack(void){
  SSP1CON2bits.ACKDT = 0;
  SSP1CON2bits.ACKEN = 1;
  while(SSP1CON2bits.ACKEN){}
}

// ========================================
//  I2C NAck送信
// ========================================
void i2c_snack(void){
  SSP1CON2bits.ACKDT = 1;
  SSP1CON2bits.ACKEN = 1;
  while(SSP1CON2bits.ACKEN){}
}

// ========================================
//  OLED初期化
// ========================================
void oled_init(void){
  // 表示モード,アドレスモード指定
  i2c_start();
  i2c_send(DEV_OLED_W);
  i2c_send(0x00);
  i2c_send(0xa0);  // 表示モード設定 左右 - 通常:0xa0 / 逆転:0xa1
  i2c_send(0xc0);  // 表示モード設定 上下 - 通常:0xc0 / 逆転:0xc8
  i2c_send(0x20);  // アドレッシングモード指定
  i2c_send(0x00);  //   → Horizontalモード
  i2c_send(0x21);  // カラム指定
  i2c_send(0x00);  //   → 開始位置(0)
  i2c_send(0x7f);  //   → 終了位置(127)
  i2c_send(0x22);  // ページ指定
  i2c_send(0x00);  //   → 開始ページ(0)
  i2c_send(0x07);  //   → 終了ページ(7)
  i2c_send(0x8d);  // チャージポンプ設定
  i2c_send(0x14);  //   → On
  i2c_send(0xaf);  // 画面表示 On
  i2c_stop();
}

// ========================================
//  OLED表示
// ========================================
void oled_display(unsigned char data){
  i2c_start();
  i2c_send(DEV_OLED_W);
  i2c_send(0x40);
  for(int j=0; j<8; j++){
    for(int i=0; i<128; i++){
      i2c_send(data);
    }
  }
  i2c_stop();
}

XC8でコンパイル後、PICKit3を通して書き込みます。

8本のラインが上から下へスクロールするというシンプルなプログラムです。

PICのMSSPモジュールを使用したことによりI2C通信のプログラムは簡単に実装できました。

C言語によるPICプログラミング大全

f:id:mohran:20180531234626j:image

 

最近、PIC16F1系に触れる機会が多々あったので4月に発売された書籍

C言語によるPICプログラミング大全

を買いました。

ペリフェラルについての情報が一番の目的だったのですが、PICの機能全般やツールについての多くの情報が記載されており、とても役に立っています。

お値段はちょっと高めですが、PICを使う方は手元に置いておいておけば困った時の手助けになるのでは無いでしょうか。

OLED 0.96インチで遊ぶ ~その4~

今回はImagemagickのconvertを使用して文字列をPBMフォーマットに変換して表示を行ってみます。

文字列「柔術」を画像化してみます。

$ convert -font /usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf \
          -pointsize 32 \
          -extent 64x32 \
          -compress none \
          -monochrome \
          +antialias \
          label:'柔術' \
          bjj.pbm

font : フォント名
pointsize : フォントサイズ
extent : 画像サイズ
label : 文字列
を指定します。
他のオプションはPBMを生成するのに必要なオプションとなります。
フォントは色々と試してみましたがTakaoGothicが一番見やすかったです。

生成されたbjj.pbmを開くとこんな感じで見えます。(見やすいようにデータ間のスペースは削除しています)

f:id:mohran:20180529234158j:plain

指定した位置にPBMファイルを表示するスクリプトを作りましたので、これを通して表示してみます。

#!/usr/bin/perl -w

open(RFP, "<" . $ARGV[0]) || die("Fatal : Can't open file ... $ARGV[0]\n");

$pos_xs = $ARGV[1];
$pos_ys = $ARGV[2];

@pbm = ();

$w = 0;
$h = 0;
$i = 0;
while(<RFP>){
  $l = $_;
  chomp($l);

  $l =~ s/#.*$//;

  if($l eq ''){ next; }

  $i++;
  if($i==1){
    if($l ne 'P1'){ die("Error : It isn't P1 format ...\n"); }
  }elsif($i==2){
    ($width, $height) = split(/\s+/, $l);
  }else{
    $l =~ s/\s+//g;
    foreach $d (split(//, $l)){
      $pbm[$h][$w] = $d;
      $w++;
      if($w==$width){
        $h++;
        $w = 0;
      }
    }
  }
}
close(RFP);

# display set
$cmd = 'i2cset -y 1 0x3c 0x00 0xa0 0xc0 i';
system($cmd);

$pos_xe = $pos_xs + $width - 1;
$pos_ye = $pos_ys + $height / 8 - 1;

$cmd  = 'i2cset -y 1 ';
$cmd .= '0x3c 0x00 ';
$cmd .= '0x20 0x00 ';  # horizontal mode
$cmd .= sprintf("0x21 0x%02x 0x%02x ", $pos_xs, $pos_xe);  # column
$cmd .= sprintf("0x22 0x%02x 0x%02x ", $pos_ys, $pos_ye);  # page
$cmd .= 'i';
system($cmd);

$i = 0;
for($h=0; $h<$height; $h+=8){
  for($w=0; $w<$width; $w++){
    $d = unpack("C", pack("B8", $pbm[$h+7][$w] .
                                $pbm[$h+6][$w] .
                                $pbm[$h+5][$w] .
                                $pbm[$h+4][$w] .
                                $pbm[$h+3][$w] .
                                $pbm[$h+2][$w] .
                                $pbm[$h+1][$w] .
                                $pbm[$h+0][$w]));
    if($i==0){
      $cmd = "i2cset -y 1 0x3c 0x40 ";
    }
    $cmd .= sprintf("0x%02x ", $d);
    $i++;
    if($i==16){
      $i = 0;
      $cmd .= "i";
      system($cmd);
    }
  }
}

if($i != 0){
  $cmd .= "i";
  system($cmd);
}

# display enable
$cmd = 'i2cset -y 1 0x3c 0x00 0x8d 0x14 0xaf i';
system($cmd);


引数に「PBMファイル」「表示開始カラム」「表示開始ページ 」を指定します。

$ ./disp_pbm.pl bjj.pbm 32 2


こんな感じで表示されました。


色々と組み合わせて文字列を表示してみました。

なお、上記のスクリプトはPBMファイルのHeightが8の倍数であることが前提となっていますのでご注意ください。

D-NET & SJJJF TOKYO SPRING

4月は2つの大会に出場しました。

 

1つ目は4月1日に開催されたD-NET

D-NET マスターグラップリングトーナメント 02

です。

4人トーナメントで行われましたので優勝までは2回の山です。

グラップリングの試合は2年ぶり、そして2回目の出場です。

2・2・2づくしのなか5分間ヘロヘロになりながらもなんとか勝つことができました。

嬉しい優勝でした!

f:id:mohran:20180527224133j:image

 

ちなみに今大会に出場するためにパンツを新調しました。

VENUMのカッコイイパンツです(笑)

f:id:mohran:20180527231634j:image

 

 

そして2週間後の4月15日に行われた

SJJJF TOKYO SPRING JIU JITSU CHAMPIONSHIP 2018

は、ワンマッチでした。

スイープで先行するも残り時間30秒でひっくり返されてしまいポイント2-2でタイムアップ。

ASJJFルールなので延長戦です。

前回の延長戦は開始早々に巴投げを食らって負けました。

今回は自分からタックル行くつもりでいました。

が・・

コンバッチと同時に先にタックルされてしまい・・

一度は切ったものの、更なるアタックで倒されてしまいました。

残念銀メダル。

延長戦の勝率は非常に悪くこれで1勝3敗となりました。

なんとも・・。

また次頑張りたいと思います。

f:id:mohran:20180527224138j:image