フォト
無料ブログはココログ

CPUボード

2018年9月21日 (金)

Bus pirate(4) <スクリプトを動かしてみる>

相も変わらず Bus Pirateで遊んでいる。

 BusPirateには組み込みscript(BASICのサブセット)がある。
terminalインタフェースではデバイスからのレスポンスを待つのは難しいが、scriptを使うとできるようになる。

 以前に買ったLED&KEYを制御してみた。

 このモジュールのLEDコントローラにはTM1638が使われている。インタフェースは、クロック(CLK)に同期したシリアル通信で、データ(DIO)は双方向だ。デバイの選択はSTBをLにする。

 英語版のデータシートは(https://www.mikrocontroller.net/attachment/332035/TM1638_V1.3_EN.pdf)にある。

 BusPirateの raw 2-wireで制御してみる。

 接続はこんな感じ↓

BusPirateLED&KEY
MOSI --- DIO
CLK --- CLK
AUX --- STB
5V -+- VCC
VPU -+ 
GND --- GND

 ビットオーダーには注意が必要だ。SPIやI2CはMSBから送るMSB-firstだがTM1368はLSBから送るLSB-firstだから、"L"コマンドでビットオーダーを切り替えなくてはならない。

 ↓実行結果

HiZ>m 6 1 1		← raw 2-wire
R2W (spd hiz)=( 0 1 )
Ready
2WIRE>WPLc		← PowerON,PullUP,LSBfirst,ctrlAUX
Power supplies ON
Pull-up resistors ON
LSB set: LEAST sig bit first	← "L"command
a/A/@ controls AUX pin		← "c"command
2WIRE>v
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk) 
GND     3.3V    5.0V    ADC     VPU     AUX     SCL     SDA     -       -
P       P       P       I       I       I       O       I       I       I
GND     3.29V   5.02V   0.00V   5.02V   H       L       H       H       H
2WIRE>a 0x40 A		← DataCommand: WriteRegister,AutoIncremet
AUX LOW
WRITE: 0x40
AUX HIGH
2WIRE>a 0xC0		← AUX←L、AddressCommand: 00h
AUX LOW
WRITE: 0xC0
2WIRE>  0x76,0x00, 0x79,0x00, 0x38,0x00, 0x38,0x00	← "HELL" 
WRITE: 0x76
WRITE: 0x00
WRITE: 0x79
WRITE: 0x00
WRITE: 0x38
WRITE: 0x00
WRITE: 0x38
WRITE: 0x00
2WIRE>  0x3F,0x00, 0x40,0x01, 0x40,0x01, 0x40,0x01	← "O---"  
WRITE: 0x3F
WRITE: 0x00
WRITE: 0x40
WRITE: 0x01
WRITE: 0x40
WRITE: 0x01
WRITE: 0x40
WRITE: 0x01
2WIRE>A 		← AUX←H
AUX HIGH
2WIRE>a 0x8A A		← DisplayControl: DispON
AUX LOW
WRITE: 0x8A
AUX HIGH
2WIRE>

BP-HELLO

 表示を動かそうとするとコマンドを何回も入力しなければならないので、scriptで動かしてみる。

 BusPireteのscriptはBASICのサブセットなので面倒ことがある。

  • 数値は10進数だけ。16進数は使えない
     "="コマンドで10進、16進、2進の変換ができるので、10進数にする。
  • 変数への代入はLETを使う
     ×A=10、〇LET A=10
  • "DATA"、"READ"コマンドはあるけど"RESTOR"コマンドが無い
  • AUXピンが制御できない
     "AUXPIN 0"でAUXピンが制御できるはずだが、CSしか制御できない(BUG?)
  • "SEND"コマンドのビットオーダーは常にMSB-First
     ターミナルコマンド"L"を引き継がない。

 AUXピンが制御できないのは致命的だ。 仕方がないので、ターミナルコマンドでDataCommand(40h)、DispContorl(88h)を送っておいて、表示データをscriptで送ってみる。

 ↓ターミナルで送るコマンド

m 6 1 1		← raw 2-wire
WPLc		← PowerON,PullUP,LSBfirst,ctrlAUX
a 0x40 A	← DataCommand: WriteRegister,AutoIncremet
a 0xC0		← AUX←L、 AddressCommand: 00h 

 scriptを例えば"hello.bas"というファイル名で保存しておいて、ターミナル・ソフトのファイル送信機能でBusPirateに送ると簡単。 BusPirateが処理する時間を確保するために行当たり500msの時間待ちしている。

 scriptはこんな感じ↓

hello.bas
10 FOR I=1 TO 100
20   GOSUB 1000
30   DELAY 100
40 NEXT I
50 END
999  REM Disp HELLO
1000 IF I<50 THEN SEND 0
1010 IF I<50 THEN SEND 128   
1020 SEND 110
1030 SEND 0
1040 SEND 158
1050 SEND 0
1060 SEND 28
1070 SEND 0
1080 SEND 28
1090 SEND 0
1100 SEND 252
1110 SEND 0
1120 SEND 0
1130 SEND 128
1140 SEND 0
1150 SEND 128
1160 IF I<50 THEN SEND 0
1170 IF I<50 THEN SEND 128
1180 RETURN

↑SENDコマンドで送る数値はビットオーダーを変えてある。 例えば1020行の SEND 110は、表示したいパターンは01110110(76h)なので、01110110b→01101110b→6Eh→110を送る。

 scriptでLSBから1bitづつ送るようにすれば、いちいち変えなくてよいのだがどちらも面倒。

↓動いているところ。

Bphello_1ダウンロード BP-HELLO.mp4 (1110.6K)

↑途中でメッセージが移動する方向が変わる。

 待てよ、AUXではなくCSを使えばいいじゃないかと気が付いた。

###

この記事に書いた制限(BUG?)は↓のFirmware固有のものかもしれない。

HiZ>i
Bus Pirate v3b
Firmware v5.10 (r559)  Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com
CFG1:0xF9DF CFG2:0x3F7F

最新のFirmwareにアップデートしてみるか



最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年9月17日 (月)

Bus pirate(3) <SDカードをパスワード・ロックしてみる>

  Bus pirateでSDカードが読めたので、SDカードをパスワード・ロックしてみる。
実験に使ったSDカードはSanDiskの8GB SDHC。 

Sandisk_8g_sdhc

Buspirate36_sd  

【初期化】
 初期化のコマンドは、CMD0→CMD8→ACMD41(CMD55、CMD41)。 このカードはACD41(CMD55+CMD41)を2回送ると初期化できるようだ。 2回で初期化が完了しない場合はR1レスポンスが00hになるまでACMD41を送る。

SDHC_InitCmd.txt
m 5 1 1 2 1 2 2
Wv

]r:10[0x40 0x00 0x00 0x00 0x00 0x95 r:8]
[0x48 0x00 0x00 0x01 0xAA 0x86 0x87 r:8]
[0x77 0x00 0x00 0x00 0x01 0xff r:8]
[0x69 0x40 0x00 0x00 0x01 0xff r:8]
[0x77 0x00 0x00 0x00 0x01 0xff r:8]
[0x69 0x40 0x00 0x00 0x01 0xff r:8]
[0x4D 0x00 0x00 0x00 0x00 0xff r:8]

↑このようなファイルを作っておいてターミナルから送信すると入力が楽。 Bus pirateでの処理時間が必要なので、1行送信したら100ms~1000ms待つ。

↓Teratermの例
Terminaldelay

【パスワードロック】
 パスワードロックに使うコマンドはCMD16, CMD42, CMD13。

SD HostdirSD Card
SC(Lo) Select
CMD16(0x00 0x00 0x02 0x00 0xFF) BLOCK_LEN=512
R1 response 0x00=NoError
SC(Hi)
SC(Lo) Select
CMD42(0x00 0x00 0x00 0x00 0xFF)
R1 response 0x00=NoError
0xFE LockCardStructure 0xFFx(512-PWD_LEN) 0xFF 0xFF Data Packet
Data response R1+busy, busy=0x00
SC(Hi)
SC(Lo) Select
CMD13(0x00 0x00 0x02 0x00 0xFF)
Data response R2(R1+Status)
SC(Hi)

【CMD42】 
 CMD42のデータパケットで送るデータ

