; A MIDI drum machine & sampler ; needs 8Mhz clock ; 8515 chip ; 32K SRAM ; UART set to 19200 ; Jeremy Selan ; loads 4 samples. ; comm works perfectly ; plays 4 voices at a time, 1 voice per sample ; no dynamic allocation ;Polled -- no interrrupts ;Strings can come from flash or RAM. ;input a string, then output it again .include "8515def.inc" .def char =r0 ;character to send/receive .def zero =r0 .def sam0start_l=r1 ; START OF SAMPLE 0 .def sam0start_h=r2 .def sam1start_l=r3 ; START OF SAMPLE 1 & END OF SAMPLE 0 .def sam1start_h=r4 .def sam2start_l=r5 ; START OF SAMPLE 2 & END OF SAMPLE 1 .def sam2start_h=r6 .def sam3start_l=r7 ; START OF SAMPLE 3 & END OF SAMPLE 2 .def sam3start_h=r8 .def sam3end_l=r9 ; END OF SAMPLE 3 .def sam3end_h=r10 .def v0addr_l=r11 .def v0addr_h=r12 .def v1addr_l=r13 .def v1addr_h=r14 .def v2addr_l=r15 .def v2addr_h=r16 .def v3addr_l=r17 .def v3addr_h=r18 .def audio_l=r19 .def audio_h=r20 .def parm =r21 ;2nd temp register .def temp =r22 ;temporary register .def TXflash =r23 ;text to be sent is in flash if <>0 .def flag=r24 .def robin=r25 .def enable=r26 ;.equ baud96 =25 ;9600 baud constant for 4Mhz crystal .equ baud96 =25 ;19200 baud constant for 8Mhz crystal .equ azero ='0' ;0x30 ascii '0' .equ ramstart = 0x260 ;************************************** .dseg ;define variable string to be stored/transmitted in RAM StrBuffer: .byte 32 ;a string buffer ;************************************** ;print and read string macros .macro PrintFlashStr ;use: PrintFlashStr flashaddress ldi TXflash, 1 ldi ZL, low(@0<<1) ldi ZH, high(@0<<1) rcall putString .endmacro .macro PrintRamStr ;use: PrintRamStr ramaddress ldi TXflash, 0 ldi ZL, low(ramstart) ldi ZH, high(ramstart) rcall putString .endmacro .macro ReadStr ;use: ReadStr ramaddress ldi ZL, low(ramstart) ldi ZH, high(ramstart) rcall getSample .endmacro ;************************************** .cseg .org $0000 rjmp RESET ;reset entry vector reti reti reti reti reti reti rjmp TIM0_OVF ; Timer 0 overflow reti reti reti reti reti ;define fixed strings to be tranmitted from flash ;zero terminated prompt0:.db "Enter sample 0> ",0x00 prompt1:.db "Enter sample 1> ",0x00 prompt2:.db "Enter sample 2> ",0x00 prompt3:.db "Enter sample 3> ",0x00 prompt10:.db "Live Mode Enabled..",0x00 prompt11:.db "Error in Sample Conversion ",0x00 prompt12:.db "Sample Received.",0x00 ;carrage return/line feed crlf: .db 0x0d, 0x0a, 0x00 RESET: ldi temp, LOW(RAMEND) ;setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;setup UART -- enable RX, TX pins ldi temp, 0b00011000 out UCR, temp ;set baud rate to 9600 or 19200baud192 ldi temp, baud96 out UBRR, temp ; setup external SRAM ldi temp, 0b10000000 out MCUCR, temp ;now print a prompt and wait for incoming string with;initialize pointer to 1st ram location ldi YL, low(ramstart) ldi YH, high(ramstart) ; get sample 0 mov sam0start_l,YL mov sam0start_h,YH PrintFlashStr crlf PrintFlashStr prompt0 PrintFlashStr crlf mov YL,sam0start_l mov YH,sam0start_h rcall getSample mov sam1start_l,YL mov sam1start_h,YH PrintFlashStr crlf PrintFlashStr prompt12 PrintFlashStr crlf ; get sample 1 PrintFlashStr crlf PrintFlashStr prompt1 PrintFlashStr crlf mov YL,sam1start_l mov YH,sam1start_h rcall getSample mov sam2start_l,YL mov sam2start_h,YH PrintFlashStr crlf PrintFlashStr prompt12 PrintFlashStr crlf ; get sample 2 PrintFlashStr crlf PrintFlashStr prompt2 PrintFlashStr crlf mov YL,sam2start_l mov YH,sam2start_h rcall getSample mov sam3start_l,YL mov sam3start_h,YH PrintFlashStr crlf PrintFlashStr prompt12 PrintFlashStr crlf ; get sample 3 PrintFlashStr crlf PrintFlashStr prompt3 PrintFlashStr crlf mov YL,sam3start_l mov YH,sam3start_h rcall getSample mov sam3end_l,YL mov sam3end_h,YH PrintFlashStr crlf PrintFlashStr prompt12 PrintFlashStr crlf mainloop_init: PrintFlashStr crlf PrintFlashStr prompt10 PrintFlashStr crlf ; **** set up the PORTs **** ; Port B ser temp ; Set PortC all Outputs out DDRB,temp ldi temp,128 ; Clear the audio out register out PortB,temp ; set up timer 1: ; it will count up to OCR1A, then reset and set a flag ; we will need to set it at maximum ; (clock) speed for good resolution ldi temp, 0b00000010; set clear on compare A match out TIMSK, temp ; ldi temp, 0b00000010 out TCCR0, temp ; and set prescale to 8 ldi temp,0b11000000 ; set count out TCNT0,temp ;setup UART -- disable RX, TX pins ldi temp, 0b00000000 out UCR, temp ;setup port d for com link inputs in temp, DDRD andi temp, 0b11110000 out DDRD,temp ; setup r0=zero clr temp mov zero,temp sei ;turn on interrupts clr enable ; set voice to not playing mainloop: ; check to see if a button is pressed, which ; correleates to resetting vxaddr to new correct value chk0: in parm,PIND mov temp,parm andi temp,0b00000001 breq chk1 ; set voice 0 to start mov v0addr_l,sam0start_l mov v0addr_h,sam0start_h ori enable,0b00000001 chk1: mov temp,parm andi temp,0b00000010 breq chk2 ; set voice 1 to start mov v1addr_l,sam1start_l mov v1addr_h,sam1start_h ori enable,0b00000010 chk2: mov temp,parm andi temp,0b00000100 breq chk3 ; set voice 2 to start mov v2addr_l,sam2start_l mov v2addr_h,sam2start_h ori enable,0b00000100 chk3: mov temp,parm andi temp,0b00001000 breq waitloop ; set voice 3 to start mov v3addr_l,sam3start_l mov v3addr_h,sam3start_h ori enable,0b00001000 waitloop: tst flag ; has timer 1 reset? breq waitloop ;clear audio data clr audio_h clr audio_l ;******************************** ; check if voice 0 is playing v0tst: mov temp,enable andi temp,0b00000001 breq v0off mov YL,v0addr_l mov YH,v0addr_h ld temp,Y+ ; check for end of sample cp YH,sam1start_h brne cont0 cp YL,sam1start_l brne cont0 andi enable,0b11111110 cont0: mov v0addr_l,YL mov v0addr_h,YH add audio_l,temp adc audio_h,zero rjmp v1tst v0off: ldi temp,127 add audio_l,temp adc audio_h,zero ;******************************** ; check if voice 1 is playing v1tst: mov temp,enable andi temp,0b00000010 breq v1off mov YL,v1addr_l mov YH,v1addr_h ld temp,Y+ ; check for end of sample cp YH,sam2start_h brne cont1 cp YL,sam2start_l brne cont1 andi enable,0b11111101 cont1: mov v1addr_l,YL mov v1addr_h,YH add audio_l,temp adc audio_h,zero rjmp v2tst v1off: ldi temp,127 add audio_l,temp adc audio_h,zero ;******************************** ; check if voice 2 is playing v2tst: mov temp,enable andi temp,0b00000100 breq v2off mov YL,v2addr_l mov YH,v2addr_h ld temp,Y+ ; check for end of sample cp YH,sam3start_h brne cont2 cp YL,sam3start_l brne cont2 andi enable,0b11111011 cont2: mov v2addr_l,YL mov v2addr_h,YH add audio_l,temp adc audio_h,zero rjmp v3tst v2off: ldi temp,127 add audio_l,temp adc audio_h,zero ;******************************** ; check if voice 3 is playing v3tst: mov temp,enable andi temp,0b00001000 breq v3off mov YL,v3addr_l mov YH,v3addr_h ; check for end of sample cp YH,sam3end_h brne cont3 cp YL,sam3end_l brne cont3 andi enable,0b11110111 cont3: ld temp,Y+ mov v3addr_l,YL mov v3addr_h,YH add audio_l,temp adc audio_h,zero rjmp play v3off: ldi temp,127 add audio_l,temp adc audio_h,zero play: ror audio_h ror audio_l ;mov parm,audio_l ;mov temp,audio_h ror audio_h ror audio_l ;add audio_l,parm ;adc audio_h,temp ;ror audio_h ;ror audio_l out PortB,audio_l clr flag rjmp mainloop TIM0_OVF: ser flag ; does not modify the status register ldi temp,0b11000000 out TCNT0,temp reti ;********************************************* ;comm soubroutines ;********************************************* ;routine to output one char ;enter with char in char putc: ;wait until clear then send one char sbis USR, UDRE rjmp putC out UDR, char ret ;routine to input one char ;exit with char in char getc: ;wait until ready then get one char sbis USR, RXC rjmp getc in char, UDR ret ;***************************************************** ;routine to read a sample getSample: rcall getc ;get the highorder reg # nibble ldi temp, 'X' ;is digit exit? cp char, temp breq _RXend ldi temp, 0x30 ;is digit not valid? (CR,LF,...) cp char, temp ; if so, ignore brlt getSample ;rcall putc ;echo it mov parm,char rcall charTohex ;convert to hex swap parm ;make it the highorder bits mov temp, parm ;and save it rcall getc ;get the loworder reg # nibble ;rcall putc ;echo it mov parm,char rcall charTohex or parm, temp ;combine high and low nibbles st Y+, parm ;store the char rjmp getSample _RXend: ret ;***************************************************** ;routine to send a string putString: tst TXflash ;is it flash? breq _txram lpm ;char ;if so get a char rjmp _tstend _txram: ld char, Z ;if mem get a char _tstend:tst char ;is it string end marker? breq _TXend rcall putc ;emit a char adiw ZL, 1 ;set up next pointer rjmp putString _TXend: ret ; **************************************** ;utility routine to make a ascii char into a hex value ;enter with char in RXparm charTohex: cpi parm, 'A' brge _aboveA cpi parm, '0' ;error check-- is digit <'0'? brge _n1 rjmp error _n1: cpi parm, ':' ;error check -- is digit <':' brlt _n2 rjmp error ;if here then digit is 0 to 9 _n2: subi parm, '0' ret _aboveA: cpi parm, 'G' ;error check -- is digit>'f' brlt _ab1 rjmp error _ab1: subi parm, 'A'-10 ret error: PrintFlashStr crlf PrintFlashStr prompt11 PrintFlashStr crlf ret