たまりば

パソコン・インターネット パソコン・インターネット三鷹市 三鷹市

【お知らせ】ファイルが消えています
2018年12月29日 11:06

こちらでお知らせするのを忘れていましたが、ブログでない方のWentWayUp(Annex)のサイトが、先日プロバイダのコース終了により消滅しました。
それだけならよいのですが、このブログで何らかのファイルをダウンロードできる状態に置くためにも同サイトの領域を使っていましたので、現在ダウンロードできない状態になっております。

何かあればコメント欄やTwitterで言っていただけると対応できるかもしれません。

なるべく早く復旧させたいとは思っているものの、私は怠惰なのでなかなか作業が進みません。
無料かせいぜい月数百円くらいでファイルとできればサイトもできれば広告なしで保持したいとこなんですが、そういうサービスを探して比較するのが面倒で。
ストレージ系のサービスはたいていファイル置き場としての利用を禁じていますし。

---2019/01/12追記
GitHub Pagesよさそう。  

  • ポケットプリンタ制御
    2018年12月22日 17:40

    この記事はGame Boy Advent Calendar 2018の22日めです。

    最近ゲームボーイのプログラミングがマイブームだ。
    ところでポケットプリンタってあるよね。
    動く機械って萌えるよね。

    というわけでやってみた。
    使うのはもちろん使い慣れたPICマイコン。
    ちょうど最近電子ペーパーを試すのに使っていたPIC16F1508が手頃だったのでこれを使うことにした。(電子ペーパーについてもブログに書こうと思っているのだが…)
    なお固有の機能は特に使っていないのでEnhancedミッドレンジならどれでも容易に移植できるはず。SPI送信のみとかわざわざ機能調べるほうがめんどい。

    ポケットプリンタ(海外名はGameboy Printer)の制御方法の情報は下記2サイトによくまとまっている。
    In Depth: The Game Boy Printer
    https://shonumi.github.io/articles/art2.html
    Furrtek.org : Reversing GameBoy Printer
    http://furrtek.free.fr/?a=gbprinter (原文フランス語)
    http://furrtek.free.fr/?a=gbprinter&i=2 (英語; 未翻訳部あり)

    さらに実際の送受信内容のダンプが公開されているのが嬉しい。
    http://furrtek.free.fr/noclass/gbprinter/hexdump.txt
    チェックサムが「1バイトごとの和を2バイトで」という珍しい形式なのでこれが無ければ理解は困難だっただろう。

    これらサイトの情報を元に、「最低限動くプログラム」を作った。
    最初のプログラムというものは単純なら単純なほどよい。バグも入りにくいし、他人も参考にしやすい。

    具体的には、
    ・印刷する画像サイズは最小の160×16(ヘッドの1行分)
    ・上下のマージンは手動でフィードすればよいので0
    ・データの圧縮はしない(そもそも白黒でないとほとんど圧縮されなそうだし、圧縮しなくても送信に1秒掛からないし)
    ・データは送信のみ、プリンタからの返答は見ない
    ・statusコマンドのポーリングによる印刷終了判定もしない
    ・各種データはプログラムに直書き
    ・EnhancedミッドレンジPICのデータは14bit中8bitしか使えない簡易な読み方と全部読める読み方があるが、楽な前者
    ・電源ONで自動で1回だけ送信
    といった感じ。

    用紙は感熱紙自体は容易に手に入る。サイズが合わないのでノコギリで切って…
    http://furrtek.free.fr/?a=gbpcable&i=2
    「No paper ? Take a used receipt」
    なるほどその手があったか!
    不要なレシートならそのへんに落ちている。

    電池を用意し(多いなあ…)
    電池6本

    以前GBAと通信を試したときに通信ケーブル変換コネクタをばらして作った線でつないで(コネクタが入手できなければ本体をばらして線をつなぐのが早いと思う)
    GB通信ケーブルからつなぐ線

    …動かない。
    色々チェックし見つけたバグを修正したがやはり動かない。

    出力は確かに出ている。クロック線とデータ線も間違っていない。
    簡略化のためにプリンタからの応答を見なかったのはまずかったか…とも思ったがそれ以前にプリンタからのSO(Serial Out; 分かりやすくいえばMISO)線に何も出ていない。
    何も出ていないというのはつまり、常にHigh-Zになっている。
    出力していない時の信号が不定でHigh-Zにするのはまだ分かるとして、[furrtek]によれば何か信号を入れたら00が返ってくるように書かれているのだが。

    線にLEDをつないでのデバッグではこのくらいが限度だ。
    仕方ない。重い腰を上げオシロスコープを引っ張り出してきて(先日のPCのクラッシュで制御ソフトが消えていたのでインストールもして)確認してみる。
    PICからポケットプリンタへの信号
    想定どおりである。(電源の都合上この時は電圧が違うが本番は5Vで動かしている)
    ポケモンカードGBから印刷して実機の信号も見てみる。
    ゲームボーイからポケットプリンタへの信号
    こちらも想定どおりである。困った。

    実機と違うところといえば、以下2点。
    速度は[furrtek]には「1kHz以下(もっといけるかも)」くらいに書いてあったので、1kHz以下でプログラムが簡単なところとして約650Hz。
    実機の速度は約8kHzだが、ふつう同期シリアル信号というものは遅い分には問題が無いものだ。
    怪しいのは電源投入時だ。線をつないでから
    プリンタ電源ON→PIC電源ON→300msほど待つ→送信開始
    というシーケンスで操作しているが、このPIC側電源投入時にクロック線が暴れて不正なデータが入っているのかもしれない。
    しかし、先頭のマジックバイト8833というのはこの辺の同期ズレをリセットするためのものではないのか?
    つまり、電源投入時から(バイト単位でなく)ビット単位で信号を見て「1000100000110011」のパターンがあったらそこで同期するという仕組みではないのか。

    まあ他に打つ手も無いのでこの2つを修正してみることにした。
    通信速度は8kHz弱に。念のため上の画像でも見える1バイトごとに半bit分くらい止まる部分も実機に合わせた。
    PIC電源投入時の待ち時間を5秒ほどに伸ばし、電源投入シーケンスを
    PIC電源ON→(5秒の間に)プリンタ電源ON→送信開始
    とした。

    すると、
    ポケットプリンタ_ハローワールド
    成功!

    どちらが効いたのか片方づつ試すと、なんと両方とも必要だった。
    650Hzの速度では、全く反応しない。
    電源投入時のシーケンスを最初のものに戻すと、まれに成功するもののほとんど反応しない。(20回ほど試し2回成功)
    再び両方修正後のコードで何度か試すと、ほぼ確実に成功する。(失敗は接触不良か?)

    これは不思議である。
    遅い信号を弾くのはノイズを信号と判断しないためではないのだろうか。そうであれば300ms空けたところでリセットしていてほしい。
    一方そうでないなら、挿抜時のノイズを無視するためにマジックバイトがあるのではないのだろうか。そうであれば挿抜時にどんなノイズが乗っても正しく信号を受けてほしい。

    何か間違っているかもしれないが、おそらく動くようにはなった。
    もっとちゃんとした画像表示もそのうちやりたい。

    [余談]
    ・折角買った感熱紙だし切った。
    感熱紙のロールをノコギリで切った
    …55分掛かった。間に1時間の休憩を入れて。
    学研のふろくじゃなくまともなノコギリを持っておいたほうがいいな。

    ・画像データは以下のようにして作った。
    GIMPで描く
    ハローワールド
    ペイントで8×8ドットごとに並び替える(背景色を変えるとやりやすい)
    ハローワールド_並び替え
    上下反転・色反転、GIMPでトーンカーブを使って上位bitと下位bitのデータを作る
    bit分割
    モノクロビットマップで保存
    バイナリエディタで開く
    テキストエディタで適宜置換

    ・何度か試したの図↓
    何度か試した

    コード:

        list p=16F1508
        #include p16F1508.inc
        radix dec

        ;     Vdd +-v-+ Vss
        ;     RA5 |   | RA0/DAT
        ;     RA4 |   | RA1/CLK 4_1
        ;1_0 (RA3)|   | RA2 CLC1
        ;     RC5 |   | RC0 CLC2
        ;21/4 RC4 |   | RC1
        ;2_0  RC3 |   | RC2
        ;3_1  RC6 |   | RB4 3_0
        ;1_1  RC7 |   | RB5 4_0
        ;CLC3 RB7 +---+ RB6

        __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF
        __CONFIG _CONFIG2, _WRT_OFF & _STVREN_OFF & _BORV_LO & _LPBOR_OFF & _LVP_OFF

    #define DATPIN 4
    #define CLKPIN 5

        cblock 0x20

        endc
        cblock 0x70
            cntl, cnth, suml, sumh
            dat, bitcnt, waitcnt, portbuf
        ;    temp, temp2
        endc

        org 0
        goto init

        org 4
    init:
        banksel OSCCON
        movlw b'01101010'
        ;        ^^^^ || IRCF 1101=4MHz (※クロックを4MHzにすると1命令1μsで計算しやすい)
        ;             ^^ SCS SystemClockSelect 1x = internal
        movwf OSCCON

        banksel 0
        clrf PORTC
        clrf PORTB
        movlw b'00110000'
        movwf PORTA

        banksel TRISC
        clrf TRISA
        clrf TRISB
        clrf TRISC

        banksel ANSELC
        clrf ANSELC
        clrf ANSELB
        clrf ANSELA

        banksel 0

        clrf cntl
        clrf cnth
        clrf suml
        clrf sumh
        clrf dat
        clrf bitcnt
        clrf waitcnt
        clrf portbuf

        ;少し待つ
        ;//65536*5=327 680
        ;11*65536*7=5046272
        movlw .11
        movwf waitcnt

        decfsz cntl,F
        goto $+2
        decfsz cnth,F
        goto $+2
        decfsz waitcnt,F
        goto $-5

        ;init
        movlw .4
        movwf cntl
        movlw .1 ;プログラムの都合で+1
        movwf cnth
        movlw high(cmd_init)
        movwf FSR0H
        movlw low(cmd_init)
        movwf FSR0L
        call sendcmd

        ;データ
        movlw 0x84
        movwf cntl
        movlw 0x02+1
        movwf cnth
        movlw high(cmd_data)
        movwf FSR0H
        movlw low(cmd_data)
        movwf FSR0L
        call sendcmd

        ;空データ
        movlw .4
        movwf cntl
        movlw .1
        movwf cnth
        movlw high(cmd_data0)
        movwf FSR0H
        movlw low(cmd_data0)
        movwf FSR0L
        call sendcmd

        ;print
        movlw .8
        movwf cntl
        movlw .1
        movwf cnth
        movlw high(cmd_print)
        movwf FSR0H
        movlw low(cmd_print)
        movwf FSR0L
        call sendcmd

        goto $ ;終了

        ;コマンド送信
        ;具体的には、「88,33,本体,チェックサム,ダミー×2」を送信
    sendcmd:   
        clrf suml
        clrf sumh

        ;magic byte 88,33
        movlw 0x88
        call sendbyte
        movlw 0x33
        call sendbyte

        ;本体
    sendcmdloop:
        moviw FSR0++
        addwf suml,F
        btfsc STATUS,C
        incf sumh,F
        call sendbyte

        decfsz cntl,F
        goto $+2
        decfsz cnth,F
        goto sendcmdloop
        ;チェックサム
        movf suml,W
        call sendbyte
        movf sumh,W
        call sendbyte
        movlw 0
        call sendbyte
        movlw 0
        call sendbyte
        return

        ;1バイト送信
        ;相手はクロック立ち上がりで読む
    sendbyte:
        movwf dat

        movlw .18 ;タイミングを現物合わせ
        movwf waitcnt
        decfsz waitcnt,F
        goto $-1

        movlw .8
        movwf bitcnt
        clrf waitcnt
        ;DAT,CLKをlowにした値を用意
        movf PORTA,W
        andlw ~((1<<DATPIN)|(1<<CLKPIN)) ;b'11001111'
        movwf portbuf
    sendbyteloop:
        movlw .18 ;タイミングを現物合わせ
        movwf waitcnt
        decfsz waitcnt,F
        goto $-1

        movf portbuf,W ;読み込み
        rlf dat,F
        btfsc STATUS,C
        iorlw 1<<DATPIN ;データが1ならDATをhigh
        movwf PORTA ;書き込み

        movlw .20 ;タイミングを現物合わせ
        movwf waitcnt
        decfsz waitcnt,F
        goto $-1

        bsf LATA,CLKPIN ;クロック操作
        decfsz bitcnt,F
        goto sendbyteloop
        return

        ; magic 8833
        ;   cmd   comp  len L/H     sum L/H     dummy
    cmd_init:
        ;dt 0x88, 0x33,
        dt 0x01, 0x00, 0x00, 0x00; 0x01, 0x00, 0x00, 0x00
    cmd_init_len equ $-cmd_init ;やっぱりめんどいので直書きにする
    cmd_print:
        dt 0x02, 0x00, 0x04, 0x00
        dt 0x01, 0x00, 0xE4, 0x40
        ;  ???? margin palt exposure
    cmd_status:
        dt 0x0F, 0x00, 0x00, 0x00
    cmd_data0:
        dt 0x04, 0x00, 0x00, 0x00
    cmd_data:
        dt 0x04, 0x00, 0x80, 0x02
        dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x01,0x03,0x03,0x03,0x07,0x07,0x07
        dt 0x28,0x70,0xFC,0x78,0xFC,0xFE,0xFC,0xFE,0xFC,0xFE,0xFC,0xFE,0xFE,0xFC,0xF8,0xFC
        dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x3E,0x7C,0x7F,0xFE,0x7F,0x7F
        dt 0x00,0x00,0x03,0x00,0x2F,0x1F,0x1F,0x3F,0x1F,0x3F,0x1F,0x1F,0x0F,0x1F,0x07,0x0F
        dt 0x03,0x00,0x87,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xEC,0xF0
        dt 0x1E,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0x7E,0x7E,0x7E
        dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x7F,0x3F,0x7F,0x3F
        dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x0F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF
        dt 0x03,0x01,0x07,0x0F,0x0F,0x0F,0x8F,0x47,0xCF,0xE7,0xC7,0xE7,0xE7,0xE3,0xE3,0xC3
        dt 0xDF,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xF8,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0
        dt 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x1F,0x0F,0x1F,0x0F,0x1F,0x1F
        dt 0xC0,0xE0,0xC0,0xE0,0xC0,0xE0,0xE0,0xC0,0xE0,0xC0,0xCE,0xC1,0xFF,0xDF,0x9F,0xDF
        dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF
        dt 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xF8,0xF8,0xF0,0xF8,0xF0,0xF0,0xF0
        dt 0x01,0x03,0x01,0x03,0x01,0x03,0x01,0x7B,0x79,0x7B,0x79,0x7B,0x79,0x7B,0x79,0x7B
        dt 0xF8,0xF8,0xF8,0xF8,0xF0,0xF8,0xF8,0xF0,0xF8,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0
        dt 0x03,0x01,0x03,0x01,0x0B,0x01,0x11,0x09,0x39,0x19,0x18,0x39,0x78,0x39,0x39,0x78
        dt 0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFF,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,0xFF
        dt 0x00,0x01,0x00,0x01,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF
        dt 0xE7,0xEF,0xE7,0xEF,0xEF,0xE7,0xEF,0xE7,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x80
        dt 0x07,0x0F,0x0F,0x0F,0x0F,0x1F,0x3F,0x1F,0x3F,0x3F,0x3F,0x7F,0xFF,0x7F,0x7F,0xFF
        dt 0xFC,0xF8,0xFC,0xF8,0xF0,0xF8,0xF0,0xF8,0xF8,0xF0,0xE0,0xF0,0xE0,0xE0,0xC0,0xE0
        dt 0x3F,0x7F,0x7F,0x3F,0x3F,0x3F,0x3F,0x1F,0x0F,0x1F,0x0F,0x0F,0x07,0x0F,0x07,0x07
        dt 0x07,0x8F,0xC7,0x87,0xA7,0xC3,0xE3,0xC3,0xE1,0xE3,0xF1,0xF1,0xF9,0xF0,0xF0,0xF8
        dt 0xF0,0xE0,0xE0,0xF0,0xF0,0xF0,0xF8,0xF1,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF8,0x70
        dt 0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x7C,0xFE,0xFC,0xFE,0xFC,0xFC,0x60,0x80,0x00,0x00
        dt 0x3F,0x3F,0x1F,0x3F,0x3F,0x1F,0x14,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        dt 0xFF,0xFF,0xFC,0xFF,0xE8,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        dt 0xC1,0xC3,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        dt 0x80,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x03,0x01,0x0F,0x07,0x1F,0x1F
        dt 0x3F,0x1F,0x1F,0x3F,0x3F,0x7F,0xFE,0x7F,0xFE,0xFE,0xFE,0xFC,0xFA,0xFC,0xFC,0xF8
        dt 0xDF,0x8F,0x07,0x8F,0x8F,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        dt 0xFF,0xFF,0xFB,0xFC,0x90,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
        dt 0xE0,0xF0,0x01,0x00,0x01,0x01,0x01,0x03,0x03,0x07,0x0F,0x07,0x0F,0x3F,0x7F,0x7F
        dt 0x79,0xFB,0xF1,0xFB,0xF1,0xFB,0xF9,0xF3,0xF9,0xF3,0xE1,0xF3,0xF1,0xE3,0xE1,0xE3
        dt 0xE0,0xF0,0xE1,0xF0,0xE3,0xF1,0xE7,0xF3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
        dt 0x79,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF0,0xC0,0xE0,0x40,0x80
        dt 0xFF,0xFF,0xFF,0xFF,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xF8,0xFC,0x78,0xFC
        dt 0xFF,0xFF,0xFF,0xFF,0x1F,0x7F,0x03,0x07,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00
        dt 0x80,0x80,0x00,0x80,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xAA ;※末尾の55AAはデバッグ時に使ったものの消し忘れ

        end

    (2019/09/03 修正) コード中のシフト演算子がHTMLタグ扱いで消えていたのを修正しました。