; **************************************************************** ; * PCkb.asm ; * ; * version 1.32 Oct 12, 2003 Alan Probandt Portland Oregon USA ; * ; * [ Use TimesNewRoman font in text editor to format this file correctly ] ; * ; * [ when programming the AVR chip, don't forget to include the EEPROM file] ; * ; * Read keypresses from PC Keyboard into Atmel AVR 90S2313 ; * -Assemble logic changes on AVR pin 6 into PC keyboard scan codes. ; * -Decode keyboard scancodes into MIDI note numbers. ; * -Send MIDI messages out the MIDI out port 31250/8/N/1 ; * ; Key Pad - pressing two digits on the keypad changes the voice number. ; for example, pressing '3' then '7' selects voice number 37 (in decimal). ; ; * PC keyboard clock signal on AVR pin 6 (INT1) ; * PC keyboard data signal on AVR pin 7 (PORTD bit 4) ; * MIDI out (31250 baud - 8/N/1) on AVR pin 8 (PB4) ; ; Atmel AVR 2313 ; RESET low PIN 1 | VCC PIN 20 +5V ; PIN 2 PD0 | PB7 PIN 19 SCK ; PIN 3 PD1 | PB6 PIN 18 ; 3.579MHz PIN 4 XTAL1 | PB5 PIN 17 ; must use only PIN 5 XTAL2 | PB4 PIN 16 ; INT0 kbd clk PIN 6 PD2 | PB3 PIN 15 ; INT1 kbd data PIN 7 PD3 | PB2 PIN 14 ; MIDI out PIN 8 PD4 | PB1 PIN 13 ; PIN 9 PD5 | PB0 PIN 12 ; PIN 10 GND | PD6 PIN 11 ; ; ************************************************************ .nolist .include "2313def.inc" .list .equ MIDItx = 4 ; MIDI Transmit pin 8 (PB4) .equ INITIAL_BITCOUNT = 11 ; used by Get_Scan .equ PARITY_BITCOUNT = 3 ; used by Get_Scan .equ NOTEOFFSET = 34 ; check for adjustment -- Is 'Z' key really Middle C? .equ CHANGE_VOICE_OFFSET = $2e .equ SPACEBAR_OFFSET = $2d .equ REGISTER_AVAILABLE = $FF .equ POSSIBLE_NOTES = 8 .equ NOTE_ON_VELOCITY = 0x50 .equ NOTE_OFF_VELOCITY = 0 .equ NOTE_ON_MSG = $90 .equ CHANGE_VOICE_MSG = $c0 .equ MIDI_CONTROLLER_MSG = $b0 .equ ALL_NOTES_OFF_BYTE = 123 ; standard cmd $7b doesn't work on TQ5 .equ ALL_NOTES_OFF_2nd = 0 .equ CapsToggleValue = 0b01000000 .equ T_flag = 6 .equ Sign_flag = 4 .equ KeyboardClock = 2 .equ KeyboardData= 3 .equ SM_flag = 4 ; Sleep Mode (unused) - delay loop counter bit flag { 0 = long period is timed out} .equ PushSwitch1 = 4 ; keyflag register's bit values .equ Edge_flag = 7 ; use up or down edge while inputting char from keyboard .equ Caps_flag = 6 ; Caps Lock pressed on -- no NoteOff transmitted .equ Shift_flag = 5 ; the shift key (either right or left) is being pressed .equ Break_flag = 4 ; the last scancode was an $f0 - the break code sent when a key is released .equ OnOff_flag = 3 ; set means turn on the note whose MIDI number was decoded from the most recent scancode .equ Alt_flag = 2 ; the Alternate (Alt) key (either right or left) is being pressed .equ E0_flag = 1 ; the extended scancode $E0 was sent ;********************************************************************************************* ; Register definitions ; ; lower registers r0 - r15 ; r0 is temporary storage of byte retrieved from LPM instruction .def OctaveOffset = r1 .def CurrentVoiceNumber = r2 .def txbitcnt = r3 ; used by PutMIDI .def TableOffset = r5 ; used by PCKB_main to keep track of where a keypress has been found in a table .def MIDIcounter = r6 ; FastMIDINumbers, SlowMIDINumbers - which MIDI number is being sent .def regcnt = r6 ; used by PCKB_main to keep track of which notes are playing by having keys held down .def OverflowCount = r6 ; used by T0_overflow IRQ to time a quarter-second .def KPtemp = r6 ; used by PCKB_main to multiply keypad digit by 10 .def ParityCounter = r7 ; count the number of logic hi bits transmitted by the keyboard command output routine .def SustainValue = r7 ; upper registers .def temp = r16 ; scratch register .def irqtemp = r17 ; interrupt's scratch register .def bitcount = r18 ; used by INT0 irq [getscan] .def scancode = r19 ; storage of data bits received from PC keyboard .def scanbits = r20 ; shift register for holding PC keyboard data while being assembled .def keyflags = r21 ; status of previous scancodes. used to decode multiple scancode keypresses .def DecodeValue = r22 ; PC keyboard char decoded to NoteOn value, ChangeVoice value, or AllNotesOff cmd .def KPvalue = r23 ; the binary value of the pressed keypad digits. Used for new voice value. .def Velocity = r24 ; the MIDI note-On volume value .def TxData = r25 ; the byte being sent out the MIDI port - PutMIDI .dseg .org 0x60 FNtable: .BYTE 12 SoundingNotes: .BYTE POSSIBLE_NOTES .cseg .org $0000 ; AT90S2313 interrupt table rjmp reset ; Reset handler $000 .org INT0addr rjmp get_scan ; External interrupt 0 handler $001 (pin 6) PC keyboard clock .org INT1addr reti ; External interrupt 1 handler $002 .org ICP1addr reti ; Timer1 capture event handler $003 .org OC1addr reti ; Timer1 compare match $004 .org OVF1addr reti ; Timer1 overflow handler $005 .org OVF0addr reti ; Timer0 overflow handler $006 .org URXCaddr reti ; UART Rx Complete $007 .org UDREaddr reti ; UART Data Register empty $008 .org UTXCaddr reti ; UART Tx Complete $009 .org ACIaddr reti ; Analog comparator handler $00a reset: ldi temp, RAMEND out SPL ,temp ; init Stack Pointer ; set-up ports for input/output and pull-up resistors ser temp out portb,temp ; port B pull-up resistors are all on out portd,temp ; port D pull-up resistors are all on clr temp out ddrb,temp ; port b is all inputs ldi temp,(1< ; DecodeValue = $c0 (SPACE key pressed) == turn off all notes ; DecodeValue = $f0 to $fe ( special keys) Each value between $f0 and $fe has its own handler code ; DecodeValue = $ff == ignore this scancode ; ;************************************************************************************************************************** decode_data: ; first check that Break flag is clear *** chkBreakFlag: sbrc keyflags, Break_flag ; the previous scancode was $f0 when break_flag is set rjmp Break_set ; sbrc keyflags, E0_flag ; the previous scancode was $f0 when break_flag is set ; rjmp Do_E0char ; Break and Extended are clear, so do check the first three special conditions cpi scancode,$f0 ; $F0 =Breakcode finger-off-the-key identifier brne isLeftAltKey sbr keyflags, (1< falling ;; bit 7 (edge) = ff => rising cpi bitcount,INITIAL_BITCOUNT ; falling edge of the FIRST clock pulse from the PC keyboard ; start bit so do nothing breq I1two cpi bitcount,PARITY_BITCOUNT ; = 3 ; test for parity bit and stop bit brlo I1two ; must use bitcount 3 for compare because branch tests only for lower lsr scanbits ; shift data right one bit - data bit 7 gets 0 sbic PIND,PD3 ;set scancode bit if bit 3 on input port D is set (pin 7 on 2313 chip) ori scanbits,$80 ; if data from kbrd is 1, then set bit 7 only and let other bits unchanged ldi irqtemp, ( (1<