;******************************************************************************************** ;* DESCRIPTION ;* Software for MIDI keyboard by Edwin Dertien, june 2000 ;* ;* This project uses an AVR AT90S1200 controller which doesn't have any ;* RAM memory and also lacks having a hardware UART. A part of the code ;* consists of a 304-appnote type Software UART ;* ;* This software reads a keyboard matrix into a register and sends MIDI codes ;* upon changes in that register: A note on-command: ;* 0b1001nnnn 0b0kkkkkkk 0b0vvvvvvv ;* nnnn = channel number, kkkkkkk = key number, vvvvvvv = velocity, normally 127 (0b01111111) ;* or a note-off command: ;* 0b1000nnnn 0b0kkkkkkk 0b0vvvvvvv ;* ;* a damper pedal function is added as well. The pedal should be connected to PD0 ;* ;* ;* DESCRIPTION of ATMEL AVR Appnote 304 ;* ;* This Application note contains a very code efficient software UART. ;* The example program receives one character and echoes it back. ;* ;* Disclaimer: commercial use of this software without permission of the author is prohibited :* ;********************************************************************************************* .include "1200def.inc" ;***** Pin definitions .equ TxD =1 ;Transmit pin is PD1 .equ PEDAL =0 ;Pedal on PD0 ;***** Global register variables .def NoteOld1 =R0 ;Note On Array .def NoteOld2 =R1 .def NoteOld3 =R2 .def NoteOld4 =R3 .def NoteOld5 =R4 .def NoteOld6 =R5 .def NoteOld7 =R6 .def NoteNew1=R7 ;Note Off Array .def NoteNew2=R8 .def NoteNew3=R9 .def NoteNew4=R10 .def NoteNew5=R11 .def NoteNew6=R12 .def NoteNew7=R13 .def bitcnt =R16 ;bit counter .def temp =R17 ;temporary storage register .def NoteOntemp = R18 .def NoteOfftemp= R19 .def Keyread =R20 ;Keyboard input buffer .def keycount=R21 ;Keyboard matrix counter .def NoteOut= R23 ;Notenumber output buffer .def Txbyte =R24 ;Data to be transmitted .def RXbyte =R25 ;Received data .def temp1 =R26 .def temp2 =R27 .def temp3 =R28 .def temp4 =R29 .def Noteout =R31 .cseg .org 0 rjmp reset ;*************************************************************************** ;* ;* "putchar" ;* ;* This subroutine transmits the byte stored in the "Txbyte" register ;* The number of stop bits used is set with the sb constant ;* ;* Number of words :14 including return ;* Number of cycles :Depens on bit rate ;* Low registers used :None ;* High registers used :2 (bitcnt,Txbyte) ;* Pointers used :None ;* ;*************************************************************************** .equ sb =1 ;Number of stop bits (1, 2, ...) putchar: ldi bitcnt,9+sb ;1+8+sb (sb is # of stop bits) com Txbyte ;Inverte everything sec ;Start bit putchar0: brcc putchar1 ;If carry set cbi PORTD,TxD ; send a '0' rjmp putchar2 ;else putchar1: sbi PORTD,TxD ; send a '1' nop putchar2: rcall UART_delay ;One bit delay rcall UART_delay lsr Txbyte ;Get next bit dec bitcnt ;If not all bit sent brne putchar0 ; send next ;else ret ; return ;*************************************************************************** ;* ;* "delay_1S" ;* ;* This delay subroutine generates the required delay between the bits when ;* transmitting and receiving bytes. The total execution time is set by the ;* constant "c": ;* ;*************************************************************************** .equ f =34 .equ c =10 .equ d =100 .equ e =10 delay_1S: ldi temp4,e delay_1S1: ldi temp3,d delay_100mS1: ldi temp2,c delay_1mS1: ldi temp1,f delay_10uS1: dec temp1 brne delay_10uS1 dec temp2 brne delay_1mS1 dec temp3 brne delay_100mS1 dec temp4 brne delay_1S1 ret ;*************************************************************************** ;* ;* "UART_delay" ;* ;* This delay subroutine generates the required delay between the bits when ;* transmitting and receiving bytes. The total execution time is set by the ;* constant "b": ;* ;* 3·b + 7 cycles (including rcall and ret) ;* ;* Number of words :4 including return ;* Low registers used :None ;* High registers used :1 (temp) ;* Pointers used :None ;* ;*************************************************************************** ; Some b values: (See also table in Appnote documentation) ; ; 1 MHz crystal: ; 9600 bps - b=14 ; 19200 bps - b=5 ; 28800 bps - b=2 ; ; 2 MHz crystal: ; 19200 bps - b=14 ; 28800 bps - b=8 ; 57600 bps - b=2 ; 4 MHz crystal: ; 19200 bps - b=31 ; 28800 bps - b=19 ; 57600 bps - b=8 ; 115200 bps - b=2 .equ b =55 ;31250 bps @ 11.0592 MHz crystal UART_delay: ldi temp,b UART_delay1: dec temp brne UART_delay1 ret ;***** Program Execution Starts Here *************** ;********* MIDI OUTPUT ******************************** ;* * ;* Dit is de hoofdprogrammalus * ;* * ;******************************************************** reset: ldi temp,$FE out DDRD,temp ;Init port pins ldi temp,$00 out PORTD,temp clear: rcall all_note_off rcall Key_in cpi Keyread,$00 brne clear bset 6 rjmp start start: rcall Inkey ;load keyboard into bufferarray rcall Prog1 ;transport bufferarray to midi out rcall Prog2 rcall Prog3 rcall Prog4 rcall Prog5 rcall Prog6 rcall Prog7 rjmp start ;go back ;**************************************************************** ;* * ;* Hieronder staan de keyboardspecifieke variabelen * ;* Voor velocity, channel, noteon en noteoff moeten decimale * ;* waarden gegeven worden. Met 'lownote'kan in principe een * ;* Transpose (verschuiving noten) worden uitgevoerd. Dit is * ;* in principe de note-waarde van de laagste toets. * ;* * ;**************************************************************** .equ lownote=32 .equ noteon=144 .equ noteoff=128 .equ velocity=100 .equ channel=0 Inkey: cbi PORTD,3 ;zet matrix 1 hoog 000 cbi PORTD,4 cbi PORTD,6 rcall Key_in ;laad keyread PB poort rcall pedaal_in ;rcall delay_1S brts no_pedal1 or NoteNew1,NoteOld1 or Keyread,NoteNew1 or NoteNew1,Keyread no_pedal1: mov NoteOld1,NoteNew1 mov NoteNew1,Keyread sbi PORTD,3 ;zet matrix 2 hoog 001 cbi PORTD,4 cbi PORTD,6 rcall Key_in ;laad keyread PB poort ;rcall delay_1S mov NoteOld2,NoteNew2 mov NoteNew2,Keyread cbi PORTD,3 ;zet matrix 3 hoog 010 sbi PORTD,4 cbi PORTD,6 rcall Key_in ;laad keyread PB poort ;rcall delay_1S mov NoteOld3,NoteNew3 mov NoteNew3,Keyread sbi PORTD,3 ;zet matrix 4 hoog 100 sbi PORTD,4 cbi PORTD,6 rcall Key_in ;laad keyread PB poort ;rcall delay_1S mov NoteOld4,NoteNew4 mov NoteNew4,Keyread cbi PORTD,3 ;zet matrix 5 hoog 101 cbi PORTD,4 sbi PORTD,6 rcall Key_in ;laad keyread PB poort ;rcall delay_1S mov NoteOld5,NoteNew5 mov NoteNew5,Keyread sbi PORTD,3 ;zet matrix 6 hoog 110 cbi PORTD,4 sbi PORTD,6 rcall Key_in ;laad keyread PB poort ;rcall delay_1S mov NoteOld6,NoteNew6 mov NoteNew6,Keyread cbi PORTD,3 ;zet matrix 7 hoog 111 sbi PORTD,4 sbi PORTD,6 rcall Key_in ;laad keyread PB poort ;rcall delay_1S mov NoteOld7,NoteNew7 mov NoteNew7,Keyread ret Prog1: clc ldi NoteOut,lownote ;grondwaarde = laagste noot/toets com NoteOld1 mov NoteOntemp,NoteNew1 AND NoteOntemp,NoteOld1 com NoteOld1 com NoteNew1 mov NoteOfftemp,NoteOld1 AND NoteOfftemp,NoteNew1 com NoteNew1 Prog1a: lsr NoteOntemp brcs sendon ;on 1 jump sendon lsr NoteOfftemp ; brcs sendoff ;on 1 jump sendoff clc inc NoteOut ;increase noteout cpi NoteOut,lownote+8 brne Prog1a ;until NoteOut > lownote+7 ret Prog2: clc ldi NoteOut,lownote+8 ;grondwaarde = laagste noot/toets com NoteOld2 mov NoteOntemp,NoteNew2 AND NoteOntemp,NoteOld2 com NoteOld2 com NoteNew2 mov NoteOfftemp,NoteOld2 AND NoteOfftemp,NoteNew2 com NoteNew2 Prog2a: lsr NoteOntemp brcs sendon ;on 1 jump sendon lsr NoteOfftemp ; brcs sendoff ;on 1 jump sendoff clc inc NoteOut ;increase noteout cpi NoteOut,lownote+16 brne Prog2a ;until NoteOut > lownote+15 ret Prog3: clc ldi NoteOut,lownote+16 ;grondwaarde = laagste noot/toets com NoteOld3 mov NoteOntemp,NoteNew3 AND NoteOntemp,NoteOld3 com NoteOld3 com NoteNew3 mov NoteOfftemp,NoteOld3 AND NoteOfftemp,NoteNew3 com NoteNew3 Prog3a: lsr NoteOntemp brcs sendon ;on 1 jump sendon lsr NoteOfftemp ; brcs sendoff ;on 1 jump sendoff clc inc NoteOut ;increase noteout cpi NoteOut,lownote+24 brne Prog3a ;until NoteOut > lownote+23 ret sendon: ldi Txbyte,channel+noteon rcall putchar ;send channel/noteon mov Txbyte,Noteout rcall putchar ;send noteout ldi Txbyte,velocity rcall putchar ;send velocity ret sendoff:ldi Txbyte,channel+noteoff rcall putchar ;send channel/noteoff mov Txbyte,Noteout rcall putchar ;send noteout ldi Txbyte,velocity rcall putchar ;send velocity ret Prog4: clc ldi NoteOut,lownote+24 ;grondwaarde = laagste noot/toets com NoteOld4 mov NoteOntemp,NoteNew4 AND NoteOntemp,NoteOld4 com NoteOld4 com NoteNew4 mov NoteOfftemp,NoteOld4 AND NoteOfftemp,NoteNew4 com NoteNew4 Prog4a: lsr NoteOntemp brcs sendon ;on 1 jump sendon lsr NoteOfftemp ; brcs sendoff ;on 1 jump sendoff clc inc NoteOut ;increase noteout cpi NoteOut,lownote+32 brne Prog4a ;until NoteOut > lownote+31 ret Prog5: clc ldi NoteOut,lownote+32 ;grondwaarde = laagste noot/toets com NoteOld5 mov NoteOntemp,NoteNew5 AND NoteOntemp,NoteOld5 com NoteOld5 com NoteNew5 mov NoteOfftemp,NoteOld5 AND NoteOfftemp,NoteNew5 com NoteNew5 Prog5a: lsr NoteOntemp brcs sendon ;on 1 jump sendon lsr NoteOfftemp ; brcs sendoff ;on 1 jump sendoff clc inc NoteOut ;increase noteout cpi NoteOut,lownote+40 brne Prog5a ;until NoteOut > lownote+39 ret Prog6: clc ldi NoteOut,lownote+40 ;grondwaarde = laagste noot/toets com NoteOld6 mov NoteOntemp,NoteNew6 AND NoteOntemp,NoteOld6 com NoteOld6 com NoteNew6 mov NoteOfftemp,NoteOld6 AND NoteOfftemp,NoteNew6 com NoteNew6 Prog6a: lsr NoteOntemp brcs sendon2 ;on 1 jump sendon lsr NoteOfftemp ; brcs sendoff2 ;on 1 jump sendoff clc inc NoteOut ;increase noteout cpi NoteOut,lownote+48 brne Prog6a ;until NoteOut > lownote+47 ret Prog7: clc ldi NoteOut,lownote+48 ;grondwaarde = laagste noot/toets com NoteOld7 mov NoteOntemp,NoteNew7 AND NoteOntemp,NoteOld7 com NoteOld7 com NoteNew7 mov NoteOfftemp,NoteOld7 AND NoteOfftemp,NoteNew7 com NoteNew7 Prog7a: lsr NoteOntemp brcs sendon2 ;on 1 jump sendon2 lsr NoteOfftemp ; brcs sendoff2 ;on 1 jump sendoff2 clc inc NoteOut ;increase noteout cpi NoteOut,lownote+56 brne Prog7a ;until NoteOut > lownote+55 ret sendon2: ldi Txbyte,channel+noteon rcall putchar ;send channel/noteon mov Txbyte,Noteout rcall putchar ;send noteout ldi Txbyte,velocity rcall putchar ;send velocity ret sendoff2: ldi Txbyte,channel+noteoff rcall putchar ;send channel/noteoff mov Txbyte,Noteout rcall putchar ;send noteout ldi Txbyte,velocity rcall putchar ;send velocity ret ;************************************************************* ;* Keyboard input ;* loop construction for ommiting key-bouncing ;************************************************************* Key_in: in temp,PINB rcall turbonop in temp4,PINB cp temp4,temp brne Key_in rcall turbonop in temp4,PINB cp temp4,temp brne Key_in com temp mov Keyread,temp ret ;************************************************************* ;* Lees pedaal in in Tregister ;************************************************************* pedaal_in: in temp,PIND rcall turbonop in temp4,PIND cp temp,temp4 brne pedaal_in rcall turbonop in temp4,PIND cp temp,temp4 brne pedaal_in bst temp,0 ret ;************************************************************* ;* All note off commando ;************************************************************* All_note_off: ldi Txbyte,channel+176 rcall putchar ldi Txbyte,123 rcall putchar ldi Txbyte,0 rcall putchar ret ;********************************************************* ;* Stupid programming solution for generating delay loops. ;* I know that this probably will be enough ground of ;* excluding me from every future open-source group.. ;********************************************************* turbonop: nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop ret