AMIGA 500/1000/2000 Keyboard Interface

Thank you Steve,
I added PrtSc in my original Sketch and made a hint to your QWERTY Layout in the first post.

Sorry to revive a thread from the dead, but I just picked up an Amiga 2000 and my first ever Arduino. I am a keyboard enthusiast which is what led me to the Amiga 2000, with the intention that I'd be able to use it based off the information I found in this thread and a Leonardo that I purchased.

Basically, I'm a script kiddie.

I'm running into an issue, when I "Verify" the Copy Pasta I did from Steve_Reaver I get back an error that 'KeyReport' does not name a type. Here's the log:

Amiga_2000_QWERTY_Copy_Pasta:13: error: 'KeyReport' does not name a type
Amiga_2000_QWERTY_Copy_Pasta.ino: In function 'void setup()':
Amiga_2000_QWERTY_Copy_Pasta:38: error: 'DDRF' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:39: error: 'PORTF' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta.ino: In function 'void loop()':
Amiga_2000_QWERTY_Copy_Pasta:50: error: 'HID_SendReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:55: error: 'PINF' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:57: error: 'HID_SendReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta.ino: In function 'void keypress(uint8_t)':
Amiga_2000_QWERTY_Copy_Pasta:146: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:149: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:155: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:155: error: 'HID_SendReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta.ino: In function 'void keyrelease(uint8_t)':
Amiga_2000_QWERTY_Copy_Pasta:161: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:164: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:167: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:167: error: 'HID_SendReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta.ino: In function 'void keystroke(uint8_t, uint8_t)':
Amiga_2000_QWERTY_Copy_Pasta:173: error: '_keyReport' was not declared in this scope
Amiga_2000_QWERTY_Copy_Pasta:178: error: 'HID_SendReport' was not declared in this scope

I gotta assume Steve's code is good and since all I did was copy and paste, I gotta assume it's something wrong on my side.

Any input?

So it looks like I need to include a library of some sort, and I've tried all the libraries that the Arduino 1.0.5 IDE comes with but none of them worked.

Can anyone help?

Well, as I suspected, the issue was very simple and a case of being a newb.

The IDE was not set to Leonardo, and I needed to "select drivers from list" for the Leonardo and Leonardo Bootloader, and disable my Bluetooth in Device Manager.

Thanks for this code!

I just bought an Arduino Micro and connected an Amiga 2000 keyboard (the Cherry one!) to my MacBook and it's working!

As this keyboard doesn't have separate reset line, I had to remove the parts of the code (about waiting for the reset line) to get it working. Just wanted to point this out in case somebody else tries this with another 5-pin Amiga keyboard.

Bump! I'm trying to use this code on an Amiga 2000 keyboard just like PhysicalPixel but I'm not having much luck removing the rest code. Any enlightenment would be awesome.

I have been using this for a few months now...and recently I am getting stuck repeating keys...anyone else have this problem...I have checked ground and connections...next thing to do is try another arduino leonardo....?

anyway...wonder if any of the code changes that you made to the original have timing issues or if this is just a purely hardware problem with my setup...

Cheers!

Hey all!

as a newbie I managed to assemble the project successfully with a spare Amiga 500. I even wrote down some extra HELP key functions that were missing or not enough accessible.

HELP + Arrows will navigate page up/down and end/home
HELP + DEL activates INS
HELP + Return fires another PrintSCR, easier with just one hand.

                // MORE HELP FUNCTIONS  ///////////////////////////////
                else if (key==0x4c) keystroke(0x4b,0);  // Up = PgUp
                else if (key==0x4d) keystroke(0x4e,0);  // Down = PgDown
                else if (key==0x4f) keystroke(0x4a,0);  // Left = Home
                else if (key==0x4e) keystroke(0x4d,0);  // Right = End
                else if (key==0x46) keystroke(0x49,0);  // Help + DEL = Ins
                else if (key==0x44) keystroke(0x46,0);  // Help + RETURN = PrtSc 2    
                ////////////////////////////////////////////////////////

THANK YOU! :slight_smile:

Hi,
and thanks for the code!

