Last active
September 16, 2019 02:51
-
-
Save Quantum-cross/892be82bd60753944225ff22bf564737 to your computer and use it in GitHub Desktop.
Converts PS/2 mouse to be used on Amiga!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I've tested this with an arduino UNO and an arduino NANO | |
// With the nano I had to program externally, maybe the bootloader interferes? | |
// With an optical mouse you probably need to disconnect power from the amiga pin 7 | |
// and power externally as the mouse port can only supply 50 mA | |
#include <ps2.h> | |
// grab the ps2 library here: https://playground.arduino.cc/uploads/ComponentLib/ps2.zip | |
// You may need to change a line in file "ps2.h" | |
// from '#include "WProgram.h"' | |
// to '#include "Arduino.h"' | |
#include <avr/wdt.h> | |
// Mouse inputs from PS/2 | |
// Can also use "USB" mice if they also support PS/2 protocol | |
#define CLK 6 // USB Green | |
#define DAT 5 // USB White | |
// Amiga Pin | |
#define XA 8 // 4 | |
#define XB 9 // 2 | |
#define YA 10 // 1 | |
#define YB 11 // 3 | |
// If any axis is reversed then swap A/B | |
#define LB 2 // 6 | |
#define MB 3 // 5 | |
#define RB 4 // 9 | |
// See code below for explanation of this. | |
// TL;DR set this as low as you can without experiencing | |
// erratic cursor motion with fast mouse movements | |
#define DELAY_US 151 | |
PS2 mouse(CLK, DAT); | |
void setup() | |
{ | |
// Serial.begin(19200); | |
// Set outputs | |
pinMode(XA, OUTPUT); | |
pinMode(XB, OUTPUT); | |
pinMode(YA, OUTPUT); | |
pinMode(YB, OUTPUT); | |
pinMode(LB, OUTPUT); | |
pinMode(MB, OUTPUT); | |
pinMode(RB, OUTPUT); | |
digitalWrite(LB, 1); | |
digitalWrite(MB, 1); | |
digitalWrite(RB, 1); | |
// Enable WDT, in case mouse disconnects | |
wdt_enable(WDTO_500MS); | |
// Init mouse | |
mouse.write(0xff); // reset | |
mouse.read(); // ack byte | |
mouse.read(); // blank */ | |
mouse.read(); // blank */ | |
mouse.write(0xf0); // remote mode | |
mouse.read(); // ack | |
delayMicroseconds(100); | |
wdt_reset(); | |
} | |
// To hold current state of gray codes | |
byte xstate = 0; | |
byte ystate = 0; | |
void loop() | |
{ | |
char mstat; | |
unsigned char mx; | |
unsigned char my; | |
char left; | |
char right; | |
char middle; | |
char xsign; | |
char ysign; | |
char xover; | |
char yover; | |
// Get mouse data | |
mouse.write(0xeb); // give me data! | |
mouse.read(); // ignore ack | |
mstat = mouse.read(); | |
mx = mouse.read(); | |
my = mouse.read(); | |
// Parse state byte | |
// Button states | |
left = !( mstat &0b00000001); | |
right = !((mstat>>1)&0b00000001); | |
middle = !((mstat>>2)&0b00000001); | |
// Sign bits | |
xsign = (mstat>>4)&0b00000001 ; | |
ysign = (mstat>>5)&0b00000001 ; | |
// Overflow bits (not handled) | |
xover = (mstat>>6)&0b00000001 ; | |
yover = (mstat>>7)&0b00000001 ; | |
// If negative, fix the two's complement | |
if (xsign){ | |
mx = 256-mx; | |
} | |
if (ysign){ | |
my = 256-my; | |
} | |
// Write button pins | |
digitalWrite(LB, left); | |
digitalWrite(MB, middle); | |
digitalWrite(RB, right); | |
// Move pointer | |
move(mx, xsign, my, ysign); | |
// if(xsign) Serial.print("-"); | |
// Serial.print(mx, DEC); | |
// Serial.println(); | |
// Keep watchdog happy | |
wdt_reset(); | |
} | |
// Move the cursor x and y pixels | |
void move(unsigned char x, bool left, unsigned char y, bool down){ | |
while ((x > 0)||(y > 0)){ | |
if (x > 0){ | |
left ? move_left_1():move_right_1(); | |
x--; | |
} | |
if (y > 0){ | |
down ? move_down_1():move_up_1(); | |
y--; | |
} | |
// We need to put a delay here, we can't strobe the X/Y pins | |
// too fast or the amiga may miss parts of the grey code. | |
// If this happens the mouse will skip and go backwards. | |
// The way gray code works is if any bit flip is missed it is | |
// impossible to know which direction the mouse moved. | |
// delayMicroseconds(149); // This worked on my Arduino UNO | |
delayMicroseconds(DELAY_US); // 150 uS worked on my Arudino Nano | |
// Set this as low as you can without getting erratic cursor movements | |
// when moving the mouse quickly. | |
// If the delay is removed, then the mouse will be much more responsive | |
// but will also skip and go backwards with fast movements | |
// Maybe this is dependent on the noise on the X/Y lines? | |
} | |
} | |
void move_left_1(){ | |
set_gray(xstate, false, XA, XB); | |
xstate--; | |
xstate %= 4; | |
} | |
void move_right_1(){ | |
set_gray(xstate, true, XA, XB); | |
xstate = (xstate+1)%4; | |
} | |
void move_down_1(){ | |
set_gray(ystate, false, YA, YB); | |
ystate--; | |
ystate %= 4; | |
} | |
void move_up_1(){ | |
set_gray(ystate, true, YA, YB); | |
ystate = (ystate+1)%4; | |
} | |
// Probably not the best way to do this. | |
void set_gray(int state, bool up, int a, int b){ | |
if(up){ | |
switch (state){ | |
case 0: | |
digitalWrite(b, 1); | |
break; | |
case 1: | |
digitalWrite(a, 1); | |
break; | |
case 2: | |
digitalWrite(b, 0); | |
break; | |
case 3: | |
digitalWrite(a, 0); | |
break; | |
default: | |
break; | |
} | |
} | |
else{ | |
switch (state){ | |
case 0: | |
digitalWrite(a, 1); | |
break; | |
case 1: | |
digitalWrite(b, 0); | |
break; | |
case 2: | |
digitalWrite(a, 0); | |
break; | |
case 3: | |
digitalWrite(b, 1); | |
default: | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment