Friday, 25 August 2017

1351 Mouse Progress: Detecting when the SID chip drains the POT lines


The following is all from Daniƫl Mantione, who is doing great work on working out how to emulate a 1351 mouse using an Arduino, which we intend to use to make a solid-state joystick which will also work as a proportional 1351-compatible mouse:

 

The comparator

It turns out that the analog comparator on the Arduino is located on digital pins 6 and 7. It does not share any functionality with the analog ADC pins.
Two pins are necessary: The comparator compares the voltage on both pins, one cannot compare with a voltage specified in software. The internal resistance of the Arduino is incredible, pins configured as inputs have a resistance of many megaohm, so a resistor from 5V to the pin doesn't really work, you need two resistors to create a voltage divider.
I took my box of electronic components and after a bit of searching and experimenting I came up with a 100 kOhm and a 15 kOhm resistor. 100 kOhm from 5V to the pin and 15 kOhm from the pin to ground:

This did result in a voltage of 0.65V on the pin, which is good for our purposes. Now, once the voltage drops below this, we want an interrupt.
This turned out to be relatively easy to code. After a bit of experimentation, I came up with the following Arduino program:
unsigned long sid_measurement_cycles=0;

ISR(ANALOG_COMP_vect) {
sid_measurement_cycles++;
digitalWrite(LED_BUILTIN, HIGH);
delayMicroseconds(20);
digitalWrite(LED_BUILTIN, LOW);
}

void setup() {
ACSR =
(0<<ACD) | // Analog Comparator: Enabled
(0<<ACBG) | // Analog Comparator Bandgap Select: AIN0 is applied to the positive input
(0<<ACO) | // Analog Comparator Output: Off
(1<<ACI) | // Analog Comparator Interrupt Flag: Clear Pending Interrupt
(1<<ACIE) | // Analog Comparator Interrupt: Enabled
(0<<ACIC) | // Analog Comparator Input Capture: Disabled
(1<<ACIS1) | (0<ACIS0); // Analog Comparator Interrupt Mode: Comparator Interrupt on Falling Output Edge

pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
pinMode(6, INPUT); //Avoid interfering with comparator
pinMode(7, INPUT); //Avoid interfering with comparator
Serial.begin(9600);
Serial.println("Start");
}

void loop() {
if (sid_measurement_cycles % 1000 == 1) {
Serial.print("SID measurement cycles: ");
Serial.println(sid_measurement_cycles);
}
}



Basically, the analog comparator needs to be activated, told to trigger when the voltage drops below (rather than above) the reference voltage and told to generate interrupts.
The interrupt service routine is very simple: It increases a counter and then briefly flashes the internal led of the Arduino. The internal led is pin 13, and can be connected to an oscilloscope. Connecting the second input of the oscilloscope to pin 13:



...the result was as follows:




Exactly the intended result. The Arduino serial monitor shows:

Start
SID measurement cycles: 1
SID measurement cycles: 2
SID measurement cycles: 1001
SID measurement cycles: 2001
SID measurement cycles: 2002
SID measurement cycles: 3001
SID measurement cycles: 3002
SID measurement cycles: 4001


This went much smoother than I expected.

Now, the next steps are going to be quite a bit more difficult. First, we need to wait 256 microseconds. This is easy to achieve using busy waiting, but doing so, would mean that the Arduino would spend the majority of its CPU time inside the ISR. This already sounds like bad taste.

Then we need to generate pulses on POTX and POTY. Doing this with busy waiting as well, is possible would make the Arduino spend the vast majority of its time inside the ISR. Might make it unworkable to do anything usefull with the Arduno besides transmitting data.

In other words, we need to do the transmission without involving the CPU. Using the PWM generators of the Arduino would sound a good approach. This involves advanced timer programming: We first need to program a timer to generate an interrupt at exactly the right time, then program two timers to generate PWM pulses.

The Arduino has 1 16-bit timer and 2 8-bit timers. The 16-bit timer allow the timers to count at high frequency (16 MHz) and is therefore most suited for high precision. But there exists only 1 16-bit timer, while we need to generate two pulses.

In other words, I am not completely certain yet what the best approach is. Perhaps I will try first to generate a timer interrupt at the right time and then generate both pulses with busy waiting. That should already result in less than half of the CPU time spent in ISRs. As both pulses need to be generated inside a single loop, the loop body will contain branches and this might have an effect on accuracy as well. But we'll see.


