#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "ioconfig.h"
#include "c1351.h"
#include "ps2.h"
Functions | |
void | potmouse_init () |
Init all C1351-related I/O and interrupts, but don't start yet. | |
void | potmouse_start (uint8_t m) |
Set mode and start working. | |
void | potmouse_movt (int16_t dx, int16_t dy, uint8_t button) |
Report movement from PS2 mouse. | |
void | potmouse_zero (uint16_t zero) |
Define zero-point in time (normally 320us). | |
ISR (INT1_vect) | |
ISR (TIMER1_OVF_vect) |
Everything that emulates C1351 (proportional) and C1350 (Joystick) mice. Every movement of a real mouse is signalled with potmouse_movt(). In proportional (analog) mode, INT1 interrupt senses SID measurement cycle start and loads timer OCR1A/OCR1B values with accordance to reported counter values.
In Joystick mode, pulses are generated on UP/DOWN/LEFT/RIGHT joystick lines every time a movement is reported.
ISR | ( | TIMER1_OVF_vect | ) |
ISR | ( | INT1_vect | ) |
SID measuring cycle detected.
1. SID pulls POTX low
2. SID waits 256 cycles us
3. SID releases POTX
4. 0 to 255 cycles until the cap is charged
This handler stops the Timer1, clears OC1A/OC1B outputs, loads the timer with values precalculated in potmouse_movt() and starts the timer.
OC1A/OC1B (YPOT/XPOT) lines will go up by hardware. Normal SID cycle is 512us. Timer will overflow not before 65535us. Next cycle will begin before that so there's no need to stop the timer. Output compare match interrupts are thus not used.
00139 { 00140 // SID started to measure the pots, uuu 00141 00142 // disable INT1 until the measurement cycle is complete 00143 // stop the timer 00144 TCCR1B = 0; 00145 00146 // clear OC1A/OC1B: 00147 // 1. set output compare to clear OC1A/OC1B ("10" in table 37 on page 97) 00148 TCCR1A = _BV(COM1A1) | _BV(COM1B1); 00149 // 2. force output compare to make it happen 00150 TCCR1A |= _BV(FOC1A) | _BV(FOC1B); 00151 00152 // Set OC1A/OC1B on Compare Match (Set output to high level) 00153 // WGM13:0 = 00, normal mode: count from BOTTOM to MAX 00154 TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(COM1B0); 00155 00156 // load the timer 00157 TCNT1 = 0; 00158 00159 // init the output compare values 00160 OCR1A = ocr1a_load; 00161 OCR1B = ocr1b_load; 00162 00163 // start timer with prescaler clk/8 (1 count = 1us) 00164 TCCR1B = _BV(CS11); 00165 }
void potmouse_init | ( | ) |
Init all C1351-related I/O and interrupts, but don't start yet.
00033 { 00034 // Joystick outputs, all to Z and no pullup 00035 JOYPORT &= ~(_BV(JOYFIRE) | _BV(JOYUP) | _BV(JOYDOWN) | _BV(JOYLEFT) | _BV(JOYRIGHT)); 00036 JOYDDR &= ~(_BV(JOYFIRE) | _BV(JOYUP) | _BV(JOYDOWN) | _BV(JOYLEFT) | _BV(JOYRIGHT)); 00037 00038 // SID sensing port 00039 SENSEDDR &= ~_BV(POTSENSE); // SENSE is input 00040 SENSEPORT &= ~_BV(POTSENSE); // pullup off, hi-biased by OC1B 00041 00042 // SID POTX/POTY port 00043 POTPORT &= ~(_BV(POTX) | _BV(POTY)); 00044 POTDDR &= ~(_BV(POTX) | _BV(POTY)); 00045 00046 // prepare INT1 00047 GICR &= ~_BV(INT1); // disable INT1 00048 MCUCR &= ~(_BV(ISC11)|_BV(ISC10)); 00049 MCUCR |= _BV(ISC11); // ISC11:ISC10 == 10, @negedge 00050 00051 mode = POTMOUSE_C1351; 00052 }
void potmouse_movt | ( | int16_t | dx, | |
int16_t | dy, | |||
uint8_t | button | |||
) |
Report movement from PS2 mouse.
00080 { 00081 uint16_t a, b; 00082 00083 switch (mode) { 00084 case POTMOUSE_C1351: 00085 potmouse_xcounter = (potmouse_xcounter + dx) & 077; // modulo 64 00086 potmouse_ycounter = (potmouse_ycounter + dy) & 077; 00087 00088 (button & 001) ? (JOYDDR |= _BV(JOYFIRE)) : (JOYDDR &= ~_BV(JOYFIRE)); 00089 (button & 002) ? (JOYDDR |= _BV(JOYUP)) : (JOYDDR &= ~_BV(JOYUP)); 00090 (button & 004) ? (JOYDDR |= _BV(JOYDOWN)) : (JOYDDR &= ~_BV(JOYDOWN)); 00091 00092 // scale should be 2x here, but for this particular chip, 66 counts work better where 00093 // 64 counds should be. so 66/64=100/96 and times two 00094 a = ocr_zero + potmouse_ycounter*200/96; 00095 b = ocr_zero + potmouse_xcounter*200/96; 00096 00097 ocr1a_load = a; 00098 ocr1b_load = b; 00099 break; 00100 case POTMOUSE_JOYSTICK: 00101 JOYDDR &= ~(_BV(JOYFIRE) | _BV(JOYUP) | _BV(JOYDOWN) | _BV(JOYLEFT) | _BV(JOYRIGHT)); 00102 00103 (dx < 0) ? (JOYDDR |= _BV(JOYLEFT)) : (JOYDDR &= ~_BV(JOYLEFT)); 00104 (dx > 0) ? (JOYDDR |= _BV(JOYRIGHT)): (JOYDDR &= ~_BV(JOYRIGHT)); 00105 (dy < 0) ? (JOYDDR |= _BV(JOYDOWN)) : (JOYDDR &= ~_BV(JOYDOWN)); 00106 (dy > 0) ? (JOYDDR |= _BV(JOYUP)) : (JOYDDR &= ~_BV(JOYUP)); 00107 (button & 001) ? (JOYDDR |= _BV(JOYFIRE)) : (JOYDDR &= ~_BV(JOYFIRE)); 00108 (button & 002) ? (POTDDR |= _BV(POTX)) : (POTDDR &= ~_BV(POTX)); 00109 00110 TCNT1 = 65535-256; 00111 TCCR1A = 0; 00112 TCCR1B = _BV(CS12)|_BV(CS10); 00113 TIFR |= _BV(TOV1); 00114 TIMSK |= _BV(TOIE1); 00115 break; 00116 } 00117 }
void potmouse_start | ( | uint8_t | mode | ) |
Set mode and start working.
mode | see _potmode |
00054 { 00055 mode = m; 00056 switch (mode) { 00057 case POTMOUSE_C1351: 00058 // Initialize Timer1 and use OC1A/OC1B to output values 00059 // don't count yet 00060 TCCR1B = 0; 00061 00062 // POTX/Y normally controlled by output compare unit 00063 // initially should be pulled up to provide high bias on SENSE pin 00064 POTDDR |= _BV(POTX) | _BV(POTY); // enable POTX/POTY as outputs 00065 POTPORT |= _BV(POTX) | _BV(POTY); // output "1" on both 00066 00067 GIFR |= _BV(INTF1); // clear INT1 flag 00068 GICR |= _BV(INT1); // enable INT1 00069 break; 00070 case POTMOUSE_JOYSTICK: 00071 // Joystick emulation 00072 // close directional pins for ~20ms while there is movement 00073 TCCR1B = 0; 00074 TCCR1A = 0; 00075 00076 break; 00077 } 00078 }
void potmouse_zero | ( | uint16_t | zero | ) |