2021/01/22 新規作成

法人向けのETC専用カード

はじめに


PCからSPIデバイスを制御するアダプタを作りました。
USB経由で動作するものです。

最初はシリアルポートから制御するものを作っていたものの、どうしても入力信号の変化タイミングがおかしくなったりして頓挫しました(涙

ということで、シリアルポート大好き野郎からすると不本意ではありますが、USBマイコンに頼ることとなりました。

[注意] 本機で使用しているUSBのライブラリやUSBのIDについては、マイクロチップ社さんのサンプルで提供されているものを利用しています。よって本機は必ず個人利用の範囲内に留めてください。
こんなものを商品化する方はいないでしょうが、念のため・・・


ハードウェア

アダプタ本体


回路図

よくSPIで使われる MISO/MOSI/SCLK/SS(CS) の4本と、一部の特殊なデバイスで Ack や Busy などの制御に使えるよう、入力ポートと出力ポートも設けました。

出力ポートを2本目のSS(CS)信号ピンとして流用すれば、SPIデバイスを2つまで接続できるようになります。

マイコンは5Vで動作させるのに対し、SPIデバイスはひとまず3.3Vとしています。この電圧はデバイスによって変更してください。

マイコンとSPIデバイスの電圧レベルを変換するため 74HC4050 を使っています。マイコン側には3.3Vの入力になりますが、入力スレッショルドを超えているので特に問題はありませんでした。最高速度の12MHzでも安定しています。

消費電力の大きいSPIデバイスの場合、USBのバスパワーでは電力が賄えなくなる可能性があるので外部電源を用意してください。


接続例

接続するSPIデバイスによってプルアップ抵抗や使用するピンの処理が異なるため、それぞれのデバイスに合った変換回路が必要になります。と言ってもちょっとした配線だけなので、当方はユニバーサル基板の切れ端で簡単に済ませています。

新たにSPIデバイスが手に入った場合は接続例を追加していきます。

SDカード

そもそもPCを使っているのですから、わざわざUSB経由で制御するのはあまり意味がないものですが(汗

回路図

基本的な MISO/MOSI/SCLK/SS(CS) のみ使います。

SPIのモードは0で動作します。

プレイステーション1のメモリカード

本当は、このカードリーダ・ライタを作るのが目的だったわけでしてw

回路図

PS1のメモリカードはカードからのAck信号を見る必要があるため、SPIアダプタの入力ピン(IN)をAck制御に使っています。

SPIはモード3、速度は250kHzで動作します。


ソフトウェア

PICファームウェアおよびPC側サンプルソフトウェア

usbspi100.zip (196kBytes) 2022/01/22

ダウンロードしたファイルを解凍すると下表のようになります。

フォルダ構成 機能
firm PICファームウェア
PC PSMEM psmr PS1カード読み込み
psmw PS1カード書き込み
SDMMC sdmmc SDの主要部ダンプ
secdump SDのアドレス指定ダンプ
TEST iotest IOポートの操作・表示

私はMPLABを使っていませんので、PICのファームウェアはDOS窓からコンパイルしています。PC用のアプリケーションもすべてDOS窓用です。

それぞれのフォルダにある compile.bat を実行するとコンパイルできるようになっています。

PICのコンパイラはXC8の xc8.exe を使い、PC側はVisualStudio系の cl.exe を使っています。

使い方はそれぞれのフォルダに usage.txt が入っているので参照してください。


ライブラリ関数

SPIモード設定
関数 void spi_mode(BYTE bMode)
引数 bMode
0 : SPIモード0
1 : SPIモード1
2 : SPIモード2
3 : SPIモード3
戻り値 なし
備考 デフォルトはモード0になっている。

SPI速度設定
関数 void spi_speed(BYTE bSpeed)
引数 bSpeed
0〜255 : SPI速度設定値
戻り値 なし
備考 デフォルトは100kHzになっている。

SPIの速度設定値は下記で計算し、0〜255の範囲で指定する。PICの周波数は48MHz(48000kHz)とする。
PIC周波数[kHz] / SPI速度[kHz] / 4 - 1 = SPI速度設定値

例えばSPI速度を100kHzにしたい場合は
48000 / 100 / 4 - 1 = 119 になり、
6MHzなら
48000 / 6000 / 4 - 1 = 1 となる。

代表的な周波数
0 : 12MHz(最高速度)
1 : 6MHz
2 : 4MHz
3 : 3MHz
5 : 2MHz
11 : 1MHz
14 : 800kHz
19 : 600kHz
29 : 400kHz
59 : 200kHz
119 : 100kHz

Ack制御ON/OFF
関数 void spi_ack(BYTE bAckFlg)
引数 bAckFlg
0 : Ack制御OFF
1 : Ack信号立上りで認識
2 : Ack信号立下りで認識
戻り値 なし
備考 デフォルトはAck制御はOFFになっている。

Ack制御をONにすると、PICがSPIで1バイト送受信するたびにAck信号の変化を待つようになる。
Ack信号はSPIアダプタのINピンに接続すること。

値の設定には下記の定数が使用できる
SPIADP_ACK_OFF : 0
SPIADP_ACK_RISING_EDGE : 1
SPIADP_ACK_FALLING_EDGE : 2

CS制御
関数 void spi_cs(BYTE bFlg)
引数 bFlg
0 : CSピンをLOW
1 : CSピンをHIGH
戻り値 なし

入力ピンの状態取得
関数 BYTE spi_get_input_pin(void)
引数 なし
戻り値 0 : 入力ピンはLOW
1 : 入力ピンはHIGH

出力ピンの状態設定
関数 void spi_set_output_pin(BYTE bFlg)
引数 bFlg
0 : 出力ピンをLOW
1 : 出力ピンをHIGH
戻り値 なし

出力ピンの状態取得
関数 BYTE spi_get_output_pin(void)
引数 なし
戻り値 0 : 出力ピンはLOW
1 : 出力ピンはHIGH

データ読み書き(複数バイト)
関数 BYTE spi_rw(BYTE bLen, BYTE *pbSndDat, BYTE *pbRcvDat)
引数 bLen
0〜62 : 送受信サイズ

pbSndDat
送信データバッファのアドレス

pbRcvDat
受信データバッファのアドレス

戻り値 0〜62 : 正常終了
0xFF : エラー
備考 正常終了の戻り値は引数の bLen がそのまま返る

送信データバッファの先頭から順番にSPIで送信され、受信データは受信データバッファに書き込まれる。

受信後のデータのみ必要(送信済みのデータは不要)であれば、送受信バッファは同一のものを指定できる。この場合は送信データの上から受信データが上書きされる。
spi_rw(6, (BYTE*)&TRxBuff, (BYTE*)&TRxBuff);

送信済みのデータを壊さず残しておきたい場合はそれぞれ別のバッファを用意する。
spi_rw(6, (BYTE*)&TxBuff, (BYTE*)&RxBuff);

データ読み書き(1バイト)
関数 BYTE spi_rw_single(BYTE bDat)
引数 bDat
送信データ
戻り値 受信データ
備考 1バイト単位で送受信する場合に使用する。
spi_rw()に比べて送受信バッファを用意しなくて済む。

データの送受信が少量の用途向き。


使い方

ファームウェアを書き込んだUSB-SPIアダプタをPCに接続すると、[HID準拠ベンダー定義デバイス] としてWindowsに認識されるはずです。

認識が完了したら、サンプルプログラムを実行します。

当サイト内の検索