2020年1月21日火曜日

FM77AV用PS/2キーボード変換器の不具合を修正

FM77AV用のPS/2変換器のビープ音が鳴るという不具合を修正しました


2019年7月19日に公開しましたPS/2キーボード変換器ですが、身近の方々や、ご希望の方に基板やプログラム書き込み済みのATtiny85を配布したりして使っていただいておりました。
最近ある方から、キーを押すたびにビープ音が出て困るというお話をいただきました。
私自身も4年以上使用していましたが、常にボリュームをゼロにしていましたので全く気づいていませんでした。何故か常用しているFM77AV40SXではビープ音は出ませんが、最近入手したFM77AV1では出ました。

キーを押すたびにビープ音が出る原因ですが、RS232Cカードの件でお世話になりましたysflight.comさんのブログによりますと、キーを離したときにリリースコードを発行していないからだということでした。
リリースコードをどのように構成すればよいのか分からず、ysflgith.comさんのプログラムを読んでみたりしていたのですが、40ビットコードを30ビットに変換して処理されていることもあってか処理内容が理解できず、思い余って直接ysflight.comさんに助けを求めましたところ、快く教えていただけました。とても丁寧に解説していただいたのでようやく理解することができました。ありがとうございました。

ysflight.comさんによれば40ビットのコード中の、第4ビットからの8ビットのみを変換すれば良いとのことでした。
ということで処理が必要なのは先頭からの2バイトのみということになりますので、コードを確認したところ、第1バイトは常に0xb4で、第2バイトは0xcc,0xcb,0xb4,0xb3の4通りしかありませんでしたので、それらに必要な処理をした結果は以下のようになりました。
  0xb4, 0xcc -> 0xb3, 0x4c
  0xb4, 0xcb -> 0xb3, 0x4b
  0xb4, 0xb4 -> 0xb3, 0x34
  0xb4, 0xb3 -> 0xb3, 0x33
キーを押下したときのコードの第1,2バイトを上のように置き換えたものをリリースコードとして押下コードの直後に発行することで、無事にビープ音を消すことができました。
その部分のプログラムを以下に示します。



// convert from codeno to serial code
// change keycode to serial code for FM77AV
void outserialdata(unsigned char kcode)
{
 ...
 
  flgE0 = 0;
  flgE1 = 0;
  if (pgm_read_byte(&pscode0[i]) == kcode) {
   cnvcode(i);
   cnvreleasecode(i); // !!! Added to mute the beep !!!
  }
 ...
 
  flgSFTCTRL = 0;
  svsftctrl = 0;
  if (pgm_read_byte(&pscode0[i]) == kcode) {
   cnvcode(i);
   cnvreleasecode(i); // !!! Added to mute the beep !!!
  }
 ...
}


int cnvcode(unsigned int codeno)
{
 unsigned char kc;
 int i; 

 serial2port(0xb4);  // 1st byte
    for (i=0; i<4; i++) { // 2nd-5th bytes
  kc = pgm_read_byte(&fmcode0[codeno][i]);
  serial2port(kc);
    }
 PORTB |= _BV(4);  // PORTB = 0x10(KSDATA=H)
// _delay_ms(20);   // important!!! for 2key pressed
 _delay_ms(1);
    return 0;
}

// convert from codeno to serial releasecode
// only the following four release code patterns to be changed
// 1st  2nd byte
// 0xb4,0xcc -> 0xb3,0x4c
// 0xb4,0xcb -> 0xb3,0x4b
// 0xb4,0xb4 -> 0xb3,0x34
// 0xb4,0xb3 -> 0xb3,0x33
int cnvreleasecode(unsigned int codeno)
{
 unsigned char kc;
 int i; 

 serial2port(0xb3);  // 1st byte
 kc = pgm_read_byte(&fmcode0[codeno][0]); // read 2nd byte
 switch (kc) {
  case 0xcc: serial2port(0x4c);
      break;
  case 0xcb: serial2port(0x4b);
      break;
  case 0xb4: serial2port(0x34);
      break;
  case 0xb3: serial2port(0x33);
      break;
 }
    for (i=1; i<4; i++) { // 3rd-5th bytes
  kc = pgm_read_byte(&fmcode0[codeno][i]);
  serial2port(kc);
    }
 PORTB |= _BV(4);  // PORTB = 0x10(KSDATA=H)
// _delay_ms(20);   // important!!! for 2key pressed
 _delay_ms(1);
    return 0;
}

// serial code out to PORTB(bit4)
// In an 8-bit pattern, the 4th bit is always equal to the 3rd bit
// pulse length (8bit->skip the 4th bit)
//  100us,125us,175us,100us,125us,175us
void serial2port(unsigned char kc)
{
 int i;

    for (i=0; i<8; i++) {
     if ((i+1) % 4 != 0) {  // skip bit3,7
      if((kc & 0x80) == 0x80) {
    PORTB &= ~_BV(4); // PORTB = 0x00(KSDATA=L)
   } else {
    PORTB |= _BV(4); // PORTB = 0x10(KSDATA=H)
      }
  }
  // wait100,125,175us();
     switch (i) {
      case 0:
     case 4:
    _delay_us(100);
    break;
      case 1:
      case 5:
    _delay_us(125);   
       break;
      case 2:
     case 6:
    _delay_us(175);
       break;
      case 3:
      case 7:
       break;
     }
     kc = kc << 1;
 }
}



キーコード番号を得て、それを4バイトのキーコードに変換して出力するルーチン中で
関数cnvcode()に続いてcnvreleasecode()を実行しています。
実際にポートに出力する関数serial2port()も手直ししました。
以前は各ビットの出力時間は全て等しく100usでしたが、ysflight.comさんが実機で確認されています長さに合わせて100us,125us,175us(第4ビットはパス)に変更してあります。

また、以前のプログラムではキーが連打されたときにキーコードを正しく認識するためにcnvcode()の末尾に20msのdeleyを入れていましたが、リリースコードでキーが離されたことを認識できますのでそれが不要となりました。(なしにはできず、1msのdelayは必要でしたが。)
結果として、かなりの高速で連打しても正しく入力ができるようになりました。
OneDriveにプログラムを公開してありますので、詳しくはそちらをご覧ください。

貴重なアドバイスをいただいたysflight.comさんに感謝いたします。

【追記】変換器を購入された方で、ご自分でATtiny85に書き込めない方には、新しいプログラムを書き込んだATtiny85をお送りしますので、私からの連絡をお待ちください。


0 件のコメント:

コメントを投稿