Tuesday, 22 August 2017

First steps towards 1351 mouse support for MEGA65 and MEGAstick

Last week I mentioned how we have a student working on the MEGAstick, a solid-state joystick specially designed for the MEGA65, but also backward compatible with the C64 etc.

In response to that, DaniĆ«l from the Netherlands kindly offered to help, because it turns out that the 1351 is not as simple as it first seems.  I already knew that it worked by sending mouse position information as analog signals to the paddle (POT) inputs on the joystick ports.  What I didn't know, was that the 1351 uses carnal knowledge about how the SID chip scans the analogue inputs.

The SID drains the POT inputs for 256 clock cycles to pull the voltage down, and then counts for up to 255 clock cycles until the voltage reaches a threshold.  The higher the resistance, the longer it takes, and the higher the reading in the POT registers.  The 1351 uses this to know when the SID chip is about to start counting, and then outputs a 5V pulse for a length of time proportional to the movement of the mouse since the last sample.  This lets the SID read the movement quite accurately, with only a couple of niggley problems, mostly because the 1351 has an internal 1MHz clock which doesn't exactly match the C64's 0.98 - 1.02MHz PAL/NTSC clock speeds.

Daniƫl used an oscilloscope connected to a real C64 to verify that the POT lines are easy to read from the joystick port in this way, with a clearly identifiable edge when the SID starts draining the lines.


First step, connect analog inputs of C64 joystick port to an oscilloscope.


Then connect the digital oscilloscope to the laptop and take a look ...

 And the result was indeed very nice: The pulse train is very clear, so we should be able to find some way to do this.


What Daniƫl also worked out is that the voltage peaks at only around 1.2V, which is unfortunately lower than the logic level trigger of an Arduino, which is what we are using for the joystick controller: For that we need about 3V.

Fortunately, there is another possible option, which is to use an analogue comparator in the PIC chip on the Arduino, to compare the POT lines to a ~1.2V reference voltage, and generate an interrupt from that.  This is what DaniĆ«l is currently looking into.

Meanwhile, our student is getting ready to work on implementing a continuous auto-calibration mode for when the MEGAstick is acting as a normal digital joystick.

However, what this also told is is that if we want a real 1351 or a MEGAstick to work as a mouse on the MEGA65, we need to add a mechanism that drains the pot lines in a similar way to how this works on the C64.  We will need to tweak the MEGA65 PCB to implement this.

Sunday, 20 August 2017

Launching FDISK+FORMAT direct from boot sequence

Another little job done tonight: Fixing running the FDISK/FORMAT utility from the Hypervisor.  This has been almost working for quite some time, but not quite.

 The first step has been working for some time, which is to watch for the user pressing the SPACE bar repeatedly during boot.  This interrupts the normal boot sequence and displays the list of utilities compiled into the bitstream.  These utilities hide in the top 30KB of colour RAM, where no C64 or C65 program knows how to touch, and are pre-initialised in the FPGA bitstream, so that the RAM in this location "just happens" to have these programs there.

 

What was not working was actually running the FDISK program. This was because I had written it using CC65, which does a JSR $FFD2 to set lower-case character set in its entry routine. However, when running in the Hypervisor, there is no ROM present. To solve this, the boot ROM now writes an RTS instruction at $2FFD2, so that a JSR to $FFD2 will safely do nothing and return.

That got the FDISK utility running, and after a bit of mucking about with character sets (there is only the partial Hypervisor character set available), and various other little fixes, the FDISK utility now happily starts, and tries to probe your SD card:


 Note the friendly warning message: This is an improvement from before, when it would just go right ahead and repartition and reformat your SD card without asking, on the assumption that if you ran FDISK on the MEGA65, it was to get your SD card working, not for any other purpose. It now politely asks you to type the two words DELETE EVERYTHING in capitals before it will proceed.  If you get it wrong, for example, type it in lower case, then it tells you to try again:


 If you get it correct, then it does as promised, completely reformat and repartition your SD card:

This process is quite fast, taking only a few seconds to zero out the important parts of the disk and put the half-dozen or so correct sectors in.

What is not immediately obvious here, is that the keyboard input is using the new hardware-accelerated keyboard input: Reading ASCII decoded keys, including all modifier key effects, is as simple as reading $D610 to peek at the next character, and then writing anything back to $D610 to pop the key from the queue.

Hardware animating the on-screen keyboad