Having issues thou.

I'm forth in this thread trying to get the code working on a 5pin amiga keyboard however. (CDTV, A4000 etc). Probably should be more trying this since the most liked keyboard is infact the black CDTV mitsumi tactile keyboard.

From what I can tell It should work just by removing the reset code, However I've tried removing all / parts and various variants of removal of the code cited to do with reset KBRST and waiting for reset, without any luck.

PhysicalPixel got this to work. please someone what should be removed . Exactly?

Since esveee didnt seem to get it to work as well as myself and I'm sure there are others not posting. please someone detail the edits in the code for us That fail with this.
help!

Here again to ask for some help!

I'm trying to map a few more keys, this time would be multimedia vol up/down and mute:

// VOLUME KEYS //
else if (key==0x5e) keystroke(0x80,0);  // Help + + = VOL UP
else if (key==0x4a) keystroke(0x81,0);  // Help + - = VOL DOWN
else if (key==0x43) keystroke(0x7f,0);  // Help + enter = VOL MUTE

keystroke values should be correct because I cross checked them from multiple sources. They should correspond to 128 and 129 but using a keyboard monitor I can't see ANY activitiy coming from them. Now my suspect is that the HID interface supports only values <101. Is it possible? how can I solve this problem, eventually?

again, thanks in advance :slight_smile:

