;**************************************** ; ; Moog_950 ; ======== ; ; Software for Keyboard Interface Module: ; Fatar keyboard to Moog 950 interface ; conversion ; ; Copyright (c) 2013 ; by Carsten Toensmann ; ; History ; ------- ; 15.02.2013 V0.1 ; - Start of development ; 20.03.2013 V0.9 ; - Beta Version ;**************************************** .include "m8535def.inc";microcontroller ATmega8535 ;***** definitions .equ PROGSTART = 0x000 .equ STACKP = 0x200 .equ VARIABLES = 0x201 .equ DATA_OUT = PORTC .equ KBD_BLOCKSEL = PORTA .equ DATA_IN = PINC .equ DATADIR = DDRC .equ SWITCH = PINA .equ BLOCKLEN = 8; length of key block .equ BUFLEN = 69; length of midi buffer ;equ NOTE_OFFSET = $24; NON-Formant .equ NOTE_OFFSET = $00; Formant .equ MAXNOTES = 10; size of note buffer ;***** variables .DSEG .ORG VARIABLES notebuf: .byte MAXNOTES; memory area for note values last_dac: .byte 1; memory for dac delta detection last_key: .byte 1; memory for monofonic key sequence last_voltage: .byte 1; memory for monofonic key voltage last_noteon: .byte 1; memory for note value of last note on command midi_state: .byte 1; state of midi message processing on_sent: .byte 1; reminder flag for note sequence was sent off_sent: .byte 1; reminder flag for note off was sent goff_enable: .byte 1; enable flag for gate off processing vout_enable: .byte 1; enable flag for voltage out processing switchpos: .byte 1; switch position (on / off) wpt: .byte 1; write pointer ring buffer rpt: .byte 1; read pointer ringbuffer ringbuf: .byte BUFLEN; ring buffer for incoming MIDI messages uart_rw: .byte 1; 1: UUART works in read mode, 0: write mode key_pressed: .byte 1; key pressed? 0:no 1:yes non_sent: .byte 1; note on sent? 0:no 1:yes noff_sent: .byte 1; note off sent? 0:no 1:yes ;***** interrupt vectors .CSEG .ORG PROGSTART rjmp RESET ; Reset Handler rjmp EXT_INT0 ; IRQ0 Handler rjmp EXT_INT1 ; IRQ1 Handler rjmp TIM2_COMP ; Timer 2 Compare Handler rjmp TIM2_OVF ; Timer 2 Overflow Handler rjmp TIM1_CAPT ; Timer 1 Capture Handler rjmp TIM1_COMPA ; Timer 1 Compare A Handler rjmp TIM1_COMPB ; Timer 1 Compare B Handler rjmp TIM1_OVF ; Timer 1 Overflow Handler rjmp TIM0_OVF ; Timer 0 Overflow Handler rjmp SPI_STC ; SPI Transfer Complete Handler rjmp UART_RXC ; UART RX Complete Handler rjmp UART_DRE ; UDR Empty Handler rjmp UART_TXC ; UART TX Complete Handler rjmp CADC ; AD Conversion Complete Handler rjmp EE_RDY ; EEPROM Ready Handler rjmp ANA_COMP ; Analog Comparator Handler ; ATmega8535 rjmp TWSI ; Two-wire Serial Interface Handler rjmp EXT_INT2 ; IRQ2 Handler rjmp TIM0_COMP ; Timer0 Compare Handler rjmp SPM_RDY ; Store Program Memory Ready Handler ;***** constants ; Key04 Key12 Key20 Key28 Key36 Key44 Key52 Key60 key_voltages: .db 16, 49, 82, 115, 148, 180, 213, 246 ; ; Key00 Key08 Key16 Key24 Key32 Key40 Key48 Key56 .db 0, 33, 66, 99, 131, 164, 197, 230 ; ; Key01 Key09 Key17 Key25 Key33 Key41 Key49 Key57 .db 4, 37, 70, 103, 135, 168, 201, 234 ; ; Key02 Key10 Key18 Key26 Key34 Key42 Key50 Key58 .db 8, 41, 74, 107, 139, 172, 205, 238 ; ; Key03 Key11 Key19 Key27 Key35 Key43 Key51 Key59 .db 12, 45, 78, 111, 144, 176, 209, 242 ; ; Key07 Key15 Key23 Key31 Key39 Key47 Key55 (Key63) .db 29, 62, 94, 127, 160, 193, 226, 0 ; ; Key06 Key14 Key22 Key30 Key38 Key46 Key54 (Key62) .db 25, 57, 90, 123, 156, 189, 222, 0 ; ; Key05 Key13 Key21 Key29 Key37 Key45 Key53 (Key61) .db 21, 53, 86, 119, 152, 185, 217, 0 key_values: .db 4,12,20,28,36,44,52,60 .db 0, 8,16,24,32,40,48,56 .db 1, 9,17,25,33,41,49,57 .db 2,10,18,26,34,42,50,58 .db 3,11,19,27,35,43,51,59 .db 7,15,23,31,39,47,55,0 .db 6,14,22,30,38,46,54,0 .db 5,13,21,29,37,45,53,0 ;**************************************** ; ;***** Main Program ; ;**************************************** START: ;-- set stackpointer ldi r16, high(STACKP) out SPH, r16 ldi r16, low(STACKP) out SPL, r16 ;-- configure chip operation ldi r16, $00 ; disable external interrupts out GIMSK, r16 ldi r16, $05 ; enable timer/counter 1 overflow interrupt and timer/counter 0 overflow interrupt out TIMSK, r16 ldi r16, $40 ; enable sleep function out MCUCR, r16 ldi r16, $00 ; timer/counter 1 no compare no pwm out TCCR1A, r16 out TCCR1B, r16; stop timer/counter 1 ; Port direction configuration ; ---------------------------- ;-- PORT A ldi r16,$BF; Pin 7 input, rest output out DDRA,r16 ;-- PORT B ser r16; all pins output out DDRB, r16 ;-- PORT C: data bus, controlled by function rcall set_databus_read ;-- PORT D ldi r16,$FE; PORTD Pin 0(RXD) input, rest output out DDRD, r16 bset 7 ; enable interrupts ;-- Initialization routines rcall init_dac rcall init_databus; clears data bus from dust rcall init_keyboard; keyboard scan initialisation rcall init_last_key; reset last keystroke rcall init_last_voltage; reset last cv rcall init_goff_enable rcall init_vout_enable rcall init_on_sent rcall init_off_sent rcall init_midi rcall init_noteon ;-- Main loop / scheduler MAIN: rcall scan_keyboard; scan and process fatar keyboard key strokes rcall midi_in; read and process incoming midi messages rjmp MAIN; scheduler loop STOP: rjmp STOP ; program end - full stop - in case main scheduler was left ;**************************************** ; ;***** MIDI functions ; ;**************************************** ;---------------------------------------- ; Function midi_in ; ; Processes incoming midi messages ;---------------------------------------- midi_in: push xl push xh push r16 push r17 push r18 push r19 push r20 push r21 midi_in_12: ;-- check for internal (kbd) or external (midi) processing mode in r16,SWITCH; read Switch andi r16,$40; isolate bit 6 tst r16; switch off? (internal) brne midi_in_09; if not continue rjmp midi_in_exit; no MIDI processing but keybord scan midi_in_09: ;-- read and process midi data (external processing) rcall set_uart_read; prepare UART for reading midi_in_08: ;-- check for received data ldi xl,low(wpt); get buffer write pointer ldi xh,high(wpt) ld r17,x ldi xl,low(rpt); get buffer read pointer ldi xh,high(rpt) ld r20,x cp r17,r20; anything to do? breq midi_in_12; if no continue waiting midi_in_07: ;-- read byte from buffer ldi xl,low(ringbuf); get buffer start address ldi xh,high(ringbuf) add xl,r20; compute current buffer address ld r16,x; read midi byte ;-- read current midi message state ldi xl,low(midi_state) ldi xh,high(midi_state) ld r18,x tst r18; check state 0 brne midi_in_01; if not check next state ;-- state 0: Byte has to be 0x90! cpi r16,$90; start of midi message? brne midi_in_05; if not next buffer byte ldi r18,$01; else set next state st x,r18 rjmp midi_in_05; set next buffer pointer and leave function midi_in_01: cpi r18,$01; check state 1 brne midi_in_03; if not check next state ;-- state 1: Byte represents note value ldi xl,low(vout_enable); voltage out is enabled? ldi xh,high(vout_enable) ld r18,x tst r18 brne midi_in_11; if not set next state rcall get_voltage; read corresponding output cv ldi xl,low(last_voltage) ldi xh,high(last_voltage) st x,r16 ldi xl,low(goff_enable); enable gate off ldi xh,high(goff_enable) clr r18 st x,r18 ldi xl,low(vout_enable); disable voltage out ldi xh,high(vout_enable) ldi r18,$01 st x,r18 midi_in_11: ldi xl,low(midi_state) ldi xh,high(midi_state) ldi r18,$02; set next state st x,r18 rjmp midi_in_05; set next buffer pointer and leave function midi_in_03: cpi r18,$02; check state 2 brne midi_in_exit; if not leave function (no valid state found) ;-- state 2: Byte represents note volume / 0 means note off tst r16; note off? breq midi_in_04; if yes switch off gate ldi xl,low(last_voltage) ldi xh,high(last_voltage) ld r16,x rcall dac_out; provide cv sbi PORTB,4; just gate on, no processing of volume rjmp midi_in_06 midi_in_04: ldi xl,low(goff_enable); gate off enabled? ldi xh,high(goff_enable) ld r16,x tst r16 brne midi_in_06; gate off disabled cbi PORTB,4; gate off ldi r16,$01; disable gate off st x,r16 ldi xl,low(vout_enable); enable voltage out ldi xh,high(vout_enable) clr r16 st x,r16 midi_in_06: ldi xl,low(midi_state) ldi xh,high(midi_state) clr r18; set next state (= initial state) st x,r18 ;-- compute next read pointer address midi_in_05: inc r20 cpi r20,BUFLEN; max buffer reached? brlt midi_in_02; if not continue clr r20; reset read buffer midi_in_02: ldi xl,low(rpt); get buffer read pointer ldi xh,high(rpt) st x,r20; save new read pointer rjmp midi_in_08; check for next byte midi_in_exit: pop r21 pop r20 pop r19 pop r18 pop r17 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function get_voltage ; ; Reads output voltage of an incoming ; MIDI note from internal constant tables ; ; Input: r16: note value ; Output: r16: corresponding control voltage ;---------------------------------------- get_voltage: push zl push zh push r0 push r17 dec r16; test clr r17; counter of list items ldi zh,high(key_values<<1); start address list of key numbers ldi zl,low(key_values<<1) get_voltage_02: lpm; value => r0 cp r0,r16; found incoming note in list? breq get_voltage_01; if yes find corresponding voltage adiw zl,1; next list position inc r17 cpi r17,64; end of list reached? brlt get_voltage_02 clr r16; note value not found rjmp get_voltage_exit get_voltage_01: ;-- read corresponding voltage ldi zh,high(key_voltages<<1); start address list of cvs ldi zl,low(key_voltages<<1) add zl,r17; add list position brcc get_voltage_03; check carry flag inc zh; add carry get_voltage_03: lpm; read voltage mov r16,r0; provide voltage get_voltage_exit: pop r17 pop r0 pop zh pop zl ret ;---------------------------------------- ; Function init_noteon ;---------------------------------------- init_noteon: push xl push xh push r16 ;-- clear last_noteon ser r16 ldi xl,low(last_noteon) ldi xh,high(last_noteon) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function init_midi ; ; o Initializes UART with 31250 baud ; (MIDI, Clock devider value corresponds to ; 8 Mhz crystal and 31250 baud) ; o Enables MIDI I/O ;---------------------------------------- init_midi: push xl push xh push r16 push r17 ;-- clear read / write pointer of MIDI input buffer clr r16 ldi xl,low(wpt) ldi xh,high(wpt) st x,r16 ldi xl,low(rpt) ldi xh,high(rpt) st x,r16 ;-- MIDI related variables ldi xl,low(midi_state); state of midi message processing ldi xh,high(midi_state) st x,r16 ldi r16,$01; to enforce UART write mode ldi xl,low(uart_rw); flag UART operation mode ldi xh,high(uart_rw); 0 = write mode, 1 = read mode st x,r16 ;-- set clock divider for baud rate clr r17 ldi r16,$0f; clock devider out UBRRL,r16 out UBRRH,r17 pop r17 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function midi_on ; ; Send note on sequence ; ;---------------------------------------- midi_on: push r16 push xl push xh ;-- send sequence rcall set_uart_write ldi r16,$90; send midi channel out UDR,r16 sleep ldi xl,low(last_key); send note value ldi xh,high(last_key) ld r16,x out UDR,r16 sleep ;-- register last noteon value ldi xl,low(last_noteon) ldi xh,high(last_noteon) st x,r16 ldi r16,$7f; send note volume OUT UDR,r16 sleep ;-- register note on has been sent ldi r16,$01 ldi xl,low(non_sent); flag note on has been sent ldi xh,high(non_sent) st x,r16 clr r16 ldi xl,low(noff_sent); flag note off can be sent ldi xh,high(noff_sent) st x,r16 midi_on_01: pop xh pop xl pop r16 ret ;---------------------------------------- ; Function midi_off ; ; Send note off sequence ; ;---------------------------------------- midi_off: push r16 push xl push xh ;-- send sequence rcall set_uart_write ldi r16,$90; send midi channel out UDR,r16 sleep ldi xl,low(last_noteon); send note value ldi xh,high(last_noteon) ld r16,x out UDR,r16 sleep clr r16; send note volume 0 (=off) OUT UDR,r16 sleep ;-- register note off has been sent ldi xl,low(non_sent); flag note on can be sent ldi xh,high(non_sent) st x,r16 ldi r16,$01 ldi xl,low(noff_sent); flag note off has been sent ldi xh,high(noff_sent) st x,r16 pop xh pop xl pop r16 ret ;---------------------------------------- ; Function set_uart_read ; ; Prepares UART for reading (midi in) ;---------------------------------------- set_uart_read: push r16 ldi r16,$90; prepare UART for reading out UCSRB,r16 pop r16 ret ;---------------------------------------- ; Function set_uart_write ; ; Prepares UART for sending (midi out) ;---------------------------------------- set_uart_write: push r16 push xl push xh ldi xl,low(uart_rw); flag UART operation mode ldi xh,high(uart_rw); 0 = write mode, 1 = read mode ld r16,x tst r16; UART already in write mode? breq set_uart_write_01; if yes leave function ldi r16,$48; prepare UART for sending out UCSRB,r16 clr r16; register UART has write mode st x,r16 set_uart_write_01: pop xh pop xl pop r16 ret ;---------------------------------------- ; Function set_buffer ; ; ; Initialises a memory area (buffer) of a ; given size with a given value ; ; Input: r16: value to be stored ; xl, xh: buffer start address ; r17: length of buffer ;---------------------------------------- set_buffer: push r18 clr r18; initial counter value set_buffer_01: st x,r16; write byte adiw xl,1; next buffer position inc r18; next counter cp r18,r17; check end of buffer reached brlt set_buffer_01; not yet reached pop r18 ret ;**************************************** ; ;***** Keyboard functions ; ; µC pin functions: ; ; PB0(01): Bit 2 of keyboard block adress ; PB1(02): Bit 1 of keyboard block adress ; PB2(03): Bit 0 of keyboard block adress ; ; PA7(33): read keyboard ; PA6(34): freeze keboard data ; PA5(35): provide data of keys 1-4 ; of one block scan on data bus ; PD7(21): provide data of keys 5-8 ; of one block scan on data bus ; ;**************************************** ;---------------------------------------- ; Function init_databus ; ; ; Clears data bus from dust ;---------------------------------------- init_databus: push r16 clr r16 rcall set_databus_write out DATA_OUT,r16 pop r16 ret ;---------------------------------------- ; Function init_keyboard ; ; ; initialises keyboard scan ;---------------------------------------- init_keyboard: push r16 push xl push xh ;-- disable keyboard interface cbi PORTB,0; GAB1: don't provide key data 1-4 cbi PORTD,7; GAB2: don't provide key data 5-8 rcall set_databus_read; set databus input clr r16 ldi xl,low(non_sent); flag note on can be sent ldi xh,high(non_sent) st x,r16 ldi r16,$01 ldi xl,low(noff_sent); flag don't send note off ldi xh,high(noff_sent) st x,r16 pop xh pop xl pop r16 ret ;---------------------------------------- ; Function scan_kbd ; ; Scans fatar keyboard blockwise ;---------------------------------------- scan_keyboard: push r16 push r17 push r18 push r20 push xl push xh ;-- check for internal (kbd) or external (midi) processing mode in r16,SWITCH; read Switch andi r16,$40; isolate bit 6 cpi r16,$40; switch on? (external) breq scan_kbd_exit; no keybord scan but MIDI processing ;-- init variables clr r16 ldi xl,low(key_pressed); flag key was recognized in scan process ldi xh,high(key_pressed) st x,r16 scan_kbd_next_block: out KBD_BLOCKSEL,r16; select kbd block rcall debounce rcall scan_kbd_block; read data from fatar keyboard rcall process_kbd_block inc r16; next kbd block cpi r16,$08; there are 8 kbd blocks brlt scan_kbd_next_block ;-- check result of scan process of whole keyboard ldi xl,low(key_pressed); flag key was recognized in scan process ldi xh,high(key_pressed) ld r16,x tst r16; no key was pressed? breq scan_kbd_nokey ;-- a key was pressed ldi xl,low(non_sent); flag note on has been sent ldi xh,high(non_sent) ld r16,x tst r16; has a note on already been sent? brne scan_kbd_01; yes ;-- note on has not been sent yet rcall midi_on; send note on rjmp scan_kbd_exit; leave function scan_kbd_01: ;-- note on has been sent, but has a new key been pressed? ldi xl,low(last_noteon); last note on value that has been sent ldi xh,high(last_noteon) ld r16,x ldi xl,low(last_key); last pressed key of scan cycle ldi xh,high(last_key) ld r18,x cp r16,r18 breq scan_kbd_exit; new note value is higher or equal, so leave function ;-- different note values / more than one key pressed in parallel rcall midi_off; note off old value rcall midi_on; note on new value rjmp scan_kbd_exit; leave function scan_kbd_nokey: ;-- no key was pressed ldi xl,low(noff_sent); flag note on has been sent ldi xh,high(noff_sent) ld r16,x tst r16 brne scan_kbd_exit; if yes leave function rcall midi_off; send note off scan_kbd_exit: pop xh pop xl pop r20 pop r18 pop r17 pop r16 ret ;---------------------------------------- ; Function scan_kbd_block ; ; enables keyboard scan and reads data ; ; returns lower keybord block in r20 ; higher keyboard block in r17 ;---------------------------------------- scan_kbd_block: sbi PORTB,0; GAB1: provide key data 1-4 clr r20; clear lower manual half register in r20,DATA_IN; read keyboard data cbi PORTB,0; GAB1: don't provide key data 1-4 sbi PORTD,7; GAB2: provide key data 5-8 clr r17; clear upper manual half register in r17,DATA_IN; read keyboard data cbi PORTD,7; GAB2: don't provide key data 5-8 ret ;---------------------------------------- ; Function process_kbd_block ; ; Processes scanned fatar keyboard data ; ; Input: r20: data key 1-4 ; r17: data key 5-8 ; r16: key block number (0-7) ; ; Only the second contacts are checked, ; as no velocity processing is done ;---------------------------------------- process_kbd_block: push r19 push zh push zl ;-- compute address of note voltage constant clr r19; counter := 0 ldi zh,high(key_voltages<<1); start address list of key voltages ldi zl,low(key_voltages<<1) process_keyblock_03: cp r19,r16; destination block number reached? breq process_keyblock_04 adiw zl,BLOCKLEN; add offset inc r19; next counter rjmp process_keyblock_03 process_keyblock_04: ;-- check if any key of this block is pressed ;-- check lower manual half andi r20,$55; isolate relevant bits tst r20; check if zero breq process_keyblock_01; if no key is pressed jump to upper manual half check sbrc r20,0; second contact of first key? rcall key_1 sbrc r20,2; second contact of second key? rcall key_2 sbrc r20,4; second contact of third key? rcall key_3 sbrc r20,6; second contact of fourth key? rcall key_4 ldi r19,$01 ldi xl,low(key_pressed); flag key was recognized in scan process ldi xh,high(key_pressed) st x,r19 ;-- check upper manual half process_keyblock_01: andi r17,$55; isolate relevant bits tst r17; check if zero breq process_keyblock_exit; if no key is pressed leave function sbrc r17,0; second contact of fifth key? rcall key_5 sbrc r17,2; second contact of sixth key? rcall key_6 sbrc r17,4; second contact of seventh key? rcall key_7 sbrc r17,6; second contact of eighth key? rcall key_8 ldi r19,$01 ldi xl,low(key_pressed); flag key was recognized in scan process ldi xh,high(key_pressed) st x,r19 process_keyblock_exit: pop zl pop zh pop r19 ret ;---------------------------------------- ; Function process_key ; ; Processes key of scanned key block ; ; Input: zl,zh: Address of note value ;---------------------------------------- process_key: push xl push xh push r0 push r19 lpm; load (Z) into r0 => load note voltage from list ldi xl,low(last_voltage) ldi xh,high(last_voltage) st x,r0; save new key voltage ;-- get corresponding note number from list adiw zl,32; jump to note value table adiw zl,32 lpm; read note number ldi xl,low(last_key) ldi xh,high(last_key) ldi r19,NOTE_OFFSET add r0,r19 st x,r0; save new key voltage process_key_02: pop r19 pop r0 pop xh pop xl ret ;---------------------------------------- ; Function key_1 ; ; Processes key 1 of scanned key block ;---------------------------------------- key_1: rcall process_key; no offset in list of note values ret ;---------------------------------------- ; Function key_2 ; ; Processes key 2 of scanned key block ;---------------------------------------- key_2: push zl push zh adiw zl,$01; offset in list of note values rcall process_key pop zh pop zl ret ;---------------------------------------- ; Function key_3 ; ; Processes key 3 of scanned key block ;---------------------------------------- key_3: push zl push zh adiw zl,$02; offset in list of note values rcall process_key pop zh pop zl ret ;---------------------------------------- ; Function key_4 ; ; Processes key 4 of scanned key block ;---------------------------------------- key_4: push zl push zh adiw zl,$03; offset in list of note values rcall process_key pop zh pop zl ret ;---------------------------------------- ; Function key_5 ; ; Processes key 5 of scanned key block ;---------------------------------------- key_5: push zl push zh adiw zl,$04; offset in list of note values rcall process_key pop zh pop zl ret ;---------------------------------------- ; Function key_6 ; ; Processes key 6 of scanned key block ;---------------------------------------- key_6: push zl push zh adiw zl,$05; offset in list of note values rcall process_key pop zh pop zl ret ;---------------------------------------- ; Function key_7 ; ; Processes key 7 of scanned key block ;---------------------------------------- key_7: push zl push zh adiw zl,$06; offset in list of note values rcall process_key pop zh pop zl ret ;---------------------------------------- ; Function key_8 ; ; Processes key 1 of scanned key block ;---------------------------------------- key_8: push zl push zh adiw zl,$07; offset in list of note values rcall process_key pop zh pop zl ret ;**************************************** ; ;***** Common functions ; ;**************************************** ;---------------------------------------- ; Function init_last_key ; ; Resets last keystroke memory ;---------------------------------------- init_last_key: push xl push xh push r16 clr r16 ;-- init last keystroke ldi xl,low(last_key) ldi xh,high(last_key) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function init_last_voltage ; ; Resets last cv memory ;---------------------------------------- init_last_voltage: push xl push xh push r16 ldi r16,$ff ;-- init last output voltage ldi xl,low(last_voltage) ldi xh,high(last_voltage) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function init_on_sent ; ; Enables note on processing ;---------------------------------------- init_on_sent: push xl push xh push r16 clr r16 ;-- enable gate off processing ldi xl,low(on_sent) ldi xh,high(on_sent) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function init_off_sent ; ; Disables note off processing ;---------------------------------------- init_off_sent: push xl push xh push r16 ldi r16,$01 ;-- enable gate off processing ldi xl,low(off_sent) ldi xh,high(off_sent) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function init_goff_enable ; ; Enables gate off processing ;---------------------------------------- init_goff_enable: push xl push xh push r16 clr r16 ;-- enable gate off processing ldi xl,low(goff_enable) ldi xh,high(goff_enable) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function init_vout_enable ; ; Enables voltage out processing ;---------------------------------------- init_vout_enable: push xl push xh push r16 clr r16 ;-- enable voltage out processing ldi xl,low(vout_enable) ldi xh,high(vout_enable) st x,r16 pop r16 pop xh pop xl ret ;---------------------------------------- ; Function check_switch ; ; Checks the condition of the external ; switch (on / off) ; ; Output: r16: $40: Switch closed ; $00: Switch open ;---------------------------------------- check_switch: ;-- check switch position (on / off) in r16,SWITCH; read port A andi r16,$40; isolate bit 7 ret ;---------------------------------------- ; Function reset_watchdog ; ; Resets Timer for a time depending on crystal ; ; Input: r17: Prescale Timer ; ;---------------------------------------- reset_watchdog: push r16 clr r16; start value timer/counter 1 out TCNT1L, r16 out TCNT1H, r16 out TCCR1B, r17; prescaler pop r16 ret ;---------------------------------------- ; Function debounce_elem ; ; Waits for some time, depending on crystal ; With an 8Mhz crystal this function waits ; for 0.000032 secs ;---------------------------------------- debounce_elem: push r16 clr r16; start value timer/counter 1 out TCNT0, r16 ldi r16, $01; prescale timer/counter = clock out TCCR0, r16 sleep pop r16 ret ;---------------------------------------- ; Function debounce ; ; Waits for Waits for 0.000128 sec ;---------------------------------------- debounce: push r16; counter clr r16; init counter debounce_01: rcall debounce_elem; wait some time inc r16; next counter cpi r16,$80; number of iterations brlt debounce_01; if not reached once again pop r16 ret ;---------------------------------------- ; Function init_wait ; ; Waits for some time, depending on crystal ; With an 8Mhz crystal this function waits ; for 0.065536 secs ;---------------------------------------- init_wait: push r17 ldi r17,$02; set prescaler rcall reset_watchdog; initiates timer sleep pop r17 ret ;---------------------------------------- ; Function set_databus_write ; ; Sets direction of data bus to output ;---------------------------------------- set_databus_write: push r16 ser r16; set data bus as output out DATADIR, r16 pop r16 ret ;---------------------------------------- ; Function set_databus_read ; ; Sets direction of data bus to input ;---------------------------------------- set_databus_read: push r16 clr r16; set data bus as input out DATADIR, r16 pop r16 ret ;---------------------------------------- ; Function dac_out ; ; Sets controller port pins according ; to register value ; ; Input: r16 ; ; Output: Bit 8 (A1) MSB: PD3 ; 7 (A2) : PB3 ; 6 (A3) : PB1 ; 5 (A4) : PB2 ; 4 (A5) : PD4 ; 3 (A6) : PD5 ; 2 (A7) : PD6 ; 1 (A8) LSB: PD2 ; ; As DAC reacts inverting the bits has ; to be inverted as well ; ;---------------------------------------- dac_out: push r17 push xl push xh ;-- check if anything has changed (delta detection) ldi xl,low(last_dac); set variable start adress ldi xh,high(last_dac) ld r17,x cp r17,r16 breq dac_out_exit; nothing to do push r16 ;-- Determine bits to set (clear) dac_out_01: andi r16,$01; extract bit 0 brne dac_out_011 cbi PORTD,2; "set" output bit 0 rjmp dac_out_02 dac_out_011: sbi PORTD,2; "clear" output bit 0 dac_out_02: pop r16 push r16 andi r16,$02; extract bit 1 brne dac_out_022 cbi PORTD,6; "set" output bit 1 rjmp dac_out_03 dac_out_022: sbi PORTD,6; "clear" output bit 1 dac_out_03: pop r16 push r16 andi r16,$04; extract bit 2 brne dac_out_033 cbi PORTD,5; "set" output bit 2 rjmp dac_out_04 dac_out_033: sbi PORTD,5; "clear" output bit 2 dac_out_04: pop r16 push r16 andi r16,$08; extract bit 3 brne dac_out_044 cbi PORTD,4; "set" output bit 3 rjmp dac_out_05 dac_out_044: sbi PORTD,4; "clear" output bit 3 dac_out_05: pop r16 push r16 andi r16,$10; extract bit 4 brne dac_out_055 cbi PORTB,2; "set" output bit 4 rjmp dac_out_06 dac_out_055: sbi PORTB,2; "clear" output bit 4 dac_out_06: pop r16 push r16 andi r16,$20; extract bit 5 brne dac_out_066 cbi PORTB,1; "set" output bit 5 rjmp dac_out_07 dac_out_066: sbi PORTB,1; "clear" output bit 5 dac_out_07: pop r16 push r16 andi r16,$40; extract bit 6 brne dac_out_077 cbi PORTB,3; "set" output bit 6 rjmp dac_out_08 dac_out_077: sbi PORTB,3; "clear" output bit 6 dac_out_08: pop r16 push r16 andi r16,$80; extract bit 7 brne dac_out_088 cbi PORTD,3; "set" output bit 7 rjmp dac_out_09 dac_out_088: sbi PORTD,3; "clear" output bit 7 dac_out_09: ;-- store value for dac delta detection pop r16 ldi xl,low(last_dac); set variable start adress ldi xh,high(last_dac) st x,r16 dac_out_exit: pop xh pop xl pop r17 ret ;---------------------------------------- ; Function init_dac ; ; clears output voltage ;---------------------------------------- init_dac: push r16 push xl push xh ;-- constant value clr r16; 0V output rcall dac_out ;-- store value for dac delta detection ldi xl,low(last_dac); set variable start adress ldi xh,high(last_dac) st x,r16 pop xh pop xl pop r16 ret ;---------------------------------------- ; Function debug_dac ; ; checks DAC function ;---------------------------------------- debug_dac: ;-- constant value ldi r16,$66; 2V output rcall dac_out rjmp stop ;---------------------------------------- ; Function debug_switch ; ; Toggles bit mask 10101010 on data bus ; depending on switch position ;---------------------------------------- debug_switch: rcall set_databus_write; set direction of databus to output debug_switch_02: rcall check_switch; result in r16 cpi r16, $40; switch closed? brne debug_switch_01 ldi r16,$aa ; test bit mask on data bus for 'switch closed' out DATA_OUT,r16 rjmp debug_switch_02 debug_switch_01: ldi r16,$55 ; test bit mask on data bus for 'switch open' out DATA_OUT,r16 rjmp debug_switch_02 ;---------------------------------------- ; Function wait_a_second ; ; Waits for one second ;---------------------------------------- wait_a_second: push r18 ;--wait some time clr r18; init counter wait_01: rcall init_wait; waits for ca. 0.065536 secs inc r18; next counter cpi r18,$0f; number of iterations (for one second) brlt wait_01; if not reached once again pop r18 ret ;---------------------------------------- ; Function debug ; ; Writes a bit mask 10101010 on data bus ; and stops run ;---------------------------------------- debug: ;--wait some time clr r18; init counter debug_01: rcall init_wait; waits for ca. 0.065536 secs inc r18; next counter cpi r18,$0f; number of iterations (for one second) brlt debug_01; if not reached once again rcall set_databus_write; set direction of databus to output ldi r16,$aa ; test bit mask on data bus out DATA_OUT,r16 ret ;**************************************** ; ;***** Interrupts ; ;**************************************** ;---------------------------------------- ;***** Reset Handler ;---------------------------------------- RESET: rjmp START ;***** IRQ0 Handler EXT_INT0: reti ;***** IRQ1 Handler EXT_INT1: reti ;***** Timer 2 Compare Handler TIM2_COMP: reti ;***** Timer 2 Overflow Handler TIM2_OVF: reti ;***** Timer 1 Capture Handler TIM1_CAPT: reti ;***** Timer 1 Compare A Handler TIM1_COMPA: reti ;***** Timer 1 Compare B Handler TIM1_COMPB: reti ;---------------------------------------- ;***** Timer 1 Overflow Handler ;---------------------------------------- TIM1_OVF: reti ;---------------------------------------- ;***** Timer 0 Overflow Handler ;---------------------------------------- TIM0_OVF: push r16 clr r16 ; stop timer/counter 0 out TCCR0, r16 pop r16 reti ;***** SPI Transfer Complete Handler SPI_STC: reti ;---------------------------------------- ;***** UART RX Complete Handler ; reads MIDI byte and stores it in ; ringbuffer ;---------------------------------------- UART_RXC: push zl push zh push r0 push r16 push r18 in r18,UDR; read MIDI Byte from UART ldi zl,low(wpt); get write position ldi zh,high(wpt) ld r0,z ldi zl,low(ringbuf) ldi zh,high(ringbuf) add zl,r0 st z,r18; save MIDI byte in ringbuf ldi r16,BUFLEN cp r0,r16; reached high end of ringbuf? brge uart_rxc_01 inc r0 rjmp uart_rxc_02 uart_rxc_01: clr r0 uart_rxc_02: ldi zl,low(wpt); set write position ldi zh,high(wpt) st z,r0 uart_rxc_exit: pop r18 pop r16 pop r0 pop zh pop zl reti ;***** UDR Empty Handler UART_DRE: reti ;***** UART TX Complete Handler UART_TXC: reti ;---------------------------------------- ;***** AD Conversion Complete Handler ; max. value: $3ff <=> 5V ; important: both result registers have ; to be read and ADCL has to be read first ;---------------------------------------- CADC: reti ;***** EEPROM Ready Handler EE_RDY: reti ;***** Analog Comparator Handler ANA_COMP: reti ;***** Two-wire Serial Interface Handler TWSI: reti ;***** IRQ2 Handler EXT_INT2: reti ;***** Timer0 Compare Handler TIM0_COMP: reti ;***** Store Program Memory Ready Handler SPM_RDY: reti