その昔、秋月で(初代)PlayStation用メモリーカードをPCに取り込むためのキットを売っていました。
私もひとつ買ったのですが、だいぶ前に処分してしまいました。

最近、取り込みたいメモカが出てきたのですが、今だとPS3用のメモリーカードアダプタを使うしかないようです。
ところが、すでに生産終了で、中古はプレミアがついて高価になっています。
といっても大した額ではないのですが、ピン配とプロトコルさえわかれば自力でなんとかなりそうだと思い調べました。
そして、以下の情報を見つけました。

http://kaele.com/~kashima/games/ps_jpn.txt

http://www002.upp.so-net.ne.jp/jsrc/densi/psm.html

これならArduinoで作れそう、ということで作ってみました。

ハードウェア

古いプレステをバラしてメモカを差す部分を取り出し、シールドと裏側の基板を外して
Arduino nano(互換品)で作った基板を接続します。


抵抗は全て10kです。

ソフトウェア

前掲の資料をもとにメモカ内のデータをシリアルにダンプするプログラムを作成します。
シリアルのスピードは、115200bpsだと時々化けるので、57600bpsにしました。
#define ACK_N 2
#define CLK   3
#define SEL_N 4
#define CMD   10
#define DAT   11

volatile uint8_t intrflag;
uint8_t errflag;
uint8_t data[128];

void intr() { intrflag = 1; }

inline void clkwait() { delayMicroseconds(2); }

uint8_t acs(uint8_t cmd = 0, uint8_t cmp_flag = 0, uint8_t cmp_value = 0, uint8_t ignore_ack = 0) {
  intrflag = ignore_ack;
  uint8_t d = 0;
  for (uint8_t i = 0; i < 8; i++) {
    clkwait();
    digitalWrite(CLK, LOW);
    digitalWrite(CMD, cmd & 1 ? HIGH : LOW);
    cmd >>= 1;
    clkwait();
    digitalWrite(CLK, HIGH);
    d >>= 1;
    d |= digitalRead(DAT) == HIGH ? 0x80 : 0;
  }
  if (cmp_flag && cmp_value != d) errflag = 1;
  for (uint16_t t = 0; t < 5000 && !intrflag; t++)
    clkwait();
  if (!intrflag) errflag = 1;
  return d;
}

void frame(uint16_t num) {
  uint8_t led = 0;
  while (1) {
    digitalWrite(LED_BUILTIN, led = !led ? HIGH : LOW);
    digitalWrite(SEL_N, LOW);
    errflag = 0;
    acs(0x81);
    if (!errflag) break;
    digitalWrite(SEL_N, HIGH);
    for (uint16_t j = 0; j < 50000; j++) clkwait();
  }
  acs(0x52);
  acs(0, 1, 0x5a);
  acs(0, 1, 0x5d);
  acs(num >> 8);
  acs(num);
  acs(0, 1, 0x5c);
  acs(0, 1, 0x5d);
  uint8_t x = acs(0, 1, num >> 8);
  x ^= acs(0, 1, num);
  for (uint8_t i = 0; i < 128; i++) x ^= data[i] = acs();
  if (x != acs()) errflag = 1;
  acs(0, 1, 0x47, 1);
  digitalWrite(SEL_N, HIGH);
}

void setup() {
  pinMode(DAT, INPUT);
  pinMode(ACK_N, INPUT);
  pinMode(CMD, OUTPUT);
  digitalWrite(CMD, HIGH);
  pinMode(SEL_N, OUTPUT);
  digitalWrite(SEL_N, HIGH);
  pinMode(CLK, OUTPUT);
  digitalWrite(CLK, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(ACK_N), intr, FALLING);
  Serial.begin(57600);
}

void loop() {
  for (uint16_t i = 0; i < 1024;) {
    frame(i);
    if (errflag) continue;
    char s[16];
    sprintf(s, "# frame %03x\n", i);
    Serial.print(s);
    for (uint8_t j = 0; j < 128; j++) {
      sprintf(s, "%02x", data[j]);
      Serial.print(s);
      if ((j & 0x1f) == 0x1f) Serial.print('\n');
    }
    i++;
  }
  digitalWrite(LED_BUILTIN, LOW);
  delay(-1);
}

使い方

Arduino IDEを起動してシリアルモニタを表示し、57600bpsを選んでおきます。
プログラムをアップロードするとビルトインLEDが点滅するので、メモカを差します。
ダンプが始まり、1分ちょっとで停止します。frame 3ffまでダンプされていれば正常です。
念のため、2回繰り返して等しいことを確認すれば安心です。
ダンプは16進テキストなので、以下のようなperlスクリプトでバイナリに変換します。
#! /usr/bin/perl

open(D, "> Mcd001.mcr") || die;
while (<>) {
	chomp;
	print D pack("H*", $_) if /^\w/;
}
close D;
exit 0;

このページの情報は自由に使用できますが、いっさいの保証もサポートもありません。
何らかの損害を受けたとしても、免責とします。