OK, I managed to do it by myself by udating HID code from here http://stefanjones.ca/blog/arduino-leonardo-remote-multimedia-keys/
(it says to just change two files but it didn't work for me until I replaced the whole hardware\arduino\cores\arduino folder with the one from the repository)

and adding this to the list of HELP keys:

// VOLUME KEYS //
else if (key==0x5e) { Remote.increase(); Remote.clear();}  // Help + + = VOL UP
else if (key==0x4a) { Remote.decrease(); Remote.clear();}  // Help + - = VOL DOWN
else if (key==0x43) { Remote.mute(); Remote.clear();}      // Help + enter = VOL MUTE

Tested on a WIN7 machine, works nicely :wink:

I'm trying to do the same setup: convert a defunct amiga 500 into a usb keyboard + 2 joysticks with a spare Arduino.

The issues is that the arduino that I've for testing is a Nano with a ATmega328 chip, not a ATmega32u4 like the micro or the leonardo. It does not seem to include the keyboard support library: it reports errors as _keyReport as an undefined type, like with fl0w3n.

Is it truly unsupported, or do I need to add it manually somehow? I would preffer a solution that would help me use the hardware I have.

Hello, does anyone knows how to activate the Arrow-Keys an the Num-Block?

Hi all,

This is 2016 and some things had to be done to adapt the source code Olaf wrote to the 1.6.9 IDE with the Arduino Leonardo Rev 4.0.
Forgive me if it sounds absolutely obvious to everyone else, but I prefer to link to the question I asked, in case it is helpful to anyone, as noob as I am !

http://forum.arduino.cc/index.php?topic=369773.0

#include <Keyboard.h> // FOR NEWEST IDE 1.6.9

#define BITMASK_A500CLK 0b00010000    // IO 8
#define BITMASK_A500SP  0b00100000    // IO 9
#define BITMASK_A500RES 0b01000000    // IO 10
#define SYNCH_HI        0
#define SYNCH_LO        1
#define HANDSHAKE       2
#define READ            3
#define WAIT_LO         4
#define WAIT_RES        5
#define HID_SendReport(id,data,len) HID().SendReport(id,data,len) // IDE 1.6.9
KeyReport _keyReport;
uint32_t counter = 0;
uint8_t Joy, MemoJoy1, MemoJoy2, state, bitn, key, fn,keydown, ktab[0x68]={
  // Tilde, 1-9, 0, sz, Accent, backslash, Num 0 (00 - 0F)
  0x35, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x2D, 0x2E, 0x31,    0, 0x62,
  // Q bis +, -, Num 1, Num 2, Num3 (10 - 1F)
  0x14, 0x1A, 0x08, 0x15, 0x17, 0x1C, 0x18, 0x0C, 0x12, 0x13, 0x2F, 0x30, 0   , 0x59, 0x5A, 0x5B,
  // A-#, -, Num 4, Num 5, Num 6 (20 - 2F)
  0x04, 0x16, 0x07, 0x09, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x33, 0x34, 0x32, 0,    0x5C, 0x5D, 0x5E,
  // <>,Y- -, -, Num . , Num 7, Num 8, Num 9 (30 - 3F)
  0x64, 0x1D, 0x1B, 0x06, 0x19, 0x05, 0x11, 0x10, 0x36, 0x37, 0x38,    0, 0x63, 0x5F, 0x60, 0x61,
  // Space, BS, Tab, Enter, Return, ESC, Del, -, -, -, Num -, -, up, down, right, left (40 - 4F)
  0x2C, 0x2A, 0x2B, 0x58, 0x28, 0x29, 0x4C,    0,    0,    0, 0x56,    0, 0x52, 0x51, 0x4F, 0x50,
  // F1-F10, -, -, Num /, Num *, Num +, - (50 - 5F)
  0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,    0,    0, 0x54, 0x55, 0x57,    0,
  // modifiers: Shift left, Shift right, -, Win left, Crtl left, Ctrl right, Alt left, Alt right
  0x02, 0x20, 0x00, 0x08, 0x01, 0x10, 0x04, 0x40
};

void setup() {
 // Keyboard (Port B)
  DDRD = ~(BITMASK_A500CLK | BITMASK_A500SP | BITMASK_A500RES);  // direction INPUT
}

void loop() {
 
  // Keyboard
    if (((PINB & BITMASK_A500RES)==0) && state!=WAIT_RES) {   // Reset
    interrupts();
    keystroke(0x4C,05);        // CTRL+ALT+DEL
    fn=0;
    state=WAIT_RES;
  }
 
  else if (state==WAIT_RES) {   // Waiting for reset end
    if ((PINB & BITMASK_A500RES)!=0) state=SYNCH_HI;
  }
 
  else if (state==SYNCH_HI) {   // Sync-Pulse HI
    if ((PINB & BITMASK_A500CLK)==0) state=SYNCH_LO;
  }

  else if (state==SYNCH_LO) {   // Sync-Pulse LOW
    if ((PINB & BITMASK_A500CLK)!=0) state=HANDSHAKE;
  }
 
  else if (state==HANDSHAKE) {  // Handshake
    if (counter==0) {
      DDRB |= BITMASK_A500SP;   // set IO direction to OUTPUT
      PORTB &= ~BITMASK_A500SP; // set OUTPUT to LOW
      counter=millis();
    }
    else if (millis()-counter>10) {
      counter=0;
      DDRB &= ~BITMASK_A500SP;   // set IO direction to INPUT
      state=WAIT_LO;
      key=0;
      bitn=7;
    }
  }
 
  else if (state==READ) {        // read key message (8 bits)
    if ((PINB & BITMASK_A500CLK)!=0) { 
      if (bitn--){
        key+=((PINB & BITMASK_A500SP)==0)<<(bitn); // key code (add bits 0...6)
        state=WAIT_LO;
      }
      else {  // read last bit (key down)   
        keydown=((PINB & BITMASK_A500SP)!=0); // true if key down
        interrupts();
        state=HANDSHAKE;
        if (key==0x5F)  fn=keydown;  // "Help" key: special function on/off
        else if (key==0x62) keystroke(0x39,0x00);  // CapsLock
        else {
          if (keydown){
            // keydown message received
            if (fn) {
              // special function with "Help" key
              if (key==0x50) keystroke(0x44,0);  // F11
              else if (key==0x51) keystroke(0x45,0);  // F12
              else if (key==0x5A) keystroke(0x53,0);  // NumLock
              else if (key==0x5B) keystroke(0x47,0);  // ScrollLock
              else if (key==0x02) keystroke(0x14,0x40);  // @
              else if (key==0x04) keystroke(0x35,0x02);  // °
            }
            else {
              if ((key==0x2B) && (_keyReport.modifiers & 0x22)) keystroke(0x35,0x00);  // ^ (with shift)
              else if (key==0x00) if (_keyReport.modifiers & 0x22) keystroke(0x30,0x40); else keystroke(0x35,0x20); // ~,`
              else if (key==0x0D) if (_keyReport.modifiers & 0x22) keystroke(0x64,0x40); else keystroke(0x2D,0x40); // |,\
              else if (key==0x5A) if (_keyReport.modifiers & 0x22) keystroke(0x24,0x40); else keystroke(0x25,0x40); // {,[
              else if (key==0x5B) if (_keyReport.modifiers & 0x22) keystroke(0x27,0x40); else keystroke(0x26,0x40); // },]
              else if (key < 0x68) keypress(key);  // Code table
            }
          }
          else {
            // keyrelease message received
            if (key < 0x68) keyrelease(key);  // Code table
          }
        }
      }
    }
  }
 
  else if (state==WAIT_LO) {   // waiting for the next bit
    if ((PINB & BITMASK_A500CLK)==0) {
      noInterrupts();
      state=READ;
    }
  }
}


void keypress(uint8_t k) {
 
  if (k > 0x5f) _keyReport.modifiers |= ktab[key];  // modifier
  else { 
    for (uint8_t i=0; i<6; i++) {
      if (_keyReport.keys[i] == 0) {
         _keyReport.keys[i] = ktab[key];
         break;
      }
    }
  }
  HID_SendReport(2,&_keyReport,8);
}


void keyrelease(uint8_t k) {

  if (k > 0x5f) _keyReport.modifiers &= ~ktab[key];  // modifier
  else { 
    for (uint8_t i=0; i<6; i++) {
      if (_keyReport.keys[i] == ktab[key]) _keyReport.keys[i] = 0;
    }
  }
  HID_SendReport(2,&_keyReport,8);
}


void keystroke(uint8_t k, uint8_t m) {
 
  unsigned short memomodifiers = _keyReport.modifiers; // save last modifier state
    for (uint8_t i=0; i<6; i++) {
      if (_keyReport.keys[i] == 0) {
         _keyReport.keys[i] = k;
         _keyReport.modifiers = m;
         HID_SendReport(2,&_keyReport,8);
         _keyReport.keys[i] = 0;
         _keyReport.modifiers = memomodifiers; // recover modifier state
         HID_SendReport(2,&_keyReport,8);
         break;
      }
    }
}

On a side note, I had to swap pins 8 & 9 for it to work. It seems it is Amiga-keyboard dependent. If it doesn't work with the proposed setup, just swap the cables connected to these pins.

And my deepest thanks to the nice people who wrote that code and to the person who gave me the issue's solution :slight_smile:

Of course, this is typed with my A500 keyboard :smiley:

I'm working on this same project and found I also had to swap pins 8 and 9. Once I do that though the keyboard outputs a stream of ~ characters. I took apart the keyboard to clean it and I'm concerned that I might have ruined it or not put it back together correctly. Anyone else run into problems like this?

I had exactly the same issue.

I uploaded the empty program to the Arduino, then unplugged it, and then reuploaded the program to the Arduino.

Also, check your connections and change the USB cable. I had two, one generic and one from my Samsung smartphone. Only the Samsung one gave good results.

Dear Olivier,

Please apologize my delayed answer. I read your mail today and saw that you have fixed the problem allready.
Many thanks for publishing the solution in this thread!

Yes , its a long time ago I made this code, but it still works surprisingly well ;-). I use the keyboard on my retro amiga notebook conversion every day. Im actually writing this post on the Amiga Keyboard. Attached are some pictures of my Amiga 500 conversion.

I hope your amiga project works as well and my code is usefull for you and all other members.

yours sincerely
Olaf

Olaf, in your pictures, what are the two big green components connected to 5 volts and ground?

Those are condensators. I suspect it's to make sure the disk and power led get the constant 5V they need, as I have read somewhere that the Arduino couldn't provide with constant current.

If the specs of these condensators could be given, that would be nice !

And thanks Olaf for the code again :slight_smile:

I have this working and have wired up an A500 keyboard :slight_smile:

Thanks Olaf and olivier78860