'**************************************************************************** '* * '* 16 bit 24EP128MC202 microcontroller * '* Godfried-Willem Raes * '* 2017 * ' *************************************************************************** ' NOTE: Pickit3 must be used for programming these devices! ' Each interrupt has its own handler, simply write one handler for each interrupting ' device without having to work out which interrupt it is. ' Timers are more logical: specify the count going upwards that will trigger an ' interrupt rather than working out when the counter would underflow. ' COMMENTS made during development of HybrLo: '02.08.2016: 1M resistor added over X-tal pins '03.08.2016: Finaly got the clock up and running on the X-tal ' Working out the MIDI UART now. ' Midi-in buffering implemented. ' Trying to use the pwm channels... we cannot use the HPWM commands... ' Implementing velocity control with timers ' Repeats working now. '04.08.2016: Adding 12 bit ADC on channel AN0 ' Midi out looks like working using the Basic command HSROut ' 1 midi packet (3 bytes) takes some 1ms, which conforms to the standard. ' adding initialisation for the PWM channels ' This is as yet not working... '05.08.2016: with 60Mhz clock the frequency range for PWM would be 60MHz --> 915Hz ' so, for audio use we need a prescale devider :64 ' Thus the frequency range would become 14Hz --> 937.5kHz '06.08.2016: pwm begint stilaan goed te werken. ' different modes of operation implemented for the pwm channels ' pwmmodus 0 fully debugged. ' pwmmodus 2 fully debugged (3-phase motor control) ' pwmmodus 1 fully debugged (3 independent PWM channels) ' pwmmodus 3 added: AC motor with capacitor phase shifter using 2 pwm channels ' PWM principieel werkend nu. ' eventueel kunnen nog dead times toegevoegd worden indien nodig voor een toepassing ' We kunnen overbodige pwm pinnen nog disablen en beschikbaar maken voor ' andere funkties. '07.08.2016: Lookup tables for frequencies in 12-tone equal temperament added. Ambitus= 22-127 ' looks like it's possible to implement a 3-voice midi synth on this platform. ' Just did it: the 3-channel synth is working! ' Studying the implementation of 32-bit timers ' timers 2/3 and 4/5 implemented as 32-bits timers ' trying to use timer23 instead of our loop counter. ' This now works fine ' We could use timer1 as a motor speed controller for a stepper ' Timer 45 could be used as a high resolution, extreme ambitus tone generator ' Timer 1,4,5 implemented as fast timers in 16 bits for ADSR implementation ' PWM lookups added for this. '10.08.2016: Different approach to adsr - simplified, using timers ' ADSR works now, but we will need a steep lowpass filter on the output ' with this code we are at the limit of what the PIC can handle. ' As it is now, we can have 6 independent PWM channels. ' For the 3-voice synth we need them all and we used up all available timers. ' The priority settings for the IRQ's are very important for this code to work well. ' This version saved as PIC24_008.bas '11-12.08.2016: application written for midi-invertor: Mirrored_X.bas. Tested o.k. '13.08.2016: metacompiler statements for UART-TX and UART-RX added. ' Buffered midi-out fully implemented. ' For some reason the ADSR pwm is no longer working now... ' Rearranging priority levels made it work again. ' ADSR timers must have a :8 divider setting. ' This version saved as PIC24_009 ' Working version saved as P14_synth1.bas '14.08.2016: To relax the interrupt density, we could also invert the pwm functions and ' use the timers 1,4,5 for frequency generation with waveform duty cycle whilst ' the 3 real PWM channel could do the ADRS at the highest possible frequency. ' This requires PWMmodus to be set to 0. ' looks like PWM needs to be inverted now. Done. ' ADSR works fine now, but the load on the processor is still very high. ' we should try to get the divisions out of the main loop now. Done.\ ' Further improvements: decrease nr. of steps for ADSR, as 127 steps ' for an attack time of say 100ms seems largely overkill... '15.06.2016: ADSR coding restructured to make it more readible. ' Tests o.k. bit we still have glitches and seem to be working at the ' edge of what the processor can do. '23.08.2016: Evaluation board finished. This works o.k. ' bug removed in the duty cycle control: cannot be zero! ' This file now saved as HybrLo_22_24.bas '-------------------------------------------------------------------------------------- '23.08.2016: Start delopment of specific HybrLo code. ' This code implements notes 22, 23 and 24 and their octaves. '20.09.2016: Looks like release is no longer working now... ' We could try to nake the 947 constant for scaling the ADSR smaller ' ADSR_scale constant introduced. ' release bug found: scale multiply forgotten in the noteoff proc. ' if we set ADSR_scale to 1024, we can avoid many multiplies in the code... ' done with the introduction of ADSR_shift = 10 ' 10.10.2016: Recoding to avoid float's in the code. ' Now with 40dB scalings. ' Ommited ADSR flags reset on note-On command, was the first cause of the glitches. ' real time modulation of volume added using ctrl's 70-82 ' For the other boards, just change the $define Boardx_x compiler metacommand. ' 11.10.2016: Extending range with an octave... ' extending with yet one more octave... ' 12.10.2016: 40dB lookups herberekend voor bovenste bereik van de PWM ' dit zou de S/R verhouding moeten verbeteren. ' 60dB lookups added again. ' This version uploaded. Version 003. ' 13.10.2016: start implementation of ctrl#1 for frequency jitter. ' ADSR periods halved. ' Jitter controller (#1) added ' Release range reset to 512 ms. Attack and decay are now 256ms '------------------------------------------------------------------------------- ' 16.02.2017: Start from the framework of HybrLo to code for ' First thing: try to generate the required very high pitches. ' Prescalers for the timers set to :8, rather than :64 on Hybrlo ' Priorities set to 6 ' So far this works, if we shift the period lookups 2 octaves down. ' PTPER set to 512 - this works. We can even go higher it seems. ' First tests on note 84 passed. ' 19.02.2017: Lookups for the 15 different compilations added. ' Four PIC's on board 1 programmed. ' 20.02.2017: First test with the pipes mounted. ' there are glitches in the ADRS..., the principle seems to work well. ' Problems with ports being high on init... try using portb.6 for ctrl.66 ' 23.02.2017: Attack_time, decay_time, release_time changed to dword as they could overflow ' 28.02.2017: Code problems in boards 3 and 4. Ctrl66 does not seem to work. ' Problem solved: poling wrong on the Omron Relay. ' 03.03.2017: Code optimised. Shift in ADR reduced to 8. ' We have to check the tuning: the octaves are a bit wrong!!! ' Start implementing microtuning using ctrl's 72-116 ' Pitch-periods are now declared constants. ' ADSR range made consistent with PTPER : now 9 bits. ' 04.03.2017: Microtuning support added, ctrl's 72 to 117 ' all 15 processors reflashed. Version 1.1 now ' 05.03.2017: the microtuning implementation appears not to work... ' 07.03.2017: duty cycle controll is now pitch dependent. Version 1.3, saved as backup ' 08.03.2017: start implementation of just intonation tunings ' This will be version 1.4 ' here we will try to set the timer prescaler to 0, to increase ' tuning precision with a factor 8. ' This now seems to work on the test board. ' However, changing the tuning seems not to work at all. ' Maybe the timer IRQ's are blocking the calculations. ' so, let's try to disable interrupts on reception of tuning commands. ' Bug found: was not in this code, but in the GMT test-code!!! ' Mircrotuning now works. ' JI lookups lead to way too high freq's. There must be a scaling bug here. ' 09.03.2017: This bug was due to a compiler bug in that it did not calculate the constants ' at compilation time. ' Period[127] = Note95 * 5 / 32 leads to errors! ' So, we wrote a utility in PBCC to calculate all JI pitch lookups. ' There are precision errors increasing with frequency. ' Compensation for this requires further analysis. ' note 126 in EQ measures 11655.6 Hz, it should be 11840 Hz, so a 184.4Hz fault, or 1.557% ' note 84 in EQ measures 1045.1 Hz, it should be 1047 Hz, so a 1.9Hz fault, or 0.18% ' we can compensate in the lookups for these errors, assuming a linear curve. ' After applying compensations to the lookup tables the measured frequency error are: ' 0.05% for note 84, 0.06% for note 126. We consider this a very good result. ' On request of early adopters, we doubled the release time values. ' This be version 1.5: flashed in all PIC's. ' 10.03.2017: The formula to use for the calculation of the periods needs to be: ' period = ((1/freq) - t) / k ' wherein k = 1 / 60MHz and t = ISR service time, measured as 1.3us ' with this formula applied, the error for note 126 is only 0.018% ' for note 84, the error is 0.045% ' for note 85, the error is 0.022% ' 11.03.2017: lookup algorithm improved with constant ISR time ' now all errors <= 0.02% ' version 1.6 now. Flashed. ' ------------------------------------------------------------------------------------------------------------- ' 16.03.2017: Start from Pi code, coding for Rodo ' Timers need a :8 setting here ' Coding should be monophonic ' ADC to be implemented for sampling ' PWM resolution should be 12 bits ' 18.03.2017: Hardware bug remedied: 7400 replaced with 7430, 8-input NAND gate. ' ctrl 13 changed. ' Bugs: ' CC5 off should switch off sounding note ' CC4 on blocks everything ---> check sampling rate ' CC3 works ok ' CC6 only works if set to 1 ' CC5 bug solved. ' ADC sampling rate tested. ' however, the AN0 input is not working. Is it switched to input? ' TRISA was set to output... ' 21.03.2017: Still we cannot get the ADC system to work, neither in 10-bit, nor in 12-bit mode. ' Note that the analog input pins are NOT 5V tolerant!!! ' After 3 days of debugging, we finally got the ADC to work: ANSELA.0 = 1 is crucial. ' Of course with this coding, we get a strong sample rate base frequency in the output. ' To get rid of this, the sampling rate has to be raised to above 16kHz. ' Recoded for 16384 S/s in timer 5 and scaling for Timer 4 adapted accordingly in the lookup. ' IGBT mounted on the board. Tests under real load conditions can start. ' This version saved as Rodo_edrive_001.bas ' Continuing research to get ADC->PWM to work directly ' This works. ' Instead of the hardware AND construction, we could also mix the inject and the feedback signals ' into a single PWM stream. To be researched and coded. '-------------------------------------------------------------------------------------------------------------- ' 25.03.2017: Starting from edrive code, coding for the radar interfaces. ' Requirements for this code: ' 12 bit analog sampler ' 1 external interrupt for period measurement ' midi merger (Rx/Tx) ' 1 PWM output for FM modulation of the microwave emitter ' 31.03.2017: External IRQ on INT0 working ' ADC not working ' 01.04.2017: Sampling working now. ' Adding data acquisition code ' Midi transmit input to output added. ' 02.04.2017: PDC2 connected to blue LED's for speed monitoring ' PDC3 connected to white LED's for surface monitoring ' DC offsets in hardware changed. This was a hardware bug... ' Start coding a a gesture mapping for radar 1. ' Version 1.0 ready for testing on ' 03.04.2017: metacompiler commands for the two radar boards added. ' CC70: dT for derivative of speed added ' CC71: dT for derivative of surface added ' CC74: noise level for surface data ' First tests on ' red lite goes on, blue never ' Controllers tested. ' Midi merge works fine so far. ' 04.04.2017: Note repetitions added using Task0. This works. ' Implement Channel aftertouch for communication between radar1 and 2? ' Further work on the RadaRodo piece. ' e-bow not working in radar modus... ' 05.04.2017: Second radar board hardware finished. ' e-bow bug found: time was defined as word. Must be dword! ' blue light bug found: symbol definition was wrong. ' main-loop has very high jitter with the RadaRoto piece as ' midi out seems to cause quite some timing uncertainty. ' 06.04.2017: jitter coding improved. ' now used floats for much better integration at the detriment of speed. ' IRQ priorities changes. ' 07.04.2017: Dead-time introduction for INT0 to avoid jitter (INT0 coding) ' Controllers 75 and 76 introduced for DC_Offset adjustment. ' Test code for this added in GMT+slagwerk - Rodo. ' Compilation problems: asm faults reported... ' The floats in the IRS seem to be the problem... ' 08.04.2017: using differenciator/rectifier using only words in the ADC ISR ' sampling rate lowered to 1024 S/s ' speed sampling rate lowered to ca. 250 S/s ' 09.04.2017: Nothing seems to work anymore now, except the 12 bit ADC... ' Hardware bug solved: oscillation on the 3v3 analog supply pin... ' No more floats and irq calls in IRS's ' Seems to work fine now. Retest on ... ' Sensitivities have to be changed now. ' Test o.k. but lights not working. ' Range for accel changed in radarodo task ' dynamic during repeats made interactive. ' Radar 2 board updated also. Strange observation: this board using ' the same component values as Radar 1 does not have the oscillation problem... ' 10.04.2017: Version 003 now ' INT0 coding improved. ' First tests on Rodo with 2 radars ' start-up sequence changed. Now initialisation are sent by Radar 2 only ' aftertouch used for communication between Radar1 and Radar2 ' dS implemented now, but not yet used in composition coding ' 11.04.2017: Version 004 now ' still after start-up the ebow does not work. It only starts working ' if we send the appropriate controllers after start-up. (CC3, CC5, CC6) ' Red and Blue light coding changed, although we have no cue as to why it was not ' working. ' 12.04.2017: Red/Blue lights still not working... ' Oscillation problem solved: there is just to much vibration on the mounting plate ' thus the radars suffer from mechanical feedback. ' code restructured. ' accellerations mapping now works ' we can use different interactive programs if we implement prog. change for the selection. ' we could have different programs for radar1 and radar2 ' 13.04.2017: Procedures added for midi-out ' midi-out buffer enlarged to 512 ' loop speed limited to timer resolution ' Radar2 seems to crash. Do we still have buffer overflows? ' Bug found: indexes have to be word var's now. ' This be version 007. ' 14.04.2017: A third PCB made and finished, with a much better comparator design. ' The radar board on Rodo appear to be stable now. ' 15.04.2017: code added for autoregulation of the pitch mapping. ' 16.04.2017: ctrl. inits changed. ' 17.04.2017: Further testing. e-bow board upgraded also with larger midi-buffers. ' This does not seem to solve our problems... ' Pacing removed from main loop. ' now e-bow seems to work, but we have no sound explanation... ' 18.04.2017: Stack size increased. ' This does not make any difference... ' 19.04.2017: Start coding for a second embedded composition ' 20.04.2017: Speed algo changed in INT0 en TMR1 ' 21.04.2017: with some nop's in the midiTX procs to seems to work a lot better. ' slow timers added for automatic piece swapping ' 23.04.2017: still not working reliably. ' now trying to use tasks to sequence the controller commands ' 24.04.2017: The sequenced approach to midi seems to work now. ' Thus we do no longer use Timvals[2] for startup. ' 25.04.2017: Now at version 10. ' If Rodo stays ON for a long time (> 4 hours) the ebow stops working. ' Changing the interactive composition with a prog.change command causes all ' dampers to go down thus overloading the damper power supply. ' 26.04.2017: further testing and improving (...we hope) ' 28.04.2017: odd behaviour of the compiler... ' 29.04.2017: and we go on... ' 30.04.2017: ebow board repaired. Works again now. ' Further testing can continue. ' 01.05.2017: Radar3 and Radar4 board finished. These are not for Rodo. ' 03.05.2017: Display procedures and implementation added for Radar4 board. ' 04.05.2017: Hexdis procedure added and debugged. This works fine now. ' 06.05.2017: UART TX coding changed, avoiding internal 4 byte overflows to occur. ' This should make sequencing of midi-out data unneeded. ' We must have introduced a bug, as nothing of the interactive coding works now... ' Bug found and killed (>= ipv < in the piece switcher...) ' Now let's try to go without sequencing for midi again. ' Seems to work now... ' Surface mapping changed from quadratic, to mixed. ' Sensitivity values have to be changed now ' New sensit values: CC74 = 5, CC72,73= 36 ' 07.12.2020: timer3 read bug killed, but to be further checked as we use single bits in TMR3 here... ' it would be safer to use bits in the time variable. ' LED mapping: [ for debug and monitoring] ' Green = midi transfer ' Orange = speed detection ' Yellow = sampling rate speed ' White = doppler surface detection ' Blue = acceleration detection ''------------------------------------------------------------------------------------------------------------- ' START: Device = 24EP128MC202 ' this code should also work on 24EP32MC202, 24EP64MC202, 24EP256MC202, 24EP512MC202 ' and dsPIC33EP32MC202, dsPIC33EP64MC202, dsPIC33EP128MC202, dsPIC33EP256MC202, dsPIC33EP512MC202 ' and dsPIC33EP32MC502, dsPIC33EP64MC502, dsPIC33EP128MC502, dsPIC33EP256MC502, dsPIC33EP512MC502 Clear ' conditional compile constants: '$define Rodo_Radar1 ' left side radar, notes 48-78 $define Rodo_Radar2 ' right side radar, notes 49 - 77 '$define Radar3 ' test board as yet uncommitted '$define Radar4 ' test board with hex display ' port-assignments - hardware specifics '************************************** Symbol watchdog_led PORTB.6 ' red LED - pin 15 Symbol Int0 PORTB.7 ' external interrupt $ifndef Radar4 Symbol yellow_led PORTA.4 Symbol green_led PORTB.4 Symbol orange_led PORTB.5 Symbol loopcnt PORTB.0 ' pin 4 $else Symbol loopcnt PORTB.4 ' pin 11, as we cannot use the left dot on the display anyway... $endif Config FPOR = ALTI2C1_OFF, ALTI2C2_OFF ' I2C support OFF Config FWDT = WDTPOST_PS256, WINDIS_OFF, PLLKEN_ON, FWDTEN_OFF ' FWDTEN_OFF disables the WDT (watchdog timer) RCON.5 = 0 ' clear the watchdog enable bit for reset = SWDTEN_OFF ' first configure the clock... ' select internal FRC at POR not using PLL: Config FOSCSEL = FNOSC_FRC, IESO_OFF DelayMS 10 ' make sure we assign the correct pins to use for the ICD (Pickit3) Config FICD = ICS_PGD1, JTAGEN_OFF ' this sets the pins used for the programmer ' enable clock switching and configure POSC for XT mode with 10MHz crystal Config FOSC = FCKSM_CSECMD, OSCIOFNC_OFF, POSCMD_XT Main_Setup: ' configure PLL prescaler, PLL postscaler, PLL divisor PLLFBD = 46 CLKDIV.7 = 0 'PLLPOST N2=2 CLKDIV.6 = 0 CLKDIV.0 = 0 'PLLPRE N1=2 CLKDIV.1 = 0 CLKDIV.2 = 0 CLKDIV.3 = 0 CLKDIV.4 = 0 Write_OSCCONH ($3) ' = __builtin_write_OSCCONH(0x03) Write_OSCCONL (OSCCON | %1) ' = __builtin_write_OSCCONL(OSCCON | 0x01) PLL_Setup(48, 2, 2, $0300) ' should set it to 120MHz operation with 10MHz X-tal ' Fosc = 10MHz * 48 / 2 * 2 = 120MHz ' now we get a 10MHz clock signal on pin OSC2, pin10... ' ----------------------------- DelayMS 1000 ' wait for stability Declare Xtal = 120 ' set to Fosc - the clock frequency is 60MHz (MIPS) ' thus 1 instruction cycle is 16.666 ns ' new 18.04.2017: but this makes no difference at all in our code. Declare Stack_Size 200 ' by default it's 60 words or 120 bytes Declare Stack_Expand 1 ' expand stack automaticaly if required. $define Enable_UART_RX ' midi-in $define Enable_UART_TX ' midi-out $define Enable_ADC12bit ' precompiler instructions '$define Enable_ADC10bit $define Enable_PWM ' precompiler instructions $define Enable_Timer1 ' precompiler instructions - 16 bit timer $define Enable_Timer23 ' 32-bit timer '$define enable_Timer45 ' 32-bit timer $define Enable_Timer4 ' as 16 bit timer $define Enable_Timer5 ' as 16 bit timer - used as a sampling rate generator $define Enable_Int0 ' enable external interrupt 'Declare Hserial_Baud = 31250 ' USART1 baud rate - set to MIDI 'Declare Hrsout1_Pin = PORTB.8 ' RP40 ' Select the pin for TX with USART1 'Declare HRSin1_Pin = PORTB.9 ' RP41 PPS_Output(cOut_Pin_RP40, cOut_Fn_U1TX) ' Map UART1 TX pin to RP40 'RP35 PPS_Input(cIn_Pin_RP41, cIn_Fn_U1RX) ' Map UART1 RX pin to RP41 'RPI34 $ifdef Rodo_Radar1 ' left side Symbol BlueLite = 113 ' links Symbol YellowLite = 115 Symbol RedLite = 120 Symbol FWhiteLite = 124 Symbol BWhiteLite = 125 Symbol RotRedLites = 126 Symbol DC_Offset_Init = 2048 ' halfway value for ADC in 12 bits Symbol NrNotes = 16 Symbol LastNote = 15 Symbol NrEnotes = 22 Symbol LastEnote = 21 $endif $ifdef Rodo_Radar2 ' right side Symbol BlueLite = 112 ' rechts Symbol YellowLite = 114 Symbol RedLite = 121 Symbol FWhiteLite = 124 Symbol BWhiteLite = 125 Symbol RotRedLites = 126 Symbol DC_Offset_Init = 2048 Symbol NrNotes = 15 Symbol LastNote = 14 Symbol NrEnotes = 22 Symbol LastEnote = 21 $endif 'constant initialisations for the midi input parser: Symbol Midichannel = 7 ' Rodo_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 TXBufSize $03FF ' 1023 '511 Symbol TXBufArraysize $0400 ' 1024 '512 must be a power of 2 Symbol RCBufSize $03FF ' midi receive buffer Symbol RCBufArraySize $0400 Symbol NrTasks = 7 ' used for gesture input to rodo command tasks Symbol LastTask = 6 ' = NrTasks - 1 Symbol lowtes = 48 Symbol hightes = 78 Symbol KPhightes = 97 ' valid for key-pressure mode only Symbol OnVal = 85 ' %01010101 pattern 'constants used for the operation of the PWM modules ' the modus operandi should be set at compile time! ' For the Hybr boards PWMmodus must be 0. ' For the Pi boards also PWMmodus 0. Symbol PWMmodus = 0 ' 0 = all pwm channels have the same period (frequency) ' PDC1, PDC2, PDC3 steer the PWM setting for each channel ' PTPER is the register to control the period (frequency) and thus the resolution ' PHASE1, PHASE2, PHASE3 steer the phase between output channels ' This mode can be used for ADSR control on 3 channels. ' 1 = the three PWM channels have individual period (frequency) controls ' controlled with the PHASE1, PHASE2, PHASE3 registers ' PDC1, PDC2, PDC3 registers steer the PWM ' PWM-value must be < Period ' this mode could be used to implement a 3-voice midi synth ' We only use the PWMH pins for output here, so portB.15, portB.13 and portB.11 ' are free and can be used for adrs control ' 2 = 3-phase motor control mode ' PTPER controls the period (frequency) ' MDC controls the duty cycle for the 3 channels ' PHASE1, PHASE2, PHASE3 steer the phase between the channels ' we start-up with 120 degree phase shifts. ' 3 = 2-phase ac motor using a capacitor phase shifter ' PTPER controls the period (frequency) ' MDC controls the duty cycle for the 3 cha ' PHASE1, PHASE2, PHASE3 steer the phase be' port I/O settings: ' we start-up with 90 degree phase shifts. 'TRISA = %100001 ' AN0 set to input, others set to output - we dont use these ports TRISA.0 = 1 ' irrelevant, as by default AN0 is analog input TRISB = %0101011110000000 ' PortB.7 is external interrupt input Output watchdog_led $ifndef Radar4 Output green_led ' PortB.4 Output orange_led ' PortB.5 Output yellow_led ' PortA.4 $endif $ifdef Radar4 ' used for 1 digit display here Output PORTB.4 ' left dot not implemented in display Output PORTB.5 Output PORTA.4 Output PORTB.0 Output PORTB.1 Output PORTA.1 $endif $ifdef Enable_Timer1 ' used for Rodo-Radar -period timer ' this timer is triggered and reset by Int0 on the negative edge of the comparator signal IPC0bits_T1IP0 = 1'1 ' set priority 1 IPC0bits_T1IP1 = 0'1 '1 ' on hybrlo set to 5 IPC0bits_T1IP2 = 0'1 ' 6 = 011 ' setting prescaler to :256, time units become 4.266 us ' longest period before overflow is 279 ms. T1CON.5 = 1 T1CON.4 = 1 ' ----------------------- T1CON.15 = 1 ' start timer IFS0bits_T1IF = 0 ' clear Timer1 interrupt flag Clear TMR1 ' reset to zero, so we count up to &HFFFF Set PR1 ' set to maximum count &HFFFF IEC0bits_T1IE = 1 ' Enable the Timer1 interrupt ' stays enabled in the Rodo_Radar application $endif $ifdef Enable_Timer23 ' main loop clock T2CONBITs_T32 = 1 ' 32- bit timer start T2CONbits_TCS = 0 ' internal clock T2CONbits_TON = 1 T2CONbits_TSIDL = 0 T2CON.5 = 1 ' pre-scale 256 T2CON.4 = 1 ' id. TMR2 = 0 TMR3HLD = 0 Set PR2 'PR2 = 65535 Set PR3 'PR3 = 65535 IPC2bits_T3IP0 = 0 '1 ' set priority to 0 IPC2bits_T3IP1 = 0 IPC2bits_T3IP2 = 0 IFS0bits_T3IF = 0 ' clear IRQ flag IEC0bits_T3IE = 1 ' enable timer 3 interrupt $endif $ifdef enable_Timer45 T4CONBITs_T32 = 1 ' 32- bit timer start T4CONbits_TCS = 0 ' internal clock T4CONbits_TON = 1 T4CONbits_TSIDL = 0 T4CON.5 = 1 ' pre-scale 256 T4CON.4 = 1 TMR4 = 0 TMR5 = 0 PR4 = 65535 PR5 = 65535 IPC7bits_T5IP0 = 1 ' set priority to 3 IPC7bits_T5IP1 = 1 IPC7bits_T5IP2 = 0 IFS1bits_T5IF = 0 ' clear IRQ flag IEC1bits_T5IE = 1 ' enable timer 5 interrupt $endif $ifdef Enable_Timer4 ' used as speed sampling clock ' prescaler can be slower, to make a 1 second buffer... T4CON.15 = 1 ' start timer in 16 bit mode T4CON.13 = 0 T4CON.6 = 0 ' prescaler set to 0: timing resolution should be 1/60MHz = 16.6666ns ' 01 = dive by 8 ' 10 = divide by 64 ' prescaler set to 11: divide by 256, so timing resolution becomes 4.266 us T4CON.5 = 1 T4CON.4 = 1 ' ------------------------ T4CON.3 = 0 ' operate as 16 bit timer T4CON.1 = 0 ' internal clock IPC6bits_T4IP0 = 1 ' set priority to 3 IPC6bits_T4IP1 = 1 IPC6bits_T4IP2 = 0 PR4 = 1000 ' geeft 234 S/s Clear IFS1.11 ' clear interrupt flag Set IEC1.11 ' enable interrupt $endif $ifdef Enable_Timer5 ' used as sampling rate clock in for the ADC T5CON.15 = 1 ' start timer in 16 bit mode T5CON.13 = 0 T5CON.6 = 0 ' prescaler set to 0: T5CON.5 = 1 '0 T5CON.4 = 1 '0 ' ---------------------- T5CON.1 = 0 ' internal clock IPC7bits_T5IP0 = 1 ' set priority to 5 IPC7bits_T5IP1 = 0 IPC7bits_T5IP2 = 1 IFS1bits_T5IF = 0 ' clear IRQ flag 'PR5 = 29300 ' sampling rate should be 2048 S/s PR5 = 234 '58500 ' for 1024 S/s - gives 812 S/s measured. IEC1bits_T5IE = 1 ' enable timer 5 interrupt $endif $ifdef Enable_UART_RX ' init UART1-receiver: 31250 Baud ' generates an interrupt for each byte received U1MODE.0 = 0 ' = U1MODEbits.STSEL = 0 ' 1 stop-bit U1MODE.1 = 0 ' U1MODEbits.PDSEL = 0 ' 8 bit no parity U1MODE.2 = 0 U1MODE.5 = 0 ' =U1MODE_bits.ABAUD = 0 ' no autobauding U1MODE.3 = 0 ' = U1MODEbits.BRGH =0 ' 0 = standard speed mode - 16 clocks per bit U1MODE.4 = 0 ' logic high is the idle state for the input serial data (default) U1MODE.7 = 0 ' wakeup disabled U1MODE.8 = 0 U1MODE.9 = 0 U1BRG = 119 ' 239 ' voor 120MHz 119 ' voor 60MHz ((60000000 / Hserial_baud) / 16) - 1 ' BRGVAL U1STA.5 = 0 ' no bit8 U1STA.6 = 0 ' U1STAbits.URXISEL = 0 ' receive interrupt mode selection bits U1STA.7 = 0 ' interrupt flag is set when a byte is received U1MODE.15 = 1 '=U1MODEbits.UARTEN = 1 U1MODE.12 = 0 ' disable IrDA IPC2.12 = 0 ' set priority level to 6 for receiver IPC2.13 = 1 ' 1 IPC2.14 = 1 ' tested with change to 4, 1 step lower then the note timers...[09.10.2016] ' back to 6 on 10.10.2016, as this was not the cause for the glitches. IEC0.11 = 1 ' enable IRQ for receiver IEC4.1 = 1 ' enable IRQ for error trapping on receiver $endif $ifdef Enable_UART_TX ' UART1 transmitter: 31250 Baud U1STA.15 = 0 ' interrupt generated when character transferred to tx buffer and buffer is empty U1STA.10 = 1 ' transmit enable bit U1STA.11 = 0 ' U1STA.9 = UTXBF Transmit buffer full 1= full, 0 = we can write ' U1STA.8 = TRMT read only bit 1=shift register is empty and transmit buffer is empty ' 0=buffer had data, transfer in progress or queued Clear IFS0.12 ' clear transmit interrupt flag Set IEC0.12 ' enable interrupt IPC3.0 = 0 IPC3.1 = 1 IPC3.2 = 1 ' set priority to 6 $endif $ifdef Enable_ADC10bit ' this should initialise the ADC to 10 bit sampling mode with 4 simultaneous sample and holds ' would be perfect for a quadrada interface with 4 radars. ' AD1CON1: AD1CON1.10 = 0 ' 1 = select 12-bit mode, 1 S&H AD12B bit ' 0 = 10 bit mode with 4 S&H's AD1CON1.13 = 0 ' continue adc in idle mode AD1CON1.9 = 0 ' conversion to right alligned integer 0000 dddd dddd dddd AD1CON1.8 = 0 ' id. AD1CON1.7 = 1'0 '1 ' auto-convert mode - internal counter ends sampling and starts conversion AD1CON1.6 = 1'0 '1 ' id. AD1CON1.5 = 1' '1 ' id ' if 111 the samp bit (ADC1CON1.1) is automaticaly cleared to end sampling and start conversion. ' setting these 3 bits to 0 configures manual mode AD1CON1.4 = 0 ' SSRCG sample trigger source group. Must be 0 'AD1CON1.2 = 1 ' 1 = sampling immediately after last conversion. SAMP bit is autoset. ' this overrides the sampling rate generator... AD1CON1.2 = 0 ' sampling starts when the SAMP bit is set AD1CON1.1 = 0 ' the SAMP bit is AD1CON1.1 ' when AD1CON1.0 is 1, the ADC conversion has completed. ' this causes an interrupt. ' AD1CON2: AD1CON2.15 = 0 ' ref AvDD and AsSS AD1CON2.14 = 0 AD1CON2.13 = 0 AD1CON2.10 = 0 ' 0=no scan ' bits 6-2 = 0 ==> generates interrupt after every sample conversion AD1CON2.6 = 0 AD1CON2.5 = 0 AD1CON2.4 = 0 AD1CON2.3 = 0 AD1CON2.2 = 0 AD1CON2.1 = 0 ' always fill buffer from the start adres AD1CON2.0 = 0 ' use channel input selects for sample MUXA ' AD1CON3: AD1CON3.15 = 0 ' 0 = clock derived from system clock ' 1 = clock derived from internal RC clock AD1CON3.12 = 1 ' 10000 = 16 Tad -autosample time bits AD1CON3.11 = 0 ' / AD1CON3.10 = 0 '/ AD1CON3.9 = 0 ' / AD1CON3.8 = 0 '/ AD1CON3.Byte0 = 16 '127 '16 ' ADCS ADC1 conversion clock select bits (sampling rate) ' 255 gives toggle period = 3.9kHz so sampling rate is 7.8kS/s [measured 18.03.2017] ' 127 should give 7.8kHz and SR = 15.6kS/s ' measured : 7.81285kHz, SR = 15.6257 kS/s ' 63 15.5kHz and SR = 31.2kS/s ' 31 31 kHz and SR = 62.4kS/s ' 15 61 kHz and SR = 124.8kS/s ' 16 gives 58kHz (measured 08.2016) ' in manual mode the sampling rate is controlled by timer5 in our coding ' this setting sets the conversion speed. AD1CON4.8 = 0 ' no DMA - results stored in ADC1BUF0 to ADC1BUFF registers AD1CON4.2 = 0 ' allocate just 1 word for the buffer AD1CON4.1 = 0 ' / AD1CON4.0 = 0 ' / Clear AD1CHS0 ' clear complete register. AN0 is input channel Clear AD1CSSH AD1CSSL.0 = 1 ' select AN0 for input scan ' Set AD1CSSH.9 ' select AN0 for input scan 21.03.2017 added??? Clear AD1CSSL AD1CSSL.0 = 1 ' select AN0 for input scan ANSELA.0 = 1 ' AN0 is analog input - this is crucial!!! ' now we have to enable the interrupt and find out how to transfer data to an array IEC0.13 = 1 ' 1 = enable IRQ ' 0 = disable IRQ 'IPC3 <6:4> set the priority level to 5 IPC3.6 = 1 IPC3.5 = 0 IPC3.4 = 1 AD1CON1.15 = 1 ' adc module ON - done at the end of the configuration ' --------------------------------------------------------------------------------- $endif $ifdef Enable_ADC12bit ' 30.03.2017: used to sample the radar signal ' 01.04.2017: Sampling rate should be ca. 2048 S/s ' For the radar we try to set automatic sample and manual conversion mode. ' 09.04.2017: For radar we brought the sampling rate down to ca. 840 S/s ' Clearing AD1CON1.1 (SAMP bit) starts the conversion ANSELA.0 = 1 ' AN0 is analog input - this is crucial!!! ' AD1CON1: AD1CON1.15 = 0 ' ADC module must be off before changing to 12-bit mode AD1CON1.10 = 1 ' 1 = select 12-bit mode, 1 S&H AD12B bit ' 0 = 10 bit mode with 4 S&H's AD1CON1.13 = 0 ' continue adc in idle mode AD1CON1.9 = 0 ' conversion to right alligned integer 0000 dddd dddd dddd AD1CON1.8 = 0 ' id. ' setting AD1CON1.9 to 1 and AD1CON1.8 to 0 gives fractional format dddd dddd dddd 0000 ' 07.04.2017: set to fractional formar for ease on integration ' so now we should have dddd dddd dddd 0000 ' did'nt help us any further, so set back to 0000 dddd dddd dddd ' SSRC bits AD1CON1.7 = 0 ' 1'0 '1 ' auto-convert mode - internal counter ends sampling and starts conversion AD1CON1.6 = 0 '1'0 '1 ' id. AD1CON1.5 = 0 '1' '1 ' id ' if 111 the samp bit (ADC1CON1.1) is automaticaly cleared to end sampling and start conversion. ' setting these 3 bits to 0 configures manual mode AD1CON1.4 = 0 ' SSRCG sample trigger source group. Must be 0 ' ASAM bit: AD1CON1.2 = 1 ' sampling immediately after last conversion. SAMP bit is autoset. 'AD1CON1.2 = 0 ' sampling starts when the SAMP bit is set ' the SAMP bit is AD1CON1.1 ' when AD1CON1.0 is 1, the ADC conversion has completed. ' this causes an interrupt. ' so now AD1CON1 should be &B0100000000000100 ' AD1CON2: AD1CON2.15 = 0 ' ref AvDD and AsSS AD1CON2.14 = 0 AD1CON2.13 = 0 AD1CON2.10 = 0 ' no scan AD1CON2.9 = 0 ' convert CH0 AD1CON2.8 = 0 ' / ' bits 6-2 = 0 ==> generates interrupt after every sample conversion AD1CON2.6 = 0 AD1CON2.5 = 0 AD1CON2.4 = 0 AD1CON2.3 = 0 AD1CON2.2 = 0 AD1CON2.1 = 0 ' always fill buffer from the start adres AD1CON2.0 = 0 ' use channel input selects for sample MUXA ' AD1CON3: ' AD1CON3.15 = 0 ' clock derived from system clock ' AD1CON3.12 = 1 ' 10000 = 16 Tad -autosample time bits must be >3 after datasheet ' AD1CON3.11 = 1 ' / ' AD1CON3.10 = 1 '/ ' AD1CON3.9 = 1 ' / ' AD1CON3.8 = 1 '/ ' the example code in the manual clears AD1CON2.byte1 completely.... Clear AD1CON3.Byte1 Set AD1CON3.Byte0 ' = 255 'AD1CON3.Byte0 = 32 ' 255 '127 '16 ' ADCS ADC1 conversion clock select bits (sampling rate) ' 255 gives toggle period = 3.9kHz so sampling rate is 7.8kS/s [measured 18.03.2017] ' 127 should give 7.8kHz and SR = 15.6kS/s ' measured : 7.81285kHz, SR = 15.6257 kS/s ' 63 15.5kHz and SR = 31.2kS/s ' 31 31 kHz and SR = 62.4kS/s ' 15 61 kHz and SR = 124.8kS/s ' 16 gives 58kHz (measured 08.2016) ' in manual mode the sampling rate is controlled by timer5 in our coding ' this setting sets the conversion speed. ' AD1CON4: 'AD1CON4.8 = 0 ' no DMA - results stored in ADC1BUF0 to ADC1BUFF registers 'AD1CON4.2 = 0 ' allocate just 1 word for the buffer DMABL<2:0> 'AD1CON4.1 = 0 ' / 'AD1CON4.0 = 0 ' / Clear AD1CON4 ' as in the manual for automatic sample and manual conversion Clear AD1CHS0 ' clear complete register. AN0 is input channel for CH0 Clear AD1CHS123 ' not implemented in 12 bit mode Clear AD1CSSH Clear AD1CSSL ' now we have to enable the interrupt and find out how to transfer data to an array IEC0.13 = 1 ' 1 = enable IRQ ' 0 = disable IRQ 'IPC3 <6:4> set the priority level to 5 IPC3.6 = 1 IPC3.5 = 0 IPC3.4 = 1 IFS0.13 = 0 ' clear interrupt flag AD1CON1.15 = 1 ' adc module ON - done at the end of the configuration ' --------------------------------------------------------------------------------- $endif $ifdef Enable_Int0 ' 31.03.2017: This works fine now. [ Rodo-Radar code] ' external int. signal is generated on window-cross of the Doppler signals ' used for half period measurement. ' IFS0.0 = INT0IF bit interrupt flag ' IEC0.0 = INT0IE bit interrupt enable flag ' IPC0.0, IPC0.1, IPC0.2 interrupt priority bits, INT0IP bits IPC0.0 = 0 ' priority level set to 4 IPC0.1 = 0 IPC0.2 = 1 Set IEC0.0 ' 0 = disable interrupt on start-up ' 1 = enable interrupt on start-up Clear IFS0.0 ' clear irq flag INTCON2.0 = 1 ' 0 = irq on positive edge INT0EP bit ' 1 = irq on negative edge ' the comparator output is high at rest INTTREG.Byte0 = %00001000 ' do we need this? $endif $ifdef Enable_PWM ' PWM channel initialisation ------------------------------------------------------ ' CNPD1 ' enable internal pull down resistor to reset the FLT32 flag on init ' disable interrupts: IEC5.14 = 0 IEC5.15 = 0 IEC6.0 = 0 ' clear interrupt flags: Clear IFS5.14 Clear IFS5.15 Clear IFS6.0 ' pwm time base control register: PTCON 'PTCON.pwm Clear PTCONbits_PTEN ' = PTCON.15 = 0 ' pwmx disabled for setting the bits, should be enabled at the end. PTEN 'PTCON Timebase control register Clear PTCONbits_PTSIDL ' = PTCON.13 ' PTCONbits_SESTAT 'PTCON.12 ' status bit to read Clear PTCONbits_SEIEN ' PTCON.11 disable special event interrupt 'Set PTCONbits_EIPU ' PTCON.10 1 = active period register is updated immediately Clear PTCONbits_EIPU ' PTCON.10 0 = active period register updates occur on PWMx cycle boundaries : setting changed 09.10.2016 Clear PTCONbits_SYNCPOL ' PTCON.9 sync active high. Irrelevant here as we do not use sync Clear PTCONbits_SYNCOEN ' PTCON.8 = 0 ' disable sync output Clear PTCONbits_SYNCEN ' PTCON.7 = 0 ' no external sync Clear PTCONbits_SYNCSRC0 'PTCON.4 Clear PTCONbits_SYNCSRC1 'PTCON.5 Clear PTCONbits_SYNCSRC2 'PTCON.6 Clear PTCONbits_SEVTPS0 'PTCON.0 special event postscaler bits Clear PTCONbits_SEVTPS1 'PTCON.1 Clear PTCONbits_SEVTPS2 'PTCON.2 Clear PTCONbits_SEVTPS3 'PTCON.3 '%110 = / 64 ' timing resolution should become 64x8.5ns = 544ns = 0.544us ' PTPER register primary master time base period register 'PTPER = 64 '32678 ' master time base period register --> PWM frequency 16-bits ' 1 unit is 8.33ns with a 60MHz Fcy ' so 32678 would give 3673 Hz Select PWMmodus Case 0 ' this works o.k. now 'PWMCON1.9 = 0 ' ITB: Independent time base mode if set to 1 'PWMCON2.9 = 0 ' PTPER register steers time base if set to 0 'PWMCON3.9 = 0 ' we do not have a SPHASE1, 2, 3 register thus independent pwm control is not possible ' cfr manual example 14-14, p.44 Clear PWMCON1 Clear PWMCON2 Clear PWMCON3 ' PTCON2 register ' pwm input clock prescaler, set to 1 (no division) 'Set PTPER ' set to lowest frequency = 1831,16 Hz ' for the ADSR implementation we should set this as fast as possible! 'PTPER = 1024 ' 256 '1024 ' would this limit the useable range for PWM values??? ' 1024 gives a pwm base frequency of 117kHz PTPER = 4096 ' it gives 29kHz base freq ' with this setting we have 12-bit resolution, matching the ADC resolution Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Clear PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Clear PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 Clear PDC1 Clear PDC2 Clear PDC3 Clear PHASE1 Clear PHASE2 Clear PHASE3 Set MDC ' set to longest period ' used in radar interface for debugging and FM modulation: ' The IOCON1, IOCON2, IOCON3 registers are protected and locked with a key. IOCON1.15 = 1 ' pwm module controls the PWM1H pin - pin 25 IOCON1.14 = 1 ' pwm module controls the PWM1L pin - pin 26 : radar FM control ' polarity bits: ' we invert polarity for PWM1 only: IOCON1.13 = 0 ' 1 - pwmH pin is active low '0 = pwmH pin is active high IOCON1.12 = 0 ' 1 = pwmL pin is active low '0 = pwmL pin is active high - radar FM ' set to redundant outputs: IOCON1.11 = 0 ' 10 = push pull mode, 01 = redundant mode, 00 = complimentary IOCON1.10 = 1 ' IOCON1.9 = 0 ' no override IOCON1.8 = 0 'id. IOCON1.1 = 1 ' 1= swap pins, 0 = no pin swaps ' IOCON1 = %1100 0100 0000 0010 = &HC402 IOCON2.15 = 1 ' blue led IOCON2.14 = 1 ' blue led IOCON2.13 = 0 IOCON2.12 = 0 IOCON2.11 = 1 ' 10 push pull mode IOCON2.10 = 0 IOCON2.9 = 0 IOCON2.8 = 0 ' IOCON2 = %1100 1000 0000 0000 = &HC800 IOCON3.15 = 1 ' white led IOCON3.14 = 1 ' white led must be set to 0 if the pins have to be used as nomal I/O pins. IOCON3.13 = 0 IOCON3.12 = 1 IOCON3.11 = 1 ' push pull IOCON3.10 = 0 ' IOCON3 = IOCON2 = &HC800 ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC402, w0 ' required value for IOCON1 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC800, w0 ' required value for IOCON2 - complementary Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC800, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 ' now we have ports free for the timer-tone generators: ' not used in Rodo_Radar ' Symbol Note_Port1 PORTB.15 ' Symbol Note_Port2 PORTB.13 ' Symbol Note_Port3 PORTB.11 ' Output Note_Port1 ' Output Note_Port2 ' Output Note_Port3 Case 1 ' cfr. example 14-18, p.48 in manual 'PWMCON1.9 = 1 ' ITB: Independent time base mode if set to 1 'PWMCON2.9 = 1 ' PTPER register steers time base if set to 0 'PWMCON3.9 = 1 ' we do not have a SPHASE1, 2, 3 register thus independent pwm control is not possible ' IOCON1,2,3 must be $C000 PWMCON1 = $0200 PWMCON2 = $0200 PWMCON3 = $0200 ' PTCON2 register ' pwm input clock prescaler, set to /64 Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Set PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Set PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 Set PTPER '= 256 ' test value - probably irrelevant in this mode Set PHASE1 ' freq to lowest Set PHASE2 Set PHASE3 Clear PDC1 ' duty cycles note: PDC1 < PHASE1 Clear PDC2 Clear PDC3 Set MDC ' ? clear mdc - seems irrelevant here ' make the pwmL port free for general I/O: IOCON1.15 = 1 IOCON1.14 = 0 IOCON2.15 = 1 IOCON2.14 = 0 IOCON3.15 = 1 IOCON3.14 = 0 ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON1 -pwmL disabled. Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 ' now we have ports free for ADRS: Symbol ADSR_Port1 PORTB.15 Symbol ADSR_Port2 PORTB.13 Symbol ADSR_Port3 PORTB.11 Output ADSR_Port1 Output ADSR_Port2 Output ADSR_Port3 Case 2 ' 3-phase motor control setting ' ref. ,manual 14-16, p. 46 'PWMCON1.9 = 0 ' ITB: Independent time base mode if set to 1 'PWMCON2.9 = 0 ' PTPER register steers common time base if set to 0 'PWMCON3.9 = 0 PWMCON1 = $0100 PWMCON2 = $0100 PWMCON3 = $0100 ' PTCON2 register ' pwm input clock prescaler, set to /64 Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Set PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Set PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 Clear MDC ' master duty cycle control - set to zero on init Set PTPER ' lowest freq. Clear PHASE1 ' 0 graden PHASE2 = 21845 ' 120 graden PHASE3 = 43690 ' 240 graden ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON1 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 Case 3 ' 2-phase ac motor PWMCON1 = $0100 PWMCON2 = $0100 Clear PTcon2bits_PCLKDIV0 Set PTcon2bits_PCLKDIV1 Set PTcon2bits_PCLKDIV2 Clear MDC Set PTPER Clear PHASE1 PHASE2 = 16384 ' 90 graden ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON1 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 EndSelect ' common settings: PWMCON1.12 = 0 'fault interrupt disabled PWMCON2.12 = 0 PWMCON3.12 = 0 PWMCON1.11 = 0 'current limit disabled PWMCON2.11 = 0 PWMCON3.11 = 0 PWMCON1.10 = 0 'trigger event interrupts disabled PWMCON2.10 = 0 PWMCON3.10 = 0 ' PWMCON1.9 = 1 ' ITB: Independent time base mode if set to 1 ' PWMCON2.9 = 1 ' PTPER register steers time base if set to 0 ' PWMCON3.9 = 1 ' we do not have a SPHASE1, 2, 3 register thus independent pwm control is not possible ' PWMCON1.8 = 0 'PCD1 en SDC1 registers provide duty cycle info - ' PWMCON2.8 = 0 ' PWMCON3.8 = 0 PWMCON1.7 = 1 ' dead time disabled PWMCON2.7 = 1 PWMCON3.7 = 1 ' PWMCON1.6 = 0 ' PWMCON2.6 = 0 ' PWMCON3.6 = 0 ' PWMCON1.3 = 0 ' PWMCON2.3 = 0 ' PWMCON3.3 = 0 ' PWMCON1.2 = 0 ' edge aligned mode CAM bit. Ignored when ITB = 0 ' PWMCON2.2 = 0 ' PWMCON3.2 = 0 ' PWMCON1.1 = 0 ' PWMCON2.1 = 0 ' PWMCON3.1 = 0 ' PWMCON1.0 = 1 ' PWMCON2.0 = 1 ' PWMCON3.0 = 1 ' The pwm1 to pwm3 values for the duty cycle are in the PDC1, PDC2 and PDC3 registers ' The phases in the PHASE1, PHASE2, PHASE3 registers, if not used for frequency. AUXCON1 = 0 AUXCON2 = 0 AUXCON3 = 0 Set PTCONbits_PTEN ' = PTCON.15 pwmx should be enabled at the end. $endif Variables: ' variable declarations: ' variables for midi reception and parsing: ' if buffers are > 255, indexes must be word! Dim RCIdxIn As Word ' Pointer to the next empty location in the buffer Dim RCIdxOut As Word ' Pointer to the location of the oldest character in the buffer Dim RCBuffer[RCBufArraySize] As Byte ' Array for holding received characters in the uart Dim TXBuffer[TXBufArraysize] As Byte ' buffer for midi-output UART Dim TXIdxIn As Word Dim TXIdxOut As Word Dim Bytein As Byte ' midi byte read from buffer Dim StBit As Bytein.7 ' highest bit of ByteIn ' midi variables Dim statusbyte As Byte Dim noteUit As Byte ' note off + release value Dim release As Byte Dim noteAan As Byte ' note on + release value Dim velo As Byte Dim notePres As Byte ' note pressure + pressure value Dim pres As Byte Dim Ctrl As Byte ' continuous controller + value Dim value As Byte Dim prog As Byte ' program change + program-byte Dim aft As Byte ' channel aftertouch Dim pblsb As Byte ' pitch bend lsb Dim pbmsb As Byte ' pitch bend msb ' variables for the timing system: Dim time As Dword ' 4 us resolution - must be Dword! Dim otime As Dword Dim maxtim As time.31 ' overflow bit, will cause timer reset after 6 hours Dim i As Word Dim j As Word ' used in timer4 ISR Dim idx As Byte Dim Nxt As Dword ' must be dword Dim TimVals[NrTasks] As Dword Dim resort_flag As Bit Dim velflags As Word ' 16 bit variables and floats for the PWM system (not used in this code) Dim pwm1value As Word Dim pwm2value As Word Dim pwm3value As Word Dim pwm1freq As Word Dim pwm2freq As Word Dim pwm3freq As Word Dim pwm1phase As Word Dim pwm2phase As Word Dim pwm3phase As Word ' vaiables for speed measurement in INT0 and Timer1 30.03.2017 Dim Period_Flags As Word Dim Period_Invalid_Flag As Period_Flags.0 ' set on timer 1 overflow: movement absent or too slow Dim Period_Jitter_Flag As Period_Flags.1 ' jitter in period calculation algorithm Dim No_Data_Flag As Period_Flags.2 ' set when amplitudes are under noise level Dim t1val As Dword ' used in INT0 ISR changed to dword 20.04.2017 Dim t0val As Dword Dim T1overflow As Word Dim AvSpeed As Dword ' averaged speed value ' these seem to offend the compiler if used in an ISR: Dim T4float As Float ' integrator for speed Dim ADfloat As Float ' integrator for ADC values used in task 3 ' variables for data acquisition Dim sample As Word ' used in the ADC, 12 bit value Dim oldsample As Word Dim dif As SWord Dim rec As Word Dim recp As Word Dim recn As Word Dim DataBuffer[256] As Word ' adc databuffer for sampler - surface ' this buffer contains 125 ms of data ' when the sample rate is 2048 S/s ' 250 ms with 1024 S/s Dim DataInIdx As Byte ' pointer to the most recent data Dim DataOutIdx As Byte ' not used here ' Dim DC_Offset As Word ' could also be a symbol ' adjustable with controllers 75 and 76 Dim accel As SWord ' bipolar calculated in timer4 ISR ' first derivative of speed Dim Speedbuffer[256] As Word ' 250ms buffer if the sample rate is 1000 S/s Dim SpeedInIdx As Byte ' pointer to the most recent data Dim Spd[256] As Word ' filled in the INT0 ISR Dim SpdInIdx As Byte Dim SpdOutIdx As Byte ' controllers: Dim CC1 As Byte ' ebow jitter Dim CC2 As Byte ' ebow duty cycle Dim CC3 As Byte ' ebow mute switch Dim CC4 As Byte ' feedback switch Dim CC5 As Byte ' inject switch Dim CC6 As Byte ' KP switch Dim CC7 As Byte ' ebow sustain level Dim CC11 As Byte ' inject level Dim CC65 As Word ' interactivity disable switch 0 = ON, >0 = OFF Dim Init As Word ' flag for interactivity mode initialisation RadaRodo Dim coldboot As Word ' set to 1 on init - stays 0 until power is switched off Dim difword As Word Dim CC70 As difword.Byte0 ' time interval for acceleration accel Dim surfword As Word Dim CC71 As surfword.Byte0 ' time interval for dS1. differential of surface Dim dS As SWord ' first derivative of surface data Dim CC72 As Word ' sensit for RodoRising radar 1 Dim CC73 As Word ' sensit for RodoRising radar 2 Dim noiseword As Word Dim CC74 As noiseword.Byte0 Dim CC75 As SWord ' for pitch mapping (divider) on ebow notes Dim CC77 As Word ' for pitch mapping (divider) on beater notes Dim CC78 As Word ' for accelleration mapping in RadaRodo (multiplier) ' variables for RadaRodo Dim Nt[NrNotes] As Byte ' mapping Dim eNt[NrEnotes] As Byte Dim nidx As Word Dim noot As Byte ' note for interactive mode RadaRodo Dim oldnoot As Byte Dim ebnoot As Byte ' note for ebow in interactive mode RadaRodo Dim oldebnoot As Byte '$ifdef Rodo_Radar2 ' its not harmfull to also include it in the Radar1 code Dim R1ebnoot As Byte ' ebow note played by radar 1 '$endif Dim veel As Byte ' velocity byte for RadaRodo Dim lites As Word Dim Blue As lites.0 ' on/off flags Dim Red As lites.1 Dim Yellow As lites.2 Dim FWhite As lites.3 Dim BWhite As lites.4 Dim RotRed As lites.5 Dim ritme As Word Dim tg As ritme.0 ' beaters toggle bit for composition code Dim ebtg As ritme.1 ' ebow toggle bit for composition code Dim lbtg As ritme.2 ' toggle for blue and red lights Dim entg As ritme.3 ' periodically switch ebow on and off, to avoid feedback Dim cttg As ritme.4 ' used to send controllers every minute from radar2 Dim aval As SWord ' limited accelleration value must be signed bipolar! Dim ctrlcnt As Word ' counter in sequencer for midi controllers Dim IApiece As Word ' set with prog.change to select an interactive mapping. ' this way it is possible to embed different compositions. ' Variables for RodoRising (piece 2): [IApiece = 2] Dim Qm As Float ' quantity of movement: dS * accel Dim sens As Word ' sensitivity for trigger Dim duur As Dword ' Variable for automated time scheduling of the embedded compositions. Dim Klok As Word ' if we increment this variable on each change of TIM3.8 ' it has a pace of 71", or a bit over a minute Dim Kltg As ritme.8 Dim start As Word Dim halt As Word ' stop is a reserved statement, hence we use halt Dim duration As Word ' memo: controllers defined on the Rodo ebow control board: ' Dim CC1 As Word ' jitter ctrl ' Dim CC2 As Word ' duty cycle control ' Dim CC3 As E_Drive_Flags.0 ' e-bow on/off or mute flag ' Dim CC4 As E_Drive_Flags.1 ' feedback on/off flag ' Dim CC5 As E_Drive_Flags.2 ' note inject mode on/off flag ' Dim CC6 As E_Drive_Flags.3 ' note on/off or keypressure commands for note inject ' Dim CC7 As Word ' Dim CC11 As Word Dim Dur2[128] As Word ' durations for tasks Dim Dur[128] As Word ' chromatic mapping Dim EbTimes[10] As Dword ' 24.04.2017 - for controller sequencing of ebow functions Variable_Inits: Clear IApiece ' so we start with RadaRodo Clear Init ' force initialisation GoSub Dur_Lookup1 GoSub Dur_Lookup2 GoSub Note_Lookup Set coldboot ' reset after initialisation Clear RCBuffer ' Rx Clear RCIdxIn ' Clear the buffer internal pointer Clear RCIdxOut ' Clear the buffer external pointer Clear time Clear otime Clear TXBuffer ' Tx Clear TXIdxIn Clear TXIdxOut Set TimVals ' array Clear velflags Clear DataBuffer ' ADC - surface data Clear DataInIdx Clear DataOutIdx ' not used Clear Speedbuffer ' speeddata - buffer Clear SpeedInIdx Clear Spd ' period buffer Clear SpdInIdx Clear SpdOutIdx $ifndef Radar4 Low green_led Low yellow_led Low orange_led $else HexDis (15) ' blank display $endif ' initialise data acquisition system: (this is allways ON even when interactivity is disabled) Set IEC0.0 ' enable external INT0 IRQ for speed measurement Set IEC0bits_T1IE ' start Timer1 IRQ Set IEC0.13 ' enable ADC IRQ Clear IFS0.13 ' clear ADC IRQ flag $ifdef Rodo_Radar1 PDC1 = 0 ' 12 bits resolution - for FM on the radar $endif $ifdef Rodo_Radar2 PDC1 = 4095 ' making sure both radars are on different frequencies $endif Clear AD1CON1.0 ' clear done bit ADC Set AD1CON1.1 ' start sampling ' start timer 5 as sampling rate generator for the ADC: PR5 = 288 ' without prescaler we had 58500 '14606 Clear IFS1.12 ' clear irq flag Set IEC1bits_T5IE ' set IEC1.12 ' start IRQ ' same for timer 4, sampling speed and accelleration: PR4 = 1000 'without prescaler 64000 Clear IFS1bits_T4IF ' clear interrupt flag Set IEC1bits_T4IE ' enable interrupt oldsample = DC_Offset_Init Clear CC65 ' so interactivity is on on cold boot accel = 0 aval = 0 Clear lites Clear ritme CC70 = 10 ' dt for derivative of speed CC71 = 36 ' dt for derivative of surface CC72 = 36 ' sensit. for rodorising radar 1 CC73 = 36 ' sensit. for rodorising radar 2 CC74 = 5 ' noise floor for surface data CC75 = 1 ' pitch mapping divider for ebow notes CC77 = 1 ' pitch mapping sensitivity (divider) for beater notes ' 15.04.2017: autoregulating now. ' the controller can be set to reset the value. CC78 = 1 ' accelleration mapping multiplier ' this corresponds to midi value 0 ' as we add 1 in the controller procedure GoSub Init_RadaRodo ' this will clear coldboot once GoTo MAIN ' jump over interrupt handlers Interrupt_handling: ' ------------------- Isr- INT0Interrupt ' used to measure period of radar doppler frequency ' this interrupt is received on a low going edge of the comparator signal. ' timer1 is started here for period measurement ' in this version the INT0 stays always enabled ' 20.04.2017: overflow counter added such that we can measure very slow speeds as well ' In principle it is impossible that the input signal stays low ' With the change of comparator circuit, we are now measuring full ' periods, no longer half periods. ' If the doppler frequency for a movement of 1 m/s is 70Hz the period is 14.28 ms ' This is equivalent to a count of 3354 units ' Taking 5 m/s as maximum possible speed of movement, the minimum valid count becomes 670 ' Taking 1cm/s as slowest possible speed, the maximum count becomes 335400 units. ' Inverting the periods to speed or frequency values gives us a range of 1 to 500 Clear IFS0.0 ' clear interrupt flag ' new coding: t1val.Word0 = TMR1 t1val.Word1 = T1overflow Clear TMR1 ' reset timer Clear T1overflow If t1val > t0val + 670 Then Clear t0val If t1val > 335400 Then t1val = 335400 Inc SpdInIdx Spd[SpdInIdx] = 335400 / t1val ' 1 to 500 Clear Period_Invalid_Flag Else ' in this case we had glitches on the input Set Period_Invalid_Flag t0val = t1val ' or t0val = t0val + t1val ??? EndIf EndIsr- Isr- T1Interrupt ' timer1 interrupt ' happens on timer1 overflow (279 ms) ' here to be used for period measurement triggered with INT0 ' if this interrupt happens, we have a timer overflow. Clear IFS0bits_T1IF ' Reset the Timer1 interrupt flag Clear TMR1 ' this is required as we always start the chrono from 0 ' Clear IEC0bits_T1IE ' disable timer 1 interrupt (stop timer, it is started in INT0) Inc T1overflow ' increment timer overflow counter ' each unit is 279 ms 'Toggle green_led ' this works EndIsr- Isr- T3Interrupt Clear IFS0bits_T3IF ' 32-bit value reached (T2/T3 combined) ' this is our main timer! ' this interrupt should never happen... EndIsr- Isr- T4Interrupt ' sampler for movement speed ' used for accelleration measurement and maintenance of a speed databuffer ' this is a periodic timer set to 234 S/s Clear IFS1bits_T4IF ' 16-bit value reached , clear interrupt flag ' Clear IEC1bits_T4IE ' disable interrupt Clear TMR4 ' average available speed measurements acquired in the INT0 ISR: Clear AvSpeed Clear j While SpdOutIdx <> SpdInIdx Inc SpdOutIdx Inc j AvSpeed = AvSpeed + Spd[SpdOutIdx] Wend If j > 0 Then AvSpeed = AvSpeed / j TimVals[4] = time + 200 ' enable integrator for speed data Set resort_flag ' for sorttimers ' toggle yellow_led ' 09.04.2017: 117Hz or sampling rate = 234 S/s EndIsr- Isr- T5Interrupt ' used as sampling rate clock source for the ADC ' for rodo-radar we set it at 2048 S/s in a first experiment. ' this is about twice the highest possible frequency in the input signal (ca. 1kHz) ' thus meeting the Nyquist law. ' 08.04.2017: set to 1024 S/s ' 09.04.2017: Prescaler set to :256 Clear IFS1bits_T5IF ' 32-bit value reached if T4/T5 operation ib 32 bits ' 16-bit value reached if operated alone. Clear TMR5 Clear AD1CON1.1 ' start conversion of the automatically acquired sample 'Toggle yellow_led ' for debug, measurement of sampling rate ' 09.04.2017: 406Hz, so 812 S/s EndIsr- Isr- U1RXInterrupt ' UART receive IRQ - midi receiver Clear IFS0.11 ' reset UART1 receive irq flag 'Inc RCIdxIn ' Move up the buffer index (0-255) ' if we make the buffer larger, we need to AND ' the index with the size of the buffer -1. RCIdxIn = (RCIdxIn + 1) & RCBufSize RCBuffer[RCIdxIn] = U1RXREG 'Toggle midi_led 'debug EndIsr- Isr- U1ErrInterrupt ' this irq is generated on UART1 receive errors ' this interrupt is enabled by setting IEC4.1 ' error handling: Clear IFS4.1 ' clear interrupt flag If U1STA.2 = 1 Then 'Set framing_error_led ' no longer happening EndIf If U1STA.1 = 1 Then ' = overrun error 'Set overrun_error_led ' not happening Clear U1STA.1 EndIf EndIsr- Isr- U1TXInterrupt ' UART send IRQ Clear IFS0bits_U1TXIF ' reset UART1 transmit IRQ flag $ifndef Radar4 Toggle green_led ' transmit monitor $endif EndIsr- Isr- AD1Interrupt ' this irq happens after every ADC conversion ' the sampling rate is controlled by timer 5 , here 2048 S/s ' use of floats here crashes the compiler. ' even using a multiply seems impossible ' 08.04.2017: sampling rate down to 1024 S/s Clear IFS0.13 ' clear AD1 interrupt flag Clear AD1CON1.0 ' clear the conversion-done flag sample = ADC1BUF0 ' 12-bit value format 0000 xxxx xxxx xxxx ' differenciator version with rectification: If sample > oldsample Then recn = sample - oldsample Else recn = oldsample - sample ' rec now 0 --> 2048 EndIf rec = recn + recp ' minimal integration 0 --> 4096 recp = recn oldsample = sample ' now we use a one shot timer to perform integration using floats ' thus integration will be synchronous with the sampling rate ' there can be jitter! TimVals[3] = time + 120 Set resort_flag ' for sorttimers ' Toggle orange_Led ' for testing sampling rate. Sampling rate is this frequency * 2 EndIsr- Isr- PWM1Interrupt Clear IFS5.14 EndIsr- Isr- PWM2Interrupt Clear IFS5.15 EndIsr Isr- PWM3Interrupt Clear IFS6.0 EndIsr- GetMidi: If RCIdxIn <> RCIdxOut Then RCIdxOut = (RCIdxOut + 1) & RCBufSize Bytein = RCBuffer[RCIdxOut] Else Set Bytein EndIf Return 'GetADC: ' here we can perform data extraction and signal conditioning ' the data-buffer has 256 words ' as we sample at 2048 S/s this covers 125 ms 'Return Proc mPlay (stat_byte As Byte, not_byte As Byte, vel_byte As Byte) ' can be used for all 3-byte midi messages TXIdxIn = (TXIdxIn + 1) & TXBufSize ' overflow at 1023 TXBuffer[TXIdxIn] = stat_byte TXIdxIn = (TXIdxIn + 1) & TXBufSize TXBuffer[TXIdxIn] = not_byte TXIdxIn = (TXIdxIn + 1) & TXBufSize TXBuffer[TXIdxIn] = vel_byte EndProc Proc mOut (stat_byte As Byte, dat_byte As Byte) ' can be used for all 2-byte midi messages TXIdxIn = (TXIdxIn + 1) & TXBufSize ' overflow at 1023 TXBuffer[TXIdxIn] = stat_byte TXIdxIn = (TXIdxIn + 1) & TXBufSize TXBuffer[TXIdxIn] = dat_byte EndProc Proc HexDis (dat_byte As Byte) ' displays a number on the Radar4 display $ifdef Radar4 PORTB.5 = dat_byte.0 ' a-input PORTB.0 = dat_Byte.1 ' b-input PORTB.1 = dat_Byte.2 ' c-input PORTA.1 = dat_Byte.3 ' d-input PORTA.4 = dat_Byte.4 ' right dot 'PortB.4 = dat_Byte.5 ' left dot - not implemented on the display IC $endif EndProc MAIN: If coldboot = 1 Then $ifdef Rodo_Radar1 ' board 1 sends a message to board 2 ' board 2 sends the initialisation on reception of this command mOut (Aftertouch_Status, 1) Clear coldboot $endif ' in Radar2 coldboot is cleared after initialisation EndIf While 'Repeat ' timer23 version: ' overflows after 5 hours. time.Word0 = TMR2 ' time is a dword var time.Word1 = TMR3HLD ' resolution is 4.224 us 'slowdown loopspeed: [this does not improve the coding a bit...] 'Until time <> otime 'otime = time $ifdef Enable_UART_RX ' if receiver is enabled GoSub GetMidi ' Read data from the serial buffer ' Start the midi parser. ' bytes can come in at a maximum rate of 300us each Midi_Parse: If Bytein > Pitchbend_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 EndIf GoTo Midi_Parse_done '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 Set velo Case Keypres_Status statusbyte = Bytein Set notePres Set pres Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status ' tuning and piece selection statusbyte = Bytein Set prog Case Aftertouch_Status ' used by Radar 1 to send messages to Radar 2 statusbyte = Bytein Set aft Case Pitchbend_Status statusbyte = Bytein Set pblsb Set pbmsb EndSelect Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Midi_Parse_done 'disregard Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein 'message complete, so we can do the action... Select noteUit Case lowtes To hightes ' relay to the midi transmit buffer mPlay (NoteOff_Status, noteUit, release) Case 112 To 127 ' lights ' relay to the midi transmit buffer mPlay (NoteOff_Status, noteUit, release) EndSelect Set noteUit 'reset EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then ' note off via velo=0 Select noteAan Case lowtes To hightes ' transmit Tx mPlay (NoteOn_Status, noteAan, 0) Case 112 To 127 mPlay (NoteOn_Status, noteAan, 0) EndSelect Else Select noteAan Case lowtes To hightes ' transmit TX mPlay (NoteOn_Status, noteAan,velo) Case 112 To 127 ' lights mPlay (NoteOn_Status, noteAan, velo) EndSelect EndIf Set noteAan EndIf Case Keypres_Status If notePres = 255 Then notePres = Bytein Else pres = Bytein Select notePres Case lowtes To KPhightes ' transmit TX mPlay (Keypres_Status, notePres, pres) EndSelect Set notePres EndIf Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller ' midi TX handled in procedure EndIf Case ProgChange_Status If prog = 255 Then 'single byte message prog = Bytein Select prog Case 0 ' transmit TX mOut (ProgChange_Status, prog) Case 12 To 23 mOut (ProgChange_Status, prog) Case > 63 IApiece = prog - 64 ' valid for radar 1 and 2 Clear Init ' so this counts from 0 to 63 $ifdef Rodo_Radar1 mOut (ProgChange_Status, prog) Select IApiece Case 0 GoSub Init_RadaRodo Case 1 GoSub Init_RodoRising EndSelect $endif ' radar 2 does not have to forward this command. ' however, radar 2 should send the initialisations ' to rodo. $ifdef Rodo_Radar2 Select IApiece Case 0 Set TimVals[6] Clear ctrlcnt Set resort_flag GoSub Init_RadaRodo Case 1 Set TimVals[6] Clear ctrlcnt Set resort_flag GoSub Init_RodoRising EndSelect $endif $ifdef Radar4 HexDis (IApiece) $endif EndSelect Set prog EndIf Case Aftertouch_Status If aft = 255 Then aft = Bytein ' we use it only to send msg's to radar 2 board... ' so there is no code for Radar1 here. $ifdef Rodo_Radar2 ' receive the ebow note played by radar 1 ' radar 1 should set the note to 0 when it's no longer playing Select aft Case 0 Clear R1ebnoot ' Case 1 ' ' command to send initialisations to Rodo ' TimVals[2] = time + 351617 ' 1.5 seconds ' Set resort_flag ' ' timer calls Init_RadaRodo Case lowtes To KPhightes ' receive the note radar1 is playing on the bow R1ebnoot = aft EndSelect $endif Set aft EndIf Case Pitchbend_Status If pblsb = 255 Then pblsb = Bytein Else pbmsb = Bytein mPlay (Pitchbend_Status, pblsb, pbmsb) Set pblsb EndIf EndSelect EndIf $endif Midi_Parse_done: ' interactivity code: ' If CC65 = 0 Then ' if the radars are enabled: ' here we can select a piece/mapping depending on the value of IApiece (0-63) ' this has to be activated when we get other composers to write ' interactive mappings for . ' It is also possible to embed midi files if we decide on an appropriate format. ' This may require some extra tasks for timing. ' for timing: If TMR3.8 <> Kltg Then Kltg = TMR3.8 Inc Klok ' time units are ca. 71", so a bit more than minutes EndIf Select IApiece Case 0 If halt > Klok Then ' so halt must be set on entry GoSub RadaRodo Else Clear Klok Clear Init ' this should cause the init procedure to be called GoSub Init_RodoRising IApiece = 1 EndIf Case 1 If halt > Klok Then GoSub RodoRising Else Clear Klok Clear Init GoSub Init_RadaRodo ' becomes Init_Piece3 later on IApiece = 0 ' becomes next piece later on EndIf ' when we have more pieces we can go on as: ' case 2 ' If halt <= Klok Then ' Gosub piece3 ' else ' Clear Klok ' Clear Init ' Gosub Init_RadaRodo ' IApiece = 0 ' endif EndSelect Else ' in this case interactive code is disabled. Clear Klok ' reset the slow timer EndIf If resort_flag = 1 Then GoSub SortTimers 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 ' note repetitions If oldnoot > 0 Then aval = accel * CC78 If aval > 0 Then If aval > 40 Then aval = 40 ' send note ON: If DataBuffer[DataInIdx] > CC74 Then ' cc74 sets the noise level mPlay (NoteOn_Status, oldnoot, DataBuffer[DataInIdx]) ' so amplitude will be modulated in real time TimVals[0] = time + Dur[aval] ' so note repetition speed is a function of positive acceleration Else Clear oldnoot Set TimVals[0] EndIf Else Set TimVals[0] Clear oldnoot EndIf Else Set TimVals[0] ' cancel repetitions EndIf Case 1 ' ebow task this is a one-shot for note-off If oldebnoot > 0 Then mPlay (Keypres_Status, oldebnoot, 0) Clear oldebnoot EndIf Set TimVals[1] Case 2 ' new sequenced coding 25.04.2017 ' not working 29.04.2017 ' should be obsolete 05.05.2017 ' If Red = 1 Then ' mPlay (NoteOff_Status, RedLite, 0) ' Clear Red ' Else ' mPlay (NoteOn_Status, RedLite, 127) ' Set Red ' EndIf Set TimVals[2] Case 3 ' integration task for ADC data, used to keep float operations outside the ' interrupt handlers. ' now this task is started from within the ADC interupt handler 'ADfloat = (ADfloat * 0.995) + (rec * 0.005) ' 12 bit 0-4095 - works but integrates too much ADfloat = (ADfloat * 0.95) + (rec * 0.05) ' 06.05.2017 Inc DataInIdx 'DataBuffer[DataInIdx] = Sqr(ADfloat * 4) ' 0-127 range quadratic - this works, but gives to small discrimination 'DataBuffer[DataInIdx] = Sqr(ADfloat) * (ADFloat / 2048) ' not compiling..., so we split it: 'DataBuffer[DataInIdx] = SQR(ADFloat) ' 0-64 'DataBuffer[DataInIdx] = DataBuffer[DataInIdx] * (1 + (ADfloat/ 4096)) ' 06.05.2017: ' DataBuffer[DataInIdx] = Sqr(ADfloat) ' 0-64 ' DataBuffer[DataInIdx] = DataBuffer[DataInIdx] * (1.5 + (ADfloat/ 8192)) ' or: (best mapping so far...) DataBuffer[DataInIdx] = Sqr(ADfloat * 2) ' 0-90.5 DataBuffer[DataInIdx] = DataBuffer[DataInIdx] * (0.5 + (ADfloat/ 56)) 'DataBuffer[DataInIdx] = ADfloat / 32 ' 0-127 - linear dS = DataBuffer[DataInIdx] - DataBuffer[DataInIdx - CC71] ' CC71: derivative time interval PDC3 = DataBuffer[DataInIdx] << 4 ' 0-4064 - white LED's ' 09.04.2017: low frequency oscillation noticed here ' synchronous with watchdog LED... ' Noticed a 117kHz oscillation on the analog voltage (1V pp !!!) ' input pin on the PIC (pin 28) ' Hardware bug! Use different coil with higher inductance here. ' Coil replaced with 1 Ohm wirewound resistor. Works fine now... ' This problem was not observed on Radar1. Set TimVals[3] 'Toggle Yellow_led ' for sampling rate measurement - 09.04.2017: 406Hz or SR = 812 S/s o.k. Case 4 ' integration task for speed ' task started from within the interrupt handler T4float = (T4float * 0.95) + (AvSpeed * 0.05) ' store speed data in a buffer: ' this buffer has a length of 250ms Inc SpeedInIdx ' move up the buffer index - must be a byte variable! Speedbuffer[SpeedInIdx] = T4float ' calculate the first derivative, or acceleration: accel = T4float - Speedbuffer[SpeedInIdx - CC70] ' CC70 sets the derivative time interval: 1- 255 'Toggle yellow_led ' for sampling rate measurement. - gives 117Hz, so sampling rate is now 234 S/s PDC2 = Speedbuffer[SpeedInIdx] << 5 ' blue LED - speed monitor ' for debug and range checking: ' If ABS(accel) > 4 then ' > 64 is impossible. > 50 happens but not often > 30 ok > 5 tested o.k. ' set Orange_led ' so we can safely multiply the value by 2 to get a range of -64 to + 63 ' else ' Clear Orange_led ' endif Set TimVals[4] Case 5 ' used for RodoRising Clear velflags.5 Set TimVals[5] Case 6 ' used as a sequencer for rodo controllers on Radar2 ' this would now probably also work without sequencing (05.05.2017) $ifdef Rodo_Radar2 Select ctrlcnt Case 0 mPlay (Control_Status, 3, 0) Clear CC3 Clear ebnoot TimVals[6] = time + EbTimes[ctrlcnt] '5000 ' 21ms Inc ctrlcnt $ifndef Radar4 Set orange_led $endif Case 1 mPlay (NoteOn_Status, FWhiteLite, 0) ' visual cue for ebow off TimVals[6] = time + EbTimes[ctrlcnt] '3604480 ' 3604480 = off time 15" Inc ctrlcnt $ifndef Radar4 Clear orange_led $endif Case 2 mPlay (Control_Status, 5, OnVal) CC5 = OnVal TimVals[6] = time + EbTimes[ctrlcnt] '5000 Inc ctrlcnt $ifndef Radar4 Set orange_led $endif Case 3 If IApiece = 0 Then mPlay (Control_Status, 6, OnVal) CC6 = OnVal Else mPlay (Control_Status, 6, 0) Clear CC6 EndIf TimVals[6] = time + EbTimes[ctrlcnt] Inc ctrlcnt $ifndef Radar4 Clear orange_led $endif Case 4 mPlay (Control_Status, 7, 110) ' sustain value CC7 = 110 TimVals[6] = time + EbTimes[ctrlcnt] '5000 Inc ctrlcnt $ifndef Radar4 Set orange_led $endif Case 5 mPlay (Control_Status, 2, 127) ' duty cycle CC2 = 127 TimVals[6] = time + EbTimes[ctrlcnt] '5000 Inc ctrlcnt $ifndef Radar4 Clear orange_led $endif Case 6 mPlay (Control_Status, 1, 20) ' jitter CC1 = 20 TimVals[6] = time + EbTimes[ctrlcnt] '5000 Inc ctrlcnt $ifndef Radar4 Set orange_led $endif Case 7 mPlay (Control_Status, 3, OnVal) ' only now it will play CC3 = OnVal TimVals[6] = time + EbTimes[ctrlcnt] '5000 Inc ctrlcnt $ifndef Radar4 Set orange_led $endif Case 8 mPlay (NoteOn_Status, FWhiteLite, 127) ' visual cue for ebow on TimVals[6] = time + EbTimes[ctrlcnt] ' 3604480 ' on time 15" Inc ctrlcnt Case 9 TimVals[6] = time + EbTimes[ctrlcnt] '5000 Clear ctrlcnt EndSelect $endif ' $ifdef Rodo_Radar1 ' ' on radar1 we use this timer for sending aftertouch commands to Radar2 ' ' should now (05.05.2017) be obsolete ' mOut (Aftertouch_Status, ebnoot) ' Set TimVals[6] ' $endif 'Case Else ' ' in dit geval is idx geset ' GoTo jumpout EndSelect GoSub SortTimers ' find a new nxt and idx EndIf ' beveiliging tegen overflow crashes... ' we never saw this happening. If maxtim = 1 Then Clear TMR2 Clear TMR3HLD Clear time Set TimVals $ifdef Radar4 HexDis (14) $endif ' reboot: Clear coldboot Clear IApiece GoTo MAIN EndIf Else ' no timers running, so to avoid overflows, we can safely reset the loop timer ' not sure whether this can ever happen with this code, as we always have timers active. ' verified: it does happen! (06.05.2017) If maxtim = 1 Then Clear TMR2 Clear TMR3HLD ' this resets maxtim ' ' for debug: ' $ifdef Radar4 ' Hexdis (14) ' t displayed ' $endif EndIf EndIf $ifdef Enable_UART_TX Midi_OutPut: ' the internal buffer is only 4 bytes large! ' should we check for U1STA.9 to be 0? If this bit is 1, the buffer is full. If TXIdxOut <> TXIdxIn Then ' in dit geval is er een byte te versturen If IFS0bits_U1TXIF = 0 Then ' interrupt flag is reset ' added 06.05.2017: - this should make sequencing midi out unneeded. If U1STA.8 = 1 Then ' checking U1STA.9 =0 does not work TXIdxOut = (TXIdxOut + 1) & TXBufSize ' circular buffer U1TXREG = TXBuffer[TXIdxOut] EndIf EndIf EndIf $endif $ifndef Radar4 Toggle loopcnt ' for loopspeed measurement: 1.93 us now (258kHz) with jitter! 12.04.2017 ' with the t0 construction now: 15us to 8.84us (65kHz to 113kHz) 15.04.2017 $endif $ifdef Radar4 'HexDis (time.Byte3) ' only here for display test. - this works fine. Toggle PORTB.4 ' loopspeed measurement , on not-connected left dot on display. $endif watchdog_led = time.16 ' this is the red LED on each PIC. Wend '-------------------------- end of the main program 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 i Repeat If TimVals[i] < Nxt Then Nxt = TimVals[i] idx = i EndIf Inc i Until i = NrTasks ' after the Proton manual, the repeat construction should be faster than the ' construction using a for next loop: 'For i = 0 To LastTask ' If TimVals[i] < Nxt Then ' Nxt = TimVals[i] ' idx = i ' EndIf 'Next i Clear resort_flag Return ' ************************************************************************************** ' procedures for midi receiver: Controller: ' here we have to transmit all controllers implemented on , not just those for the e-bow!!! Select Ctrl Case 1 ' pitched noise generator CC1 = value mPlay (Control_Status, 1, value) Case 2 ' global waveform control CC2 = value mPlay (Control_Status, 2, value) Case 3 ' inject system with e-bow on/off controller CC3 = value mPlay (Control_Status, 3, value) Case 4 ' feedback mode on/off CC4 = value mPlay (Control_Status, 4, value) Case 5 ' note inject on/off switch CC5 = value mPlay (Control_Status, 5, value) Case 6 ' note on/off or key pressure mode CC6 = value mPlay (Control_Status, 6, value) Case 7 ' sustain level controller CC7 = value mPlay (Control_Status, 7, value) Case 11 ' sets the amplitude for the e-drive feedback mode CC11 = value mPlay (Control_Status, 11, value) Case 14 To 19 mPlay (Control_Status, Ctrl, value) ' Case 17 ' global attack time control ' Case 18 ' global decay time control ' Case 19 ' global release time control Case 64 ' sustain mPlay (Control_Status, 64, value) Case 65 ' only implemented on the radar boards. ' Radar1 board should relay this to the Radar2 board ' Radar2 board does not relay this to , but sends an allnotesoff command. $ifdef Rodo_Radar1 mPlay (Control_Status, 65, value) $endif If value > 0 Then Set CC65 ' disables interactivity ' on both radar boards ' 13.04.2017: remmed, as this seems to disable the ebow... ' $ifdef Rodo_Radar2 ' mPlay (Control_Status, 123, 0) ' send all notes off command to avoid stuck notes ' $endif Clear Init ' so if interactivity is switched on again, ' the appropriate controllers will be sent again. Else Clear CC65 ' default: Interactivity is enabled ' so it will work on startup even without midi input ' Users should set this controller to switch the radars off EndIf $ifdef Rodo_Radar2 If value > 0 Then Set TimVals[6] Set resort_flag Clear ctrlcnt EndIf $endif Case 66 mPlay (Control_Status, 66, value) 'on/off for the robot If value = 0 Then ' power down For i = 0 To LastTask Set TimVals[i] 'this stops the data acquisition... Next i Set resort_flag Clear Init ' so on restart, the controllers will be sent again. Set CC65 ' switch interactivity OFF CC74 = 5 CC72 = 36 ' sensit. for rodorising radar 1 CC73 = 36 ' sensit. for rodorising radar 2 EndIf Case 70 ' controller 70-80 are reserved for parameter control ' in interactive modes of operation. ' time interval for accelleration calculation in accel CC70 = value + value + 1 '1 to 255 ' for Radar1, we have to forward this to Radar2 board! ' the radar2 board does not need to send this any further. $ifdef Rodo_Radar1 mPlay (Control_Status, 70, value) $endif Case 71 ' time interval for dS1, differential of surface CC71 = value + value + 1 ' 1 to 255 $ifdef Rodo_Radar1 mPlay (Control_Status, 71, value) $endif $ifdef Rodo_Radar1 Case 72 ' sensit. for Qm CC72 = value $endif Case 73 'id. CC73 = value ' pass this also to Radar 2: $ifdef Rodo_Radar1 mPlay (Control_Status, 73, value) $endif Case 74 ' set noise level for surface data ' init value to be determined from experiments.[ 5 on init] CC74 = value ' 0-127 ' pass this also to Radar 2: $ifdef Rodo_Radar1 mPlay (Control_Status, 74, value) $endif ' so radar2 will not further propagate this command Case 75 ' 15.04.2017: implemented to set/reset the sensitivity for ebow notes ' on speed mapping. ' The value is autoregulating in the code. ' Default value on cold boot is 1 value = 127 - value CC75 = 1 + (value/NrEnotes) $ifdef Rodo_Radar1 mPlay (Control_Status, 75, value) $endif Case 76 ' 15.04.2017: resets(or presets) the sensitivity for pitch mapping of the ' rods with beaters for Radar 1 ' The value is autoregulated in the code. ' Default on coldboot is CC76 = 1 value = 127 - value ' 127 -> 0 CC77 = 1 + (value / NrNotes) ' 8 -> 1 ' this (CC77) is not a typo! ' we use CC77 for both radars in the coding ' only in the midi implementation, they have ' different numbers. ' this controller is not forwarded to Radar 2 and thus only affects Radar1 Case 77 ' 09.04.2017: changes sensitivity for speed on pitch mapping in radarodo ' 15.04.2017: now this controller is autoregulating. ' sending it will reset the value but autoregulation will ' allways remain active. 'value = 127 - value ' 127 -> 0 'CC77 = 1 + (value / NrNotes) ' 8 -> 1 ' so moving the controller up (in GMT or midi) increases the sensitivity $ifdef Rodo_Radar1 ' relay this to Radar 2 mPlay (Control_Status, 76, value) ' 76 is not a typo here! $endif ' radar 2 does not propagate this command. Case 78 '10/04/2017: multiplier for accelleration values in RadaRodo for Radar 1 '15/04/2017: autoregulation implemented. CC78 = value + 1 '$ifdef Rodo_Radar1 ' relay this to Radar 2 ' mPlay (Control_Status, 78, value) '$endif ' radar 2 does not propagate this command Case 79 ' 15.04.2017: accel. multiplier for Radar 2 ' just pass through as CC78 to Radar 2 $ifdef Rodo_Radar1 ' relay this to Radar 2 mPlay (Control_Status, 78, value) ' no typo! $endif Case 100 $ifdef Rodo_Radar1 ' FM modulation for radar 1 ' we no not need to pass this through If value < 127 Then PDC1 = value << 5 ' make 12-bits Else PDC1 = 4095 ' max. EndIf $endif Case 101 ' FM modulation for radar 2 $ifdef Rodo_Radar2 If value < 127 Then PDC1 = value << 5 ' make 12-bits Else PDC1 = 4095 EndIf $endif $ifdef Rodo_Radar1 ' we have to pass this on: mPlay (Control_Status, 101, value) $endif Case 123 ' just pass it through mPlay (Control_Status, 123, 0) EndSelect Set Ctrl 'mandatory reset Return Init_RadaRodo: ' this procedure sends all controllers required to start the RadaRodo piece. ' In fact, only one of the two radar boards should do this. The second board ' being the best candidate. There should be delays to make sure the start-up ' sequence is handled properly. $ifdef Rodo_Radar2 ' send initial controllers as required for the interactive coding ' this needs a delay, as on cold boot the rodo-e-bow pic may not be ready ' as fast as this processor EbTimes[0] = 5000 ' 21ms EbTimes[1] = 3604480 ' 15" EbTimes[2] = 5000 EbTimes[3] = 5000 EbTimes[4] = 5000 EbTimes[5] = 5000 EbTimes[6] = 5000 EbTimes[7] = 5000 EbTimes[8] = 3604480 ' 15" EbTimes[9] = 5000 ' using task sequencer: Clear ctrlcnt ' this will cause a start with ebow off TimVals[6] = time + 5000 Set resort_flag $endif Set Init IApiece = 0 ' to be further implemented: ' for time scheduling of embedded compositions start = Klok duration = 5 ' would be 5 x 71" = 355" = ca. 6' halt = start + duration ' in the loop, we should now compare klok with halt and ' as soon as klok > halt, change the piece. Clear coldboot ' added 05.05.2017 Return Init_RodoRising: $ifdef Rodo_Radar2 ' as sending controllers in a row did not work, ' we try using a sequenced task now: EbTimes[0] = 5000 ' 21ms EbTimes[1] = 240298 ' 1" off EbTimes[2] = 5000 EbTimes[3] = 5000 EbTimes[4] = 5000 EbTimes[5] = 5000 EbTimes[6] = 5000 EbTimes[7] = 5000 EbTimes[8] = 3604480 ' 15" on EbTimes[9] = 5000 Clear ctrlcnt ' = 0 TimVals[6] = time + 5000 Set resort_flag $endif Set Init IApiece = 1 start = Klok duration = 5 ' would be 5 x 71" = 355" = ca. 6' halt = start + duration ' in the loop, we should now compare klok with halt and ' as soon as klok > halt, change the piece. Return RadaRodo: ' first interactive piece for Rodo : IApiece = 0 ' called from the main loop if and as long as CC65 = 0 If Init = 0 Then GoSub Init_RadaRodo ' should be done on cold boot 'Return ' early return from gosub EndIf If time.17 <> tg Then ' = TMR3.0 tg = time.17 ' this is task.freq = 1.8Hz or 0.55" period. ' using the mapping table: ' 15.04.2017: changed to implemenent autoregulation: ' on cold boot, and reset, we now set CC77 = 1 ' 20.04.2017: The theoretical range for the values in Speedbuffer[] are 1 to 500. ' This range corresponds to movement speeds of 1cm/s to 5m/s nidx = Speedbuffer[SpeedInIdx] / CC77 If nidx > LastNote Then Inc CC77 ' 1, 2, 3 .... nidx = LastNote EndIf noot = Nt[nidx] ' apply lookup table veel = DataBuffer[DataInIdx] ' 0-127 , quadratic - mapped on amplitude If veel > CC74 Then ' CC74 = noise floor mPlay (NoteOn_Status, noot, veel) 'oldnoot = noot ' here we start a task for note repetitions on the beaters ' however, we have no cue as to the range of accel... ' this range depends on the setting for CC70 and CC78 ' implementing autoregulation here, would require a float for CC78... aval = accel * CC78 ' 15.04.2017 changed to: (rustiger) ' If aval < -12 Then aval = -12 ' If aval > 50 Then aval = 50 ' TimVals[0] = time + Dur[12 + aval] ' Set resort_flag ' 16.04.2017: nog rustiger, repeats alleen als acceleratie positief is: ' 20.04.2017: extra voorwaarde: noot > oldnoot If aval > 0 Then If noot > oldnoot Then oldnoot = noot If aval > 40 Then aval = 40 TimVals[0] = time + Dur[aval] Set resort_flag EndIf Else ' following was shaky and often not executed, it also ' ought to be sequenced. ' new attempt to do it without sequencing now: If Red = 1 Then mPlay (NoteOff_Status, RedLite, 0) Clear Red EndIf ' sequenced coding would be: still not working 29.04.2017 ' If Red = 1 Then ' TimVals[2] = time + 255 ' with the lite code in the timer section ' EndIf ' single note only Set TimVals[0] ' cancel repeats Set resort_flag EndIf Else ' else for veel > cc74 condition ' note off condition if we are below the noise level If oldnoot > 0 Then 'sending note-off is not required in ' but without it, the dampers will not work Clear oldnoot Set TimVals[0] ' stop note repetitions EndIf 'If Red = 0 Then ' TimVals[2] = time + 255 ' with sequencing now 'EndIf 'without sequencing: If Red = 0 Then mPlay (NoteOn_Status, RedLite, 127) Set Red EndIf Set resort_flag EndIf If Period_Invalid_Flag = 1 Then ' this is a shaky condition ' this flag is set when the period counter on INT0 glitches ' this means either the movement is too fast or below detection threshold. ' This worked without sequencing as it never happens together with notes and ' other midi commands. If Yellow = 0 Then mPlay (NoteOn_Status, YellowLite, 127) Set Yellow EndIf Else If Yellow = 1 Then mPlay (NoteOff_Status, YellowLite, 0) Clear Yellow EndIf EndIf EndIf ' do some lightshow... (both radars) ' this also requires sequencing, unless we can make sure ' it does not coincide with other midi-out's If time.18 <> lbtg Then lbtg = time.18 ' this is task.freq = 0.9 Hz ' lets try a mapping on dS: ' so on increasing movement quantity, the blue light will go on ' the sensitivity for dS can be set with CC71 If dS > 1 Then ' ds is -127 to + 127 If Blue = 0 Then mPlay (NoteOn_Status, BlueLite, 127) Set Blue EndIf Else If Blue = 1 Then mPlay (NoteOff_Status, BlueLite, 0) Clear Blue EndIf EndIf EndIf ' we do the e-bow, four times slower: If time.19 <> ebtg Then ebtg = time.19 ' this is task.freq = 0.45 Hz, or every 2.2" ' using the mapping table for ebow notes: ' nidx = spd / 9 ' / 9 = 0 to 22 ' 15.04.2017: autoregulation added using CC75 nidx = Speedbuffer[SpeedInIdx] / CC75 ' 6 ' 0 to 21 If nidx > LastEnote Then Inc CC75 ' autoregulator nidx = LastEnote ' to play safe... EndIf ebnoot = eNt[nidx] veel = DataBuffer[DataInIdx] ' 0-127 If veel > CC74 Then ' CC74 = noise floor ' play noot If ebnoot <> oldebnoot Then ' zoniet laten we de noot gewoon hangen $ifdef Rodo_Radar2 If R1ebnoot = 0 Then $endif veel = veel >> 2 ' 0-31 veel = veel + 95 If veel > 127 Then veel = 127 ' safety, though it cannot happen. mPlay (Keypres_Status, ebnoot, veel) oldebnoot = ebnoot $ifndef Radar4 Set yellow_led $endif $ifdef Rodo_Radar2 Else Clear oldebnoot ' such that radar2 does not switch off the note played by radar1 EndIf $endif $ifdef Rodo_Radar1 ' message this also to the Radar 2 board ' this prevents the Radar 2 board from using the ebow ' this can be sequenced for radar1, as timer 6 is free here. ' TimVals[6] = time + 20 ' Set resort_flag ' without sequencing: mOut (Aftertouch_Status, ebnoot) ' done on timer run out $endif EndIf ' endif for ebnoot <> oldebnoot Else ' else for veel > CC74 ' noteoff If oldebnoot > 0 Then mPlay (Keypres_Status, oldebnoot, 0) Clear oldebnoot $ifndef Radar4 Clear yellow_led $endif $ifdef Rodo_Radar1 ' message this to the Radar2 board: ' this makes it possible for radar2 to use the ebow Clear ebnoot ' sequenced: 'TimVals[6] = time + 20 'Set resort_flag ' unsequenced: mOut (Aftertouch_Status, 0) ' if sequenced: done on timer run out $endif EndIf EndIf EndIf ' endif for ebow time-toggle ebtg $ifdef Rodo_Radar1 If time.23 <> entg Then ' on radar 1 we use it for the backlight ' this works fine. entg = time.23 mPlay (NoteOn_Status, BWhiteLite, entg) BWhite = entg Nop EndIf $endif Return ' return for the RadaRodo piece '------------------------------------------------------------------------------- RodoRising: ' coding for a second interactive piece for Rodo ' we get here only if CC65 = 0 and IApiece = 1 ' both radars run the same code, so we have two ' non-synchronised lines. 'Qm = (Qm * 0.9) + (dS * accel * 0.1) ' float If Init = 0 Then GoSub Init_RodoRising ' Return EndIf If dS > 0 And accel > 0 Then Qm = dS * accel ' impulse Qm = quantity of movement Else Qm = 0 EndIf ' Qm range can be max. 127 x 50 = 6350 ' so the noise levels in CC72 and CC73 ' need shifting << 4 at least ' coding for the radar ' mapping using the dS - Accel product ' both are signed values! ' the product is positive if both are positive or both negative If velflags.5 = 0 Then ' if the task is free to run... $ifdef Rodo_Radar1 If Qm > CC72 << 6 Then ' and if we are above noise level $endif $ifdef Rodo_Radar2 If Qm > CC73 << 6 Then ' we could also do CC74 * CC73 instead of shifting CC73 $endif ' CC74 is wrong here as we have a different reference Inc nidx ' allways rising pitch If nidx > LastNote Then Clear nidx ' reset at end of range noot = Nt[nidx] ' apply lookup table veel = DataBuffer[DataInIdx] ' 0-127 , quadratic - mapped on amplitude mPlay (NoteOn_Status, noot, veel) oldnoot = noot Set velflags.5 i = Speedbuffer[SpeedInIdx] duur = Dur2[i] << 4 ' dword TimVals[5] = time + duur Set resort_flag Else If oldnoot > 0 Then veel = 127 - DataBuffer[DataInIdx] ' release mPlay (NoteOff_Status, oldnoot, veel) Clear oldnoot EndIf EndIf EndIf Return Dur_Lookup1: ' in chromatic steps. Changed 17.04.2017 Set Dur[0] ' = 65536 = 0.276 " Dur[1] = 61857 Dur[2] = 58385 Dur[3] = 55108 Dur[4] = 52015 Dur[5] = 49095 Dur[6] = 46339 Dur[7] = 43738 Dur[8] = 41283 Dur[9] = 38966 Dur[10] = 36779 Dur[11] = 34714 For i = 12 To 23 Dur[i] = Dur[i-12] >> 1 ' 32767 ... Next i For i = 24 To 35 Dur[i] = Dur[i-24] >> 2 ' 16383 ... Next i For i = 36 To 47 Dur[i] = Dur[i-36] >> 3 ' 8192 ... Next i For i = 48 To 59 Dur[i] = Dur[i-48] >> 4 ' 4095 ... this should be the limit. Next i For i = 60 To 71 Dur[i] = Dur[i-60] >> 5 ' 2047 ... Next i For i = 72 To 83 Dur[i] = Dur[i-72] >> 6 ' 1023 ... Next i ' higher values are absurd here. ' we keep the old values just as placeholders. Dur[84]= 6048 ' freq= 8.26719576719577 Dur[85]= 5951 ' freq= 8.40194925222652 Dur[86]= 5855 ' freq= 8.5397096498719 Dur[87]= 5760 ' freq= 8.68055555555555 Dur[88]= 5668 ' freq= 8.82145377558222 Dur[89]= 5576 ' freq= 8.96700143472023 Dur[90]= 5486 ' freq= 9.11410864017499 Dur[91]= 5398 ' freq= 9.26268988514264 Dur[92]= 5311 ' freq= 9.41442289587648 Dur[93]= 5225 ' freq= 9.56937799043062 Dur[94]= 5141 ' freq= 9.72573429293912 Dur[95]= 5058 ' freq= 9.88533017002768 Dur[96]= 4977 ' freq= 10.0462125778581 Dur[97]= 4897 ' freq= 10.2103328568511 Dur[98]= 4818 ' freq= 10.3777501037775 Dur[99]= 4740 ' freq= 10.548523206751 Dur[100]= 4664 ' freq= 10.7204116638079 Dur[101]= 4589 ' freq= 10.8956199607758 Dur[102]= 4515 ' freq= 11.0741971207087 Dur[103]= 4442 ' freq= 11.2561909049977 Dur[104]= 4370 ' freq= 11.441647597254 Dur[105]= 4300 ' freq= 11.6279069767442 Dur[106]= 4231 ' freq= 11.8175372252422 Dur[107]= 4162 ' freq= 12.013455069678 Dur[108]= 4095 ' freq= 12.2100122100122 Dur[109]= 4029 ' freq= 12.4100273020601 Dur[110]= 3964 ' freq= 12.6135216952573 Dur[111]= 3901 ' freq= 12.8172263522174 Dur[112]= 3838 ' freq= 13.0276185513288 Dur[113]= 3776 ' freq= 13.2415254237288 Dur[114]= 3715 ' freq= 13.4589502018842 Dur[115]= 3655 ' freq= 13.6798905608755 Dur[116]= 3596 ' freq= 13.9043381535039 Dur[117]= 3538 ' freq= 14.1322781232335 Dur[118]= 3481 ' freq= 14.3636885952312 Dur[119]= 3425 ' freq= 14.5985401459854 Dur[120]= 3370 ' freq= 14.8367952522255 Dur[121]= 3316 ' freq= 15.0784077201448 Dur[122]= 3262 ' freq= 15.3280196198651 Dur[123]= 3210 ' freq= 15.5763239875389 Dur[124]= 3158 ' freq= 15.8328055731476 Dur[125]= 3107 ' freq= 16.0926939169617 Dur[126]= 3057 ' freq= 16.3559044815178 = 38.3365Hz 07.08.2016 Dur[127]= 3008 ' 04.08.2016: 8.35ms - 59.5Hz Return Dur_Lookup2: 'using timer23, 1 dur unit is 4.224 us 'used for note repetitions in Set Dur2[0] Dur2[1]= 23674 ' 07.08.2016: 2x100ms = 200ms full period --> 5Hz [o.k.14.08.2016] Dur2[2]= 22917 ' freq= 2.18178644674259 Dur2[3]= 22548 ' freq= 2.21749157353202 Dur2[4]= 22185 ' freq= 2.25377507324769 Dur2[5]= 21827 ' freq= 2.29074082558299 Dur2[6]= 21475 ' freq= 2.32828870779977 Dur2[7]= 21129 ' freq= 2.36641582658905 Dur2[8]= 20789 ' freq= 2.40511809129828 Dur2[9]= 20454 ' freq= 2.44450963136795 Dur2[10]= 20124 ' freq= 2.48459550785132 Dur2[11]= 19800 ' freq= 2.52525252525252 Dur2[12]= 19481 ' freq= 2.56660335711719 Dur2[13]= 19167 ' freq= 2.60865028434288 Dur2[14]= 18858 ' freq= 2.65139463357726 Dur2[15]= 18554 ' freq= 2.69483669289641 Dur2[16]= 18255 ' freq= 2.73897562311695 Dur2[17]= 17961 ' freq= 2.7838093647347 Dur2[18]= 17672 ' freq= 2.82933454051607 Dur2[19]= 17387 ' freq= 2.87571173865532 Dur2[20]= 17107 ' freq= 2.92278014847723 Dur2[21]= 16831 ' freq= 2.97070881112233 Dur2[22]= 16560 ' freq= 3.01932367149758 Dur2[23]= 16293 ' freq= 3.06880255324372 Dur2[24]= 16030 ' freq= 3.11915159076731 Dur2[25]= 15772 ' freq= 3.17017499365965 Dur2[26]= 15518 ' freq= 3.22206469905916 Dur2[27]= 15268 ' freq= 3.27482315954938 Dur2[28]= 15022 ' freq= 3.32845160431367 Dur2[29]= 14780 ' freq= 3.382949932341 Dur2[30]= 14542 ' freq= 3.43831660019254 Dur2[31]= 14307 ' freq= 3.4947927587894 Dur2[32]= 14077 ' freq= 3.55189315905378 Dur2[33]= 13850 ' freq= 3.6101083032491 Dur2[34]= 13627 ' freq= 3.66918617450649 Dur2[35]= 13407 ' freq= 3.72939509211606 Dur2[36]= 13191 ' freq= 3.79046319460238 Dur2[37]= 12978 ' freq= 3.85267375558638 Dur2[38]= 12769 ' freq= 3.91573341686898 Dur2[39]= 12564 ' freq= 3.97962432346386 Dur2[40]= 12361 ' freq= 4.04498017959712 Dur2[41]= 12162 ' freq= 4.1111659266568 Dur2[42]= 11966 ' freq= 4.17850576633796 Dur2[43]= 11773 ' freq= 4.24700586086809 Dur2[44]= 11583 ' 07.08.2016: geeft 10.1177 Hz Dur2[45]= 11397 ' freq= 4.38711941739054 Dur2[46]= 11213 ' freq= 4.45910996165165 Dur2[47]= 11032 ' freq= 4.53226976069616 Dur2[48]= 10855 ' freq= 4.60617227084293 Dur2[49]= 10680 ' freq= 4.6816479400749 Dur2[50]= 10508 ' freq= 4.75827940616673 Dur2[51]= 10338 ' freq= 4.83652544012381 Dur2[52]= 10172 ' freq= 4.91545418796697 Dur2[53]= 10008 ' freq= 4.99600319744204 Dur2[54]= 9846 ' freq= 5.07820434694292 Dur2[55]= 9688 ' freq= 5.16102394715111 Dur2[56]= 9532 ' freq= 5.24548887956357 Dur2[57]= 9378 ' freq= 5.33162721262529 Dur2[58]= 9227 ' freq= 5.4188793757451 Dur2[59]= 9078 ' freq= 5.50782110597048 Dur2[60]= 8932 ' freq= 5.59785042543663 Dur2[61]= 8788 ' freq= 5.68957669549385 Dur2[62]= 8646 ' freq= 5.78302105019662 Dur2[63]= 8507 ' 04.08.2016: 21Hz pulse duur = 23.8ms Dur2[64]= 8370 ' geeft nu 20ms pulsen freq= 25Hz 03.08.2016 ' 14.0017Hz 07.08.2016 Dur2[65]= 8235 ' freq= 6.07164541590771 Dur2[66]= 8102 ' freq= 6.17131572451246 Dur2[67]= 7972 ' freq= 6.27195183140993 Dur2[68]= 7843 ' freq= 6.37511156445238 Dur2[69]= 7717 ' freq= 6.47920176234288 Dur2[70]= 7593 ' freq= 6.58501251152377 Dur2[71]= 7470 ' freq= 6.69344042838019 Dur2[72]= 7350 ' freq= 6.80272108843537 Dur2[73]= 7231 ' freq= 6.91467293597013 Dur2[74]= 7115 ' freq= 7.02740688685875 Dur2[75]= 7000 ' freq= 7.14285714285714 Dur2[76]= 6888 ' freq= 7.25900116144018 Dur2[77]= 6777 ' freq= 7.37789582411096 Dur2[78]= 6667 ' freq= 7.49962501874906 Dur2[79]= 6560 ' freq= 7.62195121951219 Dur2[80]= 6454 ' freq= 7.74713356058258 Dur2[81]= 6350 ' freq= 7.8740157480315 Dur2[82]= 6248 ' freq= 8.00256081946223 Dur2[83]= 6147 ' freq= 8.13404912965674 Dur2[84]= 6048 ' freq= 8.26719576719577 Dur2[85]= 5951 ' freq= 8.40194925222652 Dur2[86]= 5855 ' freq= 8.5397096498719 Dur2[87]= 5760 ' freq= 8.68055555555555 Dur2[88]= 5668 ' freq= 8.82145377558222 Dur2[89]= 5576 ' freq= 8.96700143472023 Dur2[90]= 5486 ' freq= 9.11410864017499 Dur2[91]= 5398 ' freq= 9.26268988514264 Dur2[92]= 5311 ' freq= 9.41442289587648 Dur2[93]= 5225 ' freq= 9.56937799043062 Dur2[94]= 5141 ' freq= 9.72573429293912 Dur2[95]= 5058 ' freq= 9.88533017002768 Dur2[96]= 4977 ' freq= 10.0462125778581 Dur2[97]= 4897 ' freq= 10.2103328568511 Dur2[98]= 4818 ' freq= 10.3777501037775 Dur2[99]= 4740 ' freq= 10.548523206751 Dur2[100]= 4664 ' freq= 10.7204116638079 Dur2[101]= 4589 ' freq= 10.8956199607758 Dur2[102]= 4515 ' freq= 11.0741971207087 Dur2[103]= 4442 ' freq= 11.2561909049977 Dur2[104]= 4370 ' freq= 11.441647597254 Dur2[105]= 4300 ' freq= 11.6279069767442 Dur2[106]= 4231 ' freq= 11.8175372252422 Dur2[107]= 4162 ' freq= 12.013455069678 Dur2[108]= 4095 ' freq= 12.2100122100122 Dur2[109]= 4029 ' freq= 12.4100273020601 Dur2[110]= 3964 ' freq= 12.6135216952573 Dur2[111]= 3901 ' freq= 12.8172263522174 Dur2[112]= 3838 ' freq= 13.0276185513288 Dur2[113]= 3776 ' freq= 13.2415254237288 Dur2[114]= 3715 ' freq= 13.4589502018842 Dur2[115]= 3655 ' freq= 13.6798905608755 Dur2[116]= 3596 ' freq= 13.9043381535039 Dur2[117]= 3538 ' freq= 14.1322781232335 Dur2[118]= 3481 ' freq= 14.3636885952312 Dur2[119]= 3425 ' freq= 14.5985401459854 Dur2[120]= 3370 ' freq= 14.8367952522255 Dur2[121]= 3316 ' freq= 15.0784077201448 Dur2[122]= 3262 ' freq= 15.3280196198651 Dur2[123]= 3210 ' freq= 15.5763239875389 Dur2[124]= 3158 ' freq= 15.8328055731476 Dur2[125]= 3107 ' freq= 16.0926939169617 Dur2[126]= 3057 ' freq= 16.3559044815178 = 38.3365Hz 07.08.2016 Dur2[127]= 3008 ' 04.08.2016: 8.35ms - 59.5Hz Return Note_Lookup: $ifdef Rodo_Radar1 ' lookup table for the rod-notes Nt[0] = 48 Nt[1] = 50 Nt[2] = 52 Nt[3] = 54 Nt[4] = 56 Nt[5] = 58 Nt[6] = 60 Nt[7] = 62 Nt[8] = 64 Nt[9] = 66 Nt[10] = 68 Nt[11] = 70 Nt[12] = 72 Nt[13] = 74 Nt[14] = 76 Nt[15] = 78 ' Nrnotes = 16 ' lookuptable for the ebow-notes eNt[0] = 56 eNt[1] = 58 eNt[2] = 60 eNt[3] = 62 eNt[4] = 64 eNt[5] = 66 eNt[6] = 68 eNt[7] = 70 eNt[8] = 72 eNt[9] = 74 eNt[10] = 76 eNt[11] = 78 eNt[12] = 80 eNt[13] = 82 eNt[14] = 84 eNt[15] = 86 eNt[16] = 88 eNt[17] = 90 eNt[18] = 92 eNt[19] = 94 eNt[20] = 96 eNt[21] = 98 ' is this correct? ' NrEnotes = 22 $endif $ifdef Rodo_Radar2 Nt[0] = 49 Nt[1] = 51 Nt[2] = 53 Nt[3] = 55 Nt[4] = 57 Nt[5] = 59 Nt[6] = 61 Nt[7] = 63 Nt[8] = 65 Nt[9] = 67 Nt[10] = 69 Nt[11] = 71 Nt[12] = 73 Nt[13] = 75 Nt[14] = 77 ' Nrnotes = 15 ' lookuptable for the ebow-notes eNt[0] = 55 eNt[1] = 57 eNt[2] = 59 eNt[3] = 61 eNt[4] = 63 eNt[5] = 65 eNt[6] = 67 eNt[7] = 69 eNt[8] = 71 eNt[9] = 73 eNt[10] = 75 eNt[11] = 77 eNt[12] = 79 eNt[13] = 81 eNt[14] = 83 eNt[15] = 85 eNt[16] = 87 eNt[17] = 89 eNt[18] = 91 eNt[19] = 93 eNt[20] = 95 eNt[21] = 97 ' NrEnotes = 22 $endif Return '[EOF]