Lock Card Data Structure
Byte# Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
0 Reserved
(shall be set to 0)
ERASE LOCK_UNLOCK CLR_PWD SET_PWD
1 PWDS_LEN
2 password data
・・・
PWDS_LEN+1
  • Byte#0:
    • パスワード・設定(0x01)
      パスワード長とパスワード・データが設定される。
      この設定だけではまだロックされていない。電源をOFFにするか、LOCK_UNLOCK(0x04)でロックする。
       
    • パスワード・変更(0x01)
      既に設定されているパスワードを変更する場合は、パスワード長(PWDS_LEN)に新しいパスワード長を加算した値をセットし、パスワード・データには現在設定されているパスワードに続けて変更するパスワードを設定する。
       
    • パスワード・クリア(0x02)
      パスワード長とパスワード・データをクリアする。ロックは解除される。
       
    •  パスワード・ロック(0x04)
      SDカードがロックされデータにアクセスできなくなる。
       
    • パスワード・ロック解除(0x00)
      パスワード・ロックが解除されデータにアクセスできるようになる。
      電源を再投入するとロック状態に戻る。
       
    • 消去(0x08)
      パスワードが分からない場合でも設定されているパスワードを消去することができる。 ただし、データもすべて消去される。
       
  • Byte#1 : パスワード長。
  • Byte#2~: パスワードデータを設定する。 バイナリデータも設定できる
    パスワードは16byte以内。

【パスワード設定】

SPI>[0x50 0x00 0x00 0x02 0x00 0xFF r:8] ←CMD16:SET_BLOCK_LEN len=512
/CS ENABLED
WRITE: 0x50
WRITE: 0x00
WRITE: 0x00
WRITE: 0x02
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x6A 0x00 0x00 0x00 0x00 0xFF r:8 ←CMD42:LOCK_UNLOCK
/CS ENABLED
WRITE: 0x6A
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

SPI>0xFE 0x01 6 "abc123" 0xFF:506 0xFF 0xFF r:24] ←SET_PWD
WRITE: 0xFE   ←Data token
WRITE: 0x01   ←PWD_SET
WRITE: 0x06   ←PWDS_LEN
WRITE: "abc123" ←passowrd data
WRITE: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
                            ( 506=512-6のFFh
               )
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
WRITE: 0xFF   ←CRC(dummy)
WRITE: 0xFF   ←CRC(dummy)
READ: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x0F 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

電源OFF(カードを抜く)

SPI>[0x4d 0x00 0x00 0x00 0x00 0xff r:8]    ←CMD13 SEND_STATUS
/CS ENABLED
WRITE: 0x4D
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0x01 0xFF 0xFF 0xFF 0xFF 0xFF ←R2:0x01="Card is locked"
/CS DISABLED

PCに認識させてみると。

Sdcarddiskmgr_setpwd

 このPCはSDカードスロットがあって内部的にはUSBに繋がっているようだ。 パスワード・ロックされているSDカードは「メディアなし」と表示されている。

【パスワード・ロック解除】

SPI>[0x50 0x00 0x00 0x02 0x00 0xFF r:8]   ←CMD16 SET_BLOCK_LEN
/CS ENABLED
WRITE: 0x50
WRITE: 0x00
WRITE: 0x00
WRITE: 0x02
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x6A 0x00 0x00 0x00 0x00 0xFF r:8   ←CMD42 LOCK_UNLOCK
/CS ENABLED
WRITE: 0x6A
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

SPI>0xFE 0x00 6 "abc123" 0xFF:506 0xFF 0xFF r:24] ←UNLOCK 0x00
WRITE: 0xFE
WRITE: 0x00
WRITE: 0x06
WRITE: "abc123" ←passowrd data
WRITE: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
                            ( 506=512-6のFFh
               )
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
WRITE: 0xFF   ←CRC(dummy)
WRITE: 0xFF   ←CRC(dummy)
READ: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x0F 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x4d 0x00 0x00 0x00 0x00 0xff r:8]  ←CMD13 SEND_STATUS
/CS ENABLED
WRITE: 0x4D
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF ←R2 ロック解除
/CS DISABLE

 この状態で、データにアクセスできるようになる。 
パスワードは設定されているので、電源OFF(抜く)とパスワード・ロック状態になる。

【パスワード・クリア】

SPI>[0x4D 0x00 0x00 0x00 0x00 0xff r:8]  ←CMD13 SEND_STATUS
/CS ENABLED
WRITE: 0x4D
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0x01 0xFF 0xFF 0xFF 0xFF 0xFF ←R2:0x01=Card is locked
/CS DISABLED

SPI>[0x50 0x00 0x00 0x02 0x00 0xFF r:8]    ←CMD16:SET_BLOCK_LEN
/CS ENABLED
WRITE: 0x50
WRITE: 0x00
WRITE: 0x00
WRITE: 0x02
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x6A 0x00 0x00 0x00 0x00 0xFF r:8    ←CMD42:LOCK_UNLOCK
/CS ENABLED
WRITE: 0x6A
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

SPI>0xFE 0x02 6 "abc123" 0xFF:506 0xFF 0xFF r:24] ←0x02: CLR_PWD
WRITE: 0xFE
WRITE: 0x02
WRITE: 0x06
WRITE: "abc123" ←passowrd data
WRITE: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
                            ( 506=512-6のFFh
               )
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
       0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
WRITE: 0xFF   ←CRC(dummy)
WRITE: 0xFF   ←CRC(dummy)
READ: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x03 0xFF 0xFF
/CS DISABLED

SPI>[0x4D 0x00 0x00 0x00 0x00 0xFF r:8]   ←CMD13 SEND_STATUS
/CS ENABLED
WRITE: 0x4D
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF ←R2:ロック解除
/CS DISABLED

 ステータスを読むとロック解除になっている。 ロック解除(UNLOCK)と違うのはパスワードデータがクリアされているので電源をOFFにしてもロック解除されたままになる。
 PCに認識させてみると、

Sdcarddiskmgr_resetpwd1

 ちゃんと認識されている。 めでたしめでたし。

###

 ネットを探すと、AVRやPIC、Arduino、RaspberyPiで実装した例があるようだ。



最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年9月11日 (火)

Bus pirate(2) <SDカードを読んでみる>

 Bus pirate(2018/9/3)で先割れスプーン的だと書いたけど、便利だったのでSPIモードでSDカードを読んでみた。 uSDカードアダプタはAmazonで買った安物。 3.3VのLDOとレベルシフタが載っている。

Buspirate36_sd  

 昔SDカード/MMCカードで遊んでいたころはまだSDHC規格は無かったので知識が古い。

 調べてみると、MMCカード規格を作っていたMultiMediaCard AssociationはJDECと合併したらしい。 最近MMCカードは見かけないけど組み込み業界では eMMCとしてチップが基板に張り付けてある。

 MMCカードの規格はRenesas(旧日立)の「マルチメディアカードユーザーズマニュアル(j603002_mmc.pdf)」があるのだが、Renesasのサイトでは見つからないようだ。 ネット上では奇特な人が保存してくれているようだ。

 ここを参考にBus pirateでSDカードのデータを読んでみた。

 SDカードはSanDiskの2G microSDcard。
Sandisk_2g_sdc

【初期化】
 CMD1で初期化してみた。 初期化手順は、

  1. SPIモードにする
  2. CMD0:GO_IDLE_STATE:(要CRC)
  3. CMD1:SEND_OP_COND R1レスポンスが00hになるまで
  4. CMD2:ALL_SEND_CID
  5. CMD3:ET_RELATIVE_ADDR

これはMMCの初期化方法。 ユーザマニュアルに説明がある。 今回は、CMD2,CMD3は省略して先頭セクタを読んでみる。

 SPIモードにするには、CSをHにしてダミークロックを74クロック以上発行する。 74クロックはキリが悪いので80クロックとする。 

 BusPirateでは、"]"←CS=H、r:10←10byte(80clock)、

 コマンドレスポンスの先頭ビットは0なので0xFF以外のデータを読み出すまで待つ。ところが、BusPireteでは待つことができないのでとりあえず8byte読む。 0xFFでないデータがコマンドレスポンスだ。 (scriptを使うと待つことができる。)

【セクタ読み出し】
 読みだし手順は、

  1. CMD16:SEND_BKICKLEN
  2. CMD17:READ_SINGLE_BLK

 まずCMD16でブロックサイズを指定する。次にCMD17を送ると、コマンドレスポンスに続いてデータを読み出すことができる。 読み出す回数はコマンドレスポンス:5byte、データトークン(0xFE):1byte、ブロックデータ:512byte、CRC:2byteで520byteを指定している。 

 6byte以内にデータトークン(0xFE)が読み出せないとすべてのデータが読めない。 そのときは読み取るデータを多くする。 (r:530とか)

HiZ>m 5 1 1 2 1 2 2  ←SPIモード
SPI (spd ckp ske smp csl hiz)=( 1 0 1 0 1 0 )
Ready
SPI>Wv         ←電源ON ピンステータス表示
Power supplies ON
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     CLK     MOSI    CS      MISO
P       P       P       I       I       I       O       O       O       I
GND     3.29V   5.02V   0.00V   0.00V   H       L       H       H       L

SPI>]r:10                 ←SPImode
/CS DISABLED
READ: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

