;-----------------------------------------------------------------------------------------------; ; Program: Trig-Gate-CV Delay ; ; 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 program delays in-1 (trigger), in-2 (gate), and in-3 (cv) ' by a variable amount defined by in-4. In-1 and in-2 are input ' logic levels with a threshold of 2.5 volts. In-3 is sampled ' on the falling transition (1 to 0) of the trigger. ' ' Out-1 and out-2 are logic levels of 5 volts. ' ' A simple timestamp compare will fail when time_count reaches ' maximum value which will occur at at 50 days (1 mS * 2^32) ' of continuous operation. ' ' inputs: ' start = active shift cv up one octave ' stop = active shift cv down one octave ' in-1 = trigger in (minimum pulse width 3 mS) ' in-2 = gate in ' in-3 = cv in (sampled on falling edge of trigger) ' in-4 = delay amount (3 mS to delay_factor S) ' midi-in = n/a ' ' outputs: ' out-1 = delayed trigger (0, 5 volts) ' out-2 = delayed gate (0, 5 volts) ' out-3 = delayed cv ' out-4 = 0 ' aux = 0 ' midi-out= n/a ' speakjet= voice output ' ' run led = toggles @ 0.5 S ' stop led = indicates high transition detected on trigger or gate in ' ' written by David J. Brown ' revision: 0.1S2 ' Sept 25, 2010 ' history: 0.1S2 added enable for Studio ' 0.1X changed shiftout for Studio, removed serial speakjet ; 0.1 added display of program name ' 0.0 initial code for trig-gate-cv delay program ' date: May 16, 2004 ' '########################################### ' ' ### CONDITIONAL COMPILING OPTION ### ' set MIDI INTERRUPT mode ' ' comment out next line for polled mode ; midi_int_en con 1 'define to enable midi-in interrupts ' comment to set polled midi-in mode ' '########################################### ' ' ### CONDITIONAL COMPILING OPTION ### ' set TIMER INTERRUPT mode ' note: Run led will blink if timer_int_en defined ' ' comment out next line to disable timer interrupts timer_int_en con 1 'define to enable timer interrupts ' comment to disable timer interrupts ' '########################################### ' 'djb template written by David J. Brown 'based on code from Brice Hornback and Grant Richter 'revision: 0.41 ' May 13, 2004 'history: 0.41 upper case conversion to lower, variables and ' labels renamed ' 0.4 added averaged input input driver (polled or ' interrupt mode), display_led driver (for debug), ' speakjet driver, renamed program to djb template ' 0.3 added program header information, modified ' pin initialization ' 0.2 initialize aux output low and speakjet pins ' 0.1 added DAC & led initialization, 1 mS timestamp, ' stop led blinks when midi data received, run ' led toggles @ 0.5 S for health indication ' 0.0 initial release of midi input & output program 'date: April 13, 2004 '******************************************* ' module: PSIM-1 REV1b ' processor Type: Basic Micro - Basic Atom Pro24M '******************************************* ' ' Basic Micro Atom Pro-24M Configuration ' ' P0 - in-1 ' P1 - in-2 ' P2 - in-3 ' P3 - in-4 ' P4 - start button (momentary normally open switch) ' P5 - stop button (momentary normally open switch) ' P6 - j3 pin 2 (speakjet buffer half full) ' P7 - j3 pin 1 (serial data to speakjet) ' P8 - aux digital I/O ' P9 - stop led ' P10 - run led ' P11 - load_dacs ' P12 - ser_data ' P13 - clock ' P14 - j5 pin 1 (midi-in) ' P15 - j5 pin 2 (midi-out) ' '******************************************* ' 'pin constants pin_j1 con 0 'in-1 pin pin_j2 con 1 'in-2 pin pin_j3 con 2 'in-3 pin pin_j4 con 3 'in-4 pin start_b con 4 'start button and jack stop_b con 5 'stop button and jack aux_j con 8 'aux jack stop_led con 9 'stop led (red) run_led con 10 'run led (green) load_dacs con 11 'load dac pin ser_data con 12 'serial data to dac pin clock con 13 'dac clock pin 'i/o variable 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 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 driver variable declarations midi_data var byte 'variable: check_midi, send_midi, get_rcx_bfr, send_note_on, send_note_off midi_data_isr var byte 'variable: midi_in_isr rcx_status var byte 'variable: check_midi, send_midi rcx_ptr_strt var byte 'received data start pointer (first data in buffer): get_rcx_bfr rcx_ptr_end var byte 'received data end pointer (last data in buffer+1): check_midi, midi_in_isr rcx_bfr_num var byte 'number of bytes in data buffer: check_midi, get_rcx_bfr, midi_in_isr rcx_data_flg var bit 'received data flag (1=data, 0=no data): get_rcx_bfr rcx_bfr_len con 8 'midi-in buffer length: rcx_bfr rcx_bfr var byte(rcx_bfr_len) 'midi-in data buffer: check_midi, get_rcx_bfr, midi_in_isr 'timer variable declarations #ifdef timer_int_en time_count var long 'timer count value: tm_isr #endif 'input variable declarations in_jx_ptr var byte 'in-x buffer pointer: get_inputs_avg in_j1_tmp var long 'in-1 temporary variable: get_inputs_avg in_j2_tmp var long 'in-2 temporary variable: get_inputs_avg in_j3_tmp var long 'in-3 temporary variable: get_inputs_avg in_j4_tmp var long 'in-4 temporary variable: get_inputs_avg in_j1_bfr var long(2) 'in-1 last 4 samples buffer: get_inputs_avg in_j2_bfr var long(2) 'in-2 last 4 samples buffer: get_inputs_avg in_j3_bfr var long(2) 'in-3 last 4 samples buffer: get_inputs_avg in_j4_bfr var long(2) 'in-4 last 4 samples buffer: get_inputs_avg 'lcd variable declarations idx var byte 'message index lcd_msg bytetable $f0,$7d,$0a,$18,"Trig-GateCV Delay",$f7 'misc variable declarations led_data var byte 'variable: display_led 'delay variable declarations delay_val var word 'number of timer clocks to delay: trig_look_x, gate_look_x tmr_bfr_len con 128 'transition buffer length: trig_look_x, gate_look_x tmr_bfr var long(tmr_bfr_len) 'transition timestamp buffer: trig_look_x, gate_look_x, tm_isr val_bfr var word(tmr_bfr_len) 'trigger and gate output buffer: trig_look_x, gate_look_x, tm_isr cv_bfr var word(tmr_bfr_len) 'cv output buffer: trig_look_0, tm_isr tmr_bfr_num var byte 'number of entries in buffer: tm_isr tmr_ptr_strt var byte 'timestamp start pointer (first data in buffer): tm_isr tmr_ptr_end var byte 'timestamp end pointer (last data in buffer+1): trig_look_x, gate_look_x, tm_isr next_time var long 'next timestamp to find: tm_isr check_it var bit 'flag to check timestamp: tm_isr trig_dir var bit 'trigger transition flag 0=looking low, 1=looking hi: trig_look_x, gate_look_x gate_dir var bit 'gate transition flag 0=looking low, 1=looking hi: trig_look_x, gate_look_x delay_factor con 3 'delay scale factor in seconds (1 to 10) ' '******************************************* ' '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 midi hardware 'these next 6 commands need to be in this order! let scr3=%00000000 'reset Serial Control Register let smr=%00000000 'set Serial Mode Register ' asynchronous ' 8 bits ' parity disabled ' even parity (disabled) ' 1 stop bit ' multiprocessor mode disabled ' brr clock source direct let brr=15 'set Bit Rate Register for 31500 baud pauseus 100 'let brr settle for 50 uS let scr3=%00110000 'set Serial Control Register ' transmit or receive interrupts disabled ' transmit and receive enabled ' multiprocessor interrupt disabled ' transmit end interrupt disabled ' internal baud rate generator let pmr1=%00001110 'set Port Mode Register ' P17 general I/O port ' P16 general I/O port ' P15 general I/O port ' P14 general I/O port ' txd output ' P10 general I/O port ' #ifdef timer_int_en 'initialize timer hardware for 10 mS interrupts let tmrw=%10001000 'set Timer Mode Register to enable count let tcrw=%10110000 'set Timer Control Register ' TCNT cleared by compare match ' /8 internal clock let tierw=%01110000 'set Timer Interrupt register to disable overflow interrupt let tsrw=%01110000 'set Timer Status Register to default let tior0=%10001000 'set Timer I/O Regiseter 0 to default let tior1=%10001000 'set Timer I/O Register 1 to default let gra=2000 'set General Register A ' 16 MHz clock /8 = 2 MHz ' 2000 counts = 1 mS interrupt #endif ' 'initialize misc variables let rcx_ptr_strt=0 'set receive start pointer let rcx_ptr_end=0 'set receive end pointer let rcx_bfr_num=0 'set receive buffer to empty 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 led_data=0 'set led data to 0 let in_jx_ptr=0 'set in-x pointer to 0 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 let tmr_ptr_strt=0 'set buffer to empty let tmr_ptr_end=0 let tmr_bfr_num=0 let check_it=0 'set check_it flag false let trig_dir=1 'start by looking for hi transitions let gate_dir=1 ' 'display program name idx=0 do midi_data=lcd_msg(idx) gosub send_midi let idx=idx+1 while midi_data<>$f7 ' 'enable timer interrupts #ifdef timer_int_en let time_count=0 'set real time counter to 0 oninterrupt timerwint_imiea, tm_isr enable timerwint_imiea 'enable timer interrupt #endif ' 'enable midi interrupts #ifdef midi_int_en oninterrupt sci3int_rdrf, midi_in_isr enable sci3int_rdrf 'enable midi-in interrupt #endif ' enable 'added for Studio ' check_trig: adin pin_j1, in_j1 'get in-1 adin pin_j4, in_j4 'get in-4 let in_j4=in_j4*delay_factor 'scale appropriately if trig_dir=0 then trig_look_0 trig_look_1: if in_j1<255 then check_gate 'look for hi transition on trigger 'got a hi transition let delay_val=in_j4 disable timerwint_imiea 'put time value into timer buffer 'check to see if buffer full if tmr_bfr_num=tmr_bfr_len then 'buffer is full 'simply loose transition else 'buffer has space let tmr_bfr(tmr_ptr_end)=time_count+delay_val let val_bfr(tmr_ptr_end)=$7ff 'set hi transition high stop_led let tmr_bfr_num=tmr_bfr_num+1 let tmr_ptr_end=tmr_ptr_end+1 if tmr_ptr_end=tmr_bfr_len then tmr_ptr_end=0 'wrap pointer at max value endif endif enable timerwint_imiea trig_dir=0 goto check_gate ' trig_look_0: if in_j1>256 then check_gate 'look for low transition on trigger 'got a low transition let delay_val=in_j4 disable timerwint_imiea 'put time value into timer buffer 'check to see if buffer full if tmr_bfr_num=tmr_bfr_len then 'buffer is full 'simply loose transition else 'buffer has space let tmr_bfr(tmr_ptr_end)=time_count+delay_val let val_bfr(tmr_ptr_end)=0 'set low transition adin pin_j3, in_j3 'get cv let in_j3=in_j3+4 'round up some before quantizing 'scale by 2/17 quantizes 'scale by 32 for output 'start shifts up an octave 'stop shifts down an octave let cv_bfr(tmr_ptr_end)=(((in_j3*2)/17)*32)+(in4*384)-(in5*384) low stop_led let tmr_bfr_num=tmr_bfr_num+1 let tmr_ptr_end=tmr_ptr_end+1 if tmr_ptr_end=tmr_bfr_len then tmr_ptr_end=0 'wrap pointer at max value endif endif enable timerwint_imiea trig_dir=1 goto check_gate ' check_gate: shiftout ser_data,clock,fastmsbpre,[(out_j1+49152)\16] pulsout load_dacs,1 'pulse loaddacs for each channel shiftout ser_data,clock,fastmsbpre,[(out_j2+32768)\16] pulsout load_dacs,1 'pulse loaddacs for each channel shiftout ser_data,clock,fastmsbpre,[(out_j3+16384)\16] pulsout load_dacs,1 'pulse loaddacs for each channel shiftout ser_data,clock,fastmsbpre,[0] pulsout load_dacs,1 'pulse loaddacs for each channel adin pin_j2, in_j2 'get in-2 adin pin_j4, in_j4 'get in-4 let in_j4=in_j4*delay_factor 'scale appropriately if gate_dir=0 then gate_look_0 gate_look_1: if in_j2<255 then check_trig 'look for hi transition on gate 'got a hi transition let delay_val=in_j4 disable timerwint_imiea 'put time value into timer buffer 'check to see if buffer full if tmr_bfr_num=tmr_bfr_len then 'buffer is full 'simply loose transition else 'buffer has space let tmr_bfr(tmr_ptr_end)=time_count+delay_val let val_bfr(tmr_ptr_end)=$87ff 'set low transition - bit15 indicates gate high stop_led let tmr_bfr_num=tmr_bfr_num+1 let tmr_ptr_end=tmr_ptr_end+1 if tmr_ptr_end=tmr_bfr_len then tmr_ptr_end=0 'wrap pointer at max value endif endif enable timerwint_imiea gate_dir=0 goto check_trig ' gate_look_0: if in_j2>256 then check_trig 'look for low transition on gate 'got a low transition let delay_val=in_j4 disable timerwint_imiea 'put time value into timer buffer 'check to see if buffer full if tmr_bfr_num=tmr_bfr_len then 'buffer is full 'simply loose transition else 'buffer has space let tmr_bfr(tmr_ptr_end)=time_count+delay_val let val_bfr(tmr_ptr_end)=$8000 'set low transition - bit15 indicates gate low stop_led let tmr_bfr_num=tmr_bfr_num+1 let tmr_ptr_end=tmr_ptr_end+1 if tmr_ptr_end=tmr_bfr_len then tmr_ptr_end=0 'wrap pointer at max value endif endif enable timerwint_imiea gate_dir=1 goto check_trig ' '******************************************* ' subroutines '******************************************* ' #ifndef midi_int_en 'poll midi-in 'puts data into buffer and sets rcx_bfr_num to number of entries 'written by David J. Brown check_midi: let rcx_status=ssr if rcx_status&%01000000 then 'data has been received let midi_data=rdr 'read Receiver Data Register if midi_data<>$FE then 'ignore if active status 'put midi_data into receive buffer 'check to see if buffer full if rcx_bfr_num=rcx_bfr_len then 'buffer is full 'simply loose data else 'buffer has space let rcx_bfr(rcx_ptr_end)=midi_data let rcx_bfr_num=rcx_bfr_num+1 let rcx_ptr_end=rcx_ptr_end+1 if rcx_ptr_end=rcx_bfr_len then rcx_ptr_end=0 'wrap pointer at max value endif endif endif else 'no data received 'check if error if rcx_status&%00111000 then 'error condition let rcx_status=rcx_status&%10000111 let ssr=rcx_status 'reset error bits endif endif return #endif ' 'gets midi_data from buffer 'rcx_data_flg=1 if successful, rcx_data_flg=0 if no data in buffer 'written by David J. Brown get_rcx_bfr: #ifdef midi_int_en disable sci3int_rdrf 'isr uses the same variables #endif 'check to see if buffer empty if rcx_bfr_num=0 then 'buffer is empty rcx_data_flg=0 'set empty flag else 'buffer has data let midi_data=rcx_bfr(rcx_ptr_strt) let rcx_bfr_num=rcx_bfr_num-1 let rcx_ptr_strt=rcx_ptr_strt+1 if rcx_ptr_strt=rcx_bfr_len then let rcx_ptr_strt=0 'wrap pointer at max value endif let rcx_data_flg=1 'set data returned flag endif #ifdef midi_int_en enable sci3int_rdrf #endif return ' 'output 3 byte midi note-on command send_note_on: let midi_data=note_on+midi_chan gosub send_midi let midi_data=midi_note gosub send_midi let midi_data=midi_vel gosub send_midi return ' 'output 3 byte midi note-off command send_note_off: let midi_data=note_off+midi_chan gosub send_midi let midi_data=midi_note gosub send_midi let midi_data=midi_vel gosub send_midi return ' 'subroutine to send midi_data 'waits until transmitter ready send_midi: let rcx_status=ssr if rcx_status&%10000000 then 'check transmitter ready 'ready to transmit let tdr=midi_data 'send data to tdr return endif goto send_midi ' #ifndef input_int_en 'sample in-1 to in-4 'injx 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 'injx is input value averaged over last four samples (0 - 1023) 'injx_bfr(0) & injx_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_jx_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_jx_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_jx_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_jx_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_jx_ptr=(in_jx_ptr+1)&$03 'increment pointer and wrap at 3 return #endif ' 'routine to display led_data to out leds 'note: sets outjx values to 0 'written by David J. Brown display_led: let out_j1=0 'output high nibble of data let out_j2=0 let out_j3=0 let out_j4=0 let out_j1.bit11=led_data.bit7 'sets output value to 2048 if bit is 1 let out_j2.bit11=led_data.bit6 let out_j3.bit11=led_data.bit5 let out_j4.bit11=led_data.bit4 gosub load_outputs pause 750 'display high nibble let out_j1.bit11=led_data.bit3 'output low nibble of data let out_j2.bit11=led_data.bit2 let out_j3.bit11=led_data.bit1 let out_j4.bit11=led_data.bit0 gosub load_outputs pause 750 'display low nibble let out_j4=0 let out_j3=0 let out_j2=0 let out_j1=0 gosub load_outputs 'turn all leds off return ' 'output outjx values to dacs 'based on code written by Grant Richter '750 uS execution time load_outputs: 'add addresses to values 'shift out 16 bits mode 4 shiftout ser_data,clock,fastmsbpre,[(out_j1+49152)\16] pulsout load_dacs,1 'pulse loaddacs for each channel shiftout ser_data,clock,fastmsbpre,[(out_j2+32768)\16] pulsout load_dacs,1 'pulse loaddacs for each channel shiftout ser_data,clock,fastmsbpre,[(out_j3+16384)\16] pulsout load_dacs,1 'pulse loaddacs for each channel shiftout ser_data,clock,fastmsbpre,[out_j4\16] pulsout load_dacs,1 'pulse loaddacs for each channel return ' '******************************************* 'interrupt service routines '******************************************* ' #ifdef timer_int_en 'interrupt service routine for timer 'increments time_count 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 out10=time_count.bit9 'toggle run led if check_it=1 then have_time if tmr_bfr_num<>0 then 'buffer has data let check_it=1 'have transition let next_time=tmr_bfr(tmr_ptr_strt) let tmr_bfr_num=tmr_bfr_num-1 endif if check_it=0 then skip_compare have_time: if time_count>next_time then 'time for transition if val_bfr(tmr_ptr_strt).bit15=1 then 'out-2 gate let out_j2=val_bfr(tmr_ptr_strt)&$7FFF else 'out-1 trigger let out_j1=val_bfr(tmr_ptr_strt) if out_j1=0 then 'it is trailing edge of trigger so also output cv let out_j3=cv_bfr(tmr_ptr_strt) endif endif let tmr_ptr_strt=tmr_ptr_strt+1 if tmr_ptr_strt=tmr_bfr_len then let tmr_ptr_strt=0 'wrap pointer at max value endif let check_it=0 'assume no more transitions endif skip_compare: resume #endif ' #ifdef midi_int_en 'interrupt service routine for midi-in data 'puts data into buffer and sets rcx_bfr_num to number of entries 'priority given to midi-in over timer interrupts 'written by David J. Brown midi_in_isr: 'read Receiver Data Register must be first instruction to clear interrupt let midi_data_isr=rdr 'read Receiver Data Register disable timerwint_imiea 'disable timer interrupts if midi_data_isr<>$fe then 'ignore if active status 'check to see if buffer full if rcx_bfr_num=rcx_bfr_len then 'buffer is full 'simply loose data else 'put data into buffer let rcx_bfr(rcx_ptr_end)=midi_data_isr let rcx_bfr_num=rcx_bfr_num+1 'set rcx_bfr_num to number of entries let rcx_ptr_end=rcx_ptr_end+1 'increment pointer for next entry if rcx_ptr_end=rcx_bfr_len then rcx_ptr_end=0 'wrap pointer at max value endif endif endif enable timerwint_imiea resume #endif ' '******************************************* 'end of program '*******************************************