' ******************************************************************** ' * PIC firmware for * ' * damper solenoids * ' * coded by dr.Godfried-Willem Raes * ' * http://www.logosfoundation.org/instrum_gwr/tubo/picworks * ' * source code development directory: * ' * Tubo_damp6691.bas * ' * version 1.0 * ' ******************************************************************** ' 10.09.2019: Starting of from the code for Melauton, as the same PCB is used here. ' first needed to adapt coding to new compiler! (cfr. hex-lpt driver coding) ' First sketch compiles o.k. to be tested... ' Curious to know the loopspeed now, with so many timers... ' To test this, we first need testcode in GMT ' 16.09.2019: If the timer sorting turns out too slow, we can go back to the coding ' used for rodo. In that case we need Velflags again. ' If the damp time would be a constant, we would need no sorting at all, ' as time timers would always be in the same order. ' If it's a variable, there can be problems if the value changes whilst timers ' are still active. ' Klung also uses 28 output boards, so that's also a good and tested example ' 22.09.2019: First test on the board, using the priority timers and 18 tasks. ' we do not get midi-in to work anymore... ' IRQ coding copied from Balsi-hub (where it works...) ' still midi-in not working here... ' 24.09.2019: we krijgen de midi interrupt maar niet aan de praat... ' back to the working IRQ code as used for the hub. ' still not working... ' Found: adding a single HRSOut command made it all work... ' Ctrl 25 implemented ' Ctrl 64 (sustain ON/OFF) implemented ' The durations of the damper pulses are now 35ms to 250ms ' After full testing on the development board with LED's, this version ' flashed on the damper board. ' 25.09.2019: The alternative version, now named _000 also works fine now. ' Board completed with a full set of IRLS34BPBF Mosfets. ' 26.09.2019: dampers flags added ' to do: limit polyphony to 4 or 5 notes... ' to know how many dampers are active, we can count the bits set in dampers. ' 28.09.2019: First test with the PCB and the damper assembly. ' It works but we need to work on the scaling and, maybe, reduce the trajectory mechanically ' to improve response speed on the side of the solenoids. ' 04.11.2019: Starting from the preliminary code for Damp4865, adapting to 6691 here. ' nrd, counter for the number of active dampers, added. ' metacompile instructions added for evaluation of loopcountversion versus timer0 version. ' The versions lead to different scalings for the velocities! ' The timer0 version runs about 10% faster but resolution is lower. ' If the coils draw 300mA, and the power supply can deliver 12A, we can safely have 40 coils active. ' In this case we do not need to limit the number of active dampers. ' If the coils draw more than 460mA, we need the dmax limit. ' 05.11.2019: The range for velo's in the counter-compilation is now 26ms to 220ms. ' 06.11.2019: Compiler upgraded to version 3.7.3.1, Proton24 to 1.0.6.4 ' 14.11.2019: As we now have three different kinds of solenoids, we need to implement the same amount ' of different lookup-tables as well. (Tremba[], Ledex[], Black[] ' Also, we do need dmax! ' Implemented now, but we need to check the ranges and the value for dMax ' A more elegant solution would be to measure the current drawn using one of the AD inputs... ' 26.11.2019: First test with all solenoids connected. ' oscillation observed on first start-up (Red LED flashing fast...) ' 27.11.2019: Scaling tests. First attempt to rescaling. ' The scaling appears to be extremely dependent on the allignment of the solenoids. ' Irregularities observed in the pulse lengths... ' 03.12.2019: Lookups changed for center values at 64 ' 10.12.2019: Implementation for ctrl 123 remmed out, such that on allnotes off, sounding notes will ' still be damped, unless sustain is on of course. ' Changed such that sounding notes will be damped, with limitations for the amount of active dampers. Include "18F4620.inc" ' (40MHz) ' Mapping defines for midi-events on pin outputs and inputs: ' This is very specific for the 26 output board 2019 ' mapping: $define Damp66 PORTA.0 $define Damp67 PORTA.1 $define Damp68 PORTA.2 $define Damp69 PORTA.3 $define Damp70 PORTA.4 $define Damp71 PORTA.5 $define Damp72 PORTE.0 ' - pin8 $define Damp73 PORTE.1 $define Damp74 PORTE.2 $define Damp75 PORTC.0 $define Damp76 PORTC.1 $define Damp77 PORTC.2 $define Damp78 PORTC.3 $define Damp79 PORTD.0 $define Damp80 PORTD.1 ' pin 20 $define Damp81 PORTD.7 $define Damp82 PORTD.6 $define Damp83 PORTD.5 $define Damp84 PORTD.4 $define Damp85 PORTC.5 $define Damp86 PORTC.4 $define Damp87 PORTD.3 $define Damp88 PORTD.2 $define Damp89 PORTB.0 $define Damp90 PORTB.1 $define Damp91 PORTB.2 $define Loopspeed PORTB.4 ' for loopspeed measurement 'red LED for debug: $define Debug_Led PORTB.3 ' for testing - red led - watchdog - activated in IRQ code. ' metacompiler constants: (only one of these should be defined) '$define loopcountversion ' compiles a version using the loopcounter - this has more jitter. $define counterversion ' compiles a version using timer0 as a 32 bit timer . This is stable now. Declare All_Digital = True ' makes all analog pins, digital for I/O Clear SSPCON1.5 ' make sure RC3 is free for use. ' configure the input and output pins: TRISA = %11000000 'bits set to 0 are output, 1 = input - bits 6 and 7 are the clock! TRISB = %11100000 'bits 6 and 7 are for the ICP, bit 5 is the red LED TRISC = %11000000 'RC6 en RC7 zijn USART I/O and must be set to input TRISD = %00000000 'all bits can be used TRISE = %11101000 'low nibble only, bit3 (RE3) is MCLR 'bit 4 must be zero to disable PSP mode on port D - gwr 20.01.2012 'this was the bug we had! 'constant definitions: ' midi-mappings: Symbol Lowtes = 66 ' tubo - high side Symbol Hightes = 91 ' for his board 'initialisations for the midi input parser: Symbol Midichannel = 4 ' Tubo_Channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel Symbol Control_Status = 176 + Midichannel Symbol ProgChange_Status = 192 + Midichannel ' 1 byte message Symbol Aftertouch_Status = 208 + Midichannel ' 1 byte follows Symbol Pitchbend_Status = 224 + Midichannel ' lsb msb follow Symbol NrTasks = 26 Symbol LastTask = NrTasks - 1 Symbol dMax = 12 ' maximum number of simultaneous active dampers ' Setup the USART Declare Hserial_Baud = 31250 ' Set baud rate for the USART to MIDI specs. Declare Hserial_TXSTA = 0x24 ' instead of the normal 0x20 - ?? 0x24 'Declare Hserial_Clear = On ' should clear on errors. Bytes get lost of course... ' switched on 22.09.2019 ' Create variables: Dim Cnt As Dword System '32 bit counter Dim CntHw As Cnt.Word1 ' Word System 'used in the timer0 interrupt, where it is incremented Dim CntLw As TMR0L.Word 'this is the trick to read both TMR0L and TMR0H 'it makes Cntlw the low word of cnt, when we use cnt.word0=CntLw Dim Cnt3 As Dword System Dim Cnt3Hw As Cnt3.Word1 Dim Tim3 As TMR3L.Word ' same trick for timer3 Dim Bytein As Byte System ' midi byte read from buffer Dim StBit As Bytein.7 ' highest bit of ByteIn Dim i As Byte System ' general purpose counter Dim Nxt As Dword System Dim idx As Byte System $ifdef loopcountversion Dim time As Dword System ' 32-bit, incremented in loopcounter Dim t As Byte System ' loopcounter, running at 4 times time-clock Dim tog As Byte System Dim tg As tog.0 ' divide by 4 bit $endif $ifdef counterversion ' if we use the timer0 version, we better do this: Dim time As Cnt $endif Dim maxtim As time.31 ' overflow bit, will cause timer reset after 1h45 ' Dim Sr as TMR0L.7 '512 S/s - this works but these DO NOT WORK!!!: ' Dim Sr as CntLw.Byte1 does not ' Dim Sr As TMR0H.0 'sampling rate bit, 256 S/s ' DIM Sr as CntLw.8 ' As TMR0H.1 would be 128 S/s ' As TMR0H.2 would be 64 S/s ' As TMR0H.3 would be 32 S/s ' As TMR0H.4 would be 16 S/s ' Dim b As Byte ' midi variables Dim statusbyte As Byte System Dim noteUit As Byte System ' note off + release value Dim release As Byte System Dim noteAan As Byte System ' note on + release value Dim velo As Byte System Dim notePres As Byte System ' note pressure + pressure value Dim pres As Byte System Dim Ctrl As Byte System ' continuous controller + value Dim value As Byte System Dim prog As Byte System ' program change + program-byte Dim aft As Byte System ' channel aftertouch Dim pblsb As Byte System ' pitch bend lsb Dim pbmsb As Byte System ' pitch bend msb Dim CC66 As Byte System ' global on/off switch Dim PowerOn As CC66.0 Dim TimVals[NrTasks] As Dword Dim Resort As Byte System Dim Resort_flag As Resort.0 ' flag to signal the requirement to resort timers Dim Tremba[128] As Word ' for valve holdtime - Tremba 12V valves (notes 66-71) Dim Ledex[128] As Word ' for the 4 Lucas-Ledex valves (notes 72-75) Dim Black[128] As Word ' for the Black Knight solenoid valves. (notes 76-91) Dim Tremba_duur As Word System ' cc25 - damping time - Tremba Dim Ledex_duur As Word System Dim Black_duur As Word System Dim sustain As Byte System ' cc64 - sustain switch Dim dampers As Dword ' bits used as flags for active dampers 16 bit is not enough here! Dim notes As Dword ' note-on flags Dim nrd As Byte ' number of active dampers ' Dim dMax As Byte ' upperlimit for amount of active dampers allowed ' value depends on capabilities of 12V power supply. ' changed to symbol (constant) Dim tmp As Float ' for calculation of lookup tables Dim stap As Float '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler and buffer read subroutines into memory Dim Ringbuffer[256] As Byte ' Array for holding received midi messages Include "Tubo_Damp_Irq.inc" '"Tubo_damp4865_Irq.inc" ' for UART, Timer0, Timer3 Interrupt 'Clear ' clear all RAM '----------------------------------------------------------------------------------------- ' Main program starts here MAIN: High Debug_Led DelayMS 10 ' wait for stability Low Debug_Led Low Damp66 Low Damp67 Low Damp68 Low Damp69 Low Damp70 Low Damp71 Low Damp72 Low Damp73 Low Damp74 Low Damp75 Low Damp76 Low Damp77 Low Damp78 Low Damp79 Low Damp80 Low Damp81 Low Damp82 Low Damp83 Low Damp84 Low Damp85 Low Damp86 Low Damp87 Low Damp88 Low Damp89 Low Damp90 Low Damp91 GoSub Dur_Lookup ' read lookup tables Set idx Set TimVals Clear CC66 Clear sustain ' controller 64 Clear nrd Clear notes Clear dampers Tremba_duur = Tremba[64] ' for the Tremba solenoids Ledex_duur = Ledex[64] ' for Lucas_Ledex Black_duur = Black[64] ' for Black Knight ' so default setting for CC25 becomes 64 Init_Usart_Interrupt ' Initiate the USART serial buffer interrupt ' this procedure is in the include file Clear_Serial_Buffer ' Clear the serial buffer and reset its pointers ' in the include as well ' Configure Timer0 for: ' Clear TMR0L and TMR0H registers ' Interrupt on Timer0 overflow ' 16-bit operation ' Internal clock source 40MHz ' 1:256 Prescaler : thus 40MHz / 256 = 156.250kHz ' 6.4 us per clock-tick ' Opentimer0 (Timer_INT_On & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256) ' replacing above macro with in-line coding: Clear T1CON Clear IntConBits_T0IF ' clear interrupt flag Set INTCONBITS_T0IE ' enable interrupt on overflow T0CON = %10000111 ' bit 7 = enable/disable ' bit 6 = 1=8 bot, 0=16 bit ' bit 5 = 1 pin input, 0= Internal Clk0 ' bit 4 = HL or LH transition when bit5 =1 ' bit 3 = 1= bypass prescaler, 0= input from prescaler ' bit 2-0 = prescaler select: 111= 1:256 ' Setup the High priorities for the interrupts ' TIMER1: if enabled, all midi-in is blocked, so it must interfere with the UART ' Configure Timer1 for: ' Clear TMR1L and TMR1H registers ' Interrupt on Timer1 overflow ' 16-bit read/write mode ' Internal clock source ' 1:8 Prescaler ' ' OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8) ' dit kompileert o.k. ' TIMER2: if enabled, the UART stops working... ' Opentimer2 (Timer_Int_On & T2_POST_1_16 & T2_PS_1_16) ' dit lukt... maar de timer is nodig voor de UART... ' TIMER3: ' Configure Timer3 for: ' Interrupt on Timer3 overflow ' 16-bit read/write mode ' Internal clock source ' 1:8 Prescaler ' Don’t sync external clock input ' doing it this way seems to work: Clear T3CON Clear PIR2BITS_TMR3IF ' clear IRQ flag Set PIE2BITS_TMR3IE ' irq on 'T3_OSC1En_On () ' macro - sets T3CON Clear Tim3 ' Clear TMR3L And TMR3H registers Set RCONbits_IPEN ' Enable priority interrupts Clear IPR2bits_TMR3IP ' Set Timer3 as a low priority interrupt source ' we can also set T3Con in one instruction as: T3CON = %10110001 ' oef, now it works... ' bit 7 = 16 bit mode ' bit 6,3 = 0, 0 ' bit 5,4 = 1:8 prescale ' bit 2 = 0 ' bit 1 = 0 Internal clock = Fosc/4 ' bit 0 : 1= enable timer 3, 0= disable ' maximum count = 52.42ms, 1 tick =0.8uS, freq.=19Hz ' Set up priority interrupts. ' IPR1bits_TMR1IP = 0 ' Set Timer1 as a low priority interrupt source ' INTCONbits_PEIE = 1 ' Enable peripheral interrupts ' INTCONbits_GIE = 1 ' Enable global interrupts ' Open the ADC: ' not used on this board. ' Fosc/32 ' Right justified for 10-bit operation ' Tad value of 0 ' Vref+ at Vcc : Vref- at Gnd ' Make AN0 an analogue input ' OpenADC(ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_0_TAD, ADC_REF_VDD_VSS, ADC_1ANA) ' Set PIE1bits_RCIE ' disable/enable interrupt for USART receive HRSOut Ctrl, 66, 64 ' adding this dummy made the whole program work... ' we have no explanation for this behavior. ' start the main program loop: ' Create an infinite loop Do $ifdef loopcountversion 'looptimer version: [04.11.2019: onbelast 109.8Khz, belast 91.4KHz] Inc t ' byte If t.1 = tg Then Btg tg Inc time ' dword EndIf $endif $ifdef counterversion 'timer0 version: [04.11.2019: onbelast 128kHz, belast 99 kHz] Cnt.Word0 = CntLw ' read timer 0 'time = Cnt ' make copy (dword!) ' we avoid this by declaring time as an alias for Cnt $endif ' we cannot create functions returning values in Proton... GetMidiIn () ' this function is defined in _irq.inc Bytein = MidiIn ' we cannot use MidiIn directly, as it is changed in the IRQ ' Start the midi parser. Midi_Parse: If Bytein > Control_Status Then ' here higher statusses are not implemented. If Bytein > 253 Then '254 = midiclock, 255= reset 'midiclock can interrupt all other msg's... '255 had to be intercepted since thats what we 'get when no new byte flows in. Else Clear statusbyte 'reset the status byte End If GoTo Check_Timers 'throw away... EndIf If StBit =1 Then 'should be faster than If Bytein > 127 Then 'status byte received, bit 7 is set Clear statusbyte 'if on another channel, the statusbyte needs a reset Select Bytein 'eqv to Select case ByteIn Case NoteOff_Status statusbyte = Bytein Set noteUit 'reset value. Cannot be 0 !!! Set release '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan '= 255 Set velo '= 255 Case Keypres_Status 'not used here statusbyte = Bytein notePres = 255 pres = 255 Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status statusbyte = Bytein prog = 255 Case Aftertouch_Status statusbyte = Bytein Set aft Case Pitchbend_Status ' not on this board. statusbyte = Bytein pblsb = 255 pbmsb = 255 End Select Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Check_Timers 'disregard Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein ' message complete, so we can do the action... If sustain = 0 Then ' bij sustain = 1 dempen we helemaal niet! If nrd < dMax Then ' we do limit current drawn..., the number of active coils is counted in the sort-procedure Select noteUit Case 66 ' schakel demper aan en start timer: Set Damp66 TimVals[0] = time + Tremba[release] Set Resort_flag Set dampers.0 Clear notes.0 Case 67 Set Damp67 TimVals[1] = time + Tremba[release] Set Resort_flag Set dampers.1 Clear notes.1 Case 68 Set Damp68 TimVals[2] = time + Tremba[release] Set Resort_flag Set dampers.2 Clear notes.2 Case 69 Set Damp69 TimVals[3] = time + Tremba[release] Set Resort_flag Set dampers.3 Clear notes.3 Case 70 Set Damp70 TimVals[4] = time + Tremba[release] Set Resort_flag Set dampers.4 Clear notes.4 Case 71 Set Damp71 TimVals[5] = time + Tremba[release] Set Resort_flag Set dampers.5 Clear notes.5 Case 72 Set Damp72 TimVals[6] = time + Tremba[release] Set Resort_flag Set dampers.6 Clear notes.6 Case 73 Set Damp73 TimVals[7] = time + Tremba[release] Set Resort_flag Set dampers.7 Clear notes.7 Case 74 Set Damp74 TimVals[8] = time + Tremba[release] Set Resort_flag Set dampers.8 Clear notes.8 Case 75 Set Damp75 TimVals[9] = time + Tremba[release] Set Resort_flag Set dampers.9 Clear notes.9 Case 76 Set Damp76 TimVals[10] = time + Tremba[release] Set Resort_flag Set dampers.10 Clear notes.10 Case 77 Set Damp77 TimVals[11] = time + Tremba[release] Set Resort_flag Set dampers.11 Clear notes.11 Case 78 ' Lucas Ledex solenoid Set Damp78 TimVals[12] = time + Ledex[release] Set Resort_flag Set dampers.12 Clear notes.12 Case 79 Set Damp79 TimVals[13] = time + Ledex[release] Set Resort_flag Set dampers.13 Clear notes.13 Case 80 Set Damp80 TimVals[14] = time + Ledex[release] Set Resort_flag Set dampers.14 Clear notes.14 Case 81 Set Damp81 TimVals[15] = time + Ledex[release] Set Resort_flag Set dampers.15 Clear notes.15 Case 82 ' Black Knight solenoids from here on Set Damp82 TimVals[16] = time + Black[release] Set Resort_flag Set dampers.16 Clear notes.16 Case 83 Set Damp83 TimVals[17] = time + Black[release] Set Resort_flag Set dampers.17 Clear notes.17 Case 84 Set Damp84 TimVals[18] = time + Black[release] Set Resort_flag Set dampers.18 Clear notes.18 Case 85 Set Damp85 TimVals[19] = time + Black[release] Set Resort_flag Set dampers.19 Clear notes.19 Case 86 Set Damp86 TimVals[20] = time + Black[release] Set Resort_flag Set dampers.20 Clear notes.20 Case 87 Set Damp87 TimVals[21] = time + Black[release] Set Resort_flag Set dampers.21 Clear notes.21 Case 88 Set Damp88 TimVals[22] = time + Black[release] Set Resort_flag Set dampers.22 Clear notes.22 Case 89 Set Damp89 TimVals[23] = time + Black[release] Set Resort_flag Set dampers.23 Clear notes.23 Case 90 Set Damp90 TimVals[24] = time + Black[release] Set Resort_flag Set dampers.24 Clear notes.24 Case 91 Set Damp91 TimVals[25] = time + Black[release] Set Resort_flag Set dampers.25 Clear notes.25 End Select EndIf EndIf Set noteUit 'reset EndIf 'GoTo Check_Timers Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then ' note off If sustain = 0 Then ' bij sustain 1 gebeurt helemaal niets If nrd < dMax Then ' stroombegrenzing Select noteAan Case 66 ' schakel demper aan en start timer: - Tremba solenoids Set Damp66 TimVals[0] = time + Tremba_duur ' Tremba Set Resort_flag Set dampers.0 Clear notes.0 Case 67 Set Damp67 TimVals[1] = time + Tremba_duur Set Resort_flag Set dampers.1 Clear notes.1 Case 68 Set Damp68 TimVals[2] = time + Tremba_duur Set Resort_flag Set dampers.2 Clear notes.2 Case 69 Set Damp69 TimVals[3] = time + Tremba_duur Set Resort_flag Set dampers.3 Clear notes.3 Case 70 Set Damp70 TimVals[4] = time + Tremba_duur Set Resort_flag Set dampers.4 Clear notes.4 Case 71 Set Damp71 TimVals[5] = time + Tremba_duur Set Resort_flag Set dampers.5 Clear notes.5 Case 72 Set Damp72 TimVals[6] = time + Tremba_duur Set Resort_flag Set dampers.6 Clear notes.6 Case 73 Set Damp73 TimVals[7] = time + Tremba_duur Set Resort_flag Set dampers.7 Clear notes.7 Case 74 Set Damp74 TimVals[8] = time + Tremba_duur Set Resort_flag Set dampers.8 Clear notes.8 Case 75 Set Damp75 TimVals[9] = time + Tremba_duur Set Resort_flag Set dampers.9 Clear notes.9 Case 76 Set Damp76 TimVals[10] = time + Tremba_duur Set Resort_flag Set dampers.10 Clear notes.10 Case 77 Set Damp77 TimVals[11] = time + Tremba_duur Set Resort_flag Set dampers.11 Clear notes.11 Case 78 ' Lucas-Ledex solenoids Set Damp78 TimVals[12] = time + Ledex_duur Set Resort_flag Set dampers.12 Clear notes.12 Case 79 Set Damp79 TimVals[13] = time + Ledex_duur Set Resort_flag Set dampers.13 Clear notes.13 Case 80 Set Damp80 TimVals[14] = time + Ledex_duur Set Resort_flag Set dampers.14 Clear notes.14 Case 81 Set Damp81 TimVals[15] = time + Ledex_duur Set Resort_flag Set dampers.15 Clear notes.15 Case 82 ' Black-Knight Set Damp82 TimVals[16] = time + Black_duur Set Resort_flag Set dampers.16 Clear notes.16 Case 83 Set Damp83 TimVals[17] = time + Black_duur Set Resort_flag Set dampers.17 Clear notes.17 Case 84 Set Damp84 TimVals[18] = time + Black_duur Set Resort_flag Set dampers.18 Clear notes.18 Case 85 Set Damp85 TimVals[19] = time + Black_duur Set Resort_flag Set dampers.19 Clear notes.19 Case 86 Set Damp86 TimVals[20] = time + Black_duur Set Resort_flag Set dampers.20 Clear notes.20 Case 87 Set Damp87 TimVals[21] = time + Black_duur Set Resort_flag Set dampers.21 Clear notes.21 Case 88 Set Damp88 TimVals[22] = time + Black_duur Set Resort_flag Set dampers.22 Clear notes.22 Case 89 Set Damp89 TimVals[23] = time + Black_duur Set Resort_flag Set dampers.23 Clear notes.23 Case 90 Set Damp90 TimVals[24] = time + Black_duur Set Resort_flag Set dampers.24 Clear notes.24 Case 91 Set Damp91 TimVals[25] = time + Black_duur Set Resort_flag Set dampers.25 Clear notes.25 End Select EndIf EndIf Else Select noteAan Case 66 ' coding, using the dampers flags: Clear Damp66 If dampers.0 = 1 Then ' there was a timer running Set TimVals[0] ' clear it Set Resort_flag Clear dampers.0 'Else ' Set TimVals[0] ' niet echt nodig. EndIf Set notes.0 Case 67 Clear Damp67 If dampers.1 = 1 Then ' there was a timer running Set TimVals[1] ' clear it Set Resort_flag Clear dampers.1 EndIf Set notes.1 Case 68 Clear Damp68 If dampers.2 = 1 Then Set TimVals[2] Set Resort_flag Clear dampers.2 EndIf Set notes.2 Case 69 Clear Damp69 If dampers.3 = 1 Then Set TimVals[3] Set Resort_flag Clear dampers.3 EndIf Set notes.3 Case 70 Clear Damp70 If dampers.4 = 1 Then Set TimVals[4] Set Resort_flag Clear dampers.4 EndIf Set notes.4 Case 71 Clear Damp71 If dampers.5 = 1 Then Set TimVals[5] Set Resort_flag Clear dampers.5 EndIf Set notes.5 Case 72 Clear Damp72 If dampers.6= 1 Then Set TimVals[6] Set Resort_flag Clear dampers.6 EndIf Set notes.6 Case 73 Clear Damp73 If dampers.7 = 1 Then Set TimVals[7] Set Resort_flag Clear dampers.7 EndIf Set notes.7 Case 74 Clear Damp74 If dampers.8 = 1 Then Set TimVals[8] Set Resort_flag Clear dampers.8 EndIf Set notes.8 Case 75 Clear Damp75 If dampers.9 = 1 Then Set TimVals[9] Set Resort_flag Clear dampers.9 EndIf Set notes.9 Case 76 Clear Damp76 If dampers.10 = 1 Then Set TimVals[10] Set Resort_flag Clear dampers.10 EndIf Set notes.10 Case 77 Clear Damp77 If dampers.11 = 1 Then Set TimVals[11] Set Resort_flag Clear dampers.11 EndIf Set notes.11 Case 78 Clear Damp78 If dampers.12 = 1 Then Set TimVals[12] Set Resort_flag Clear dampers.12 EndIf Set notes.12 Case 79 Clear Damp79 If dampers.13 = 1 Then Set TimVals[13] Set Resort_flag Clear dampers.13 EndIf Set notes.13 Case 80 Clear Damp80 If dampers.14 = 1 Then Set TimVals[14] Set Resort_flag Clear dampers.14 EndIf Set notes.14 Case 81 Clear Damp81 If dampers.15 = 1 Then Set TimVals[15] Set Resort_flag Clear dampers.15 EndIf Set notes.15 Case 82 Clear Damp82 If dampers.16 = 1 Then Set TimVals[16] Set Resort_flag Clear dampers.16 EndIf Set notes.16 Case 83 Clear Damp83 If dampers.17 = 1 Then Set TimVals[17] Set Resort_flag Clear dampers.17 EndIf Set notes.17 Case 84 Clear Damp84 If dampers.18 = 1 Then Set TimVals[18] Set Resort_flag Clear dampers.18 EndIf Set notes.18 Case 85 Clear Damp85 If dampers.19 = 1 Then Set TimVals[19] Set Resort_flag Clear dampers.19 EndIf Set notes.19 Case 86 Clear Damp86 If dampers.20 = 1 Then Set TimVals[20] Set Resort_flag Clear dampers.20 EndIf Set notes.20 Case 87 Clear Damp87 If dampers.21 = 1 Then Set TimVals[21] Set Resort_flag Clear dampers.21 EndIf Set notes.21 Case 88 Clear Damp88 If dampers.22 = 1 Then Set TimVals[22] Set Resort_flag Clear dampers.22 EndIf Set notes.22 Case 89 Clear Damp89 If dampers.23 = 1 Then Set TimVals[23] Set Resort_flag Clear dampers.23 EndIf Set notes.23 Case 90 Clear Damp90 If dampers.24 = 1 Then Set TimVals[24] Set Resort_flag Clear dampers.24 EndIf Set notes.24 Case 91 Clear Damp91 If dampers.25 = 1 Then Set TimVals[25] Set Resort_flag Clear dampers.25 EndIf Set notes.25 End Select Set noteAan 'reset !!! EndIf EndIf Case Keypres_Status 'not used on this board 'could be implemented to play with the dampers alone... If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres EndIf GoTo Check_Timers Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller EndIf Case ProgChange_Status 'not used here If prog = 255 Then 'single byte message prog = Bytein GoSub ProgChange EndIf Case Aftertouch_Status If aft = 255 Then ' not implemented on this board aft = Bytein GoSub Aftertouch EndIf End Select EndIf If Resort_flag = 1 Then GoSub SortTimers ' so we resort only if an incoming midi command changed something EndIf Check_Timers: If idx < NrTasks Then ' we moeten alleen checken wanneer er een timer loopt If time >= Nxt Then ' nagaan of de eerstvolgende timer afgelopen is... ' in dit geval is de eerste timer afgelopen en moeten we de juiste aktie ondernemen: Set Nxt.31 ' timer reset, is immers afgelopen ' aan de hand van idx weten we welke timer dit is Select idx Case 0 Clear Damp66 Set TimVals[0] Clear dampers.0 Case 1 Clear Damp67 Set TimVals[1] Clear dampers.1 Case 2 Clear Damp68 Set TimVals[2] Clear dampers.2 Case 3 Clear Damp69 Set TimVals[3] Clear dampers.3 Case 4 Clear Damp70 Set TimVals[4] Clear dampers.4 Case 5 Clear Damp71 Set TimVals[5] Clear dampers.5 Case 6 Clear Damp72 Set TimVals[6] Clear dampers.6 Case 7 Clear Damp73 Set TimVals[7] Clear dampers.7 Case 8 Clear Damp74 Set TimVals[8] Clear dampers.8 Case 9 Clear Damp75 Set TimVals[9] Clear dampers.9 Case 10 Clear Damp76 Set TimVals[10] Clear dampers.10 Case 11 Clear Damp77 Set TimVals[11] Clear dampers.11 Case 12 Clear Damp78 Set TimVals[12] Clear dampers.12 Case 13 Clear Damp79 Set TimVals[13] Clear dampers.13 Case 14 Clear Damp80 Set TimVals[14] Clear dampers.14 Case 15 Clear Damp81 Set TimVals[15] Clear dampers.15 Case 16 Clear Damp82 Set TimVals[16] Clear dampers.16 Case 17 Clear Damp83 Set TimVals[17] Clear dampers.17 Case 18 Clear Damp84 Set TimVals[18] Clear dampers.18 Case 19 Clear Damp85 Set TimVals[19] Clear dampers.19 Case 20 Clear Damp86 Set TimVals[20] Clear dampers.20 Case 21 Clear Damp87 Set TimVals[21] Clear dampers.21 Case 22 Clear Damp88 Set TimVals[22] Clear dampers.22 Case 23 Clear Damp89 Set TimVals[23] Clear dampers.23 Case 24 Clear Damp90 Set TimVals[24] Clear dampers.24 Case 25 Clear Damp91 Set TimVals[25] Clear dampers.25 Case Else ' in dit geval is idx geset GoTo Jumpout ' no need to resort EndSelect GoSub SortTimers ' find a new nxt and idx EndIf Else ' idx >= NrTasks, no timers running, so to avoid overflows, we can reset the timer If maxtim = 1 Then Clear time ' in both loopcountversion and in counterversion. Set TimVals EndIf EndIf Jumpout: ' here we can insert a bit toggle command to measure the loop speed Btg Loopspeed ' with no midi coming in, the square wave frequency measured here is 128kHz ' thus the idle loop time is 3.9 microseconds ' with fast midi in, the loop time becomes 99kHz [04.11.2019] ' Measurements taken with Tektronix TDS2024C oscilloscope with the counterversion (200MHz, 2GS/s) ' end of the main loop Loop SortTimers: 'look up the next smallest timer value in the Timvals array ' zoek de de volgende kleinste timer waarde: Set idx ' makes it 255 Set Nxt.31 ' nxt is set on entry. - for speed, we just set the highest bit Clear nrd ' reset counter for number of active dampers For i = 0 To LastTask ' = NrTasks -1 If TimVals[i] < Nxt Then Nxt = TimVals[i] ' NrTasks dword comparisons idx = i EndIf ' we also count the number of active dampers here: 'if dampers.i = 1 then inc nrd ' refused by the compiler... nrd = nrd + GetBit dampers, i Next i Clear Resort_flag Return KeyPres: Set notePres '= 255 Return ProgChange: ' Select prog ' Case 1 ' 16 in midi ' Case 2 ' 32 in midi - this is default ' Case 3 ' 48 in midi ' Case 4 ' 64 in midi ' Case 5 ' 80 in midi ' Case 6 ' 96 in midi ' Case 7 ' 112 in midi ' EndSelect Set prog 'this is not realy required Return Pitchbend: 'only implemented on dsPIC based robots, irrelevant here Set pblsb '= 255 Return Aftertouch: 'this is the channel aftertouch, affecting any playing note 'used for fingered vibrato on Fa 'the value of aft is used to set or modify the vibrato speed. Minimum freq=19Hz/2 = 9.54Hz ' coding using timer3: ' If aft > 0 Then ' Clear T3CONBITS_TMR3ON ' stop timer ' CC31 = aft ' VibratoPeriod = CC31 << 9 '* CC31 ' Tim3 = VibratoPeriod ' Set T3CONBITS_TMR3ON ' restart timer ' Else ' Clear CC31 ' Clear VibratoPeriod ' Clear T3CONBITS_TMR3ON ' stop timer ' EndIf Set aft ' reset Return Controller: Select Ctrl Case 25 ' is ook voor de noten 48 tot 65 ' used for setting the duration of the damping hold ' in absense of a release byte ' needs a default setting! now 64 Tremba_duur = Tremba[value] ' for the Tremba solenoids Ledex_duur = Ledex[value] ' for Lucas_Ledex Black_duur = Black[value] ' for Black Knight Case 64 ' sustain on/off switch ' 0 = OFF means dampers are active ' 1 = ON means dampers are disabled. If value = 0 Then sustain = 0 Else sustain = 1 EndIf Case 66 'on/off for the robot If value = 0 Then Clear PowerOn 'CC66.0 =0 GoSub PowerDown Else Clear sustain Tremba_duur = Tremba[64] Ledex_duur = Ledex[64] Black_duur = Black[64] Set PowerOn 'CC66.0 =1 EndIf Case 123 If sustain = 0 Then ' the is a risk here for overloading the power supply if too many dampers are active at the same time... ' hence our checks for nrd < dMax here If notes.0 = 1 Then If nrd < dMax Then ' schakel demper aan en start timer: Set Damp66 TimVals[0] = time + Tremba_duur Set Resort_flag Set dampers.0 Inc nrd EndIf EndIf If notes.1 = 1 Then If nrd < dMax Then Set Damp67 TimVals[1] = time + Tremba_duur Set Resort_flag Set dampers.1 Inc nrd EndIf EndIf If notes.2 = 1 Then If nrd < dMax Then Set Damp68 TimVals[2] = time + Tremba_duur Set Resort_flag Set dampers.2 Inc nrd EndIf EndIf If notes.3 = 1 Then If nrd < dMax Then Set Damp69 TimVals[3] = time + Tremba_duur Set Resort_flag Set dampers.3 Inc nrd EndIf EndIf If notes.4 = 1 Then If nrd < dMax Then Set Damp70 TimVals[4] = time + Tremba_duur Set Resort_flag Set dampers.4 Inc nrd EndIf EndIf If notes.5 = 1 Then If nrd < dMax Then Set Damp71 TimVals[5] = time + Tremba_duur Set Resort_flag Set dampers.5 Inc nrd EndIf EndIf If notes.6 = 1 Then If nrd < dMax Then Set Damp72 TimVals[6] = time + Tremba_duur Set Resort_flag Set dampers.6 Inc nrd EndIf EndIf If notes.7 = 1 Then If nrd < dMax Then Set Damp73 TimVals[7] = time + Tremba_duur Set Resort_flag Set dampers.7 Inc nrd EndIf EndIf If notes.8 = 1 Then If nrd < dMax Then Set Damp74 TimVals[8] = time + Tremba_duur Set Resort_flag Set dampers.8 Inc nrd EndIf EndIf If notes.9 = 1 Then If nrd < dMax Then Set Damp75 TimVals[9] = time + Tremba_duur Set Resort_flag Set dampers.9 Inc nrd EndIf EndIf If notes.10 = 1 Then If nrd < dMax Then Set Damp76 TimVals[10] = time + Tremba_duur Set Resort_flag Set dampers.10 Inc nrd EndIf EndIf If notes.11 = 1 Then If nrd < dMax Then Set Damp77 TimVals[11] = time + Tremba_duur Set Resort_flag Set dampers.11 Inc nrd EndIf EndIf If notes.12 = 1 Then If nrd < dMax Then Set Damp78 TimVals[12] = time + Ledex_duur Set Resort_flag Set dampers.12 Inc nrd EndIf EndIf If notes.13 = 1 Then If nrd < dMax Then Set Damp79 TimVals[13] = time + Ledex_duur Set Resort_flag Set dampers.13 Inc nrd EndIf EndIf If notes.14 = 1 Then If nrd < dMax Then Set Damp80 TimVals[14] = time + Ledex_duur Set Resort_flag Set dampers.14 Inc nrd EndIf EndIf If notes.15 = 1 Then If nrd < dMax Then Set Damp81 TimVals[15] = time + Ledex_duur Set Resort_flag Set dampers.15 Inc nrd EndIf EndIf If notes.16 = 1 Then If nrd < dMax Then Set Damp82 TimVals[16] = time + Black_duur Set Resort_flag Set dampers.16 Inc nrd EndIf EndIf If notes.17 = 1 Then If nrd < dMax Then Set Damp83 TimVals[17] = time + Black_duur Set Resort_flag Set dampers.17 Inc nrd EndIf EndIf If notes.18 = 1 Then If nrd < dMax Then Set Damp84 TimVals[18] = time + Black_duur Set Resort_flag Set dampers.18 Inc nrd EndIf EndIf If notes.19 = 1 Then If nrd < dMax Then Set Damp85 TimVals[19] = time + Black_duur Set Resort_flag Set dampers.19 Inc nrd EndIf EndIf If notes.20 = 1 Then If nrd < dMax Then Set Damp86 TimVals[20] = time + Black_duur Set Resort_flag Set dampers.20 Inc nrd EndIf EndIf If notes.21 = 1 Then If nrd < dMax Then Set Damp87 TimVals[21] = time + Black_duur Set Resort_flag Set dampers.21 Inc nrd EndIf EndIf If notes.22 = 1 Then If nrd < dMax Then Set Damp88 TimVals[22] = time + Black_duur Set Resort_flag Set dampers.22 Inc nrd EndIf EndIf If notes.23 = 1 Then If nrd < dMax Then Set Damp89 TimVals[23] = time + Black_duur Set Resort_flag Set dampers.23 Inc nrd EndIf EndIf If notes.24 = 1 Then If nrd < dMax Then Set Damp90 TimVals[24] = time + Black_duur Set Resort_flag Set dampers.24 Inc nrd EndIf EndIf If notes.25 = 1 Then If nrd < dMax Then Set Damp91 TimVals[25] = time + Black_duur Set Resort_flag Set dampers.25 Inc nrd EndIf EndIf Clear notes ' all bits EndIf End Select Set Ctrl 'mandatory reset Return PowerDown: 'stop all running timers Set TimVals Low Damp66 Low Damp67 Low Damp68 Low Damp69 Low Damp70 Low Damp71 Low Damp72 Low Damp73 Low Damp74 Low Damp75 Low Damp76 Low Damp77 Low Damp78 Low Damp79 Low Damp80 Low Damp81 Low Damp82 Low Damp83 Low Damp84 Low Damp85 Low Damp86 Low Damp87 Low Damp88 Low Damp89 Low Damp90 Low Damp91 Clear sustain Clear dampers ' all bits Clear notes Clear nrd Tremba_duur = Tremba[64] Ledex_duur = Ledex[64] Black_duur = Black[64] Return Dur_Lookup: ' in the loopcountversion: $ifdef loopcountversion Tremba[1] = 3008 For i = 2 To 127 Tremba[i] = Tremba[i-1] + 164 Next i Ledex[1] = 3008 ' to be checked For i = 2 To 127 Ledex[i] = Ledex[i-1] + 63 Next i Black[1] = 3008 ' to be checked For i = 2 To 127 Black[i] = Black[i-1] + 63 Next i $endif ' in the counterversion $ifdef counterversion ' Tremba solenoids notes 66 - 77 ' 27.11.2019 ' meting: velo 1 = 75ms ' velo 64 = 100ms ' velo 127 = 180ms ' 03.12.2019: code, for value 64 at center. Tremba[0] = 0 Tremba[1] = 2543 ' 1157 Tremba[64] = 3887 Tremba[127] = 5189 stap = (Tremba[64] - Tremba[1]) / 64.0 For i = 2 To 63 tmp = (stap * i) + Tremba[1] Tremba[i] = tmp Next i stap = (Tremba[127] - Tremba[64]) / 64.0 For i = 65 To 126 tmp = (stap * (i - 64)) + Tremba[64] Tremba[i] = tmp Next i ' four Ledex solenoids: ' meting: velo 1 = 7.5 ms ' velo 127 = 85 ms ' na afregeling bleek dat volgende scaling beter was: [07.12.2019] ' velo 1 = 7.4ms ' velo 64 = 81 ms ' velo 127 = 130 ms Ledex[0] = 0 Ledex[1] = 290 Ledex[64] = 3173 ' 1754 Ledex[127] = 5100 ' 3173 stap = (Ledex[64] - Ledex[1]) / 64.0 For i = 2 To 63 tmp = (stap * i) + Ledex[1] Ledex[i] = tmp Next i stap = (Ledex[127] - Ledex[64]) / 64.0 For i = 65 To 126 tmp = (stap * (i - 64)) + Ledex[64] Ledex[i] = tmp Next i ' Black Knight solenoids: ' meting: velo 1 = 7.5 ms ' velo 64 = 70 ms ' velo 127 =180 ms Black[0] = 0 Black[1] = 290 Black[64] = 2778 Black[127] = 5189 stap = (Black[64] - Black[1]) / 64.0 For i = 2 To 63 tmp = (stap * i) + Black[1] Black[i] = tmp Next i stap = (Black[127] - Black[64]) / 64.0 For i = 65 To 126 tmp = (stap * (i - 64)) + Black[64] Black[i] = tmp Next i $endif ' the tables needs to be updated after measurements and performance checking with the actual solenoids Return '[EOF]