mr.Spinner: better handling for different spinners, emulate the paddle, add readme.

This commit is contained in:
sorgelig 2020-02-23 20:18:30 +08:00
parent c7314ba0bd
commit cedc306344
2 changed files with 101 additions and 15 deletions

View File

@ -65,15 +65,22 @@
// Note: spinners pins must support interrupts!
//
///////////////// Customizable settings /////////////////////////
//uncomment following line for Beetle board pin mapping.
//#define BEETLE
// Adjust the sensitivity of spinner. >= 1
// For arduino shield spinner set it to 1.
// For 600PPR spinners set it to 8..10 for comfortable control.
#define SPINNER_SENSITIVITY 10
// Spinner pulses per revolution
// For arduino shield spinner: 20
#define SPINNER_PPR 20
// serial for special support in MiSTer
const char *gp_serial = "MiSTer PD/SP v1";
// Comment it to dosable paddle emulation by spinner
#define PADDLE_EMU
// Optional parameter. Leave it commented out.
//#define SPINNER_SENSITIVITY 1
/////////////////////////////////////////////////////////////////
// pins map
#ifdef BEETLE
@ -87,8 +94,20 @@ const char *gp_serial = "MiSTer PD/SP v1";
const int8_t pbtnpin[2] = {4,3}; // paddle button
const int8_t pdlpin[2] = {A0,A1}; // paddle pot
#endif
////////////////////////////////////////////////////////
#ifndef SPINNER_SENSITIVITY
#if SPINNER_PPR < 50
#define SPINNER_SENSITIVITY 1
#else
#define SPINNER_SENSITIVITY 2
#endif
#endif
// ID for special support in MiSTer
const char *gp_serial = "MiSTer PD/SP v1";
#include <ResponsiveAnalogRead.h>
#include "Gamepad.h"
@ -97,6 +116,7 @@ ResponsiveAnalogRead analog[2] = {ResponsiveAnalogRead(pdlpin[0], true),Responsi
int8_t pdlena[2] = {0,0};
uint16_t drvpos[2];
int16_t drvX[2] = {0,0};
void setup()
{
@ -129,6 +149,9 @@ void loop()
sendState(1);
}
const uint16_t sp_max = ((SPINNER_PPR*4*270UL)/360);
int32_t sp_clamp[2] = {0,0};
void drv_proc(int8_t idx)
{
static int8_t prev[2];
@ -138,8 +161,16 @@ void drv_proc(int8_t idx)
int8_t spval = (b << 1) | (b^a);
int8_t diff = (prev[idx] - spval)&3;
if(diff == 3) drvpos[idx]++;
if(diff == 1) drvpos[idx]--;
if(diff == 3)
{
drvpos[idx] += 10;
if(sp_clamp[idx] < sp_max-1) sp_clamp[idx]++;
}
if(diff == 1)
{
drvpos[idx] -= 10;
if(sp_clamp[idx] > 0) sp_clamp[idx]--;
}
prev[idx] = spval;
}
@ -154,13 +185,15 @@ void drv1_isr()
drv_proc(1);
}
const int16_t sp_step = (SPINNER_PPR*10)/(20*SPINNER_SENSITIVITY);
void sendState(byte idx)
{
// LEDs off
TXLED1; //RXLED1;
analog[idx].update();
// paddle
int8_t newA = !digitalRead(pbtnpin[idx]);
//int8_t newB = 0; // reserved for paddles mixed in a single USB controller.
@ -183,24 +216,30 @@ void sendState(byte idx)
{
if(!Gamepad[idx]._GamepadReport.b3 && !Gamepad[idx]._GamepadReport.b4)
{
static int prev[2] = {0,0};
static uint16_t prev[2] = {0,0};
int16_t diff = drvpos[idx] - prev[idx];
if(diff > SPINNER_SENSITIVITY)
if(diff >= sp_step)
{
newR = 1;
prev[idx] += SPINNER_SENSITIVITY;
prev[idx] += sp_step;
//Serial.println("RIGHT");
}
else if(diff < -SPINNER_SENSITIVITY)
else if(diff <= -sp_step)
{
newL = 1;
prev[idx] -= SPINNER_SENSITIVITY;
prev[idx] -= sp_step;
//Serial.println("LEFT");
}
}
#ifdef PADDLE_EMU
uint16_t val = (sp_clamp[idx]*255)/sp_max;
newX = val ^ 0x80;
#endif
}
int8_t diff = newX - Gamepad[idx]._GamepadReport.X;
// Only report controller state if it has changed

View File

@ -0,0 +1,47 @@
# mr.Spinner - Spinner and Paddle USB adapter for MiSTer
## Introduction
It's a simple adapter for 2 independent input devices in a single Arduino Micro (ATmega32U4) board.
### Paddle
For paddle you need a linear potentiometer with 10K-1M resistance and a button. You can use Atari 2600 paddles, but you need to add a simple modification to paddles. **You need to connect unconnected 3rd pin of potentiometer to a black wire of button (ground pin).**
### Spinner
You can use almost any 2-phase spinner. Hight-PPR (300+) spinners provider more smooth scroll while even simple minniature Arduino shield spinner with 20PPR is fine. PPR value includes 4 steps of 2-phase encoder, so 20PPR spinner means 80 steps. This adapter is splitting PPR to steps, so 20PPR spinner gives 80 pulses to the FPGA core. Thus even 20PPR is good enough to play all spinner games. However minniature passive spinners line the one used in Arduino shield has clicking mechanism (one cleak per PPR) which making hard to use it for playing the games. Luckily, you can disassemble such spinner (carefully strighten those 4 V-locks to remove the top part) and flatten the pimple to eliminate the clicks. After this modification you can use 20PPR spinner to play the games.
Standard Atari 2600 driving controller is 4PPR spinner which is not acceptable for using. However you can try to mod it by installing 20-40PPR passive micro spinner inside.
Optical 360-600PPR spinners are supported as well. You just need to provide the 5V power to such spinner.
### Connecting/Assembling
If you use Atari 2600 paddles, then just use standard DB9 connector. If you use driving controller then you will need 2 DB9 sockets.
Connector 1:
| DB9 | Arduino Micro pin | Beetle pin | Function |
| ----- | ------ | ------ | ------ |
| 1 | TXO(1) | TXO(1) | Spinner_A |
| 2 | RXI(0) | RXI(0) | Spinner_B |
| 3 | 3 | 10 | Paddle2 Btn |
| 4 | 4 | 11 | Paddle1 Btn |
| 5 | A0 | A0 | Paddle1 Pot |
| 6 | 6 | 9 | Spinner Btn |
| 7 | VCC | VCC | VCC |
| 8 | GND | GND | GND |
| 9 | A1 | A0 | Paddle2 Pot |
Connector 2:
| DB9 | Arduino Micro pin | Beetle pin | Function |
| ----- | ------ | ------ | ------ |
| 1 | 2 | 3 | Spinner_A |
| 2 | 7 | 2 | Spinner_B |
| 6 | 15 | 15 | Spinner Btn |
| 7 | VCC | VCC | VCC |
| 8 | GND | GND | GND |
### Notes
1. You need to set correct SPINNER_PPR value in source according to used spinner.
2. Spinner emulates the paddle as well, So bassically the spinner is the only you need for both spinner and paddle control. If you don't need paddle emulation then comment out (or remove) the line ```#define PADDLE_EMU```
3. Adapter switches to paddle by pressing the button on paddle. It switches to spinner if spinner is moved or spinner button has been pressed.
## License
This project is licensed under the GNU General Public License v3.0.