投稿

スーパーファミコン コントローラーの無線化プロジェクト:バグ有だが、一応動きはする ここまでまとめ

イメージ
  SFCに接続された側のESPはSFCの5Vから電源を供給(このSFC、USB typeCに改造済みなんで電力的に余裕がある・・ACアダプターの時に動くかは不明だがおそらく問題ないかと) 動画見ていただくとわかるように、時よりボタンを操作していないのにも関わらずドンキーコングがジャンプ(Bボタンを押した挙動)をしてしまう。 SFCに接続する側のESPのスケッチ #include <ESP8266WiFi.h> // WiFi #include <WiFiUDP.h>     // UDP #define PS_READ_PIN 5 #define DAT_OUTPIN 4 #define DAT_OUTPIN_BIT (1<<4) int button_status; // SSIDとパスワード const char *ssid = "esp8266" ; const char *password = "12345678" ; //create UDP instance static WiFiUDP udp; #define LOCAL_PORT   5000  // port number for local #define REMOTE_PORT 5000  // port number for remote // IPアドレス IPAddress localIP; //local IP address IPAddress remoteIP;  // remote address void onRising () {   noInterrupts ();   //B Y SELECT  START 上 下 左 右 A X L R HHH   //button_status = 0b1010101010101011; // for test   delayMicroseconds ( 9 );   for ( int j = 0 ; j < 16 ; j++) {     WRITE_PERI_REG (PERIPHS_G...

スーパーファミコン コントローラーの無線化プロジェクト: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 = 0b 1010101010101011 ; //ボタンが押されていたら1   for ( int j = 0 ; j < 16 ; j++) {     if ( bitRead (button_status, 15 - j) == 0B 00 ) {  ...

スーパーファミコン コントローラーの無線化プロジェクト:コントローラー状態の読み取り

イメージ
 スーパーファミコンのコントローラーは、本体からP/Sのパルスと、CLKの供給を受けて、そのタイミング事に、ボタンの押している状態を返す。 無線化する際に、本体側のP/Sなりを子機にあたるコントローラー側に無線で飛ばしてやる事も考えられるが、無線の遅延を考えるとあまり得策ではないだろうと考えた。 基本ボタンの状態だけを本体側は受信して、本体クロックにあわせて、本体にDATの信号を返すで動かす。完全に非同期。1秒に60回、16.6msec、本来の入力状態から遅延する事が考えられるが、m秒を争うゲームをする訳でもないので。 コントローラー(ゲームパッド)に向かって、本体からではなく、マイコンで生成したP/SとCLKの偽物データを送りつけて状態を読みとることをテストとして行う。 とは言え、16.6ms間隔でデータを生成したいので、これだけはTimerを使って時間をできるだけ正確にとることにする。 ESP8266TimerInterruptと先人の方々らライブラリーを用意してくれているのありがたく使う。 #include "ESP8266TimerInterrupt.h" #define PS_PIN 4  //D1 #define DAT_PIN 14   //D5 #define CLK_PIN 5 //D2 ESP8266Timer ITimer; void timertask () {   int status=0b 0 ;     digitalWrite (PS_PIN, HIGH);     delayMicroseconds ( 12 );     digitalWrite (PS_PIN, LOW);     delayMicroseconds ( 6 );     for ( int i= 0 ;i< 16 ;i++){     digitalWrite (CLK_PIN, LOW);     if ( digitalRead (DAT_PIN)==LOW){       bitWrite (status, 15 -...

スーパーファミコン コントローラーの無線化プロジェクト:ESP WiFi UDP

イメージ
(コントローラーの無線化にトライというだけでまだ出来ていませんのであしからず) 消費電力の観点からBLEがよさそうではあるが、WiFiのUDPでの2つのESPの間で通信をしてみる。基礎的な動作の確認。 サーバー側: #include <ESP8266WiFi.h> // WiFi #include <WiFiUDP.h>     // UDP // SSIDとパスワード const char *ssid = "esp8266" ; const char *password = "12345678" ; //create UDP instance static WiFiUDP udp; #define LOCAL_PORT   5000  // port number for local #define REMOTE_PORT 5000  // port number for remote IPAddress localIP; //local IP address IPAddress remoteIP;  // remote address void setup () {   Serial . begin ( 115200 );   delay ( 100 );     // AP setting   WiFi . mode (WIFI_AP);   WiFi . softAP (ssid, password);     delay ( 100 );   localIP = WiFi . softAPIP ();   Serial . println ();   Serial . print ( "AP IP address: " ); Serial . println (localIP);     // start udp   udp . begin (LOCAL_PORT);     delay ( 100 ); } void loop () {   char packetBu...

スーパーファミコン コントローラーの無線化プロジェクト:ESPからの制御

イメージ
 前回( https://funasover.blogspot.com/2025/03/blog-post.html )、SFCのコントローラーの仕様というのを確認したので、次のステップとしてEPSのマイコンを使って、信号をSFCに送り込む事を目指す。 P/SのシグナルをGPIO5に入力し、パルスの立ち上がえりを検出。割り込みを入れ、コントローターのボタンの押されている状態にあわせて、DATを出力する。 ESPを使っているので、3.3V系とSFCの5Vの電圧違いを吸収するために、レベルコンバーターを間に挟んでいる。 スケッチは、以下。 #define PS_READ_PIN 5 #define DAT_OUTPIN 4 unsigned int button_status; void onRising () {   //B Y SELECT  START 上 下 左 右 A X L R HHH   button_status = 0b 0101010101010000 ; //ボタンが押されていたら1   for ( int i = 0 ; i < 16 ; i++) {     if ( bitRead (button_status, 15 - i) == 0B 00 ) {       digitalWrite (DAT_OUTPIN, HIGH);     } else {       digitalWrite (DAT_OUTPIN, LOW);     }     if (i == 0 ) {       delayMicroseconds ( 17 );       for ( int i = 0 ; i < 2 ; i++) { asm ( " nop \n " ); };  // i<10 0.65usec     } else {       delayMicroseconds ( 10 );...

スーパーファミコン コントローラーの無線化プロジェクト:仕様確認(できるかはこれから)

イメージ
スーパーファミコンをジャンクで購入してきて、コンデンサを置換し修理。非常に古かったので色を塗りなおしたものを愛用。 そんなに遊ぶ訳ではないが、インテリア?として飾ってきた。たまに遊ぶ時に、コントローラーの線が短い・・・・。今時、無線化でしたいという欲求を満たそうというプロジェクトをやろうと一念発起。  なのでこの時点ではスーパーファミコンのコントローラーの無線化が実現できている訳ではないので、それを期待して見にきてくれた人は、ごめんなさい。これからです。 中古で購入してきたコントローラーの線を真ん中で切断。無線化が目的なので、躊躇なく切断 切断したケーブルにコネクタを圧着してつける。 ブレッドボードを使って信号をデジアナで確認する事を行った。 上からCLK, P/S, DATを表示していて、引いて観測すると16.6msec毎にP/SがLOWからHIHGに。60Hz間隔で、コントローターのボタンの状態を見に行っていることがわかる。 この一回を拡大すると以下のようになっていた。 P/SがまずLOWからHIHGになり12usec経過してLOW。その後、6usec経過してHIGHだったCLKがLOWになり以後16回H→Lを繰り返す。 上の場合は、赤い線はDATで、CLKがH→Lになるタイミングで前から、 B Y SELECT START 上 下 左 右 A X L R HHH となっているとのこと。 この場合、3回目にH→LになるときにDATがLOWになっているので、SELECTが押されている。 この場合は、CLKがH→Lになる5回目のタイミングと、10回目のタイミングでDATがHIGHからLOWになるので”上”と”X”が同時に押されている場合という事になる。 (実際に、上とXを押した状態でP/Sの立ち上がえりで、キャプチャーしているので正解。 パラレル→シリアルの仕組みというのは理解できた。 厄介なのは、結局1秒に60回つまり、コントローターのボタンがどう押されているかを読み取りに行っている訳だが、その割には、クロック間隔は6usecと結構短い。 無線で6usec以内に伝送を終えようとすると結構な速度が必要。一方で状態を読み取るのは 1秒に60回,16msecと結構間隔は長い。なので遅延は1回分ぐらいは致し方ないといったところ。 無線化のロードマップその1、動作を...

CH9329で日本語キーボード109で正しく表示する方法

イメージ
 CH9329を使う際は、 しごぶさんのCH9329のライブラリーをありがたく利用させていただいている。 https://github.com/shigobu/CH9329_Keyboard しかし、デフォルトのままでは、英語のUSキーボードの出力しかできない。正確には、ドイツ語やスペイン語といったキーボードの配列が入っているが、肝心な日本語キーボードが入っていない。 そこで、日本語キーボードへの対応をして、すべてのキーを入力できるようにする手順を残しておく事にする。 まず、ライブラリーのフォルダーに、KeyboardLayout_jp_JP.cppという名前のファイルを作成する。 中身は日本語のキーボードにあわせて以下にした。 /*  * Japanese keyboard layout.  */   #include "KeyboardLayout.h"   extern const uint8_t KeyboardLayout_jp_JP [ 128 ] PROGMEM =  {     0x00 ,        // NUL     0x00 ,        // SOH     0x00 ,        // STX     0x00 ,        // ETX     0x00 ,        // EOT     0x00 ,        // ENQ     0x00 ,        // ACK     0x00 ,        // BEL     0x2a ,        // BS   Backspa...