;-----------------------------------------------------------------------------------------------; ; Program: CVS PC-2 ; ; Developed by David J. Brown ; ; Copyright (c) April 13, 2004 David J. Brown ; ; Email: davebr@earthlink.net ; ; Web site: http://modularsynthesis.com ; ;-----------------------------------------------------------------------------------------------; ; LICENSE AGREEMENT: ; ; This program is free software. You can redistribute it and/or modify it. ; ; ; ; 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. ; ;-----------------------------------------------------------------------------------------------; ; ; Description: ; This is a Kurzweil PC-2 ribbon controller. This program will output a ribbon ; control voltage, trigger (on first contact) and gate. The control voltage ; range is 0 to 10 volts. The control voltage will revert to 5 volts on no ; contact. This voltage may be fine tuned with IN-1. ; ; Output priority will be for contact with the most right section of the ribbon. ; The output voltage is sent to the display. The variables diode, off_lm, and ; off_mr may need to be adjusted for various ribbon & diodes. ; ; Inputs: ; Start = n/a ; Stop = n/a ; In-1 = 5 volt adjust (no contact) ; In-2 = ribbon left ; In-3 = ribbon middle ; In-4 = ribbon right ; Aux = n/a ; Midi-In = n/a ; ; Outputs: ; Out-1 = cv out ; Out-2 = gate (5 volts) ; Out-3 = trigger (15 mS @ 5 volts) ; Out-4 = ribbon power ; Aux = n/a ; Midi-Out= n/a ; ; Revision: 0.3S2 ; Date Sept 23, 2010 ; History: 0.3S2 changed serial for Studio 2 ; 0.3X changed send_cc to eliminate push/pop ; 0.2 modified for CVS dedicated design ; 0.1 changed speakjet to i2c protocol, speak program name on start ; 0.0 initial release of program ; Written: April 14, 2006 ; Developed using PSIM Template by David J. Brown, April 13, 2004 ; ;-----------------------------------------------------------------------------------------------; ; ;---------ENABLE MIDI INTERRUPT CONDITIONAL COMPILE OPTION--------------------------------------; ; Note: console serial output is not compatible with interrupts ; ; ; ; COMMENT OUT NEXT LINE TO DISABLE MIDI INTERRUPTS/ENABLE POLLED ; ;midi_int_en con 1 ;define to enable midi interrupts ; ; ;comment to set polled midi mode ; ;-----------------------------------------------------------------------------------------------; ;---------ENABLE AUX_IN RISING EDGE INTERRUPT CONDITIONAL COMPILE OPTION------------------------; ; Note: console serial output is not compatible with interrupts ; ; ; ; COMMENT OUT NEXT LINE TO DISABLE AUX INPUT RISING EDGE INTERRUPTS ; ;aux_int_en con 1 ;define to enable aux_in rising edge interrupts ; ; ;comment to disable aux_in rising edge interrupts ; ;-----------------------------------------------------------------------------------------------; ;---------ENABLE TIMER INTERRUPT CONDITIONAL COMPILE OPTION-------------------------------------; ; Notes: run led will blink to verify timer operation ; ; console serial output is not compatible with interrupts ; ; ; ; COMMENT OUT NEXT LINE TO DISABLE TIMER INTERRUPTS ; ;timer_int_en con 1 ;define to enable timer interrupts ; ; ;comment to disable timer interrupts ; ; ; ; ;------ENABLE AVERAGED ANALOG-IN IN TIMER INTERRUPT CONDITIONAL COMPILE OPTION------------; ; ; ; Note: requires timer_int_en to be defined. ; ; ; ; ; ; ; ; COMMENT OUT NEXT LINE TO DISABLE ANALOG-IN ON TIMER INTERRUPTS/ENABLE POLLED ANALOG-IN ; ; ;input_int_en con 1 ;define to enable input interrupt mode ; ; ; ; ;comment to set polled input mode ; ; ; ;-----------------------------------------------------------------------------------------; ; ; ; ; ;------ENABLE RISING EDGE DETECT IN TIMER INTERRUPT CONDITIONAL COMPILE OPTION------------; ; ; ; Note: requires timer_int_en to be defined. ; ; ; ; ; ; ; ; COMMENT OUT NEXT LINE TO DISABLE RISING EDGE DETECT IN TIMER INTERRUPTS ; ; ;edge_int_en con 1 ;define to enable rising edge detect mode ; ; ; ; ;comment to disable rising edge detect mode ; ; ; ; UNCOMMENT ONE OF NEXT THREE LINES TO SELECT INPUT FOR RISING EDGE DETECT ; ; ;edge_in var in4 ;use start jack for rising edge detect input ; ; ;edge_in var in5 ;use stop jack for rising edge detect input ; ; ;edge_in var in8 ;use aux jack for rising edge detect input ; ; ; ;-----------------------------------------------------------------------------------------; ; ; ; ;-----------------------------------------------------------------------------------------------; ; BasicMicro AtomPro24 PSIM pins ; ;-----------------------------------------------------------------------------------------------; ; P0 - in-1 ; ; P1 - in-2 ; ; P2 - in-3 ; ; P3 - in-4 ; ; P4 - start button (0=normal, 1=depressed) ; ; P5 - stop button (0=normal, 1=depressed) ; ; P6 - n/a ; ; P7 - n/a ; ; P8 - aux digital input or output ; ; P9 - stop led (low=off, hi=on) ; ; P10 - run led (low=off hi=on) ; ; P11 - dac load_dacs ; ; P12 - dac ser_data ; ; P13 - dac clock ; ; P14 - midi-in ; ; P15 - midi-out ; ;-----------------------------------------------------------------------------------------------; ; DJB-LCD commands ; ;-----------------------------------------------------------------------------------------------; ; $08 - (backspace) moves the active display position one backwards ; ; $09 - (tab) moves the active display position one forward ; ; $0a - (line feed) clears the display & sets active display position to beginning of line 1 ; ; $0b - (vertical tab) sets the active display position to beginning of line 2 ; ; $0c - (form feed) vlears the display & sets active display position to beginning of line 2 ; ; $0d - (carriage return) Sets the active display position to beginning of line 1 ; ; $0e - (shift out) selects the lower characters set for display ; ; $0f - (shift in) selects the upper characters set for display ; ; $10 - program character0 row7, row6 ... row0 (bottom) ; ; $11 - program character1 row7, row6 ... row0 (bottom) ; ; $12 - program character2 row7, row6 ... row0 (bottom) ; ; $13 - program character3 row7, row6 ... row0 (bottom) ; ; $14 - program character4 row7, row6 ... row0 (bottom) ; ; $15 - program character5 row7, row6 ... row0 (bottom) ; ; $16 - program character6 row7, row6 ... row0 (bottom) ; ; $17 - program character7 row7, row6 ... row0 (bottom) ; ; $18 - sets the display mode to overwrite. New characters overwrite previous ; ; $19 - sets the display mode to scroll. Display scrolls for new characters ; ; $1a - reserved ; ; $1b - reserved ; ; $1c - set Out1 data (0=no change, 1=reset to low, 2=set to high, 3=toggle) ; ; $1d - set Out2 data (0=no change, 1=reset to low, 2=set to high, 3=toggle) ; ; $1e - set Out3 data (0=no change, 1=reset to low, 2=set to high, 3=toggle) ; ; $1f - set Out4 data (0=no change, 1=reset to low, 2=set to high, 3=toggle) ; ;-----------------------------------------------------------------------------------------------; ;pin declarations pin_j1 con p0 ;in-1 pin pin_j2 con p1 ;in-2 pin pin_j3 con p2 ;in-3 pin pin_j4 con p3 ;in-4 pin start_j var in4 ;start jack and switch stop_j var in5 ;stop jack and switch aux_j con p8 ;aux jack (output mode) aux_in var in8 ;aux jack (input mode) stop_led con p9 ;stop led (red) stop_led_out var out9 ;stop led alias used for let statement run_led con p10 ;run led (green) run_led_out var out10 ;run led alias used for let statement load_dacs con p11 ;load dac pin ser_data con p12 ;dac serial data input pin clock con p13 ;dac clock pin midi_sdata con p15 ;midi data serial output ;i/o declarations in_j1 var word ;in-1 value: get_inputs, get_inputs_avg, avg1 in_j2 var word ;in-2 value: get_inputs, get_inputs_avg, avc2 in_j3 var word ;in-3 value: get_inputs, get_inputs_avg, avg3 in_j4 var word ;in-4 value: get_inputs, get_inputs_avg, avg4 out_j1 var word ;out-1 value: load_outputs out_j2 var word ;out-2 value: load_outputs out_j3 var word ;out-3 value: load_outputs out_j4 var word ;out-4 value: load_outputs ;midi variable declarations note_off con $80 ;midi note-off command: send_note_on, send_note_off note_on con $90 ;midi note-on command: send_note_on, send_note_off cont_ctr con $b0 ;midi continuous controller; send_all_off, send_cc pgm_chg con $c0 ;midi program change command:send_prog_change midi_chan var nib ;midi channel (0 - 15): send_note_on, send_note_off midi_note var byte ;midi note value: send_note_on, send_note_off midi_vel var byte ;midi velocity value: send_note_on, send_note_off midi_pgm var byte ;midi program change value:send_prog_change midi_cc var byte ;midi continuous controller number: send_cc midi_data var byte ;variable: send_note_on, send_note_off ;timer declarations #ifdef timer_int_en time_count var long ;1 mS timer count value: tm_isr turn_off var long ;time value to turn off stop led: tm_isr #endif ;edge detect declarations #ifdef edge_int_en edge_state var byte ;eight samples of edge input: tm_isr edge_flg var byte ;edge flag (1=rising edge, 0=no rising edge): tm_isr #endif #ifdef aux_int_en aux_cnt var word ;aux interrupt count: aux_isr #endif ;input buffer declarations in_j1_ptr var byte ;in-1 buffer pointer: avgx, get_inputs_avg #ifdef input_int_en in_j2_ptr var byte ;in-2 buffer pointer: avgx in_j3_ptr var byte ;in-3 buffer pointer: avgx in_j4_ptr var byte ;in-4 buffer pointer: avgx isr_cnt var nib ;timer pass counter: tm_isr #endif in_j1_tmp var long ;in-1 temporary variable: avgx, get_inputs_avg in_j2_tmp var long ;in-2 temporary variable: avgx, get_inputs_avg in_j3_tmp var long ;in-3 temporary variable: avgx, get_inputs_avg in_j4_tmp var long ;in-4 temporary variable: avgx, get_inputs_avg in_j1_bfr var long(2) ;in-1 last 4 samples buffer: avgx, get_inputs_avg in_j2_bfr var long(2) ;in-2 last 4 samples buffer: avgx, get_inputs_avg in_j3_bfr var long(2) ;in-3 last 4 samples buffer: avgx, get_inputs_avg in_j4_bfr var long(2) ;in-4 last 4 samples buffer: avgx, get_inputs_avg ;display declarations ; num_data var byte ;data for ascii conversion: hex2ascii ; huns var byte ;hundreds digit: hex2ascii tens var byte ;tens digit: hex2ascii, display_in, display_out ones var byte ;ones digit: hex2ascii, display_in, display_out ;misc declarations fivevolts con 1920 ;5 volt output value contact var byte ;flag for ribbon contact (0=no contact, 1=contact) trigger var byte ;flag for trigger (1=first contact) ;ribbon-specific declarations ;you will need to adjust these for various configurations diode con 61 ;diode drop 61 * 10 / 1023 = 0.596 volts (measured) off_lm con 341 ;offset for left to middle transition off_mr con 642 ;offset for middle to right transition ; ;-----------------------------------------------------------------------------------------------; ; Start of program ; ;-----------------------------------------------------------------------------------------------; ; ;initialize pins ;note: setting midi-out, i2c_clock, and i2c_data to outputs can send glitches so initialize as inputs dirs=%0011111000000000 ;configure pin direction (1=output, 0=input) ;inputs: midi-in, aux, start, stop, in-4, in-3, in-2, in-1 ;outputs: load_dacs, ser_data, clock, stop led, run led, i2c clock & data low run_led ;set run led off low stop_led ;set stop led off high load_dacs ;set dac load-0 high low ser_data ;set dac data low low clock ;set dac clock low let out_j1=0 ;set out-1 low let out_j2=0 ;set out-2 low let out_j3=0 ;set out-3 low let out_j4=0 ;set out-4 low gosub load_outputs ;initialize misc variables let midi_chan=0 ;set midi channel to 0 let midi_note=0 ;set midi note to 0 let midi_vel=$40 ;set default velocity let in_j1_ptr=0 ;set in-1 pointer to 0 #ifdef input_int_en let in_j2_ptr=0 ;set in-2 pointer to 0 let in_j3_ptr=0 ;set in-3 pointer to 0 let in_j4_ptr=0 ;set in-4 pointer to 0 let isr_cnt=0 ;set isr pass counter to 0 #endif let in_j1_bfr(0)=0 ;set in-1 buffer data to 0 let in_j1_bfr(1)=0 let in_j2_bfr(0)=0 ;set in-2 buffer data to 0 let in_j2_bfr(1)=0 let in_j3_bfr(0)=0 ;set in-3 buffer data to 0 let in_j3_bfr(1)=0 let in_j4_bfr(0)=0 ;set in-4 buffer data to 0 let in_j4_bfr(1)=0 #ifdef edge_int_en let edge_state=0 ;set current state to 0 let edge_flg=0 ;reset edge flag #endif ;enable aux_in rising edge interrupts #ifdef aux_int_en let aux_cnt=0 ;reset count let pmr1=pmr1|%00100000 ;set Port Mode Register to enable irq1 let iegr1=iegr1|%00000010 ;set irq1 to rising edge let irr1=irr1&%11111101 ;clear any pending interrupt oninterrupt irq1int,aux_isr enable irq1int ;enable rising edge interrupts enable #endif ;initialize timerW hardware for 1 mS interrupts #ifdef timer_int_en let tmrw=%10001000 ;set Timer Mode Register to enable count let tcrw=%10110000 ;set Timer Control Register ; clear on compare match A ; 16 MHz clock /8 prescalar S = 2 MHz timer clock let gra=2000 ;2 MHz / 2000 = 1 mS ;enable timerW interrupt let time_count=0 ;set real time counter to 0 let turn_off=0 ;set time to turn off to time_count oninterrupt timerwint_imiea, tm_isr enable timerwint_imiea ;enable timer interrupt enable #endif ;enable midi interrupts #ifdef midi_int_en pause 250 ;let processors initialize sethserial1 h31200,h8databits,hnoparity,h1stopbits hserout [$f0,$7d,$0a,$18,"KurzPC-2",$f7] ;clear, overwrite, program name #endif ; ;-----------------------------------------------------------------------------------------------; ; Main program ; ;-----------------------------------------------------------------------------------------------; ; let trigger=0 ;reset trigger flag let out_j4=2150 ;set ribbon to 5.6 volts loop: gosub get_inputs let contact=0 ;reset gate let out_j1=fivevolts+(in_j1/64)-8 ;center output with offset if in_j2>(diode/2) then let in_j2=in_j2-diode ;subtract diode drop let out_j1=in_j2*5/2 ;set output from left ribbon let contact=1 ;set gate endif if in_j3>(diode/2) then let in_j3=(512+diode)-in_j3 ;reverse middle and subtract diode drop let out_j1=((in_j3*10/15)+off_lm)*15/4 ;set output from middle ribbon let contact=1 ;set gate endif if in_j4>(diode/2) then let in_j1=in_j4-diode ;subtract diode drop let out_j1=((in_j4*10/15)+off_mr)*15/4 ;set output from right ribbon let contact=1 ;set gate endif let out_j2=fivevolts*contact ;set gate if contact made if trigger=0 and contact=1 then let out_j3=fivevolts*contact ;set trigger if first contact else let out_j3=0 endif gosub load_outputs let trigger=contact ;set trigger to contact ; let stop_led_out=contact pause 15 let out_j3=0 ;reset trigger gosub load_outputs ; let out_j1=((out_j1/4)*25)/24 ;convert to 4 digit voltage ; let ones=out_j1/100 ;convert to integer digits ; let tens=(out_j1-(ones*100))/10 ; if ones=10 then ; let ones=$11 ;convert 10 to A ; endif ; hserout [$f0,$7d,$0b,"Vout=",ones+$30,".",dec tens,$f7] ;home2 & display out_j1 voltage goto loop ; ;-----------------------------------------------------------------------------------------------; ; Subroutines ; ;-----------------------------------------------------------------------------------------------; ; #ifdef midi_int_en ;output midi note-on command send_note_on: let midi_data=note_on+midi_chan hserout [midi_data,midi_note,midi_vel] return ; ;output midi note-off command send_note_off: let midi_data=note_off+midi_chan hserout [midi_data,midi_note,0] return ; ;output midi all notes off command send_all_off: let midi_data=cont_ctr+midi_chan hserout [midi_data,$7b,0] return ; ;output midi program change command send_prog_change: let midi_data=pgm_chg+midi_chan hserout [midi_data,midi_pgm] return ; ;output midi continuous controller command ;midi_cc is controller number ;midi_data is controller data send_cc: let tempb=midi_data let midi_data=cont_ctr+midi_chan hserout [midi_data,midi_cc] let midi_data=tempb hserout [midi_data] return #endif ; #ifndef input_int_en ;sample in-1 to in-4 ;in_jx is input value (0 - 1023) ;150 uS execution time get_inputs: adin pin_j1,in_j1 adin pin_j2,in_j2 adin pin_j3,in_j3 adin pin_j4,in_j4 return ; ;sample and average in-1 to in-4 ;in_jx is input value averaged over last four samples (0 - 1023) ;in_jx_bfr(0) & in_jx_bfr(1) are last four word samples ;600 uS execution time ;written by David J. Brown get_inputs_avg: adin pin_j1,in_j1_bfr.word1(in_j1_ptr) ;get in-1 into buffer let in_j1_tmp=in_j1_bfr(0)+in_j1_bfr(1) ;add two high words together and low words together let in_j1=(in_j1_tmp.word1+in_j1_tmp.word0)/4 adin pin_j2,in_j2_bfr.word1(in_j1_ptr) ;get in-2 into buffer let in_j2_tmp=in_j2_bfr(0)+in_j2_bfr(1) ;add two high words together and low words together let in_j2=(in_j2_tmp.word1+in_j2_tmp.word0)/4 adin pin_j3,in_j3_bfr.word1(in_j1_ptr) ;get in-3 into buffer let in_j3_tmp=in_j3_bfr(0)+in_j3_bfr(1) ;add two high words together and low words together let in_j3=(in_j3_tmp.word1+in_j3_tmp.word0)/4 adin pin_j4,in_j4_bfr.word1(in_j1_ptr) ;get in-4 into buffer let in_j4_tmp=in_j4_bfr(0)+in_j4_bfr(1) ;add two high words together and low words together let in_j4=(in_j4_tmp.word1+in_j4_tmp.word0)/4 let in_j1_ptr=(in_j1_ptr+1)&$03 ;increment pointer and wrap at 3 return #endif ; ;output out_jx values to dacs ;750 uS execution time load_outputs: ;add dac address to out_jx values and shift 16 bits using mode 4 shiftout ser_data,clock,fastmsbpre,[(out_j1|$c000)\16] pulsout load_dacs,1 ;clock loaddacs shiftout ser_data,clock,fastmsbpre,[(out_j2|$8000)\16] pulsout load_dacs,1 ;clock loaddacs shiftout ser_data,clock,fastmsbpre,[(out_j3|$4000)\16] pulsout load_dacs,1 ;clock loaddacs shiftout ser_data,clock,fastmsbpre,[out_j4\16] pulsout load_dacs,1 ;clock loaddacs return ; ;-----------------------------------------------------------------------------------------------; ; Interrupt service routines ; ;-----------------------------------------------------------------------------------------------; ; #ifdef aux_int_en ;interrupt service routine for aux input rising edge aux_isr: let aux_cnt=aux_cnt+1 ;count number of aux interrupts resume ;ignore overflow #endif ; #ifdef timer_int_en ;interrupt service routine for timer ;increments time_count value ;turn off stop led at turn_off value ;toggle run led at 512 mS intervals ;written by David J. Brown tm_isr: let time_count=time_count+1 ;increment real time count if time_count=turn_off then ;value to turn off stop led low stop_led endif let run_led_out=time_count.bit9 ;toggle run led at 512 mS intervals #endif #ifdef edge_int_en ;check for trigger rising edge ;pulse width must be > 1ms timer interval let edge_state=edge_state<<1 ;shift previous state left let edge_state.bit0=edge_in ;set low bit to current input state if edge_state=$01 then ;edge detect requires 7 previous lows and current high let edge_flg=1 ;set edge flag endif #endif #ifndef input_int_en resume ;resume if input polled mode #else ;sample in-1 - in-4 at specific intervals ;injx is input averaged over last 4 samples (0 - 1023) ;injx_bfr(0) & injx_bfr(1) are last 4 word samples ;written by David J. Brown let isr_cnt=isr_cnt+1 ;change the following table to modify the scan rate for each input ;175 uS execution time so maximum of one sample and average per interrupt ;currently set for: in-1 @ 2 mS, in-2 @ 4 mS, in-3 @ 8 mS, in-4 @ 8 mS branch isr_cnt, [avg1,avg2,avg1,avg3,avg1,avg2,avg1,avg4,avg1,avg2,avg1,avg3,avg1,avg2,avg1,avg4] ;sample in-1 avg1: adin pin_j1,in_j1_bfr.word1(in_j1_ptr) ;get in-1 into buffer let in_j1_tmp=in_j1_bfr(0)+in_j1_bfr(1) ;add two high words together and low words together let in_j1=(in_j1_tmp.word1+in_j1_tmp.word0)/4 let in_j1_ptr=(in_j1_ptr+1)&$03 ;increment pointer and wrap at 3 resume ;sample in-2 avg2: adin pin_j2,in_j2_bfr.word1(in_j2_ptr) ;get in-2 into buffer let in_j2_tmp=in_j2_bfr(0)+in_j2_bfr(1) ;add two high words together and low words together let in_j2=(in_j2_tmp.word1+in_j2_tmp.word0)/4 let in_j2_ptr=(in_j2_ptr+1)&$03 ;increment pointer and wrap at 3 resume ;sample in-3 avg3: adin pin_j3,in_j3_bfr.word1(in_j3_ptr) ;get in-3 into buffer let in_j3_tmp=in_j3_bfr(0)+in_j3_bfr(1) ;add two high words together and low words together let in_j3=(in_j3_tmp.word1+in_j3_tmp.word0)/4 let in_j3_ptr=(in_j3_ptr+1)&$03 ;increment pointer and wrap at 3 resume ;sample in-4 avg4: adin pin_j4,in_j4_bfr.word1(in_j4_ptr) ;get in-4 into buffer let in_j4_tmp=in_j4_bfr(0)+in_j4_bfr(1) ;add two high words together and low words together let in_j4=(in_j4_tmp.word1+in_j4_tmp.word0)/4 let in_j4_ptr=(in_j4_ptr+1)&$03 ;increment pointer and wrap at 3 resume #endif ; ;-----------------------------------------------------------------------------------------------; ; End of program ; ;-----------------------------------------------------------------------------------------------;