I have done a bit more work on the on-screen keyboard, adding hardware animation for it to appear from the bottom off the screen, and also to horizontally centre itself, and choose the correct width, based on the current video mode, so that it fills (or almost fills) the full width of the screen.  

Together, these features are important for adding touch-screen support, where touching the screen should cause the on-screen keyboard to automatically appear in a sensible place, and without the key boxes being too small to use, and all ideally without having to trap to the hypervisor (you might want to be typing something into the hypervisor).

I now have it running fairly well in simulation, and am currently building a bitstream with these changes incorporated.  But since I have the framework already for producing image files of the running simulation, I figured it would be fun to make an animated GIF of the keyboard appearing. 


Note that the speed it will appear on screen in reality will be faster than this, as animated GIFs only support a fairly low maximum animation speed.

Friday, 18 August 2017

Solid-state Joystick

This is not something that I was expecting to be doing this year, but sometimes opportunities just pop up.

Early in the year, one of my colleagues, Damian, showed me one of these strain-gauge solid-state joysticks that they were using as part of the undergraduate engineering curriculum:


Their goal was to teach the students how to read strain-gauges.  But I immediately saw the applicability for making a no-moving-parts super-robust joystick for the MEGA65 and all other retro computer users.

Strain-gauges measure the strain on an object, by effectively measuring the stretching or compression force on the sensor caused by deformation of the object under strain (apologies to any mechanical engineers who are probably cringing at my description here).  All you have to do is to try to move the joystick handle, and the gauges will pick up the minute deformation of the steel plate it is connected to.  This is how those touchpoint pointing devices that you find in the keyboards of some laptops work.

Seeings as we have only one sick TAC2 joystick in the lab, and haven't really seen anything worth replacing it with on the market, we decided to explore designing a MEGA65/C64/Amiga/Atari compatible joystick around this concept -- especially since we had working hardware on hand to work with.

The teaching unit was designed to work with an Arduino, so I went and bought one this morning, and between meetings today hacked up a tiny Arduino sketch to interface to it.  I figured we only needed 2 of the 4 sensors, since they are at 90 degrees to each other.  It turned out that all we needed to do was to tare two of the sensors, i.e., subtract their value when the stick is standing un-touched, and then monitor the sign and magnitude of deviation from zero for the two sensors, and we could quite easily detect all 8 directions with good reliability. The lack of travel makes this a potentially very fast joystick for those games where you have to toggle rapidly from side to side.



The only caveat with using only two sensors instead of four is that we can't then interpret a tap on the top of the joystick. While such tap detection is a fun idea, for a retro gaming joystick, it isn't really required, as you can't tap a stick while yanking it around at high speed.  Thus we will still need to have a real fire button, but it does mean we can save on sensors and the associated amplification circuitry for reading them.

Current idea for the fire button(s) is to have a fire button which interrupts an infra-red sensor, like a shop door sensor.  That way, there will be the absolute minimum of moving parts, short of making the fire button touch-sensitive -- but that doesn't feel right.

Otherwise, the biggest challenge we saw was the drift in readings, which means that there is a need for recalibration.  This is a well known problem with the Touchpoint devices, as they have to fairly frequently recalibrate. This occurs automatically, and shouldn't be a big problem, but we will have to implement the algorithm for this. 

Apparently a common approach is to look for a steady reading with very little variation as an indication of it being stationary, and recalibrate to that point. This would be quite easy to implement.

Otherwise from an electronic perspective, we just need to add the joystick port signalling, which is fairly easy to do.

Simultaneously, we can also start looking at laying out the important parts of the Arduino and the strain gauge shield onto a single PCB that can fit over the metal base plate.  We have a student who will hopefully look at this as part of their project, but I might also talk to Damian about this.  

I would also like to add PWM output onto the pot lines, so that we can have it support 1351 mouse mode, using the proportional/analog nature of the strain gauges to allow the joystick to work as a pointing device for GEOS, so that you don't need to swap joystick and mouse all the time.

Then the plan is to design the plastic case and knob for it, and make necessary adjustments to the metal base plate, so that we can assemble these into complete working joysticks, and indeed have a design that is feasible to produce in modest quantities. Maybe we will design it for a clear case, so that the no-moving-parts insides are visible. Either that or traditional Joystick Black.

Either way, if we like the result, and they are robust enough in practice, we might look at making them available to folks if there is sufficient interest.