SPIでEEPROM(AT93C86)と接続して読み書きを行って見ます
〔Arduinoの動かせ方入門に戻る〕
EEPROMで93C86シリーズと言うのが有り各社から販売されています、
これは3線式シリアル(Microwire:マイクロワイヤ)で接続するEEPROMで、
MicrowireはSPIと似ていますが少し異なるインターフェイスです。
なのでぇ、例えばATMELが出しているAT93C86はMicrowireだけどぉ、
AT25シリーズでSPIを販売している所からも見てもぉ、やっぱりぃ別物みたいなぁ。
だが、少し工夫をすればSPIでも接続が可能です、今回はその紹介です。
今回は上手く接続が出来ましたが、場合によってはダメな場合が有るかもね。
MicrowireとSPIの違いは?
・SPIはモトローラが提唱した規格でMicrowireはナショナル・セミコンダクタが提唱した規格です。
・SPIはSS信号を通常HIGHで出力し、接続したいスレーブにはLOWを出力して通信を行います。
Microwireは逆です、また、SS信号の立ち上がりでデータを読み取り、立下りで読み取り終了に使用
します。だからMicrowireはSS信号をコマンドを送受信する度にHigh/Low操作する必要が有ります。
・SPIはデータの送信が8バイト単位で、Microwireは決まっていませんコマンドにより可変します。
なので、Microwire方式をSPIで送受信するならデータを8バイトの単位で区切って数回に渡り送受信
する必要が有ります。
・SPIはデータの送信と受信が同時に発生しますが、Microwireは送信を行った後受信に移行します。
(8バイトに区切るのでダミービットを作ったり、受信する為にダミーデータを送信する必要が有ります)
この実験ではATMELのAT93C86を使用し、x8bitモードで行っています。
また、他社の93C86シリーズも利用出来ます、
それと、93C76シリーズも利用可能ですが93C76は93C86(16KBit:2048Byte)の半分の容量しかないのでアドレス指定時の上位1ビット使いません。
尚、AT93C86は秋月電子のこちらから購入しています。
また、AT93C86のマニュアルはこちらですが、
こちらのSTMicroelectronics社M93C86のマニュアルの
方が判りやすいかもね。 *3)
あと、SPIの基本概要等はこちらの記事を参考にして下さい。
[配線図]
プルダウン抵抗について
STMicroelectronics社M93C86のマニュアルを見ると抵抗が付いています、 *3)
「SS(CS)ラインが何処にも無接続状態になった場合にEEPROMが選択されていない状態(GND接地)になるからいいよ」
みたいなぁ、事が書いて在ります、なので適当に付けといた方が良いかも(無くても動作はします)。
あとぉ、自分で基板を起こす場合はAT93C86の電源ピン8番と5番の間に0.1uFコンデンサ(バイパスコンデンサ)を取り付けた方が良いです。
「安定した電源電圧を確保する必要が有る為、VCC/VSSパッケージのピンの近くに適当なコンデンサ(通常100nF〜10nF)でVCCラインを分離することをお勧めします」
Google 翻訳の直訳です、みたいなぁ事が書いてあるようなぁ。
ORGピンについて
AT93C86の6番ピンは読み書きするデータのサイズを変更する場合に使用します。
+5V(VDD)に配線すると16bitモードです、2バイト(WORD)単位でのアクセスでアドレスは0-1023です。
GND(VSS)に配線すると8bitモードです、1バイト単位でのアクセスでアドレスも0-2047になります。
今回のライブラリは8bitモードのみ対応です。
SS(CS)ピンについて
通常SPIは、スレーブデバイスがAとBの2個が接続されているとするとSS信号線が各A/Bに1本ずつ
配線されます、でぇ、通信したいデバイスのSS信号をLOWにします、MicrowireはHIGHです。
ただ、MicrowireはこのSS信号のHIGH立上りが通信開始のタイミングでLOWで通信終了なので、
送受信する度にSS信号をHIGH/LOW頻繁に切り替える必要が有ります。
尚、ArduinoのSPIライブラリを使用していますが、
このライブラリはSS信号の10番ピンを初期化でHIGHにしているだけです。
《ダウンロードスケッチについて》
↓ここからArduino用サンプルスケッチファイルをダウンロードして下さい。
sk93C86.lzh(Ver1.00:2012/01/30)
sk93C86.zip pde->ino *4)
解凍すると下の様に展開されます。
[sk93C86]─┬─[examples]───[AT93C86]--- AT93C86.ino
├ sk93C86.cpp
├ sk93C86.h
└ keywords.txt
ArduinoIDE0022がインストールされているフォルダー、インストール先を変更していないなら
[C:\Program Files\arduino-0022\libraries]です。
この場所に上記解凍ファイルを[sk93C86]ディレクトリ丸ごと移動します。
また、こちらの[ライブラリ登録]を参考すればより理解が深まるかもぉ?いや、こんがらがるかもぉ。
AT93C86.ino ・・・・・本体のサンプルスケッチ
sk93C86.cpp ・・・・・93C86(16Kbite) EEPROM 関数ライブラリソース
sk93C86.h ・・・・・・ヘッダファイル
keywords.txt ・・・・・キーワードファイル
注意)
ArduinoIDE 1.0.1以降からArduinoライブラリ用インクルードファイル名が変更されています、
なのでこれ以降を利用している人は、sk93C86.cpp と sk93C86.h に
#include "WProgram.h" と記述しています、これを #include "arduino.h" に変更願います。 *2)
PS. スケッチは変更しました。 *4)
AT93C86.ino
AT93C86.inoを開くには、
IDEを起動して、メニューバーの「File」→「Examples」→「sk93C86」→[AT93C86]
をクリック操作すればファイルが開かれます。
次に、IDEツールバーの「Upload」ボタンをクリックしてコンパイルとarduinoボードに書込みを行います。
IDEのシリアルモニターCOM画面を表示させましょう。
起動が成功すると画面には数値が"10 20 30"と表示されます、表示が異なる場合は配線等を見直して下さい。
EEPROMの0番地から3バイト[10][20][30]を書き込み、その後に0番地から3バイト読み込んで表示しているだけです。
AT93C86は16Kbit(+8bitモードで2048Kbyte)なので0番地から2047番地までアクセス出来ます。
skMC24xxx.h
93C86(16Kbite) EEPROM 関数のインクルードファイルです。
このライブラリを利用する場合は、メニューバーの「Sketch」→「ImportLibray...」→「sk93C86」を
クリック操作すれば、"#include <sk93C86.h>"がスケッチに追加されます。
まぁ、手動でキー入力しても良いんですけどね。
skMC24xxx.cpp
このライブラリはAT93C86とデータのやり取りを行う為の関数集です。
まず利用する場合は下記2行を記述します。
#include <SPI.h>
#include <sk93C86.h>
93C86(16Kbite) EEPROM 関数ライブラリの使い方を説明します。
sk93C86
EEPROM関数ライブラリを使用する為に必要な宣言(初期化)を行います。
sk93C86 MEM(protect) ;
protect : 0=EEPROMに書込みを禁止する(読み込みは可能) 1=EEPROMに書込みを許可する
MEMの名前は任意に変更可能です。
AT93C86のシリアルクロックレートは最大2MHzですので、FOSC(16MHz)/8で初期化されています。
sk93C86 MEM(1) ; 以下はこの宣言例で記述します。
MEM.WEN()
EEPROM書き込みプロテクトです、書き込みを許可する処理です。
MEM.WDS()
EEPROM書き込みプロテクトです、書き込みを禁止する処理です(読み込みは可能)。
ans = MEM.Read(adrs,*data,num)
EEPROMの指定番地から指定した個数だけデータを読み出す処理です。
adrs :読み出し開始のデータアドレス位置を指定します。(AT93C86なら0〜2047番地)
*data:読み出したデータを保存する為の配列変数を指定します。
num :読み出すデータの個数を指定します。(この個数分だけ配列変数は確保します)
ans :他のEEPROMライブラリと互換性を確保する為に単純に0を返すだけです
例)0番地から2バイト読み込み、シリアルモニターに表示する
char dt[4] ;
MEM.Read(0x00,dt,2) ;
Serial.print(dt[0],HEX) ;
Serial.print(' ') ;
Serial.print(dt[1],HEX) ;
※ 2046番地から4バイト読み出した場合は、[2046][2047][0][1]番地と言った感じに0番地に
戻って読み出されます。
ans = MEM.Write(adrs,*data,num)
EEPROMの指定番地へ指定した個数だけデータを書き込む処理です。
adrs :書き込み開始のデータアドレス位置を指定します。(AT93C86なら0〜2047番地)
*data:書き込むデータを保存した配列変数を指定します。
num :書き込むデータの個数を指定します。
ans :他のEEPROMライブラリと互換性を確保する為に単純に0を返すだけです
例)0番地から2バイト書き込む
char dt[4] ;
dt[0] = 1 ;
dt[1] = 2 ;
MEM.Write(0x00,dt,2) ;
※ 2047番地を超えた場合は、0番地から上書きされます注意して下さい。
※ 書き込み禁止状態で書き込んだ場合、メモリには書き込まれませんが、
書き込み通信は正常に終了するので注意が必要かもね。
注意 ArduinoのWireライブラリの送受信バッファが32バイトしか有りません、
だからEEPROMに読み書きするサイズは最大で32バイトです。
整数型(int)で読み書きする技
上のMEM.Read/MEM.Writeはバイト単位(char)で読み書きを行いますが、
この関数で整数型(int)でも読み書き出来ます。
下の例はint型で書き込んでint型で読み込んでいます、int型は2バイトですね、だから
int dt ;
dt = 123 ;
MEM.Write(0x00,&dt,2) ; // 書き込み
MEM.Read(0x00,&dt,2) ; // 読み込み
ってやればOKです、当然int型で書き込んだらint型で読み込まないとだめですよ。
93C46/93C56/93C66の場合は?
+8bitモードで使用するなら"sk93C86.c"ライブラリのオペコード部分とアドレスの長さを変更すれば
利用可能ですが.....
下記の様に変更すればOKと思いますが、このシリーズ持っていないのでデバッグ出来ていません。
93C46シリーズ
MEM_WEN()
SPI.transfer(0b00001001) ; // オペコード"10011"
SPI.transfer(0b10000000) ;
MEM_WDS()
SPI.transfer(0b00001000) ; // オペコード"10000"
SPI.transfer(0b00000000) ;
MEM_Read()
// 送信データ(オペコード"110"とアドレス"7bit")の作成
dt1 = 0b00000011 ;
dt2 = 0b00000000 | (adrs & 0b0000000001111111) ;
MEM_Write()
// 送信データ(オペコード"101"とアドレス"7bit")の作成
dt1 = 0b00000010 ;
dt2 = 0b10000000 | (adrs & 0b0000000001111111) ;
93C56/93C66シリーズ
MEM_WEN()
SPI.transfer(0b00100110) ; // オペコード"10011"
SPI.transfer(0b00000000) ;
MEM_WDS()
SPI.transfer(0b00100000) ; // オペコード"10000"
SPI.transfer(0b00000000) ;
MEM_Read()
// 送信データ(オペコード"110"とアドレス"9bit")の作成
dt1 = 0b00001100 | ((adrs & 0b0000000100000000) >> 8) ;
dt2 = (adrs & 0b0000000011111111) ;
MEM_Write()
// 送信データ(オペコード"101"とアドレス"9bit")の作成
dt1 = 0b00001010 | ((adrs & 0b0000000100000000) >> 8) ;
dt2 = (adrs & 0b0000000011111111) ;
《え、3線式シリアル接続ぅ??》
SPIは[SS][SDO][SDI][SCK]で接続なら4線じゃねぇ、
だが、マスターとスレーブ1対1ならSSいらないよねでぇ3線式?
でもねぇ、スレーブ2個接続するならSSを2本配線しないといけないからなぁ
それってぇ、なんだかなぁ....
Microwireもぉ、[CS][DO][DI][SK]接続しないといけないからやっぱぁ4線じゃねぇ、
だが、Microwireはデータを送信した後、データを受信するので左図の様に配線するとぉ3線式?。
(この配線で実験はしていません)
(SPIは送信と受信が同時に起きるのでこんな配線をしてはだめですよ)
でもねぇ、スレーブ2個接続するならやっぱりぃCSを2本配線しないといけないからなぁ
これもぉ、なんだかなぁ....
いんちきっぽ〜い、やっぱりI2C接続かぁ?スレーブ何個接続しようと2本だしねぇって感じぃ。
・ EEPROM(AT93C86)とPICを接続した記事はこちらを参照下さい。
・ EEPROM(24LC256/1024)とArduinoを接続した記事はこちらを参照下さい。
・ EEPROM(24LC256/1024)とPICを接続した記事はこちらを参照下さい。
《読者様からの情報》
*1)
★ UNOさんからの情報です。
「93C46/93C56/93C66の場合は?」の記述に加えて、次の変更が必要でした。
AT93C56は、シーケンシャルリードに対応していません。
なので、AT93C56Aにするか、シーケンシャルリードを諦めるかのどちらかです。
私の場合は、後者の変更で、無事に読み書きできるようになりました。
と言う事らしいです、でぇ、AT93C56のデータシートを改めてよくみてみたらAT93C56/66は
AT93C56A/66Aを使う様に推奨されています。*1)
スケッチの拡張子を"pde"から"ino"に変更(*4) 2020/04/07
リンク切れ見直し(*3) 2017/01/10
追記(*2) 2012/09/14
追記(*1) 2012/07/12
【きむ茶工房ガレージハウス】
Copyright (C) 2006-2020 Shigehiro Kimura All Rights Reserved.