arduinoでメモリをいっぱい使いたいので512Kバイト増設してみた。
メモリと言えば、PC8801だと、RAM64Kバイト、N88BASICのROMが40Kバイト
漢字ROMはmk2で標準搭載とかでした。CPUはZ80互換のNEC製ですね。
16bitのPC9801でRAMが128Kバイト、F以降は漢字ROMが標準装備でした。
MZ80はRAMが48Kバイト、クリーンゆえROMがあんまり無かったですね。
異色のモトローラ系のCPUを搭載したFM7、CPUは6809、ROM44Kバイト,RAM64Kバイトでした。
各メーカー独自設計でいろいろで楽しかったですね。
その後MSXの規格統一の波があったり。
90年代の
DOS/Vの上陸とWindowsの流れで黒船に国内のいろいろがやられたイメージです。
一太郎とか花子とかワープロやお絵かきソフト懐かしいですね。
メモリに戻ると、
その当時はメモリ増設するだけで何万円もかかったりとメモリ高かったですよねー。
今ではすっごい安くなりました。今回のは128Kバイトで300円とかですよ。
さて、我々の、arduino=ATMEGA328ですが、
ATMEGAで最大クラスのメモリを搭載していますが、
32Kバイトのプログラムエリア(=ROM)と1Kバイトのデータ用ROM、2KバイトのRAMがあります。
さすがにこれだけだと、いろいろ不便ですよね。
今回は実験ですけど、漢字ROMとして使いたいと考えましたので、
300Kバイトは欲しいと考えました。
漢字フォント、文字コード変換用テーブルとかいろいろ要りますよね。
写真
ケーブルのトンネルですね。
こちらI2CのEEPROMになります。
https://akizukidenshi.com/catalog/g/g103570/
書き換え回数に制限があり、
100万回ライト/イレース可能 となっています。
・・・ 実質無限か?とも思えますけど。
今回テストするだけでも100回ぐらい書きましたけど。
実運用上は1回書いたら読み込むだけなんで問題なしです。
24FC1025ピン配置
A0 : I2Cアドレス指定
A1 : I2Cアドレス指定
A2 : ON推奨 LOWだと、半分無駄になる
WP : WriteProtect=ライトプロテクト LOWだと書き込み可能 HIGHは書き込み禁止
SCL: arduinoのSCLへ
SDA: arduinoのSDAへ
A0,A1,A2 I2Cアドレス
LO,LO,HI 0x50, 0x54,
HI,LO,HI 0x51, 0x55,
LO,HI,HI 0x52, 0x56,
HI,HI,HI 0x53, 0x57
LO=GND,HI=VCC
非推奨ですが、何のために有るのかわかりません。
A2をLOにすると、0x54,0x55,0x56,0x57にアクセスできなくなります。
回路図
ポイントは上記ピン配置でも触れましたけど
A0、A1、A2の接続でそれぞれのICのI2Cアドレスが変化する点です。
ICのメモリブロック一つで64Kバイトになります。
今回のICひとつあたり、2ブロック持っていて合計128Kバイトです。
IC4個で8ブロック、512Kバイトになります。
I2Cアドレスを考慮しながらプログラムするのは
やり難くてしょうがないので
I2Cアドレスを気にしないでメモリにアクセスできるようにすることを目標に
メモリ読み書き用の関数を作成しました。
int WriteFC1025(uint32_t address, uint8_t *data, uint32_t len);
uint32_t ReadFC1025(uint32_t address, uint8_t *data, uint32_t len);
全体で512キロバイトのエリアになるので16bitに3ビット足して
19ビット=0x00000~0x7FFFFでメモリを指定可能です。
上位の3ビットはI2Cアドレス指定用に(関数内で)使っています。
このICを使うにあたりの制限や、arduinoのI2Cの制限とか色々ありましたので、
以下箇条書きしておきます。
■今回色々調べた事箇条書き(重複記載あり)
8ピンのICで一つ当たり1024Kbitを記録できます。
1024bit=128Kbye
今回4個接続しますので
512Kbyteになります。
1ブロックあたりは64Kbyteで
24FC1025 は 2ブロック持っている
アドレスが16bit=0x0000~0xFFFF(65535)なので、
バンク切り替え的な考え方で指定する。
実際にはI2Cアドレスで指定する。
A2をVCCにすると、IC内の2ブロック(両方のブロック)が動く
A2をGNDをにすると、1ブロックのみが動く
参照(重複記載あり)
http://try3dcg.world.coocan.jp/note/i2c/24fc1025.html
A2をGNDをに接続したとき(1ブロックのみ動作)のI2Cアドレス
A0=0,A1=0の場合0x50
A0=1,A1=0の場合0x51
A0=0,A1=1の場合0x52
A0=1,A1=1の場合0x53
A2をVCCをに接続したとき(2ブロックの両方動作)のI2Cアドレス
A0=0,A1=0の場合0x50と0x54
A0=1,A1=0の場合0x51と0x55
A0=0,A1=1の場合0x52と0x56
A0=1,A1=1の場合0x53と0x57
上記の通りA0、A1によって4つのI2Cアドレスに切り替え可能。
24FC1025を同時に4つまで制御可能なので、
128Kbyte×4個=512Kbyteまでアクセス可能
個別ルール
ArduinoのI2Cライブラリの制限で
連続書き込みは30バイト、
連続読み込みは32バイトの制限あり
24FC1025は 128Byte x 512ページで構成されている。
連続書き込み時にはページ境界を超えることができない。
ページ境界を跨ぐ場合には、一旦トランザクションを終了し、
開始アドレスを設定しなおす必要がある。
JUGEMテーマ:電子工作
■プログラム
//
// 24FC1025を利用したメモリ読み書き
// メモリアドレスとして0x00000~0x7FFFFを指定可能
// int WriteFC1025(uint32_t address, uint8_t *data, uint32_t len);
// uint32_t ReadFC1025(uint32_t address, uint8_t *data, uint32_t len);
//
#include <Wire.h>
//24FC1025を4個接続して
// 512Kbyteの連続したメモリとして扱う。
int i2c_address[8]={
0x50, 0x54, //ひとつめ
0x51, 0x55, //ふたつめ
0x52, 0x56, //みっつめ
0x53, 0x57 //よっつめ
};
//
//i2c_addressテーブルを利用してI2Cアドレスを返す
// addressは0x00000~0x7FFFFを指定可能
//
int getI2cAdress(uint32_t address)
{
int i2cIdx=address >> 16;
int i2cAddr = i2c_address[i2cIdx];
//Serial.print("getI2cAdress address=");Serial.print(address, HEX);Serial.print(" i2cAddr=");Serial.println(i2cAddr, HEX);
return i2cAddr;
}
//
//30バイト以下の書き込み 128バイト境界を考慮しない
//arduino制限の30バイト単位での読み書きを基本にする
//
int writeFC1025_short(uint32_t address, uint8_t *data, uint32_t len)
{
//Serial.print("writeFC1025_short address=");Serial.print(address, HEX);
// Serial.print(" len=");Serial.println(len);
int i2cAddr = getI2cAdress(address);
address = address & 0x0000FFFF;
//Serial.print("write i2cAddr=");Serial.println(i2cAddr, HEX);
//Serial.print("write address=");Serial.println(address, HEX);
if(len > 30){
Serial.println("error length 30 over [writeFC1025_short]");
return -1;
}
Wire.beginTransmission(i2cAddr);
Wire.write(highByte(address));
Wire.write(lowByte(address));
uint32_t nBytes = Wire.write(data, len);
Wire.endTransmission();
delay(3);
if(nBytes==len){
return 0;
}
else{
return -1;
}
}
//
//128バイト境界の処理
// 128バイトのページ毎に分割
// チップ成約で128バイト境界を超えて連続書き込みはできない
//
int writeFC1025_devide128(uint32_t address, uint8_t *data, uint32_t len)
{
uint32_t kabemade = address % 128;
kabemade = 128 - kabemade;
int nRc;
if(len > kabemade){
nRc = writeFC1025_short(address, data, kabemade);
if(nRc!=0){
return -1;
}
nRc = writeFC1025_short(address + kabemade, data + kabemade, len - kabemade);
if(nRc!=0){
return -1;
}
}
else{
nRc = writeFC1025_short(address, data, len);
if(nRc!=0){
return -1;
}
}
return 0;
}
//
//メモリに書き込みする
// addressは0x00000~0x7FFFFで指定。
//
int WriteFC1025(uint32_t address, uint8_t *data, uint32_t len)
{
uint32_t nokori_len = len;
uint8_t *p = data;
uint32_t a = address;
if(0x7FFFF < (address+len)){
Serial.println("error address over 0x7FFFF [WriteFC1025]");
return -1;
}
//
while(1){
int nRc;
if(nokori_len<=30){
//writeFC1025_short(a, p, nokori_len);
nRc = writeFC1025_devide128(a, p, nokori_len);
if(nRc!=0){
return -1;
}
break;
}
else{
//writeFC1025_short(a, p, 30);
nRc = writeFC1025_devide128(a, p, 30);
if(nRc !=0){
return -1;
}
a=a+30;
p=p+30;
nokori_len = nokori_len - 30;
}
}
return 0;
}
//
//30バイト以下の読み込み 128バイト境界を考慮しない
// arduino制限の30バイト単位での読み書きを基本にする
//
uint32_t readFC1025_short(uint32_t address, uint8_t *data, uint32_t len)
{
//Serial.print("readFC1025_short address=");Serial.print(address, HEX);
// Serial.print(" len=");Serial.println(len);
int i2cAddr = getI2cAdress(address);
address = address & 0x0000FFFF;
//Serial.print("read i2cAddr=");Serial.println(i2cAddr, HEX);
//Serial.print("read address=");Serial.println(address, HEX);
if(len > 30){
Serial.println("error length 30 over [readFC1025_short_short]");
return -1;
}
//
Wire.beginTransmission(i2cAddr);
Wire.write(highByte(address));
Wire.write(lowByte(address));
Wire.endTransmission();
Wire.requestFrom(i2cAddr, len);
int i=0;
unsigned long time = millis();
while(1){
if(Wire.available()){
data[i] = Wire.read();
i++;
if(i>=len){
break;
}
}
else{
if(time>millis()){
time=millis();
}
if((millis()-time)>1000){
//Serial.println("timeout break");
break;
}
}
}
return i;
}
//
//128バイト境界の処理
// 128バイトのページ毎に分割
// ブロックの境界を超える場合にI2Cアドレスが異なるため、
// 連続読み込みができない。2回に分けて書き込み
//
uint32_t readFC1025_devide128(uint32_t address, uint8_t *data, uint32_t len)
{
uint32_t kabemade = address % 128;
kabemade = 128 - kabemade;
uint32_t total_length=0;
if(len > kabemade){
total_length = readFC1025_short(address, data, kabemade);
total_length += readFC1025_short(address + kabemade, data + kabemade, len - kabemade);
}
else{
total_length = readFC1025_short(address, data, len);
}
}
//
//メモリから読み込む
// addressは0x00000~0x7FFFFで指定。
//
uint32_t ReadFC1025(uint32_t address, uint8_t *data, uint32_t len)
{
uint32_t nokori_len = len;
uint8_t *p = data;
uint32_t a = address;
uint32_t total_read_len = 0;
uint32_t read_len = 0;
//
while(1){
if(nokori_len<=30){
read_len = readFC1025_devide128(a, p, nokori_len);
//read_len = readFC1025_short(a, p, nokori_len);
nokori_len = nokori_len - read_len;
total_read_len = total_read_len + read_len;
break;
}
else{
read_len = readFC1025_devide128(a, p, 30);
//read_len = readFC1025_short(a, p, 30);
a=a+read_len;
p=p+read_len;
nokori_len = nokori_len - read_len;
total_read_len = total_read_len + read_len;
}
}
return total_read_len;
}
//
//デバッグ用 25FC1025メモリから直接読み取って値を返す。遅い
//
uint8_t debugReadFC1025byte(int i2cAddr, uint32_t address)
{
address = address & 0x0000FFFF;
//Serial.print("read i2cAddr=");Serial.println(i2cAddr, HEX);
//Serial.print("read address=");Serial.println(address, HEX);
uint8_t data;
Wire.beginTransmission(i2cAddr); // 送信開始
Wire.write(highByte(address)); // アドレスの上位1バイトをキューに送信
Wire.write(lowByte(address)); // アドレスの下位1バイトをキューに送信
Wire.endTransmission(); // 送信完了
Wire.requestFrom(i2cAddr, 1); // 受信開始
data = Wire.read(); // データの読み出し
return data;
}
//
//デバッグ用 25FC1025メモリに書き込む 遅い
//
void WriteFC1025byte(int i2cAddr, uint32_t address, uint8_t data)
{
address = address & 0x0000FFFF;
//Serial.print("write i2cAddr=");Serial.println(i2cAddr, HEX);
//Serial.print("write address=");Serial.println(address, HEX);
Wire.beginTransmission(i2cAddr); // 送信開始
Wire.write(highByte(address)); // アドレスの上位1バイトをキューに送信
Wire.write(lowByte(address)); // アドレスの下位1バイトをキューに送信
Wire.write(data); // 書き込むデータをキューに送信
Wire.endTransmission(); // 送信完了
delay(4);
}
//
//デバッグ用 25FC1025メモリから直接読み取る
//
void debug_dump(int i2cAddr, uint32_t address, uint32_t len)
{
Serial.print("debug dump i2cAddr=");Serial.println(i2cAddr, HEX);
Serial.print(" address=");Serial.println(address, HEX);
Serial.print(" len=");Serial.println(len);
uint8_t byte;
int i=0;
int kosu = 0;
while(1){
byte = debugReadFC1025byte(i2cAddr, address);
Serial.print(byte, HEX);Serial.print(" ");
kosu++;
if(kosu>=16){
kosu=0;
Serial.println("");
}
i++;
if(i>=len){
break;
}
address++;
}
Serial.println("");
}
//
//デバッグ用 メモリ内容をダンプ出力
//
void dump(uint8_t *data, uint32_t len)
{
Serial.print("dump len=");Serial.println(len);
int i=0;
int kosu = 0;
while(1){
Serial.print(data[i], HEX);Serial.print(" ");
kosu++;
if(kosu>=16){
kosu=0;
Serial.println("");
}
i++;
if(i>=len){
break;
}
}
Serial.println("");
}
void setup() {
Serial.begin(115200);
Serial.println("¥nstart:");
Serial.println("begin:");
Wire.begin();
Serial.println("setClock:");
Wire.setClock(1000000); //I2C 1Mhz
unsigned long start;
unsigned long sa;
//メモリをきれいにする
Serial.println("clear0-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x50, 0x0000+i, 0);
}
Serial.println("clear0-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x50, 0xff00+i, 1);
}
Serial.println("clear1-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x51, 0x0000+i, 2);
}
Serial.println("clear1-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x51, 0xff00+i, 3);
}
Serial.println("clear2-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x52, 0x0000+i, 4);
}
Serial.println("clear2-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x52, 0xff00+i, 5);
}
Serial.println("clear3-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x53, 0x0000+i, 6);
}
Serial.println("clear3-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x53, 0xff00+i, 7);
}
Serial.println("clear4-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x54, 0x0000+i, 8);
}
Serial.println("clear4-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x54, 0xff00+i, 9);
}
Serial.println("clear5-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x55, 0x0000+i, 0xa);
}
Serial.println("clear5-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x55, 0xff00+i, 0xb);
}
Serial.println("clear6-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x56, 0x0000+i, 0xc);
}
Serial.println("clear6-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x56, 0xff00+i, 0xd);
}
Serial.println("clear7-1:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x57, 0x0000+i, 0xe);
}
Serial.println("clear7-2:");
for(int i=0;i<256;i++){
WriteFC1025byte(0x57, 0xff00+i, 0xf);
}
Serial.println("clear End:");
//試しに書き込み
uint8_t buffer100[100];
// 6 7 8 9 90
//1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
memcpy(buffer100, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzAB", 100);
start = millis();
int nRc = WriteFC1025(0x70000, buffer100, 100); //先頭から書き込み
if(nRc!=0){
Serial.println("error WriteFC1025");
}
sa = millis()- start;
Serial.print("write 100byte = ");Serial.print(sa);Serial.println("ms");
nRc = WriteFC1025(0x7FFFF, buffer100, 100); //1ブロック目の一番最後から書き込んで1ブロックの先頭まで書き込み
if(nRc!=0){
Serial.println("error WriteFC1025");
}
//上記の書き込みがちゃんと書かれているかを見る
char read_data[512];
int read_len;
//メモリのアドレス直接指定でちゃんと書かれているかを確かめる
Serial.println("****");
Serial.println("DUMP");
Serial.println("****");
read_len = ReadFC1025(0x00000, read_data, 256);
Serial.print("read data 0x00000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x0FF00, read_data, 256);
Serial.print("read data 0x0FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x10000, read_data, 256);
Serial.print("read data 0x10000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x1FF00, read_data, 256);
Serial.print("read data 0x1FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x20000, read_data, 256);
Serial.print("read data 0x20000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x2FF00, read_data, 256);
Serial.print("read data 0x2FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x30000, read_data, 256);
Serial.print("read data 0x30000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x3FF00, read_data, 256);
Serial.print("read data 0x3FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x40000, read_data, 256);
Serial.print("read data 0x40000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x4FF00, read_data, 256);
Serial.print("read data 0x4FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x50000, read_data, 256);
Serial.print("read data 0x50000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x5FF00, read_data, 256);
Serial.print("read data 0x5FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x60000, read_data, 256);
Serial.print("read data 0x60000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x6FF00, read_data, 256);
Serial.print("read data 0x6FF00 ");dump(read_data, read_len);
Serial.println("****");
read_len = ReadFC1025(0x70000, read_data, 256);
Serial.print("read data 0x70000 ");dump(read_data, read_len);
read_len = ReadFC1025(0x7FF00, read_data, 256);
Serial.print("read data 0x7FF00 ");dump(read_data, read_len);
}
void loop()
{
}