スーパーファミコン コントローラーの無線化プロジェクト:attachinterrupt後のバラつき問題
スーパーファミコン コントローラーの無線化プロジェクトの続き
(今回で結論として今のアプローチでは無線化は形の上では動かせた(ドンキーコングの1面がクリアできるぐらい)。しかし、バグ(時折Bボタンが押されてしまう)が取り切れないとないという結論。)
デジアナでキャプチャーした二つを見比べる。比べるのは、赤のESPで生成しているDAT信号。テストで101010.....と送っているが、立ち上がり開始時間が異なる!
アルゴリズム的には、P/Sのパルスが入ってくるのを検出、その検出を基準にして、SFC側にコントローラーの信号をESPで生成して送り込むという事で対処してきた。
ほとんどの場合、2.5usecぐらいP/Sから遅れてDATのデータが始まる。以前のテストは5usecだったが、今回、ESPのCPUのクロックを80MHzから160MHzに処理速度をあげて.2.5usecの検出時間を得ている
上のグラフの二つを見比べると、最初のパルスの開始時期が異なる。
ただこのP/Sの立ち上がり検出して、DATをHIGHにするまでの時間がばらつく。
上の場合14.5usecになっている。数usecとかなら、吸収できるが、14.5usecはCLKの周期の12usecより長く意図した動作にならない!
毎回14.5usecなら修正のやりようもあるが・・・・10usecだったりと、それもランダムに事象が起こる・・
【対処】
Bボタンの所だけどうしても他より長い処理をするので、if文で最初なら・・・と条件分岐していた。他のelse以降は、12usecで一定に出力できるのに、立ち上がりにあわせて異なるではないか!!という事から・・・
まずは最初作ったソース
void onRising() {
noInterrupts();
//B Y SELECT START 上 下 左 右 A X L R HHH
button_status = 0b1010101010101011; //ボタンが押されていたら1
for (int j = 0; j < 16; j++) {
if (bitRead(button_status, 15 - j) == 0B00) {
digitalWrite(DAT_OUTPIN, LOW);
} else {
digitalWrite(DAT_OUTPIN, HIGH);
}
if (i == 0) {
delayMicroseconds(20);
for (int i = 0; i < 24; i++) { asm("nop \n"); }; // i<10 0.65usec
} else {
delayMicroseconds(11);
for (int i = 0; i < 13; i++) { asm("nop \n"); }; // i<10 0.65usec
}
}
digitalWrite(DAT_OUTPIN, LOW);
interrupts();
}
このOnRisingのイベントハンドラーの関数を以下のように書き換え。
void onRising() {
noInterrupts();
//B Y SELECT START 上 下 左 右 A X L R HHH
//button_status = 0b1010101010101011; // for test
delayMicroseconds(7);
for (int j = 0; j < 16; j++) {
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (8 - 4 * (bitRead(button_status, 15 - j))), DAT_OUTPIN_BIT);
delayMicroseconds(11);
for (int i = 0; i < 13; i++) { asm("nop \n"); }; // i<10 0.65usec
}
digitalWrite(DAT_OUTPIN, LOW);
interrupts();
}
①digitalWrite→レジスターに直接書き込みで高速化←実はこれが最終的な決め手ではなかったかもしれないが・・・。
②if文の排除
for文は使うが、if文を排除。最初のBの所は、LOWで時間調整を入れて対処!
通常意図したのがこの下のような状態。PSが立ち下がったらすぐにBボタンが立ち上がる状態。
5回に1回ぐらい遅れて立ちあがる。ただ、すごい遅延する訳ではなくて、5usecぐらい遅れる場合がある。
コメント
コメントを投稿