SPI>[0x40 0x00 0x00 0x00 0x00 0x95 r:8]   ←CMD0 GO_IDLE_STA
/CS ENABLED
WRITE: 0x40
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x95
READ: 0xFF 0x01 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF ←R1=0x01 "In Idle State"
/CS DISABLED

SPI>[0x41 0x00 0x00 0x00 0x00 0xff r:8]        ←CMD1 SEND_OP_COND 
/CS ENABLED
WRITE: 0x41
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x01 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF ←R1=0x01 "In Idle State"
/CS DISABLED

SPI>[0x41 0x00 0x00 0x00 0x00 0xff r:8]    ←CMD1 SEND_OP_COND
/CS ENABLED
WRITE: 0x41
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF ←R1=0x00 成功
/CS DISABLED
SPI>[0x50 0x00 0x00 0x02 0x00 0xff r:8]    ←CMD16 SET_BLOCK_LEN
/CS ENABLED
WRITE: 0x50
WRITE: 0x00
WRITE: 0x00
WRITE: 0x02
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF ←R1 Response=0x00 成功

SPI>[0x51 0x00 0x00 0x00 0x00 0xff r:520]   ←CMD17 READ_SINGLE_BLOCK
/CS ENABLED
WRITE: 0x51
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0xFF 0x00 0xFF 0xFF 0xFE 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
                  (                        
                   )                       
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x03 0x3D 0x00 0x06 0x3F 0xFF 0xD7 0xF9 0x00 0x00 0x00
      0x07 0x89 0x3C 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x55 0xAA
0x5D 0xE1
/CS DISABLED

 ↑先頭から3byte目がR1レスポンス(0x00)。続いてデータトークン(0xFE)、SDカードの先頭セクタ。パーティションテーブル(下線部分)と末尾に55h、AAhがある。 最後の2byteはCRC(0x5D,0xE1)。

【SDHCカード】
 SanDisk SDHC 8GBも読んでみる。

Sandisk_8g_sdhc

 このカードはCMD1で初期化する方法は使えない。 初期化手順は、SD AssociationからDLできる [Physical Layer Simplified Specification]に解説がある。

  1. SPIモードにする
  2. CMD0: GO_IDLE_STATE:(要CRC)
  3. CMD8: SEND_IF_COND:(要CRC)
  4. ACMD41:SD_APP_OP_COND (CMD55+CMD41) R1レスポンスが00hになるまで 
  5. CMD58: READ_OCR

CMD8のパラメータは、0x00、0x00、電圧、チェックパターン(レスポンスで同じ値が返る)。 電圧は3.3vで使うので0x01、チェックパターンは0xAAを使う。 なぜって、ネット上にCRC(0x87)を計算した人がいるから。 ここは決め打ちでよさそう。

 CMD58は省略。データ読み出しはCMD16とCMD17上の例と同じ。

HiZ>m 5 1 1 2 1 2 2
SPI (spd ckp ske smp csl hiz)=( 1 0 1 0 1 0 )
Ready

SPI>Wv
Power supplies ON
Pinstates:
1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk)
GND 3.3V 5.0V ADC VPU AUX CLK MOSI CS MISO
P P P I I I O O O I
GND 3.29V 5.02V 0.00V 0.00V H L H H L

SPI>]r:10                ←SPImode
/CS DISABLED READ: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

SPI>[0x40 0x00 0x00 0x00 0x00 0x95 r:8] ←CMD1 GO_IDLE_STATE
/CS DISABLED
READ: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS ENABLED
WRITE: 0x40
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x95
READ: 0xFF 0x01 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

/CS DISABLED
SPI>[0x48 0x00 0x00 0x01 0xAA 0x87 r:8]  ←CMD8 SEND_IF_COND
/CS ENABLED
WRITE: 0x48
WRITE: 0x00
WRITE: 0x00
WRITE: 0x01
WRITE: 0xAA
WRITE: 0x86
WRITE: 0x87
READ: 0x01 0x00 0x00 0x01 0xAA 0xFF 0xFF 0xFF  ←R1:Idle R7:
/CS DISABLED

SPI>[0x77 0x00 0x00 0x00 0x01 0xff r:8]   ←CMD55 APP_CMD
/CS ENABLED
WRITE: 0x77
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x01
WRITE: 0xFF
READ: 0xFF 0x01 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x69 0x40 0x00 0x00 0x01 0xff r:8] ←CMD41 PP_SEND_OP_COND
/CS ENABLED
WRITE: 0x69
WRITE: 0x40
WRITE: 0x00
WRITE: 0x00
WRITE: 0x01
WRITE: 0xFF
READ: 0xFF 0x05 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x77 0x00 0x00 0x00 0x01 0xff r:8] ←CMD55 APP_CMD
/CS ENABLED
WRITE: 0x77
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x01
WRITE: 0xFF
READ: 0xFF 0x01 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x69 0x40 0x00 0x00 0x01 0xff r:8] ←CMD41 PP_SEND_OP_COND
/CS ENABLED
WRITE: 0x69
WRITE: 0x40
WRITE: 0x00
WRITE: 0x00
WRITE: 0x01
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x50 0x00 0x00 0x02 0x00 0xff r:8] ←CMD16 SET_BLOCK_LEN len=512byte
/CS ENABLED
WRITE: 0x50
WRITE: 0x00
WRITE: 0x00
WRITE: 0x02
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
/CS DISABLED

SPI>[0x51 0x00 0x00 0x00 0x00 0xff r:520] ←CMD17 READ_SINGLE_BLK
/CS ENABLED
WRITE: 0x51
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0x00
WRITE: 0xFF
READ: 0xFF 0xFF 0x00 0xFF 0xFF 0xFE 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
                  (                        
                   )                       
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x82 0x03 0x00 0x0B 0x50 0xCA 0xC6 0x00 0x20 0x00 0x00
      0x00 0xC0 0xEC 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
      0x00 0x00 0x00 0x00 0x55 0xAA
0x68 0xC0
/CS DISABLED

 CMD8は PhysicalSpec Ver2.0から使えるらしい。 CMD8→ACMD41→CMD1の順に初期化するとどのカードでも使える。

 昔AVRでSD/MMCにアクセスするプログラムを作ったときは、初期化で苦労した記憶がある。 いまほど情報もなかったし、Arduinoも無かったから。

 今時は情報も多いし、Bus pirateのようなツールで試すと、F/Wレベルでの試行錯誤を減らせる。

###

 SDカードのライセンスにまつわるエトセトラは。Chanさんやねむさいんの、

が参考になる。



最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年9月 3日 (月)

Bus pirate <先割れスプーン的だが便利だ>

Bus pirate 3.6aをスイッチサイエンスで買った。

Buspirate36_2
↑(スイッチサイエンスの箱の上で撮った。宣伝ではありません)

Bus pirateDANGEROUSPROTOTYPESのオープンソースのユニバーサル・バスインタフェースで、スイッチサイエンスで売っているのはSpeed Studioが造っている。

今回買ったのはver3.6aだ。 実はver4.0が出ていて、マルツは4.0を売っているのだが、ちょっと急いでいたので即日発送のスイッチサイエンスで買った。 (実は、v4.0の部品も買ってあるのだが...)

 このボードを一言でいうと、1-wireやI2CやSPI、マイコン系の萬プロトコルの制御ができるツール。他に周波数測定やPWMが発生できる。

 わざわざこんな先割れスプーン的なツールを買わなくてもマイコンを使ったらできる。 Arduinoはライブラリが充実しているので簡単にできるのだが...

 Bus pirateはFT232の先にPIC24FJ64GA002が繋がっていて、レベルシフタでバスに繋がっている。

Buspirate36_1  

Ft232rl Pic24f

ターミナルソフトでつないでコマンドを入力して制御してみる。

"?"を入力するとコマンド一覧が表示される。
"i"を入力するとファームウェアの情報が表示される。

