mirror of
https://github.com/LIV2/AVR-PS2-KBC.git
synced 2025-12-06 00:23:47 +00:00
Initial Commit
This commit is contained in:
commit
317bdcb59a
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
*.sym
|
||||
*.lss
|
||||
*.hex
|
||||
*.elf
|
||||
*.o
|
||||
*.lst
|
||||
*.eep
|
||||
*.map
|
||||
9
README.md
Normal file
9
README.md
Normal file
@ -0,0 +1,9 @@
|
||||
PS2KBD for Atmel ATTINY861
|
||||
==============
|
||||
|
||||
This is a simple PS/2 to Ascii converter I wrote for my 6502 based homebrew computer.
|
||||
|
||||
Pin 4 goes high to signal the host that a new character is ready to be read.
|
||||
Pin 9 is PS/2 CLK
|
||||
Pin 8 is PS/2 DATA
|
||||
ASCII Character is written to Port A
|
||||
16
license.txt
Normal file
16
license.txt
Normal file
@ -0,0 +1,16 @@
|
||||
PS2KBC, a PS2 Controler implemented on the Atmel ATTINY861.
|
||||
Copyright (C) 2015 Matt Harlum
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
383
makefile
Normal file
383
makefile
Normal file
@ -0,0 +1,383 @@
|
||||
# WinAVR Sample makefile written by Eric B. Weddington, J<>rg Wunsch, et al.
|
||||
# Modified (bringing often-changed options to the top) by Elliot Williams
|
||||
# Modified (cleaned the code a bit) by Aleksandar (Aleks) Lazarov
|
||||
|
||||
# make all = Make software (hex, elf)
|
||||
# make clean = Clean out built project files.
|
||||
# make coff = Convert ELF to AVR COFF (for use with AVR Studio 3.x or VMLAB).
|
||||
# make extcoff = Convert ELF to AVR Extended COFF (for use with AVR Studio
|
||||
# 4.07 or greater).
|
||||
# make install = Download the hex file to the device, using avrdude. Please
|
||||
# customize the information regarding the programmer and
|
||||
# avrdude settings below first!
|
||||
# make filename.s = Just compile filename.c into the assembler code only
|
||||
# To rebuild project do "make clean" then "make all".
|
||||
|
||||
# Microcontroller Type
|
||||
MCU=attiny861
|
||||
|
||||
# Target file name (without extension).
|
||||
TARGET = ps2kbd
|
||||
|
||||
# Programming hardware: type `avrdude -c ?` to get a full listing.
|
||||
AVRDUDE_PROGRAMMER = usbasp
|
||||
|
||||
# Port to which the programmer is connected
|
||||
#AVRDUDE_PORT = /dev/tty.usbmodem1411
|
||||
|
||||
############# Don't need to change below here for most purposes (Elliot)
|
||||
|
||||
# Optimization level, can be [0, 1, 2, 3, s]. 0 turns off optimization.
|
||||
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
||||
OPT = s
|
||||
|
||||
# Output format. (can be srec, ihex, binary)
|
||||
FORMAT = ihex
|
||||
|
||||
# List C source files here. (C dependencies are automatically generated.)
|
||||
SRC = $(TARGET).c
|
||||
|
||||
# If there is more than one source file, append them above, or modify and
|
||||
# uncomment the following:
|
||||
#SRC += foo.c bar.c
|
||||
|
||||
# You can also wrap lines by appending a backslash to the end of the line:
|
||||
#SRC += baz.c \
|
||||
#xyzzy.c
|
||||
|
||||
|
||||
|
||||
# List Assembler source files here.
|
||||
# Make them always end in a capital .S. Files ending in a lowercase .s
|
||||
# will not be considered source files but generated files (assembler
|
||||
# output from the compiler), and will be deleted upon "make clean"!
|
||||
# Even though the DOS/Win* filesystem matches both .s and .S the same,
|
||||
# it will preserve the spelling of the filenames, and gcc itself does
|
||||
# care about how the name is spelled on its command-line.
|
||||
ASRC =
|
||||
|
||||
|
||||
# List any extra directories to look for include files here.
|
||||
# Each directory must be seperated by a space.
|
||||
EXTRAINCDIRS =
|
||||
|
||||
|
||||
# Optional compiler flags.
|
||||
# -g: generate debugging information (for GDB, or for COFF conversion)
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see gcc manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -ahlms: create assembler listing
|
||||
CFLAGS = -g -O$(OPT) \
|
||||
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
|
||||
-Wall -Wstrict-prototypes \
|
||||
-Wa,-adhlns=$(<:.c=.lst) \
|
||||
$(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||
|
||||
|
||||
# Set a "language standard" compiler flag.
|
||||
# Unremark just one line below to set the language standard to use.
|
||||
# gnu99 = C99 + GNU extensions. See GCC manual for more information.
|
||||
#CFLAGS += -std=c89
|
||||
#CFLAGS += -std=gnu89
|
||||
#CFLAGS += -std=c99
|
||||
CFLAGS += -std=gnu99
|
||||
|
||||
|
||||
|
||||
# Optional assembler flags.
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -ahlms: create listing
|
||||
# -gstabs: have the assembler create line number information; note that
|
||||
# for use in COFF files, additional information about filenames
|
||||
# and function names needs to be present in the assembler source
|
||||
# files -- see avr-libc docs [FIXME: not yet described there]
|
||||
ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
|
||||
|
||||
|
||||
# Optional linker flags.
|
||||
# -Wl,...: tell GCC to pass this to linker.
|
||||
# -Map: create map file
|
||||
# --cref: add cross reference to map file
|
||||
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
||||
|
||||
|
||||
|
||||
# Additional libraries
|
||||
|
||||
# Minimalistic printf version
|
||||
#LDFLAGS += -Wl,-u,vfprintf -lprintf_min
|
||||
|
||||
# Floating point printf version (requires -lm below)
|
||||
#LDFLAGS += -Wl,-u,vfprintf -lprintf_flt
|
||||
|
||||
# -lm = math library
|
||||
LDFLAGS += -lm
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
|
||||
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
|
||||
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
|
||||
|
||||
#AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||
AVRDUDE_FLAGS = -p $(MCU) -c $(AVRDUDE_PROGRAMMER)
|
||||
# Uncomment the following if you are using arduino (or any other programmer
|
||||
# that needs custom baud rate) as a programmer.
|
||||
#AVRDUDE_FLAGS += -b 19200
|
||||
|
||||
# Uncomment the following if you want avrdude's erase cycle counter.
|
||||
# Note that this counter needs to be initialized first using -Yn,
|
||||
# see avrdude manual.
|
||||
#AVRDUDE_ERASE += -y
|
||||
|
||||
# Uncomment the following if you do /not/ wish a verification to be
|
||||
# performed after programming the device.
|
||||
#AVRDUDE_FLAGS += -V
|
||||
|
||||
# Increase verbosity level. Please use this when submitting bug
|
||||
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
|
||||
# to submit bug reports.
|
||||
AVRDUDE_FLAGS += -v -v
|
||||
|
||||
#Run while cable attached or don't
|
||||
#AVRDUDE_FLAGS += -E reset #keep chip disabled while cable attached
|
||||
#AVRDUDE_FLAGS += -E noreset
|
||||
|
||||
#AVRDUDE_WRITE_FLASH = -U lfuse:w:0x04:m #run with 8 Mhz clock
|
||||
|
||||
#AVRDUDE_WRITE_FLASH = -U lfuse:w:0x21:m #run with 1 Mhz clock #default clock mode
|
||||
|
||||
#AVRDUDE_WRITE_FLASH = -U lfuse:w:0x01:m #run with 1 Mhz clock no start up time
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Define programs and commands.
|
||||
SHELL = bash
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
|
||||
|
||||
# Programming support using avrdude.
|
||||
AVRDUDE = avrdude
|
||||
|
||||
|
||||
REMOVE = rm -f
|
||||
COPY = cp
|
||||
|
||||
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
||||
ELFSIZE = $(SIZE) -A $(TARGET).elf
|
||||
|
||||
|
||||
|
||||
# Define Messages
|
||||
# English
|
||||
MSG_ERRORS_NONE = Errors: none
|
||||
MSG_BEGIN = -------- begin --------
|
||||
MSG_END = -------- end --------
|
||||
MSG_SIZE_BEFORE = Size before:
|
||||
MSG_SIZE_AFTER = Size after:
|
||||
MSG_COFF = Converting to AVR COFF:
|
||||
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
||||
MSG_FLASH = Creating load file for Flash:
|
||||
MSG_EEPROM = Creating load file for EEPROM:
|
||||
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
||||
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
||||
MSG_LINKING = Linking:
|
||||
MSG_COMPILING = Compiling:
|
||||
MSG_ASSEMBLING = Assembling:
|
||||
MSG_CLEANING = Cleaning project:
|
||||
|
||||
|
||||
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
|
||||
# Default target: make program!
|
||||
all: begin gccversion sizebefore $(TARGET).elf $(TARGET).hex $(TARGET).eep \
|
||||
$(TARGET).lss $(TARGET).sym sizeafter finished end
|
||||
|
||||
|
||||
# writeflash: $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
||||
|
||||
# Eye candy.
|
||||
# AVR Studio 3.x does not check make's exit code but relies on
|
||||
# the following magic strings to be generated by the compile job.
|
||||
begin:
|
||||
@echo
|
||||
@echo $(MSG_BEGIN)
|
||||
|
||||
finished:
|
||||
@echo $(MSG_ERRORS_NONE)
|
||||
|
||||
end:
|
||||
@echo $(MSG_END)
|
||||
@echo
|
||||
|
||||
|
||||
# Display size of file.
|
||||
sizebefore:
|
||||
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi
|
||||
|
||||
sizeafter:
|
||||
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
|
||||
|
||||
|
||||
|
||||
# Display compiler version information.
|
||||
gccversion :
|
||||
@$(CC) --version
|
||||
|
||||
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in
|
||||
# AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: $(TARGET).elf
|
||||
@echo
|
||||
@echo $(MSG_COFF) $(TARGET).cof
|
||||
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
||||
|
||||
|
||||
extcoff: $(TARGET).elf
|
||||
@echo
|
||||
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
||||
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
||||
|
||||
|
||||
|
||||
|
||||
# Program the device.
|
||||
install: $(TARGET).hex $(TARGET).eep
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
||||
|
||||
|
||||
|
||||
|
||||
# Create final output files (.hex, .eep) from ELF output file.
|
||||
%.hex: %.elf
|
||||
@echo
|
||||
@echo $(MSG_FLASH) $@
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
%.eep: %.elf
|
||||
@echo
|
||||
@echo $(MSG_EEPROM) $@
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
%.lss: %.elf
|
||||
@echo
|
||||
@echo $(MSG_EXTENDED_LISTING) $@
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
%.sym: %.elf
|
||||
@echo
|
||||
@echo $(MSG_SYMBOL_TABLE) $@
|
||||
avr-nm -n $< > $@
|
||||
|
||||
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
.SECONDARY : $(TARGET).elf
|
||||
.PRECIOUS : $(OBJ)
|
||||
%.elf: $(OBJ)
|
||||
@echo
|
||||
@echo $(MSG_LINKING) $@
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
%.o : %.c
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
%.s : %.c
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
%.o : %.S
|
||||
@echo
|
||||
@echo $(MSG_ASSEMBLING) $<
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Target: clean project.
|
||||
clean: begin clean_list finished end
|
||||
|
||||
clean_list :
|
||||
@echo
|
||||
@echo $(MSG_CLEANING)
|
||||
$(REMOVE) $(TARGET).hex
|
||||
$(REMOVE) $(TARGET).eep
|
||||
$(REMOVE) $(TARGET).obj
|
||||
$(REMOVE) $(TARGET).cof
|
||||
$(REMOVE) $(TARGET).elf
|
||||
$(REMOVE) $(TARGET).map
|
||||
$(REMOVE) $(TARGET).obj
|
||||
$(REMOVE) $(TARGET).a90
|
||||
$(REMOVE) $(TARGET).sym
|
||||
$(REMOVE) $(TARGET).lnk
|
||||
$(REMOVE) $(TARGET).lss
|
||||
$(REMOVE) $(OBJ)
|
||||
$(REMOVE) $(LST)
|
||||
$(REMOVE) $(SRC:.c=.s)
|
||||
$(REMOVE) $(SRC:.c=.d)
|
||||
$(REMOVE) *~
|
||||
|
||||
# Automatically generate C source code dependencies.
|
||||
# (Code originally taken from the GNU make user manual and modified
|
||||
# (See README.txt Credits).)
|
||||
#
|
||||
# Note that this will work with sh (bash) and sed that is shipped with WinAVR
|
||||
# (see the SHELL variable defined above).
|
||||
# This may not work with other shells or other seds.
|
||||
#
|
||||
%.d: %.c
|
||||
set -e; $(CC) -MM $(ALL_CFLAGS) $< \
|
||||
| sed 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' > $@; \
|
||||
[ -s $@ ] || rm -f $@
|
||||
|
||||
|
||||
# Remove the '-' if you want to see the dependency files generated.
|
||||
-include $(SRC:.c=.d)
|
||||
|
||||
|
||||
|
||||
# Listing of phony targets.
|
||||
.PHONY : all begin finish end sizebefore sizeafter gccversion coff extcoff \
|
||||
clean clean_list program
|
||||
328
ps2kbd.c
Normal file
328
ps2kbd.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
PS2KBC, a PS2 Controler implemented on the Atmel ATTINY861.
|
||||
Copyright (C) 2015 Matt Harlum
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include "ps2kbd.h"
|
||||
#include <util/delay.h>
|
||||
|
||||
|
||||
// Volatile, declared here because they're used in and out of the ISR
|
||||
volatile uint8_t rcv_byte = 0;
|
||||
volatile uint8_t rcv_bitcount = 0;
|
||||
volatile uint8_t send_bitcount = 0;
|
||||
volatile uint8_t scancode = 0;
|
||||
volatile uint8_t strobe = 0 ;
|
||||
volatile uint8_t ssp = 0; // 0 = Start/ 1 = stop/ 2 = parity
|
||||
volatile uint8_t sr = 0; // 0 = 0 - Receive, 0 = 1 = Send
|
||||
volatile uint8_t send_parity = 0;
|
||||
volatile uint8_t send_byte = 0;
|
||||
volatile uint8_t parity_errors = 0; // Currently unused but will provide error info to host computer
|
||||
volatile uint8_t framing_errors = 0;
|
||||
|
||||
|
||||
int calc_parity(unsigned parity_x)
|
||||
{
|
||||
// Calculate Odd-Parity of byte needed to send PS/2 Packet
|
||||
unsigned parity_y;
|
||||
parity_y = parity_x ^ (parity_x >> 1);
|
||||
parity_y = parity_y ^ (parity_y >> 2);
|
||||
parity_y = parity_y ^ (parity_y >> 4);
|
||||
return parity_y & 1;
|
||||
}
|
||||
|
||||
void framing_error(uint8_t num)
|
||||
{
|
||||
// Deal with PS/2 Protocol Framing errors. delay for the rest of the packet and clear interrupts generated during the delay.
|
||||
framing_errors++;
|
||||
GIMSK &= ~(1 << INT0);
|
||||
_delay_ms(8);
|
||||
GIFR |= (1 << INTF0); // Clear Interrupt flag
|
||||
GIMSK |= (1 << INT0);
|
||||
}
|
||||
|
||||
void sendps2(uint8_t data, uint8_t responseneeded)
|
||||
{
|
||||
/* Complicated shit to send a PS/2 Packet.
|
||||
Begin the request by making both inputs outputs, drag clock low for at least 100us then take data low and release clock.
|
||||
the device will soon after start clocking in the data so make clk an input again and pay attention to the interrupt.
|
||||
The device will clock in 1 start bit, 8 data bits, 1 parity bit then 1 stop bit. It will then ack by taking data low on the 12th clk (though this is currently ignored) and then it will respond with an 0xFA ACK */
|
||||
uint8_t send_tries = 3;
|
||||
scancode = 0;
|
||||
do
|
||||
{
|
||||
send_byte = data;
|
||||
send_parity = calc_parity(send_byte);
|
||||
GIMSK &= ~(1 << INT0); // Disable interrupt for CLK
|
||||
DDRB |= (1 << DDB6 | 1 << DDB5); // CLK/Data are now Outputs
|
||||
PORTB &= ~(1 << PB6); // Bring Clock low
|
||||
_delay_us(150);
|
||||
PORTB &= ~(1 << PB5); // Bring data Low
|
||||
PORTB |= (1 << PB6); // Release clock and set it as an input again, clear interrupt flags and re-enable the intterupts
|
||||
DDRB &= ~(1 << DDB6);
|
||||
GIFR |= (1 << INTF0);
|
||||
GIMSK |= (1 << INT0);
|
||||
sr = 1;
|
||||
while (sr == 1) {} // All the work for sending the data is handled inside the interrupt
|
||||
DDRB &= ~(1 << DDB6 | 1 << DDB5); // Clock and Data set back to input
|
||||
while (strobe == 0) {} // Wait for ACK packet before proceeding
|
||||
strobe = 0;
|
||||
send_tries--;
|
||||
} while ((send_tries) && (scancode != 0xFA)); // If the response is not an ack, resend up to 3 times.
|
||||
|
||||
if (responseneeded) // Are we expecting a response besides ACK?
|
||||
{
|
||||
while (strobe == 0) {}
|
||||
strobe = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void parity_error(void)
|
||||
{
|
||||
parity_errors++;
|
||||
sendps2(0xFE,0); // Inform the KBD of the Parity error and request a resend.
|
||||
}
|
||||
|
||||
ISR (INT0_vect)
|
||||
{
|
||||
if (sr == 1) { //Send bytes to device.
|
||||
if (send_bitcount >=0 && send_bitcount <=7) // Data Byte
|
||||
{
|
||||
if ((send_byte >> send_bitcount) & 1) {
|
||||
PORTB |= (1 << PB5);
|
||||
}
|
||||
else
|
||||
{
|
||||
PORTB &= ~(1 << PB5);
|
||||
}
|
||||
}
|
||||
else if (send_bitcount == 8) // Parity Bit
|
||||
{
|
||||
if (send_parity)
|
||||
{
|
||||
PORTB &= ~(1 << PB5);
|
||||
}
|
||||
else
|
||||
{
|
||||
PORTB |= (1 << PB5);
|
||||
}
|
||||
}
|
||||
else if (send_bitcount == 9) // Stop Bit
|
||||
{
|
||||
PORTB |= (1 << PB5);
|
||||
}
|
||||
if (send_bitcount < 10)
|
||||
{
|
||||
send_bitcount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_bitcount = 0;
|
||||
sr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else { // Receive from device
|
||||
uint8_t result = 0;
|
||||
|
||||
if (PINB & (1 << PB5))
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
if (rcv_bitcount <=9)
|
||||
{
|
||||
if (rcv_bitcount >=1 && rcv_bitcount <= 8)
|
||||
{
|
||||
rcv_byte |= (result << (rcv_bitcount - 1)); //Scancode Byte
|
||||
}
|
||||
else if (rcv_bitcount == 0)
|
||||
{
|
||||
ssp = result; // Start Bit
|
||||
}
|
||||
else if (rcv_bitcount == 9)
|
||||
{
|
||||
ssp |= (result << 2); // Parity Bit
|
||||
}
|
||||
rcv_bitcount++;
|
||||
}
|
||||
else if (rcv_bitcount >= 10)
|
||||
{
|
||||
ssp |= (result << 1); // Stop Bit
|
||||
if ((ssp & 0x2) != 0x02) // Check start and stop bits.
|
||||
{
|
||||
framing_error(ssp);
|
||||
}
|
||||
else if (calc_parity(rcv_byte) == (ssp >> 2))
|
||||
{
|
||||
parity_error();
|
||||
strobe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scancode = rcv_byte;
|
||||
strobe = 1;
|
||||
}
|
||||
rcv_bitcount = 0;
|
||||
rcv_byte = 0;
|
||||
result = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main (void) {
|
||||
volatile uint8_t kb_register = 0; // 0 = keyup | 1 = shift | 2 = ctrl | 3 = alt | 4 = capslock | 5 = numlock | 6 = scroll lock
|
||||
volatile char ret_char = 0;
|
||||
DDRB &= ~(1 << DDB6 | 1 << DDB5); // PINB6 = PS/2 Clock, PINB5 = PS/2 Data both set as input
|
||||
DDRB |= (1 << DDB3);
|
||||
DDRA |= (0xFF);
|
||||
MCUCR |= (1 << ISC01 | 1 << PUD); // Interrupt on Falling Edge, force disable pullups
|
||||
GIMSK |= (1 << INT0); // Enable Interrupt on PINB2 aka INT0
|
||||
|
||||
sei();
|
||||
sendps2(0xff,1); // reset kbd
|
||||
sendps2(0xf0,0); // Set Codeset
|
||||
sendps2(0x02,0); // Codeset 2
|
||||
|
||||
|
||||
while (1) {
|
||||
if (strobe)
|
||||
{
|
||||
GIMSK &= ~(1 << INT0); // Disable interrupt for CLK
|
||||
DDRB |= (1 << DDB6); // CLK now an outout
|
||||
PORTB &= ~(1 << PB6); // Bring Clock low, inhibit keyboard until done processing event
|
||||
if (kb_register & (1 << KB_KUP)) //This is a keyup event
|
||||
{
|
||||
switch(scancode)
|
||||
{
|
||||
case 0x12:
|
||||
case 0x59:
|
||||
kb_register &= ~(1 << KB_SHIFT);
|
||||
break;
|
||||
case 0x14:
|
||||
kb_register &= ~(1 << KB_CTRL);
|
||||
break;
|
||||
case 0x11:
|
||||
kb_register &= ~(1 << KB_ALT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
kb_register &= ~(1 << KB_KUP);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(scancode)
|
||||
{
|
||||
case 0xF0: //Key up
|
||||
kb_register |= (1 << KB_KUP);
|
||||
break;
|
||||
case 0xE0: //Extended key sequence
|
||||
kb_register |= (1 << KB_EXT);
|
||||
break;
|
||||
case 0x12:
|
||||
case 0x59: // Shift
|
||||
kb_register |= (1 << KB_SHIFT);
|
||||
break;
|
||||
case 0x66: //backspace
|
||||
ret_char = 0x7F;
|
||||
break;
|
||||
case 0x5A: //enter
|
||||
ret_char = 0x0D;
|
||||
break;
|
||||
case 0x0D: //tab
|
||||
ret_char = 0x09;
|
||||
break;
|
||||
case 0x14: //ctrl
|
||||
kb_register |= (1 << KB_CTRL);
|
||||
break;
|
||||
case 0x11: //alt
|
||||
kb_register |= (1 << KB_ALT);
|
||||
break;
|
||||
case 0x76: //esc
|
||||
ret_char = 0x1B;
|
||||
break;
|
||||
case 0x58: //capslock
|
||||
kb_register ^= (1 << KB_CAPSLK);
|
||||
sendps2(0xed,0);
|
||||
sendps2((kb_register >> 4),0); // Set KBD Lights
|
||||
break;
|
||||
case 0x77: //numlock
|
||||
kb_register ^= (1 << KB_NUMLK);
|
||||
sendps2(0xed,0);
|
||||
sendps2((kb_register >> 4),0); // Set KBD Lights
|
||||
break;
|
||||
case 0x7E: //scrllock
|
||||
kb_register ^= (1 << KB_SCRLK);
|
||||
sendps2(0xed,0);
|
||||
sendps2((kb_register >> 4),0); // Set KBD Lights
|
||||
break;
|
||||
default: // Fall through for Alphanumeric Characters
|
||||
if (kb_register & (1 << KB_CTRL)) // ASCII Control Code
|
||||
{
|
||||
ret_char = ps2_to_ascii_shifted[scancode];
|
||||
if ((ret_char >=0x41) && (ret_char <= 0x5A)) //Make sure we don't read outside the valid range of codes
|
||||
{
|
||||
ret_char ^= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_char = 0;
|
||||
}
|
||||
}
|
||||
else if (kb_register & (1<< KB_SHIFT)) {
|
||||
ret_char = ps2_to_ascii_shifted[scancode];
|
||||
}
|
||||
else if (kb_register & (1 <<KB_CAPSLK)) {
|
||||
ret_char = ps2_to_ascii[scancode];
|
||||
if ((ret_char >= 0x61) && (ret_char <= 0x7A))
|
||||
{
|
||||
ret_char ^= 0x20;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_char = ps2_to_ascii[scancode];
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret_char)
|
||||
{
|
||||
PORTA = ret_char;
|
||||
PORTB |= 1 << PB3;
|
||||
_delay_us(10);
|
||||
PORTB &= ~(1 << PB3);
|
||||
ret_char = 0;
|
||||
PORTA = 0;
|
||||
}
|
||||
}
|
||||
strobe = 0;
|
||||
PORTB |= (1 << PB6); // Release clock and set it as an input again, clear interrupt flags and re-enable the interupts
|
||||
DDRB &= ~(1 << DDB6);
|
||||
GIFR |= (1 << INTF0);
|
||||
GIMSK |= (1 << INT0);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
ps2kbd.h
Normal file
58
ps2kbd.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
PS2KBC, a PS2 Controler implemented on the Atmel ATTINY861.
|
||||
Copyright (C) 2015 Matt Harlum
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#define KB_KUP 0
|
||||
#define KB_SHIFT 1
|
||||
#define KB_CTRL 2
|
||||
#define KB_ALT 3
|
||||
#define KB_CAPSLK 4
|
||||
#define KB_NUMLK 5
|
||||
#define KB_SCRLK 6
|
||||
#define KB_EXT 7
|
||||
|
||||
|
||||
#ifndef F_CPU
|
||||
#define F_CPU 8000000UL
|
||||
#endif
|
||||
|
||||
const uint8_t ps2_to_ascii[] = // Scancode > Ascii table.
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', 0, // 00-0F
|
||||
0, 0, 0, 0, 0, 'q', '1', 0, 0, 0, 'z', 's', 'a', 'w', '2', 0, //10-1F
|
||||
0, 'c', 'x', 'd', 'e', '4', '3', 0, 0, ' ', 'v', 'f', 't', 'r', '5', 0, //20-2F
|
||||
0, 'n', 'b', 'h', 'g', 'y', '6', 0, 0, 0, 'm', 'j', 'u', '7', '8', 0, //30-3F
|
||||
0, ',', 'k', 'i', 'o', '0', '9', 0, 0, '.', '/', 'l', ';', 'p', '-', 0, //40-4F
|
||||
0, 0, '\'', 0, '[', '=', 0, 0, 0, 0, 0, ']', 0, '\\', 0, 0, //50-5F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, '1', 0, '4', '7', 0, 0, 0, //60-6F
|
||||
'0', '.', '2', '5', '6', '8', 0, 0, 0, '+', '3', '-', '*', '9', 0, 0, //70-7F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //80-8F
|
||||
};
|
||||
|
||||
const uint8_t ps2_to_ascii_shifted[] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', 0, // 00-0F
|
||||
0, 0, 0, 0, 0, 'Q', '!', 0, 0, 0, 'Z', 'S', 'A', 'W', '@', 0, //10-1F
|
||||
0, 'C', 'X', 'D', 'E', '$', '#', 0, 0, ' ', 'V', 'F', 'T', 'R', '%', 0, //20-2F
|
||||
0, 'N', 'B', 'H', 'G', 'Y', '^', 0, 0, 0, 'M', 'J', 'U', '&', '*', 0, //30-3F
|
||||
0, '<', 'K', 'I', 'O', ')', '(', 0, 0, '>', '?', 'L', ':', 'P', '_', 0, //40-4F
|
||||
0, 0, '"', 0, '{', '+', 0, 0, 0, 0, 0, '}', 0, '|', 0, 0, //50-5F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, '1', 0, '4', '7', 0, 0, 0, //60-6F
|
||||
'0', '.', '2', '5', '6', '8', 0, 0, 0, '+', '3', '-', '*', '9', 0, 0, //70-7F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //80-8F
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user