[b82c7b3] | 1 | /* Amiga Keyboard reading on Atmel AVR
|
---|
| 2 | * Copyright 2010, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
|
---|
| 3 | * Distributed under the terms of the MIT Licence */
|
---|
| 4 |
|
---|
| 5 | #include <avr/io.h>
|
---|
| 6 | #include <avr/interrupt.h>
|
---|
| 7 | #include <avr/pgmspace.h>
|
---|
| 8 | #include <util/delay.h>
|
---|
| 9 |
|
---|
[38f2eef] | 10 | #include "amiga_keyboard.h"
|
---|
[49fd394] | 11 | // #include "keymap.h"
|
---|
[b82c7b3] | 12 |
|
---|
| 13 |
|
---|
| 14 | //PIN configuration
|
---|
| 15 | #define AK_CLK PD3 /* Also INT1 */
|
---|
| 16 | #define AK_PORT PIND
|
---|
| 17 | #define AK_DATA PD4
|
---|
| 18 |
|
---|
| 19 | volatile uint8_t kbd_data;
|
---|
| 20 | volatile uint8_t char_waiting;
|
---|
| 21 | uint8_t started;
|
---|
| 22 | uint8_t bit_count;
|
---|
| 23 | uint8_t shift;
|
---|
| 24 |
|
---|
| 25 |
|
---|
| 26 | // Notify the keyboard we got the last char right
|
---|
[cbc34d1] | 27 | static inline void acknowledge_char()
|
---|
[b82c7b3] | 28 | {
|
---|
| 29 | // We have to pull down the "DATA" line
|
---|
| 30 |
|
---|
| 31 | // Set it as an input
|
---|
| 32 | DDRD |= (1<<AK_DATA);
|
---|
| 33 |
|
---|
| 34 | // Down for 85 us
|
---|
| 35 | PORTD &= ~(1<<AK_DATA);
|
---|
| 36 | _delay_us(85);
|
---|
| 37 |
|
---|
| 38 | // Up again to let the keybord talk
|
---|
| 39 | PORTD |= (1<<AK_DATA);
|
---|
| 40 |
|
---|
| 41 | // And it's now an input again
|
---|
| 42 | DDRD &= ~(1<<AK_DATA);
|
---|
| 43 | }
|
---|
| 44 |
|
---|
| 45 |
|
---|
| 46 | // Interrupt vector - Triggered when there is activity on the clock line
|
---|
| 47 | ISR(INT1_vect)
|
---|
| 48 | {
|
---|
[cbc34d1] | 49 | static char tmp_kdata;
|
---|
[b82c7b3] | 50 | //make sure clock line is low, if not ignore this transition
|
---|
| 51 | if(AK_PORT & (1<<AK_CLK)){
|
---|
| 52 | return;
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | // First bit, reset everything then continue below
|
---|
| 56 | if(!started){
|
---|
| 57 | started = 1;
|
---|
| 58 | bit_count = 0;
|
---|
[cbc34d1] | 59 | tmp_kdata = 0;
|
---|
[b82c7b3] | 60 | }
|
---|
| 61 |
|
---|
| 62 | if(bit_count < 8) { //we started, read in the new bit
|
---|
| 63 | //put a 1 in the right place of kdb_data if PC2 is high, leave
|
---|
| 64 | //a 0 otherwise
|
---|
[cbc34d1] | 65 | if(!(AK_PORT & (1<<AK_DATA))) tmp_kdata |= (128>>bit_count);
|
---|
[b82c7b3] | 66 | bit_count++;
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | if(bit_count >= 8)
|
---|
| 70 | { // enough bits
|
---|
| 71 | started = 0;
|
---|
| 72 | bit_count = 0;
|
---|
| 73 |
|
---|
| 74 | /*
|
---|
| 75 | if(kbd_data == 0xF0){ //release code
|
---|
| 76 | release = 1;
|
---|
| 77 | kbd_data = 0;
|
---|
| 78 | return;
|
---|
| 79 | } else if (kbd_data == 0x12) { //hanlde shift key
|
---|
| 80 | if(release == 0){
|
---|
| 81 | shift = 1;
|
---|
| 82 | } else {
|
---|
| 83 | shift = 0;
|
---|
| 84 | release = 0;
|
---|
| 85 | }
|
---|
| 86 | return;
|
---|
| 87 | } else { //not a special character
|
---|
| 88 | if(release){ //we were in release mode - exit release mode
|
---|
| 89 | release = 0;
|
---|
| 90 | //ignore that character
|
---|
| 91 | } else {
|
---|
| 92 | char_waiting = 1;
|
---|
| 93 | }
|
---|
| 94 | }*/
|
---|
[cbc34d1] | 95 | kbd_data = tmp_kdata;
|
---|
[b82c7b3] | 96 | char_waiting=1;
|
---|
| 97 | }
|
---|
| 98 | }
|
---|
| 99 |
|
---|
| 100 |
|
---|
[49fd394] | 101 | /*
|
---|
[b82c7b3] | 102 | char ak_scancode_to_ascii(uint8_t data){
|
---|
| 103 | char to_ret = pgm_read_byte(&(keymap[data])); //grab character from array
|
---|
| 104 | if(shift) to_ret -= 0x20;
|
---|
| 105 | return to_ret;
|
---|
| 106 | }
|
---|
[49fd394] | 107 | */
|
---|
[b82c7b3] | 108 |
|
---|
[38f2eef] | 109 | uint8_t ak_wait_scancode(){
|
---|
[b82c7b3] | 110 | while(!char_waiting);
|
---|
[38f2eef] | 111 | return ak_read_scancode();
|
---|
| 112 | }
|
---|
| 113 |
|
---|
[b82c7b3] | 114 |
|
---|
[38f2eef] | 115 | uint8_t ak_read_scancode() {
|
---|
| 116 | while ((AK_PORT & (1<<AK_CLK)) == 0);
|
---|
[b82c7b3] | 117 | _delay_us(30);
|
---|
| 118 | acknowledge_char();
|
---|
| 119 |
|
---|
| 120 | char_waiting = 0;
|
---|
| 121 | return kbd_data;
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 |
|
---|
| 125 | void ak_init_keyboard(){
|
---|
| 126 | started = 0;
|
---|
| 127 | kbd_data = 0;
|
---|
| 128 | bit_count = 0;
|
---|
| 129 |
|
---|
| 130 | //make AK_CLK input pin
|
---|
| 131 | DDRD &= ~(1<<AK_CLK);
|
---|
| 132 | //turn on pullup resistor
|
---|
| 133 | AK_PORT |= (1<<AK_CLK);
|
---|
| 134 |
|
---|
| 135 | // Interrupt configuration
|
---|
| 136 | // We use INT1 falling edge
|
---|
| 137 | MCUCR |= (1<<ISC11);
|
---|
| 138 | MCUCR &= ~(1<<ISC10);
|
---|
| 139 |
|
---|
| 140 | // Enable INT1
|
---|
| 141 | GIMSK |= (1<<INT1);
|
---|
| 142 |
|
---|
| 143 | // Enable interrupts
|
---|
| 144 | sei();
|
---|
| 145 |
|
---|
| 146 | acknowledge_char();
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 |
|
---|