HiZ>?
General                                 Protocol interaction
---------------------------------------------------------------------------
?       This help                       (0)     List current macros
=X/|X   Converts X/reverse X            (x)     Macro x
~       Selftest                        [       Start
#       Reset                           ]       Stop
$       Jump to bootloader              {       Start with read
&/%     Delay 1 us/ms                   }       Stop
a/A/@   AUXPIN (low/HI/READ)            "abc"   Send string
b       Set baudrate                    123
c/C     AUX assignment (aux/CS)         0x123
d/D     Measure ADC (once/CONT.)        0b110   Send value
f       Measure frequency               r       Read
g/S     Generate PWM/Servo              /       CLK hi
h       Commandhistory                  \       CLK lo
i       Versioninfo/statusinfo          ^       CLK tick
l/L     Bitorder (msb/LSB)              -       DAT hi
m       Change mode                     _       DAT lo
o       Set output type                 .       DAT read
p/P     Pullup resistors (off/ON)       !       Bit read
s       Script engine                   :       Repeat e.g. r:10
v       Show volts/states               .       Bits to read/write e.g. 0x55.2
w/W     PSU (off/ON)            <x>/<x= >/<0>   Usermacro x/assign x/list all

HiZ>i
Bus Pirate v3b
Firmware v5.10 (r559)  Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
http://dangerousprototypes.com
HiZ>

ファームウェアはv5.10のようだ。 サポートページによると最新はv7.0公式はv6.3で、GitHubからDLするようだ。

とりあえず、I2CのEEPROM(24LC64)を読んでみた。
ここを参考にしましたというかそのまま試した。(https://gist.github.com/yoggy/2f2ffc198cc154539506b8755f42dce8)

Buspirate36_i2c

↑ICの足にクリップを直接つないだ。

メモ代わりに書いておく。

設定

HiZ>m ←モード設定
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>4
Set speed:
1. ~5KHz
2. ~50KHz
3. ~100KHz
4. ~400KHz

(1)>4
Ready


I2C>W      ←W:電源ON
Power supplies ON 
I2C>P      ←P:PullUp ON
Pull-up resistors ON
I2C>v      ←v:ピンステータス表示
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     SCL     SDA     -       -
P       P       P       I       I       I       I       I       I       I
GND     3.29V   5.02V   0.00V  5.03V   H       H       H       H       H

I2C>(0) ←マクロでアドレスを探す
0.Macro menu
1.7bit address search
2.I2C sniffer
I2C>(1)
Searching I2C address space. Found devices at:
0xA0(0x50 W) 0xA1(0x50 R)
I2C>

 VPU(#5)に5Vを供給しておくこと、ボードからもらうか#3に接続する。(上の画像では24LC64の#8ピンにオレンジ(5.0V)とグリーン(VPU)が繋がっている。)

 vコマンドでステータスを見ると、VPUが5.03Vになっている。

書き込み

I2C>[0xa0 0x00 0x00 0x00 0x11 0x22 0x33 0x44 0x55 0x66 0x77]  
I2C START BIT   ↑アドレス0x00 から8byte書く
WRITE: 0xA0 ACK
WRITE: 0x00 ACK
WRITE: 0x00 ACK
WRITE: 0x00 ACK
WRITE: 0x11 ACK
WRITE: 0x22 ACK
WRITE: 0x33 ACK
WRITE: 0x44 ACK
WRITE: 0x55 ACK
WRITE: 0x66 ACK
WRITE: 0x77 ACK
I2C STOP BIT
I2C>

 デバイスのアドレス(1byte目)は、マクロで探したアドレスを使う。

読み出し

I2C>[0xa0 0x00 0x00] ←アドレスを0x00に
I2C START BIT
WRITE: 0xA0 ACK
WRITE: 0x00 ACK
WRITE: 0x00 ACK
I2C STOP BIT
I2C>[0xa1 rrrrrrrr] ←8byte読む
I2C START BIT
WRITE: 0xA1 ACK
READ: 0x00
READ:  ACK 0x11
READ:  ACK 0x22
READ:  ACK 0x33
READ:  ACK 0x44
READ:  ACK 0x55
READ:  ACK 0x66
READ:  ACK 0x77
NACK
I2C STOP BIT
I2C>                                                             

コマンドは続けることができるようだ。

HiZ>m 4 4
I2C (mod spd)=( 0 3 )
Ready
I2C>WPv
Power supplies ON
Pull-up resistors ON
Pinstates:
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     SCL     SDA     -       -
P       P       P       I       I       I       I       I       I       I
GND     3.29V   5.02V   0.00V   5.03V   H       H       H       H       H
I2C>[0xa0 0 0]
I2C START BIT
WRITE: 0xA0 ACK
WRITE: 0x00 ACK
WRITE: 0x00 ACK
I2C STOP BIT
I2C>[0xa1 r:8]
I2C START BIT
WRITE: 0xA1 ACK
READ: 0x00  ACK 0x11  ACK 0x22  ACK 0x33  ACK 0x44  ACK 0x55  ACK 0x66  ACK 0x77
NACK
I2C STOP BIT
I2C>

便利かも。


最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年8月 2日 (木)

COP400

若松で買い物をしたときに、 COP420NNL/Lがあったのでついでに買った。

Cop420

 COP400シリーズはNational Semiconductorの4bit Micro controllerで、National Semiconductor COP400を見ると、子供用のゲームや


↑(http://www.handheldmuseum.com/Mattel/Mattel-FuntronicsJacks_RLGL.jpg)

Apple Lisa のKeyboard, mouse, RTC and power switch controllerに使われていたらしい。

 若松で買ったCOP420NNL/Nは データシートをみると、MaskROM外部バス無しの製品だ。COP420とCOP402を勘違いしていたようだ。 orz

 最近、COP402Nを見つけたので買ってみた。

Cop402n1←(青っぽいのはカメラのせい)

COP402はRAM256byteで外付けROM用のバスが出ているのでDIP 40pinだ。立派。

 マクロ・アセンブラがあるようだ。
http://john.ccac.rwth-aachen.de:8000/as/


最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年7月 9日 (月)

MELPS740

 最近ヤフオクの広告に三菱のマイコンの出品が表示されるようになった。

↓こんなやつ
Photo

 三菱半導体は今はRenesasになっているが、合併前に販売していたM16C、M32R、720、740シリーズは今でも販売している。

 広告に表示されるのは、MELPS740シリーズのM50747SPやM50734SPなどだ
M50747SPは 8kb MaskROM, 256bRAM、8bitTimer×3、GPIO×40、Input×8、Output×8、SIO×1
M50734SPは 外部ROM,RAM Timer:16bit×1,8bit×8, GPIO×32、Input×4、8bitA/D PWM, SIO×1

 MELPS740シリーズは6502の命令を拡張して組み込み用にした製品らしい。
半導体コレクション展示会場に解説がある。

 6502を入手しようと調べたときに、MELPS740も調べたのだが、売っているところがみつからなかった。

 出品者から修理に使うのならどの製品か教えてほしいと連絡があったが、単に興味本位でと回答しておいた。

 VTR等の組み込み機器に多く使われたらしく見かけたことが無い。 唯一バーコードリーダに使われていたのを見たことがある。 剥がして使おうかと思い調べたら外部バス無しMASK-ROMの製品(型番失念)だったので剥がすのを止めた。 

 今回 M50747を調べて気が付いた。この製品はMaskROMだけど、IOポートをバスにして外部メモリが使えるモードがある。 M50747もM50734も外部メモリが使えるのでどちらでもよいのだが、安いほうの、M50734SPを落札した。

M50734sp M50734marking

シュリンクDIPとはいえ、64PINのDIPは立派だ。

モニターが必要だなあ。 6502用のモニタが使えるのだろうか。



最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年5月28日 (月)

STM8SをVersaloonで

 今年の大型連休にふと思い立ち、ジャンク化しているSTM8S-Discoveryを引っ張り出してきた。このボードは、ターゲットCPUはSTM8S105C6でST-Linkが付いていて安価なボードだ。

 ST-Link部分にはSTM32F103が乗っている。

Versaloon

ちょっと前に、ねむいさんの記事を参考にして、この部分を改造してSWD I/F用のVersaloon互換にして使っていた。

 残った、STM8Sは使うあてもなくジャンク化していたのだが、何か動かしてみないともったいないお化けが出てきそうだ。

Stm8sdiscovery

 ということで、
コンパイラはSDCCが使える。ライタはVersaloonが使える、書き込みソフトはVersaloonに対応したvsprogというツールを使うことにした。

 vsprogは以前にインストールした記憶はあるのだが、パソコンを変えてからインストールしていない。 バイナリがあったと記憶しているのだがVersaloonの本家サイトが無くなっていてドキュメントがない。 githubからソースを落としてきてmakeした。

ところが、vsprogでフラッシュが読み書きできない。

 SWIMをサポートしていないと言われる。 でも、VersaloonとOpenOCDでstm32のデバッグができているのでVersaloonは動いているようだ。

 STM8のフラッシュメモリの読み書きにはSWIMというインタフェースを使う。 SWIMが使えるのは、STM8x-Discoveryか純正ST-LinkかVersaloonだ。

 STM32F0-DiscoveryやNucleo401のST-LINKはSWD専用になっているので使えない。

 STM8S-DiscoveryのST-LinkはSWIM専用だ。 VersaloonはSWDにもSWIMにも対応しているというので改造したのだがSWIMが使えない。

Versaloon本家のサイトが閉じているようなので、ソースを読んでみることにした。 ヘッダファイルから読み始めると、だんだん思い出してきた。

 dongle/firmware/Projects/Versaloon/GCC/makefile中のHW_BOARD=STM8SDiscoveryにしてmailするとファームウェアができて、それをJTAG-KEYそっくりさんでSTM8SDiscoveryのST-Link部分に書き込んだはず。

 STM8SDiscovery.cfgを見ると、SWIMは0になっている。つまりこのファームウエアは対応していないということ。 orz

 SWIMを1にしてmakeするとエラーがたくさん出る。 ソースを真面目に読まないといけないようだ。 サイトは閉じているしなあ。

 STM8にはUARTから使えるbootloader機能があるのでUARTがあればファームウエアは書けるようだ。

ところが、bootloaderを有効にするためにはオプションバイトの値を書き換えなければならない。 オプションバイトを書き換えるにはSWIMで書き換えるしかないようだ。

 ということで、ST-Linkを買うことにした。そっくりさんだけど。
Amazonで探すと同じような製品が沢山出てくる。その中で一番安いやつを注文した。

 注文の翌日に発送にお知らせメールが来たが、5日~12日かかるという。 国内のストックではなく大陸から直接来るのか。


最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年5月18日 (金)

i8080 <買うつもりはなかったのだけれど。つい...>

AmazonでST-Linkそっくりさんを買ったら。
お勧めが出てきた。

NEC 汎用 USART PROGRAMMABLE COMMUNICATIONS INTERFACE UPD8251AFC    ¥ 350
OKI Semiconductor 汎用品 8bit CMOS MICROPROCESSOR MSM80C85AH    ¥ 290
NEC CLOCK GENERATOR and DRIVER for 8080A UPB8224C        ¥ 320

8085に8224は必要ないだろうと一人でツッコミを入れながら、8080も売っているのか検索したら、売っていた。

NEC 8bit 2MHz MPU i8080互換 UPD8080AFC    ¥ 1,200

ちょっと高い。コレクションならセラミックパッケージの方が良いかな...

8080_s

Upb8224c_s ←クロックジェネレータ

Upd8228c_m ←システムコントトーラ

Upd8251afc ←USART

 なんだかそろってしまった。

 8080を初めて知ったのは、たしか1976頃のCQ誌で8080を使ったモールス解読器の記事だった。

 当時、コンピュータは科学特捜隊に出てくるようなイメージだった。


↑(https://cdn.snsimg.carview.co.jp/minkara/userstorage/000/038/645/744/549b14ee09.jpg?ct=cba21fcfd098)

それが、個人でコンピュータが作れることに、すごく興奮したのを覚えている。 でも、厨房だったからとても小遣いで買えるようなものではなかった。

 退職された職場の大先輩は8080が出たときに20,000円くらいで取り寄せてもらったそうだ。 秋葉の部品屋の店頭にはなかったそうだ。 今はDigikeyでポチればアメリカから3日で届く。

 8080は電源が+5Vの他に-5Vと+12Vが必要だ。
8080の回路図を最初見たときに「あ、めんどくさっ」と思った。 すぐにZ80が出てきて5V単一電源で命令も拡張されていたから、なにも好き好んで8080使わなくていいよねと思っていた。

 5V,1A、12V,0.1A、-12V,数mAの電源と聞くと、オヤジはついトランスの大きさと重さを思い浮かべてしまう。

 まあ道楽で、先人たちの苦労を垣間見るなら電源から作るのもありだが、今時ならスイッチング電源を使うよね。

 当時電源から作った先輩達からは、「この軟弱者!」と言われるのかな?
と思いながらついポチってしまった。(^^ゞ

 セラミックパッケージの8080を買うとコレクションにしてしまう可能性が高いので、あえてプラスチックパッケージを。


最近の投稿】【最近のCPUボード】【2017の投稿】 【2016の投稿】 【2015の投稿

2018年4月24日 (火)

lcc1802

 以前書いた記事(CDP1802 (15/10/11))のコメントにCDP1802用のCコンパイラの質問があったので調べてみた。 

 結論は、出力されるバイナリが大きいので、RAMを十分載せておけば使える。

lcc1802

 CDP1802は入手したがまだ動かしていない。 (^^;
SBCを作ったとしても、おそらくtinyBASICでも動かしたら満足するのだろう。というわけで、CDP1802用のCコンパイラは調べていなかった。

 調べてみるとlcc1802が見つかった。
lccはOpen SourceのコンパイラでターゲットCPUはAlpha,SPARC,MIPS,x86に対応している。 lcc1802はlccをCDP1802に対応させたもので、COSMAC ELF Membersip Cardのアドオンシールドにarduinoを持たせた 1802 olduino 用に作られたもののようだ。 
https://sites.google.com/site/lcc1802/downloads
からダウンロードできる。

インストール

 lcc42judy.zipをインストールしてみた。
zipを解凍して現れるlcc42ディレクトリをCドライブ直下(C:\)にコピーしろと書いてある。
開発系は C:\Devzにインストールしているので、ここにインストールした。 コンパイル・ドライバ(lcc)が呼び出すコマンドは同じディレクトリを探すので問題はないだろうと考えたのだが、cppが見付からないと怒られた。(^^;
どうやら、プリプロセッサ(cpp.exe)、コンパイラ(rcc.exe)、アセンブラ(asw.exe)のパスは"C:\lcc42\bin"がハードコードしてあるようだ。 仕方がないので、C:\からinkを張っておいた。

エミュレータ

 まだSBCを作っていないのでCOSMACエミュレータ Emma 02で試してみた。
Emma 02はCDP1802が使われている数々のボードやシステムのエミュレーションができる。 その中でシンプルな VELFで試してみた。

Emma02_velf

Emma02_velf_frontpanel

 COSMAC ELFはシリアル・インタフェースを持っていない。Q(#4)をTXD、EF2(#23)をRXDに使ってソフトウェアで実装してある。

 シンプルな COSMAC ELFで試しておけばSBCを作るときにシリアルインタフェースを載せなくて良い。

サンプル

 lcc1802にはサンプルが用意されている。 これらのサンプルはolduino用なので、これを変更してVELFで動くようにする。

 まずはお約束の hello worldから。 examples/helloworldディレクトリにある。

↓helloworld.c

/*
   print the string "hello World!"
*/
#include <nstdlib.h>
void main()
{
printstr("hello World!\n");
}
#include <nstdlib.c>

ライブラリ

 4行目の #include <nstdlib.h>は良いが、最終行の #include <nstdlib.c>は何?である。

 lcc1802はライブラリはなくて、最低限の関数がinclude/nstdlib.cに書いてある。printf()もあるが、最低限の機能だけで出力幅指定はできない。

 文字列出力関数のprintstr()は1文字出力にout(5,d)を呼んでいるが、VELFでは動作しないのでputc()を使うように変更しておく。

↓nstdlib.c内のprintstr()

void printstr(char *ptr){
//    while(*ptr) out(5,*ptr++);
    while(*ptr) putc(*ptr++);
}

 nstdlib.cにはfloatを扱う関数がある。 sdccは賢いので必要な関数だけリンクしてくれるがlcc1802ではnstdlib.cはいつでもコンパイルされるので使わない関数でもオブジェクトに含まれる。float関係の部分だけは "nofloats"が宣言されているとコンパイルしないようになっている。 コマンドラインオプションで -Dnofloatsとすれば良い。

ランタイムライブラリ

 ランタイムライブラリは、include/lcc1802Prolo??.incとinclude/lcc1802Epiloxx.inc。

 これらはのライブラリは、コンパイル済のライブラリをlinkerがリンクするのではなく、ソースに展開している。ソース中にnsddlib.cをインクルードし、アセンブラソース中でlcc1802Prolo??.incとlcc1802Epiloxx.incをインクルードしている。

入出力ルーチン

 IOルーチンは、include/IO1802.incに書いてある。 printf()は1文字出力にputc()を呼んでいる。  lcc1802が想定しているolduinoの1文字出力はout(5,d)を使っているので、VELFでは出力できない。

 IO1802.incに1文字出力(putc())と1文字入力(getc())を書けば良さそうだ。
ここでハタと困った。CDP1802のアセンブラは書いたことが無い。
とりあえず、Emma02にVELFのモニタソース(Emma02\data\Velf\VELFbios-v3.1.LST)があったので、この中の1文字入出力ルーチンを参考に(ほぼコピペ)、Cから引数を渡す部分と戻り値を返す部分を付け加えて、テンポラリ変数をreからrt1に変えた。

↓IO1802.inc

;**********************************************************************
;Transmit Byte via Q connected to RS232 driver
;call with R3 being the previous PC
;Byte to send in D
;Returns with D unaffected
;re.1 = D
;Destroys rt1.0
;----------------------------------------------------------------------
_putc: glo regArg1
txchar: phi rt1
ldi 9 ;9 bits to transmit (1 start + 8 data)
plo rt1
ghi rt1
shl ;set start bit
rshr ;DF=0

txcloop:
bdf $+5 ;10.5   jump to seq to send a 1 bit
req ;11.5   send a 0 bit
br $+5 ;1      jump +5 to next shift
seq ;11.5   send a 1 bit
br $+2 ;1      jump +2 to next shift (NOP for timing)
rshr ;2      shift next bit to DF flag
phi rt1 ;3      save D in rt1.1
DEC rt1 ;4      dec bit count
glo rt1 ;5      get bit count
bz txcret ;6      if 0 then all 9 bits (start and data) sent
ghi rt1 ;7      restore D
NOP ;8.5    pause 1/2 time
br txcloop ;9.5    loop back to send next bit
txcret: ghi rt1 ;7
ghi rt1 ;8
ghi rt1 ;9
NOP ;10.5
seq ;11.5 stop bit
NOP ;1
NOP ;2.5
NOP ;4
NOP ;5.5
NOP ;7
NOP ;8.5
NOP ;9
NOP ;10.5
Cretn

;**********************************************************************
;rx_char
;Receive Byte via EF2 connected to RS232 rt1ceiver
;Recieves 8 bits
;call with R3 being the previous PC
;Returns with Byte received in D and rt1.1
;Destroys rt1.0
;----------------------------------------------------------------------
_getc:
rxchar: ldi 8 ;start bit +7 bits from loop, last bit on returning
plo rt1
ldi 0
rxcw: ;wait for start bit
bn2 rxcw ;each instr takes 9us, we need 104us = 11.5
;delay 1/2 bit time to center samples
NOP ;     Don't test for correct start bit
NOP ;     it will work, if there's too much
NOP ;     noise on the line, shorten the cable!
rxcloop:
NOP ;10.5
b2 $+6 ;11.5 sample rx input bit
ori 80h ;1
br $+4 ;2
phi rt1 ;1
phi rt1 ;2
shr ;3
phi rt1 ;4
DEC rt1 ;5
glo rt1 ;6
bz rxcret ;7
ghi rt1 ;8
br rxcloop ;9
rxcret: ghi rt1 ;8
ghi rt1 ;9
NOP ;10.5
b2 $+4 ;11.5 sample last rx input bit
ori 80h ;1
plo retVal
Cretn

 

コンパイル

 この変更でIntelHexフォーマットの a.hexが作られるようになる。

C:\Users\user> lcc -Dnofloats helloworld.c
And St. Judy's Compiler FLOATS Across your code...
P2HEX/C V1.42 Beta [Bld 87]
(C) 1992,2013 Alfred Arnold
C:\Users\user\AppData\Local\Temp/lcc124682.p==>>a.hex  (3609 Bytes)

しかし、hellowroldだけで3,609byteとは。 

8Queen

 8Queen問題を解くプログラムをコンパイルしてみる。 再帰を使っているのでちゃんと動くだろうか?

/*
* 8Queen.c
* Yoshi / Apr.2018
*/

#include <nstdlib.h>

#define FALSE 0
#define TRUE (!FALSE)
#define u_char unsigned char
#define u_short unsigned short
#define NL "\r\n"
#define getchar getc
int DEBUG = 0;

char table[8];
void clrtbl(void) { int i; for(i=0;i<8;i++) table[i]=0xFF; }

void printtb(char n) {
    int x, y;
    printf(NL "-- %d --" NL, n);
    for (y=0;y<8;y++) {
        putchar('|');
        for (x=0;x<8;x++) {
            if (table[y]==x)
                 putchar('Q');
            else putchar(' ');
            putchar('|');
        }
        puts(NL);
    }
}

char check(int x, int y) {
    int i;

    if (y==0) return TRUE;
    for (i=y-1; 0<=i; i--) {
        if (2<DEBUG) printf("tb[%d]=%d" NL, i, table[i]);
        if (table[i]==x || table[i]==(x-(y-i)) || table[i]==(x+(y-i)))
            return FALSE;
    }
    return TRUE;
}

char place(int x, int y) {
    static int n = 1;

    if (DEBUG) printf("place(%d,%d):" NL, x, y);

    if (7<y) {  /* 解 */
        printtb(n++);
        return FALSE;
    }
    if (7<x) {  /* 見つからない */
        return FALSE;
    }

    if (check(x,y)) {
        table[y] = x;
        if (n==1) printtb(n);
        place(0, y+1);
        table[y] = (u_char)-1;
    }
    return place(x+1, y);
}

void main(void) {
    printf("8 Queen" NL);
    clrtbl();
    place(0,0);
    exit(0);
}

#include <nstdlib.c>

コンパイルすると、4,542byteだった。

↓実行結果

Emma02_velf_terminal

ちゃんと実行されるようだ。

まとめ

 SBCを作るときはRAMをケチらないで載せておけばlcc1802は使える。今時、32kのRAMを積んでも大した出費ではない。

 残念ながら、オリジナルのCOSMAC ELFではRAMが少ないので使えないだろう。もっともオリジナルのCOSMAC ELFを忠実に作るなら、ハンドアセンブルして、8個のスイッチでプログラムを入力する覚悟が必要だ。

 rcc.exeがASxxxxアセンブラを吐くようにするとSDCCのライブラリが使えるようになる。そして、aslinkを使うともう出力がもう少しコンパクトになると思う。 興味はあるが、そこまでやるか... 



最近の投稿】【2017の投稿】【2016の投稿】【2015の投稿

最近のCOSMAC/CDP1802

2018年4月15日 (日)

IchigoJam(11) 

LED&KEY(TM1638)をIchigojamで点けてみた。BASICで入出力ポートを制御するとさすがに遅い。あまりに遅いので、マシン語で高速化してみた。

Tm1638_yoshi1
ダウンロード TM1638_Yoshi1.mp4 (1075.3K)

YOSHIがスクロールしているのだけれど、残像が残って認識できないくらい速くなっている。

 福野さんがこのボードをマシン語で制御しておられる。(2018/4/14)
(格安7セグディスプレイ「LED&KEY」を使ってカチカチカウンターづくり、TM1638 x IchigoJam用マシン語SPIドライバの作り方)

どの部分をマシン語で書くか

  このボードに載っているLED&KEY制御用デバイス(TM1638)はSPIもどきでデータを送り受けする。で8個のLEDを制御しようとすると、 8(LED)x16bit/LED+3(command)×8bit/cmd=152bit のデータを送る必要があるから、クロックも152個必要だ。
このクロックをBASICのOUT命令でON/OFFしているから、データI/Oが152回、クロックが304回で合計456回IN/OUT命令を実行しなければならない。

 高速化するならば、データを送り受けする部分をマシン語にすれば効果があるだろう。

 メモリダンプ・プログラムを書いたときの手法でやってみる。IchigoJam(4) (2015/06/01)
Cで書いてgccでコンパイルして、逆汗して、BASICのPOKE文を作る。
逆アセンブラはgccのツールチェーンに入っているobjdumpを使った。
逆汗リストからPOKE文の作成にはawkを使った。今どきならpythonオヤジ世代ならperlだがおじいちゃん世代はawkだ。
 (IJUtils (http://ijutilities.micutil.com/#Software)のIJBin2Pokeを使うと簡単にできるらしい)

Cソース

 Cのソースはこんな感じ。

/*
* access.c
* Apr.2018/Yoshi
*/
#include <stdio.h>
#include <stdlib.h>

#define    GPIO1_MASKED_ACCESS    ((volatile uint32_t *)0x50010000)
#define    GPIO0_MASKED_ACCESS    ((volatile uint32_t *)0x50000000)

#define    BIT_LED    5    //GPIO1_5
#define    BIT_STB    0    //GPIO1_0
#define    BIT_CLK    1    //GPIO1_1
#define    BIT_DIO    5    //GPIO0_5

#define    STB_L    0
#define    STB_H    (1<<BIT_STB)
#define    CLK_L    0
#define    CLK_H    (1<<BIT_CLK)

#define    STB(d)    GPIO1_MASKED_ACCESS[1<<BIT_STB]=(d)
#define    CLK(d)    GPIO1_MASKED_ACCESS[1<<BIT_CLK]=(d)
#define    CLKIN()   GPIO1_MASKED_ACCESS[1<<BIT_CLK]
#define    DI()      GPIO0_MASKED_ACCESS[1<<BIT_DIO]
#define    DO(d)     GPIO0_MASKED_ACCESS[1<<BIT_DIO]=(d)

#define    GPIO0_DIR    *((volatile uint32_t *)0x50008000)
#define    GPIO0_10_IN    0
#define    GPIO0_10_OUT    (1<<BIT_DIO)

#pragma GCC optimize("O1")
void wait(void) {
    int w=5;
    while (0<w) {
        w--;
        CLKIN();
    }
}
#pragma GCC optimize("Os")

/*
* receive 16bit
* uint32_t recv(uint32_t data)
* arg : uint32_t data : receive data
* ret : uint32_t : receive data
*/
uint32_t recv(uint32_t data) {
    int i;
    GPIO0_DIR &= ~(1<<BIT_DIO);    //DIO -> input
    for (i=0; i<16; i++) {
        CLK(CLK_L);
        wait();
        data <<= 1;
        data |= DI();
        CLK(CLK_H);
        wait();
    }
    data >>= BIT_DIO;
    return data;
}

/*
* send 8/16bit data
* uint32_t send(uint32_t data)
* arg : uint32_t send data
* ret : uint32_t :
* rem : send data : 1xxx xxxx CCCC CCCC : command (8bit)
*                   0xxx xxDD DDDD DDDD : data(16bit)
*/
uint32_t send(uint32_t data) {
    int i = (data & 0x8000)? 8: 0;    //check command flag
    data <<= BIT_DIO;
    GPIO0_DIR |= (1<<BIT_DIO);        //DIO -> output
    STB(STB_L);
    for (; i<16; i++) {
        CLK(CLK_L);
        DO(data);
        data >>= 1;
        wait();
        CLK(CLK_H);
        wait();
    }
}

void main(void) {
    wait();
    recv(0);
    send(0);
}

  TM1638にデータを送る関数はuint32_t send(uint32_t data)でデータを受ける関数はuint32_t recv(uint32_t dummy)だ。

 IchigojamのUSR関数の解説では、hint16_t foo(uint16_t arg , uint8_t* mem, uint8_t* font)となっているが気にしない。

 第1引数にはUSR(address , num)で呼んだときのnumがR0レジスタ経由で渡される、第2引数には仮想メモリの先頭アドレスが、第3引数にはキャラクタ・パターン・テーブルの先頭アドレスが渡されるが今回は使わないので宣言しない。

 ARMの関数呼び出し規約では、4個までの引数はR0~R3レジスタを使い、5個目以上の引数はスタック経由で渡すらしい。 第2引数(uint8_t* mem)、第3引数(uint8_t* font)を宣言すると、R1とR2レジスタをコンパイラが使わなくなるので第2、第3引数は宣言しなかった。

マスクアクセス(masked access)

 Ichihojamに使われているCPU LPC1114FN28には、マスク・アクセスという機能がある。福野さんのサイトに解説がある。
(マシン語でLEDを光らせよう! - IchigoJamではじめるArmマシン語その4)

 一般に出力ポートの特定のビットを制御するときには、他のビットに影響しないようにする必要がある。
C言語では、出力ポートPxに'1'や'0'を出力するには、Px |= (1<<BIT)、Px &= ~(1<<BIT)
と書くことが多い。

もっと詳しく書くと
 W <- Px
 W <- W & (1<<BIT)
 W <-  DATA << BIT
 Px <- W

という処理が必要だ。つまり、変数Wに一旦ポートのデータを読んできて書き換えたいビットだけ書き換えてもう一度ポートに出力する処理が必要になる。

 簡単に言うと、この面倒な処理を一度のアクセスで実現するのがマスク・アクセス機能で、GPIOのベース・アドレス付近にこの機能が割り当てられている。

 C言語的には、ベースアドレスに配列 uint32_t MSKED_ACCESS[4096] があって。配列の要素がそれぞれビット・パターン(マスクパターン)に対応している。

 例えば、IchigojamのGPIO1のbit(5)に接続されているLEDを制御する場合。

 GPIO1のベースアドレスは 0x50010000で、データ・レジスタ GPIO1_DATA は 0x500103FFCにマッピングされている。

 LEDを点灯させるには GPIO1_DATA(5)に'1'を出力すればよいから

 GPIO1_DATA |= (1<<5);

となる。これをマスク・アクセスを使うと

 GPIO1_MASKED_ACCESS[1<<5] = (1<<5);

でよい。出力する値は I<<5= 0b00010000でなくても、5ビットが1であれば良く、0b11111111でも良い。

 Cで書くと手間はあまり変わらないが、マシン語に翻訳すると

      GPIO1_DATA |= (1<<5);

    movs    r3, #32     ; r3 <- 1<<BIT_LED
    ldr     r2, .L2     ; r2 <- &PIO1_DATA
    ldr     r1, [r2]    ; r1 <- *PIO1_DATA
    orrs    r3 r1       ; r1 <- *PIO1_DATA | (1<<BIT_LED)
    str     r3, [r2]    ;(PIO1_DATA <- r1
    bx      lr          ; return_
    .align  2
.L2:
    .word    0x50013FFC

   GPIO1_MASKED_ACCESS[1<<5] = (1<<5);

    movs    r2, #32     ; r2 <- 1<<BIT_LED
    ldr     r3, .L5     ; r3 <- &PIO1_MASKED_ACCESS[1<<BIT_LED]
    str     r2, [r3]    ; PIO1_MASKED_ACCESS[1<<BIT_LED] <- 1<<BIT_LED
    bx      lr          ; return    ;
    .align   2
.L5:
    .word    0x50010008 ; &PIO1_MASCED_ACCESS[1<<BIT_LED]

コードは短くなっている。

 コードが減るより重要なことは、ポートアクセスは一旦ポートの状態を読んでいるので、処理中にポートの状態が変わってしまうと誤動作してしまう。 ところが、マスクアクセスはポートの状態を読み出さないので、誤動作する心配がないということである。

ウエイト(時間待ち)

 Cのソースはごく普通に16/8bitのデータを受けて1ビットづつ出力する処理だ。

 TM1638のデータシートを見るとクロックの最小パルス幅(PWCLK)は400ns、データセットアップタイム(tSETUP) データホールドタイム(tHOLD)はそれぞれ100nsとなっている。

 BASICは遅いからクロック出力はOUT 2,0/OUT 2,1で良いが、
マシン語に置き換えると速すぎる。'1'又は'0'を出力して400nsは出力データが変わらないように時間待ちする必要がある。

最適化

 gccは-Oオプションで最適化レベルを指定できる。実行速度よりコード領域を最小化するオプション -Os は強力だ。 Ichigojamのようにマシン語で使える領域が少ない場合には有難い。

 ところが、-Osオプションで最適化すると、ループを回って時間待ちするルーチンは最適化されて無くなってしまう。

 void wait(void { int i; for (i=0;i<100;i++) ; }

の結果はどこにも影響を与えないので無くても良いということだけど、ちょっと困る。

 最適化されないようにするには、wati()関数内で volataile属性の変数にアクセスすれば良い。 volatile属性は、例えばIO関係のレジスタや割り込みで使用される変数のようにアクセスするたびに内容が変わるという意味だ。

 つまり、コンパイラに「あんたが知らないうちに値が変わってる変数だヨ」と教えておくと、最適化しないでくれる。

 これをコンパイルして、wati(),recv(),send()をBASICのPOKE文にすると

REM wait()
POKE #700,#03,#4B,#1A,#68,#1A,#68,#1A,#68,#1A,#68,#1B,#68,#70,#47,#C0,#46,#08,#00,#01,#50
REM recv()
POKE #714,#20,#21,#F8,#B5,#04,#00,#10,#25,#02,#27,#0B,#4A,#13,#68,#8B,#43,#13,#60
POKE #726,#00,#23,#09,#4E,#33,#60,#FF,#F7,#E8,#FF,#08,#4B,#1B,#68,#64,#00,#37,#60
POKE #738,#01,#3D,#1C,#43,#FF,#F7,#E0,#FF,#00,#2D,#F0,#D1,#60,#09,#F8,#BC,#02,#BC
POKE #74A,#08,#47,#00,#80,#00,#50,#08,#00,#01,#50,#80,#00,#00,#50
REM send()
POKE #758,#20,#21,#0F,#4A,#F8,#B5,#13,#68,#0B,#43,#13,#60,#00,#22,#02,#27,#0C,#4B
POKE #76A,#04,#04,#E4,#0F,#1A,#60,#E4,#00,#45,#01,#00,#23,#0A,#4E,#33,#60,#0A,#4B
POKE #77C,#1D,#60,#FF,#F7,#BF,#FF,#01,#34,#37,#60,#6D,#08,#FF,#F7,#BA,#FF,#10,#2C
POKE #78E,#F1,#D1,#F8,#BC,#02,#BC,#08,#47,#C0,#46,#00,#80,#00,#50,#04,#00,#01,#50
POKE #7A0,#08,#00,#01,#50,#80,#00,#00,#50

BASICソース

BASICのプログラムはこんな感じ

1 REM TM1638 demo2
2 CLV: VIDEO 0
3 REM === ===
3 REM [0]-[7]    :7SEG data:
3 REM [8]        :guard
3 REM [9]        :LED data
3 REM [20]-[22]  :key
3 REM [23]-[26]  :key scan data
3 REM
3 REM === FONT ===
3 REM  -- a       dpgfe dcba   dpgfe dcba   dpgfe dcba   dpgfe dcba
3 REM |f |b     0: 0011 1111 1: 0000 0110 2: 0101 1011 3: 0100 1111
3 REM  -- g       dpgfe dcba   dpgfe dcba   dpgfe dcba   dpgfe dcba
3 REM |e |c     4: 0110 0110 5: 0110 1101 6: 0111 1101 7: 0000 0111
3 REM  -- d .dp   dpgfe dcba   dpgfe dcba   dpgfe dcba   dpgfe dcba
3 REM           8: 0111 1111 9: 0110 1111 A: 0111 0111 B: 0111 1100
3 REM             dpgfe dcba   dpgfe dcba   dpgfe dcba   dpgfe dcba
3 REM           C: 0011 1001 D: 0101 1110 E: 0111 1001 F: 0111 0001
3 LET [80],#3F,#06,#5B,#4F, #66,#6D,#7D,#07, #7F,#6F,#77,#7C, #39,#5E,#79,#71
4 REM             dpgfe dcba   dpgfe dcba   dpgfe dcba   dpgfe dcba
4 REM           H: 0111 0110 L: 0011 1000 G: 0011 1101 Y: 0110 1110
4 REM             dpgfe dcba   dpgfe dcba   dpgfe dcba   dpgfe dcba
4 LET [96],#76,#38,#3D,#6E
5 D=3        :'Duty:1/16
6 'P=0        :'Position 0
7 'L=8        :'Length 8

100 REM === MAIN ===
120 REM I/O STB:1 CLK:2 DI:IN3/OUT10
120 OUT 1,1: OUT 2,1
130 GOSUB @DSPOFF
135 @SCRL
140 REM SCROOL
140 LET [0],0,0,0,[99],[80],[85],[96],[81],0    :'"YOSHI"
150 @LOOP1
160 GOSUB @GETKEY: [9]=[20]
170 'PRINT HEX$([23],4);" ";HEX$([24],4);" ";BIN$([20],8)
170 PRINT BIN$([20],8);:FOR I=0 TO 7:?CHR$(8);:NEXT
180 N=N+1:
190 IF [20]=#81 THEN GOSUB @DSPNUM: GOTO @SCRL
200 'ELSE
210  P=0: L=8: GOSUB @DSP7SEG
220  [8]=[0]: COPY #800, #802, 16
280 GOTO @LOOP1

500 REM Disp number
500 REM N:number
500 REM W:work Y:counter
500 @DSPNUM
510 W=N: LET[0],0,0,0
520 FOR Y=7 TO 3 STEP -1
530   IF W=0 THEN [Y]=0
540   [Y]=[80+W%10]: W=W/10
550 NEXT
560 GOSUB @DSP7SEG
570 RETURN

600 REM    KeyScan
600 REM    Command=#42:Rread key-scan data
600 REM    [20]:K1 [21]:K2 [22]:K3 [23]-[26] scan data
600 REM S:SendData R:RecvData Y:counter
600 @GETKEY
610 S=#42: GOSUB @SENDC
620 FOR Y=23 TO 24
630   GOSUB @RECV
640   [Y] = R
650 NEXT
660 OUT 1,1    :'STB off
670 X=#8888
680 FOR Y=0 TO 2: U=Y+20
690   [U]=    ([23]&X)>>(1-Y)        :'-1---5---2---6--
690   [U]=[U]|([24]&X)>>(3-Y)        :'-1-3-5-7-2-4-6-8
700   [U]=([U]&#FF)|([U]&#FF00)>>7   :'--------12345678
710   X=X>>1
720 NEXT
730 RETURN
                   
800 REM DISP OFF
800 REM S:Send data #80=Command:Display Off
800 @DSPOFF
810 S=#80+D: GOSUB @SENDC: OUT 1,1
820 RETURN

900 REM DISP 7SEG (address add mode)
900 REM D: Dimmer 0-7 #80:Disp OFF
900 REM P: Position
900 REM L: Length
900 REM [0]-[7]: 7SEGx8, [9]:LEDx8
900 @DSP7SEG
910 S=#40:GOSUB @SENDC: OUT 1,1        :'#40: write register | auto increment
920 S=#C0+P*2: GOSUB @SENDC            :'address
930 FOR I=0 TO (L-1)
940   S=[P+I]: GOSUB @SENDD            :'7SEG
960 NEXT
970 OUT 1,1                            :'STB off
980 @DSPON: S=#88 | D: GOSUB @SENDC: OUT 1,1    :'88H:disp on
990 RETURN

1000 REM R:Recv data(16bit)
1000 @RECV
1000 R=USR(#714,0)
1010 'OUT 10,-1            :'OUT10->IN3
1020 'FOR X=1 TO 16
1030 '  OUT 2,0            :'OUT2:CLK
1040 '  R = R<<1: R=R+IN(3)    :'IN3, DI
1050 '  OUT 2,1            :'OUT2:CLK
1060 'NEXT
1070 RETURN

1100 REM S: Send data
1100 REM 1xxxxxxx CCCCCCCC : command(8bit)
1100 REM 0xxxxxDD DDDDDDDD : data(10bit)
1100 @SENDC        :'send command
1110 S=S|#8000
1120 @SENDD        :'send data
1130 X=USR(#758,S)
1130 'OUT 1,0        :'STB on
1140 'M=16: IF S&#8000 THEN M=8
1150 'FOR X=1 TO M
1160 '  OUT 2,0        :'OUT2:CLK
1170 '  OUT 10, S&1    :'OUT3:DIO
1180 '  OUT 2,1        :'OUT2:CLK
1190 '  S = S>>1
1200 'NEXT
1210 RETURN

コマンドは8ビット、データは16ビットで送受信するように変えた。

 メモリ容量が足りないので、ソースの中にマシン語が書けない。
マシン語をメモリに書き込む処理は最初に実行すれば良い。そしてプログラム実行中に書き換える必要性はないので、プログラム実行前にダイレクトモードで実行すればよい。メモリにセーブしたい場合には、別プログラムにしてLRUNで呼び出すことになる。

 1024バイトに収まるようにパックすると、

10 'TM1638 demo2
20 CLV:VIDEO 0
30 LET[80],#3F,#06,#5B,#4F,#66,#6D,#7D,#07,#7F,#6F,#77,#7C,#39,#5E,#79,#71
40 LET[96],#76,#38,#3D,#6E:D=3:OUT 1,1:OUT 2,1:GSB @DSPOFF
50 @SCRL:LET[0],0,0,0,[99],[80],[85],[96],[81],0
60 @LOOP1:GSB @GETKEY:[9]=[20]:? BIN$([20],8):FOR I=0 TO 7:?CHR$(8);:NEXT:N=N+1
70 IF[20]=#81 GSB @DSPNUM:GOTO @SCRL
80 P=0:L=8:GSB @DSP7SEG:[8]=[0]:COPY #800,#802,16:GOTO @LOOP1
90 @DSPNUM:W=N:LET[0],0,0,0:FOR Y=7 TO 3 STEP-1:IF W=0 [Y]=0
100 [Y]=[80+W%10]:W=W/10:NEXT:GSB @DSP7SEG:RTN
110 @GETKEY:S=#42:GSB @SENDC:FOR Y=23 TO 24:GSB @RECV:[Y]=R:NEXT:OUT 1,1:X=#8888
120 FOR Y=0 TO 2:U=Y+20:[U]=([23]&X)>>(1-Y):[U]=[U]|([24]&X)>>(3-Y)
130 [U]=([U]&#FF)|([U]&#FF00)>>7:X=X>>1:NEXT:RTN
140 @DSPOFF:S=#80+D:GSB @SENDC:OUT 1,1:RTN
150 @DSP7SEG:S=#40:GSB @SENDC:OUT 1,1:S=#C0+P*2:GSB @SENDC:FOR I=0 TO(L-1):S=[P+I]
160 GSB @SENDD:NEXT:OUT 1,1
170 @DSPON:S=#88|D:GSB @SENDC:OUT 1,1:RTN
180 @RECV:R=USR(#714,0):RTN
190 @SENDC:S=S|#8000
200 @SENDD:X=USR(#758,S):RTN
'974bytes

マシン語

 わざわざ窮屈なメモリ環境でBASICからマシン語を使わなくて良いと思う。 Cで書いていると「全部Cで書いたらいいじゃないか」と思ったりして...

 趣味やパズルだと考えるとやる気がわいてくるのだけれど。^^)



最近の投稿】【最近のCPUボード】 【最近のIchigoJam】 【2017の投稿】 【2016の投稿】 【2015の投稿

より以前の記事一覧

2018年9月
            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            

最近のトラックバック