'**************************************************************************** '* My first attempts to writing code for a 16 bit PIC * '* This is a framework that implements the main features of the chip * '* as well as the software framework we typically used on 8 bit chips * '* used for our musical robots: a realtime multitasker * ' *************************************************************************** ' 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. ' '01.08.2016: Test and debug board designed, etched and soldered. ' Programming requires the PiCkit3 programmer. PicKit2 does not work! '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. '09.08.2016: Further coding. adsr not yet operational. - version saved as 007 '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. ' PCB made for this app. '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 ' There is a lot of jitter on the main loop, so we must be operating close to ' the maximum performance for this chip. ' 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. ' Coding started. ' 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. ' PCB dsign started for an evaluation board for this synth. '20.08.2016: This design could be used for '23.08.2016: Evaluation board finished. This works o.k. ' bug removed in the duty cycle control: cannot be zero! ' Start work on the coding for ' This file now saved as HybrLo_22_24.bas ' TO DO: ' enable unused pwm pins for general I/O use ' implement vibrato (slow FM modulation) ' implement microtonality +/- quartertone ' implement monophonic inharmonic oscillator ''------------------------------------------------------------------------------------------------------------- ' 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 Config FPOR = ALTI2C1_OFF, ALTI2C2_OFF ' unsure about this 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 ' wait for the clock switch to occur: 'while OSCCON & %0111000000000000 = %0011000000000000 ' mask for COSC bits 14-12 'wend ' wait for pll to lock ' this is done in de PLL_setup macro 'while osccon.5 = 1 'wend Declare Xtal = 120 ' set to Fosc $define Enable_UART_RX ' midi-in $define Enable_UART_TX ' midi-out '$define Enable_ADC12bit ' precompiler instructions $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 'Declare CCP1_Pin PORTB.15 ' pwm1L ' makes no sense as we cannot use Basic HPWM here 'Declare CCP2_Pin PORTB.14 ' pwm1H 'Declare CCP3_Pin PORTB.13 ' pwm2L 'Declare CCP4_Pin PORTB.12 ' pwm2H 'Declare CCP5_Pin PORTB.11 ' pwm3L 'Declare CCP6_Pin PORTB.10 ' pwm3H '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 ' constant declarations and port-assignments for debugging: '*********************************************************** Symbol overrun_error_led PORTB.7 ' this is pin 16 Symbol framing_error_led PORTA.4 Symbol midi_led PORTB.4 Symbol debug_led PORTB.5 ' this is pin 14 Symbol loopcnt PORTB.6 ' this is pin 15 'initialisations for the midi input parser: Symbol Midichannel = 12 ' robot_Channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel Symbol Control_Status = 176 + Midichannel Symbol ProgChange_Status = 192 + Midichannel ' 1 byte message Symbol Aftertouch_Status = 208 + Midichannel ' 1 byte follows Symbol Pitchbend_Status = 224 + Midichannel ' lsb msb follow Symbol NrTasks = 8 'constants used for the operation of the PWM modules ' the modus operandi should be set at compile time! 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) ' 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. ' constants used for the midi-mapping on our testboard: Symbol lite0 = 0 Symbol lite1 = 1 Symbol lite2 = 2 Symbol lite3 = 3 Symbol lite4 = 4 Symbol lite5 = 5 Symbol lite6 = 6 Symbol lite7 = 7 'Symbol slider1 = 12 'Symbol Slider2 = 13 'Symbol slider3 = 14 'Symbol Slider4 = 15 'Symbol slider5 = 16 'Symbol Slider6 = 17 ' port assignments: Symbol lite0_port PORTB.0 Symbol lite1_port PORTB.1 Symbol lite2_port PORTB.4 Symbol lite3_port PORTA.4 Symbol lite4_port PORTB.6 Symbol lite5_port PORTB.7 ' pwm1H, pwm2H, pwm3H used as ADSR outputs ' we configure the L outputs as normal ports for frequency generator outputs TRISA = %100001 ' set to input TRISB = %0101011100000000 'Output overrun_error_led 'Output framing_error_led 'Output midi_led Output debug_led ' watchdog led Output loopcnt $ifdef Enable_Timer1 ' used as tone generator IPC0bits_T1IP0 = 1'1 ' set priority - this is very critical! IPC0bits_T1IP1 = 0'1 '1 ' set to 5 IPC0bits_T1IP2 = 1'1 ' 6 = 011 'TMR1 = 0 ' clear the count 'PR1 = 65535 ' load Timer1 period T1CON.5 = 1 ' set prescaler to :8 = 01 , :64 = 10 , :256 = 11 T1CON.4 = 0 ' prescaler = 1 = 00 (00 does not work: it freezes the PIC) T1CON.15 = 1 ' start IFS0bits_T1IF = 0 ' clear Timer1 interrupt flag 'IEC0bits_T1IE = 1 ' Enable the Timer1 interrupt $endif $ifdef Enable_Timer23 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 TMR3 = 0 PR2 = 65535 PR3 = 65535 IPC2bits_T3IP0 = 1 ' set priority to 1 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 T4CON.15 = 1 ' start timer in 16 bit mode T4CON.13 = 0 T4CON.6 = 0 T4CON.5 = 1 ' prescaler set to :64 T4CON.4 = 0 ' 00 = :1, 01 = :8 , 10 = :64, 11 = :256 T4CON.3 = 0 ' operate as 16 bit timer T4CON.1 = 0 ' internal clock 'TMR4 = 0 'PR4 = 65535 IPC6bits_T4IP0 = 1 ' set priority to 5 IPC6bits_T4IP1 = 0 IPC6bits_T4IP2 = 1 Clear IFS1.11 ' clear interrupt flag 'Set IEC1.11 ' enable interrupt $endif $ifdef Enable_Timer5 T5CON.15 = 1 ' start timer in 16 bit mode T5CON.13 = 0 T5CON.6 = 0 T5CON.5 = 1 ' prescaler set to :64 T5CON.4 = 0 ' id. T5CON.1 = 0 ' internal clock 'TMR5 = 0 'PR5 = 65535 ' preset counter IPC7bits_T5IP0 = 1 ' set priority to 5 IPC7bits_T5IP1 = 0 IPC7bits_T5IP2 = 1 IFS1bits_T5IF = 0 ' clear IRQ flag 'IEC1bits_T5IE = 1 ' enable timer 5 interrupt $endif $ifdef Enable_UART_RX ' init UART1-receiver: 31250 Baud ' should generate 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 IPC2.14 = 1 IEC0.11 = 1 ' enable IRQ for receiver IEC4.1 = 1 ' enable IRQ for error trapping on receiver $endif $ifdef Enable_UART_TX U1STA.15 = 0 'interrupt generated when character transferred to tx buffer and buffer is empty U1STA.15 = 0 U1STA.10 = 1 ' transmit enable bit U1STA.11 = 0 Clear IFS0.12 ' clear transmit interrupt flag Set IEC0.12 ' enable interrupt IPC3.0 = 1 IPC3.1 = 1 IPC3.2 = 0 ' set priority to 3 $endif $ifdef Enable_ADC12bit ' init for ADC system: try 12 bit ADC (500kS/s) 'SMPI1. ADDMAEN = 0 AD1CON1.15 = 1 ' adc module ON AD1CON1.10 = 1 ' select 12-bit mode AD1CON1.9 = 0 ' conversion to right alligned integer 0000 dddd dddd dddd AD1CON1.8 = 0 ' id. AD1CON1.7 = 1 ' auto-convert mode AD1CON1.6 = 1 ' id. AD1CON1.5 = 1 ' id AD1CON1.4 = 0 ' SSRCG AD1CON1.2 = 1 ' sampling immediately after last conversion. SAMP bit it autoset. AD1CON2.15 = 0 ' ref AvDD and AsSS AD1CON2.14 = 0 AD1CON2.13 = 0 AD1CON2.10 = 0 ' no scan ' bits 6-2 = 0 ==> generates interrupt after every sample conversion AD1CON2.1 = 0 ' always fill buffer from the start adres AD1CON2.0 = 0 'use channel input selects for sample MUXA AD1CON3.0 = 0 ' clock derived from system 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 ' ADCS ADC1 conversion clock select bits (sampling rate) AD1CON4.8 = 0 ' no DMA - results stored in ADC1BUF0 to ADC1BUFF registers AD1CHS0 = 0 ' clear complete register. AN0 is input channel ' now we have to enable the interrupt and find out how to transfer data to an array IEC0.13 = 1 ' enable IRQ 'IPC3 <6:4> set the priority level IFS0.13 = 0 ' clear interrupt flag ' --------------------------------------------------------------------------------- $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 active period register is updated immediately 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 Case 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??? 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 ' make the pwmL port free for general I/O: (note_Ports) 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 ' 0xA800 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 the timer-tone generators: 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 pwn3 values for the dury 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: Dim inByte As Byte Dim IndexIn As Byte ' Pointer to the next empty location in the buffer Dim IndexOut As Byte ' Pointer to the location of the oldest character in the buffer Dim Ringbuffer[256] As Byte ' Array for holding received characters in the uart Dim Outbuffer[265] As Byte ' buffer for midi-output UART Dim OutIdxIn As Byte Dim OutIdxOut As Byte 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 ' 10 us resolution Dim maxtim As time.31 ' overflow bit, will cause timer reset after 6 hours Dim t As Word ' loopcounter 750kHz Dim tl As t.Byte0 Dim th As t.Byte1 Dim i As Byte Dim idx As Byte Dim Nxt As Dword Dim TimVals[NrTasks] As Dword Dim tg As Bit Dim resort_flag As Bit Dim Dur[128] As Word Dim Dur5[128] As Word Dim notes As Word Dim VelFlags As Word Dim velo0 As Byte Dim velo1 As Byte Dim velo2 As Byte Dim velo3 As Byte Dim pres0 As Byte Dim pres1 As Byte Dim pres2 As Byte Dim pres3 As Byte Dim DataBuffer[256] As Word ' adc databuffer Dim DataInIdx As Byte Dim DataOutIdx As Byte ' 32 bit vars for 32-bit timers: ' Dim Timer23 As Dword ' Timer23.Word0 = TMR2 ' this should not be possible... ' Timer23.Word1 = TMR3 ' Dim timer45 As Dword ' timer45.Word0 = TMR4 ' timer45.Word1 = TMR5 ' 16 bit variables and floats for the PWM system 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 Dim dutcy1 As Float Dim dutcy2 As Float Dim dutcy3 As Float Dim velo100 As Byte Dim velo101 As Byte Dim velo102 As Byte Dim velo103 As Byte Dim velo104 As Byte Dim velo105 As Byte Dim angle1 As Float Dim angle2 As Float Dim angle3 As Float Dim Period[128] As Word ' midi note lookup table ' variables for the ADSR system: ' Dim CC7 As Byte ' Dim CC17 As Byte ' Dim CC18 As Byte ' Dim CC19 As Byte Dim Attack1_time As Word Dim Attack1_level As Word ' derived from velo, with a log-map Dim Decay1_time As Word Dim Sustain1_level As Word ' derived from volume controller ctrl7, with log-map Dim Release1_Time As Word ' derived from release bit with noteoff commands ' Dim Volume1 As Word ' Dim Waveform1 As Word ' Dim CC27 As Byte ' Dim CC28 As Byte ' Dim CC29 As Byte Dim Attack2_time As Word Dim Attack2_level As Word ' derived from velo, with a log-map Dim Decay2_time As Word Dim Sustain2_level As Word ' derived from volume controller ctrl7, with log-map Dim Release2_Time As Word ' derived from release bit with noteoff commands ' Dim Volume2 As Word ' Dim Waveform2 As Word ' Dim CC36 As Byte ' Dim CC37 As Byte ' Dim CC38 As Byte ' Dim CC39 As Byte Dim Attack3_time As Word Dim Attack3_level As Word ' derived from velo, with a log-map Dim Decay3_time As Word Dim Sustain3_level As Word ' derived from volume controller ctrl7, with log-map Dim Release3_Time As Word ' derived from release bit with noteoff commands ' Dim Volume3 As Word ' Dim Waveform3 As Word Dim ADSR1_flags As Byte ' Dim Attack1_flag As ADSR1_flags.0 ' Dim Decay1_flag As ADSR1_flags.1 ' Dim Sustain1_flag As ADSR1_flags.2 ' Dim Release1_flag As ADSR1_flags.3 ' Dim Sustain1_tog As ADSR1_flags.4 ' Dim Attack1_tog As ADSR1_flags.5 ' Dim Decay1_tog As ADSR1_flags.6 ' Dim Release1_tog As ADSR1_flags.7 ' more logical arrangement, in time order: Dim Attack1_flag As ADSR1_flags.0 Dim Attack1_tog As ADSR1_flags.1 Dim Decay1_flag As ADSR1_flags.2 Dim Decay1_tog As ADSR1_flags.3 Dim Sustain1_flag As ADSR1_flags.4 Dim Sustain1_tog As ADSR1_flags.5 Dim Release1_flag As ADSR1_flags.6 Dim Release1_tog As ADSR1_flags.7 Dim solltime1 As Dword Dim cnt1 As Byte 'Word Dim Astepval1 As Word Dim Dstepval1 As Word Dim Rstepval1 As Word Dim ADSR2_flags As Byte ' Dim Attack2_flag As ADSR2_flags.0 ' Dim Decay2_flag As ADSR2_flags.1 ' Dim Sustain2_flag As ADSR2_flags.2 ' Dim Release2_flag As ADSR2_flags.3 ' Dim Sustain2_tog As ADSR2_flags.4 ' Dim Attack2_tog As ADSR2_flags.5 ' Dim Decay2_tog As ADSR2_flags.6 ' Dim Release2_tog As ADSR2_flags.7 Dim Attack2_flag As ADSR2_flags.0 Dim Attack2_tog As ADSR2_flags.1 Dim Decay2_flag As ADSR2_flags.2 Dim Decay2_tog As ADSR2_flags.3 Dim Sustain2_flag As ADSR2_flags.4 Dim Sustain2_tog As ADSR2_flags.5 Dim Release2_flag As ADSR2_flags.6 Dim Release2_tog As ADSR2_flags.7 Dim solltime2 As Dword Dim cnt2 As Byte Dim Astepval2 As Word Dim Dstepval2 As Word Dim Rstepval2 As Word Dim ADSR3_flags As Byte ' Dim Attack3_flag As ADSR3_flags.0 ' Dim Decay3_flag As ADSR3_flags.1 ' Dim Sustain3_flag As ADSR3_flags.2 ' Dim Release3_flag As ADSR3_flags.3 ' Dim Sustain3_tog As ADSR3_flags.4 ' Dim Attack3_tog As ADSR3_flags.5 ' Dim Decay3_tog As ADSR3_flags.6 ' Dim Release3_tog As ADSR3_flags.7 Dim Attack3_flag As ADSR3_flags.0 Dim Attack3_tog As ADSR3_flags.1 Dim Decay3_flag As ADSR3_flags.2 Dim Decay3_tog As ADSR3_flags.3 Dim Sustain3_flag As ADSR3_flags.4 Dim Sustain3_tog As ADSR3_flags.5 Dim Release3_flag As ADSR3_flags.6 Dim Release3_tog As ADSR3_flags.7 Dim solltime3 As Dword Dim cnt3 As Byte Dim Astepval3 As Word Dim Dstepval3 As Word Dim Rstepval3 As Word Dim Ont[128] As Word ' on-time lookup for pwm Dim Oft[128] As Word ' off-time lookup for pwm Dim On1 As Word ' for timer1 Dim Of1 As Word Dim On2 As Word ' for timer4 Dim Of2 As Word Dim On3 As Word ' for timer5 Dim Of3 As Word Variable_Inits: Clear Ringbuffer ' Rx Clear IndexIn ' Clear the buffer internal pointer Clear IndexOut ' Clear the buffer external pointer Clear time Clear t Clear Outbuffer ' Tx Clear OutIdxIn Clear OutIdxOut Set TimVals Clear DataBuffer ' ADC Clear DataInIdx Clear DataOutIdx GoSub Dur_Lookup GoSub Period_Lookup_Table GoSub PWM_Lookup_Table Attack1_time = 8 * 947 ' should be ca. 32ms . 64=250ms Attack1_level = 127 'does not require an init, controlled by velo byte Decay1_time = 6 * 947 ' should be ca. ... Sustain1_level = 86 ' set with CC7 Release1_Time = 10 * 947 ' set with release byte or ctrl ' Volume1 = 127 dutcy1 = 0.5 'Waveform1 = 127 ' set to 50% duty cycle Attack2_time = 8 * 947 Attack2_level = 127 Decay2_time = 6 * 947 Sustain2_level = 86 Release2_Time = 10 * 947 ' Volume2 =127 dutcy2 = 0.5 'Waveform2 = 127 Attack3_time = 8 * 947 Attack3_level = 127 Decay3_time = 6 * 947 Sustain3_level = 86 Release3_Time = 10 * 947 ' Volume3 =127 'Waveform3 = 127 dutcy3 = 0.5 GoTo MAIN ' jump over irq's Interrupt_handling: ' ------------------- Isr- T1Interrupt ' timer1 interrupt Clear IFS0bits_T1IF ' Reset the Timer1 interrupt flag ' used for pitch generator1 Clear TMR1 ' this is required! If Note_Port1 = 0 Then PR1 = On1 Set Note_Port1 Else PR1 = Of1 Clear Note_Port1 EndIf EndIsr- ' exit the interrupt Isr- T3Interrupt IFS0bits_T3IF = 0 ' 32-bit value reached (T2/T3 combined) ' this is our main timer! EndIsr- Isr- T4Interrupt Clear IFS1bits_T4IF '16-bit value reached Clear TMR4 If Note_Port2 = 0 Then PR4 = On2 Set Note_Port2 Else PR4 = Of2 Clear Note_Port2 EndIf EndIsr- Isr- T5Interrupt IFS1bits_T5IF = 0 ' 32-bit value reached if T4/T5 operation ib 32 bits ' 16-bit value reached if operated alone. Clear TMR5 If Note_Port3 = 0 Then PR5 = On3 Set Note_Port3 Else PR5 = Of3 Clear Note_Port3 EndIf EndIsr- Isr- U1RXInterrupt ' UART receive IRQ - midi receiver Clear IFS0.11 ' reset UART1 receive irq flag Inc IndexIn ' Move up the buffer index (0-255) Ringbuffer[IndexIn] = 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 IFS0bits_U1TXIF = 0 ' reset UART1 transmit IRQ flag 'Toggle midi_led ' transmit monitor EndIsr- Isr- AD1Interrupt ' this irq happens after every ADC conversion Clear IFS0.13 ' clear interrupt flag Inc DataInIdx ' move up the buffer index DataBuffer[DataInIdx] = ADC1BUF0 ' loopt tot ADC1BUFF -so 16 words deep Toggle PORTA.1 ' for testing sampling rate - 04.08.2016: gives 58.82 kHz ' this means 8.5 us for each conversion EndIsr- Isr- PWM1Interrupt Clear IFS5.14 EndIsr- Isr- PWM2Interrupt Clear IFS5.15 EndIsr Isr- PWM3Interrupt Clear IFS6.0 EndIsr- ' attempt to use a procedure... ' Proc GetMidi (byval IndexIn as byte, Byref IndexOut as word, Byref RingBuffer as word) , byte ' ' read procedure for incoming buffered midi bytes ' ' is Indexout and IndexIn global? ' If IndexIn <> Ptr8(IndexOut) then ' inc Ptr16(IndexOut) ' Result = Ptr8(Ringbuffer +IndexOut) ' else ' Result = 255 ' no new byte came in ' endif ' endproc GetMidi: If IndexIn <> IndexOut Then Inc IndexOut Bytein = Ringbuffer[IndexOut] Else Set Bytein EndIf Return GetADC: ' here we can perform data extraction and signal conditioning ' the data-buffer has 256 words and covers 2.176ms of time. Return MAIN: While ' loop counter version: ' Inc t ' word-var ' If tl.7 <> tg Then ' at 750kHz loopspeed tg.4 gives a time resolution of ca. 10 us ?? ' tg = tl.7 ' tl is low byte of t , tl.7 is the seventh bit, so divide by 128 ' 'toggle loopcnt ' geeft pulsetijden van 1.3us ' Inc time ' with 1.3us pulses, this will overflow after 5583 seconds = 1.5 hours ' EndIf ' timer23 version: ' overflows after 5 hours. time.Word0 = TMR2 ' time is a dword var time.Word1 = TMR3 ' resolution is 4.224 us $ifdef Enable_UART_RX ' if receiver is enabled GoSub GetMidi ' Read data from the serial buffer ' Start the midi parser. 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 '= 255 Set velo '= 255 Case Keypres_Status statusbyte = Bytein notePres = 255 pres = 255 Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status ' could be used for different lookup tables statusbyte = Bytein prog = 255 Case Aftertouch_Status ' not used on this board statusbyte = Bytein Set aft Case Pitchbend_Status ' used for saw bending positioning statusbyte = Bytein pblsb = 255 pbmsb = 255 EndSelect Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Midi_Parse_done 'Check_Timers 'disregard Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein 'message complete, so we can do the action... Select noteUit Case lite0 Low lite0_port Clear VelFlags.0 Clear notes.0 Set TimVals[0] Set resort_flag Case lite1 Low lite1_port Clear VelFlags.1 Clear notes.1 Set TimVals[1] Set resort_flag Case lite2 Low lite2_port Clear VelFlags.2 Clear notes.2 Set TimVals[2] Set resort_flag Case lite3 Low lite3_port Clear VelFlags.3 Clear notes.3 Set TimVals[3] Set resort_flag Case lite4 Low lite4_port Case lite5 Low lite5_port ' coding with 3 ADRS's and fixed pwm channels Case 22 To 57 'IF PWMmodus = 0 then Clear ADSR1_flags If release > 0 Then Release1_Time = release ' so if CC19 = release time was set, we use it If Release1_Time > 0 Then Set Release1_flag ' clear PDC1 performed at the end of the release cycle Rstepval1 = Release1_Time / (Sustain1_level +1 ) ' sustain_level mag niet 0 zijn! TimVals[4] = time + Rstepval1 Else ' perform a noteoff - no release phase Set TimVals[4] ' cancel timer Clear PDC1 ' stop adsr - volume to zero Clear IEC0bits_T1IE ' disable timer1 interrupt - now tone generator Clear IFS0bits_T1IF ' clear interrupt flag Clear Note_Port1 EndIf Set resort_flag 'endif Case 58 To 93 'If PWMmodus = 0 Then Clear ADSR2_flags If release > 0 Then Release2_Time = release ' so if CC29 = release time was set, we use it EndIf If Release2_Time > 0 Then Set Release2_flag ' clear PDC2 performed at the end of the release cycle Rstepval2 = Release2_Time / (Sustain2_level + 1) TimVals[5] = time + Rstepval2 Else ' perform a noteoff - no release phase Set TimVals[5] Clear PDC2 ' stop adsr Clear IEC1bits_T4IE ' disable timer4 interrupt Clear IFS1bits_T4IF ' clear interrupt flag Clear Note_Port2 EndIf Set resort_flag 'EndIf Case 94 To 127 'If PWMmodus = 0 Then Clear ADSR3_flags If release > 0 Then Release3_Time = release ' so if CC39 = release time was set, we use it EndIf If Release3_Time > 0 Then Set Release3_flag ' clear PDC3 performed at the end of the release cycle Rstepval3 = Release3_Time / (Sustain3_level + 1) TimVals[6] = time + Rstepval3 Else ' perform a noteoff - no release phase Set TimVals[6] Clear PDC3 ' stop volume Clear IEC1bits_T5IE ' disable timer5 interrupt Clear IFS1bits_T5IF ' clear interrupt flag Clear Note_Port3 EndIf Set resort_flag 'EndIf 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 lite0 Low lite0_port Clear VelFlags.0 Clear notes.0 Set TimVals[0] Set resort_flag Case lite1 Low lite1_port Clear VelFlags.1 Clear notes.1 Set TimVals[1] Set resort_flag Case lite2 Low lite2_port Clear VelFlags.2 Clear notes.2 Set TimVals[2] Set resort_flag Case lite3 Low lite3_port Clear VelFlags.3 Clear notes.3 Set TimVals[3] Set resort_flag Case lite4 Low lite4_port Case lite5 Low lite5_port Case 22 To 57 'IF PWMmodus = 0 then Clear ADSR1_flags If Release1_Time > 0 Then Set Release1_flag ' clear PDC1 performed at the end of the release cycle Rstepval1 = Release1_Time / (Sustain1_level + 1) TimVals[4] = time + Rstepval1 Else ' perform a noteoff - no release phase Set TimVals[4] Clear PDC1 ' stop volume Clear IEC0bits_T1IE ' disable timer1 interrupt Clear IFS0bits_T1IF ' clear interrupt flag Clear Note_Port1 EndIf Set resort_flag 'EndIf Case 58 To 93 'if PWMmodus = 0 then Clear ADSR2_flags If Release2_Time > 0 Then Set Release2_flag ' clear PDC2 performed at the end of the release cycle Rstepval2 = Release2_Time / (Sustain2_level + 1) TimVals[5] = time + Rstepval2 Else ' perform a noteoff - no release phase Set TimVals[5] Clear PDC2 ' stop tone Clear IEC1bits_T4IE ' disable timer4 interrupt Clear IFS1bits_T4IF ' clear interrupt flag Clear Note_Port2 EndIf Set resort_flag 'EndIf Case 94 To 127 'if PWMmodus = 0 then Clear ADSR3_flags If Release3_Time > 0 Then Set Release3_flag ' clear PDC3 performed at the end of the release cycle Rstepval3 = Release3_Time / (Sustain3_level + 1) TimVals[6] = time + Rstepval3 Else ' perform a noteoff - no release phase Set TimVals[6] Clear PDC3 ' stop Clear IEC1bits_T5IE ' disable timer5 interrupt Clear IFS1bits_T5IF ' clear interrupt flag Clear Note_Port3 EndIf Set resort_flag 'EndIf EndSelect Else Select noteAan Case lite0 velo0 = velo High lite0_port If velo0 < 127 Then Set notes.0 Set VelFlags.0 TimVals[0] = time + Dur[velo0] Else Clear notes.0 Clear VelFlags.0 Set TimVals[0] EndIf Set resort_flag Case lite1 High lite1_port velo1 = velo If velo1 < 127 Then Set notes.1 Set VelFlags.1 TimVals[1] = time + Dur[velo1] '10 Else Clear notes.1 Clear VelFlags.1 Set TimVals[1] EndIf Set resort_flag Case lite2 High lite2_port velo2 = velo If velo2 < 127 Then Set notes.2 Set VelFlags.2 TimVals[2] = time + Dur[velo2] '10 Else Clear notes.2 Clear VelFlags.2 Set TimVals[2] EndIf Set resort_flag Case lite3 High lite3_port velo3 = velo If velo3 < 127 Then Set notes.3 Set VelFlags.3 TimVals[3] = time + Dur[velo3] Else Clear notes.3 Clear VelFlags.3 Set TimVals[3] EndIf Set resort_flag Case lite4 High lite4_port Case lite5 High lite5_port Case 22 To 57 Attack1_level = velo ' here velo is always > 0 'IF PWMmodus =0 then ' program timer1 as frequency generator ' dutcy1 = Waveform1 / 254 On1 = Period[noteAan] * dutcy1 Of1 = Period[noteAan] - On1 Clear Note_Port1 Clear IFS0bits_T1IF ' clear irq flag Set IEC0bits_T1IE ' enable timer1 interrupt ' now use the pwm1 channel for the ADSR Clear ADSR1_flags ' start new cycle Clear PDC1 ' start from volume = 0 Set Attack1_flag Astepval1 = Attack1_time / Attack1_level If Attack1_level <> Sustain1_level Then Dstepval1 = Decay1_time / Abs(Attack1_level - Sustain1_level) EndIf TimVals[4] = time + Astepval1 Set resort_flag 'endif Case 58 To 93 Attack2_level = velo 'If PWMmodus =0 Then ' program timer4 as frequency generator 'dutcy2 = Waveform2 / 254 On2 = Period[noteAan] * dutcy2 Of2 = Period[noteAan] - On2 Clear IFS1bits_T4IF ' clear irq flag Set IEC1bits_T4IE ' enable timer4 interrupt Clear Note_Port2 ' now use the pwm2 channel for the ADSR Clear ADSR2_flags ' start new cycle Clear PDC2 ' start from volume = 0 Set Attack2_flag Astepval2 = Attack2_time / Attack2_level If Attack2_level <> Sustain2_level Then Dstepval2 = Attack2_time / Abs(Attack2_level - Sustain2_level) EndIf TimVals[5] = time + Astepval2 Set resort_flag 'EndIf Case 94 To 127 Attack3_level = velo 'If PWMmodus =0 Then ' program timer5 as frequency generator 'dutcy3 = Waveform3 / 254 On3 = Period[noteAan] * dutcy3 Of3 = Period[noteAan] - On3 Clear IFS1bits_T5IF ' clear irq flag Set IEC1bits_T5IE ' enable timer5 interrupt Clear Note_Port3 ' now use the pwm3 channel for the ADSR Clear ADSR3_flags ' start new cycle Clear PDC3 ' start from volume = 0 Set Attack3_flag Astepval3 = Attack3_time / Attack3_level If Attack3_level <> Sustain3_level Then Dstepval3 = Attack3_time / Abs(Attack3_level - Sustain3_level) EndIf TimVals[6] = time + Astepval3 Set resort_flag 'EndIf EndSelect Set noteAan '= 255 EndIf EndIf Case Keypres_Status If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres EndIf Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller EndIf Case ProgChange_Status ' not used for Flex If prog = 255 Then 'single byte message prog = Bytein GoSub ProgChange EndIf Case Aftertouch_Status ' not used for flex If aft = 255 Then aft = Bytein GoSub Aftertouch EndIf Case Pitchbend_Status ' used for position control in flex If pblsb = 255 Then pblsb = Bytein Else pbmsb = Bytein GoSub Pitchbend EndIf EndSelect EndIf $endif Midi_Parse_done: 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 Toggle lite0_port 'LATB.4 TimVals[0] = time + Dur[velo0] Case 1 Toggle lite1_port 'LATA.4 TimVals[1] = time + Dur[velo1] Case 2 Toggle lite2_port 'LATB.6 TimVals[2] = time + Dur[velo2] Case 3 Toggle lite3_port 'LATB.7 TimVals[3] = time + Dur[velo3] Case 4 ' noot1 adsr Select ADSR1_flags Case 1 ' if we get here, the first attack steptime has passed Clear cnt1 Set Attack1_tog ' now becomes = 3 TimVals[4] = time + Astepval1 Case 3 If cnt1 < Attack1_level Then Inc cnt1 ' increase volume until attack_level reached PDC1 = Ont[cnt1] TimVals[4] = time + Astepval1 Else ' attack level reached Clear ADSR1_flags ' becomes 0 If Attack1_level = Sustain1_level Then ' no decay phase required Set Sustain1_flag ' = 16 Set TimVals[4] cnt1 = Sustain1_level EndIf If Attack1_level > Sustain1_level Then Set Decay1_flag ' becomes 4 cnt1= Attack1_level ' start value for the decay PDC1 = Ont[cnt1] TimVals[4] = time + Dstepval1 Else ' attack level <= sustain level Set Decay1_tog ' further increase flag... becomes 8 cnt1 = Attack1_level PDC1 = Ont[cnt1] TimVals[4] = time + Dstepval1 EndIf EndIf Case 4 ' decay flag is set Dec cnt1 PDC1 = Ont[cnt1] TimVals[4] = time + Dstepval1 If cnt1 = Sustain1_level Then Clear Decay1_flag ' becomes 0 Set Sustain1_flag ' value becomes 16 now ' shouldn't we cancel the timer now? Set TimVals[4] EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt1 PDC1 = Ont[cnt1] TimVals[4] = time + Dstepval1 If cnt1 = Sustain1_level Then Clear Decay1_tog ' becomes 0 Set Sustain1_flag ' becomes 16 Set TimVals[4] EndIf Case 64 ' release flag is set cnt1 = Sustain1_level Set Release1_tog ' becomes 192 TimVals[4] = time + Rstepval1 Case 192 ' release-phase If cnt1 > 0 Then Dec cnt1 PDC1 = Ont[cnt1] TimVals[4] = time + Rstepval1 Else ' if we get here, release time has passed Clear ADSR1_flags ' Release1_flag Clear PDC1 ' so we can switch off the volume Clear TMR1 ' stop tone generator Clear IEC0bits_T1IE ' disable timer1 interrupt Clear IFS0bits_T1IF ' clear interrupt flag Clear Note_Port1 Set TimVals[4] EndIf EndSelect Case 5 ' noot2 adsr Select ADSR2_flags Case 1 ' if we get here, the first attack steptime has passed Clear cnt2 Set Attack2_tog ' now becomes = 3 TimVals[5] = time + Astepval2 Case 3 If cnt2 < Attack2_level Then Inc cnt2 ' increase volume until attack_level reached PDC2 = Ont[cnt2] TimVals[5] = time + Astepval2 Else ' attack level reached Clear ADSR2_flags ' becomes 0 If Attack2_level = Sustain2_level Then ' no decay phase required Set Sustain2_flag ' = 16 Set TimVals[5] cnt2 = Sustain2_level EndIf If Attack2_level > Sustain2_level Then Set Decay2_flag ' becomes 4 cnt2= Attack2_level ' start value for the decay PDC2 = Ont[cnt2] TimVals[5] = time + Dstepval2 Else ' attack level <= sustain level Set Decay2_tog ' further increase flag... becomes 8 cnt2 = Attack2_level PDC2 = Ont[cnt2] TimVals[5] = time + Dstepval2 EndIf EndIf Case 4 ' decay flag is set Dec cnt2 PDC2 = Ont[cnt2] TimVals[5] = time + Dstepval2 If cnt2 = Sustain2_level Then Clear Decay2_flag ' becomes 0 Set Sustain2_flag ' value becomes 16 now ' shouldn't we cancel the timer now? Set TimVals[5] EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt2 PDC2 = Ont[cnt2] TimVals[5] = time + Dstepval2 If cnt2 = Sustain2_level Then Clear Decay2_tog ' becomes 0 Set Sustain2_flag ' becomes 16 Set TimVals[5] EndIf Case 64 ' release flag is set cnt2 = Sustain2_level Set Release2_tog ' becomes 192 TimVals[5] = time + Rstepval2 Case 192 ' release-phase If cnt2 > 0 Then Dec cnt2 PDC2 = Ont[cnt2] TimVals[5] = time + Rstepval2 Else ' if we get here, release time has passed Clear ADSR2_flags ' Release1_flag Clear PDC2 ' so we can switch off the volume Clear TMR4 ' stop tone generator Clear IEC1bits_T4IE ' disable timer4 interrupt Clear IFS1bits_T4IF ' clear interrupt flag Clear Note_Port2 Set TimVals[5] EndIf EndSelect Case 6 ' noot3 adsr Select ADSR3_flags Case 1 ' if we get here, the first attack steptime has passed Clear cnt3 Set Attack3_tog ' now becomes = 3 TimVals[6] = time + Astepval3 Case 3 If cnt3 < Attack3_level Then Inc cnt3 ' increase volume until attack_level reached PDC3 = Ont[cnt3] TimVals[6] = time + Astepval3 Else ' attack level reached Clear ADSR3_flags ' becomes 0 If Attack3_level = Sustain3_level Then ' no decay phase required Set Sustain3_flag ' = 16 Set TimVals[6] cnt3 = Sustain3_level EndIf If Attack3_level > Sustain3_level Then Set Decay3_flag ' becomes 4 cnt3= Attack3_level ' start value for the decay PDC3 = Ont[cnt3] TimVals[6] = time + Dstepval3 Else ' attack level <= sustain level Set Decay3_tog ' further increase flag... becomes 8 cnt3 = Attack3_level PDC3 = Ont[cnt3] TimVals[6] = time + Dstepval3 EndIf EndIf Case 4 ' decay flag is set Dec cnt3 PDC3 = Ont[cnt3] TimVals[6] = time + Dstepval3 If cnt3 = Sustain3_level Then Clear Decay3_flag ' becomes 0 Set Sustain3_flag ' value becomes 16 now ' shouldn't we cancel the timer now? Set TimVals[6] EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt3 PDC3 = Ont[cnt3] TimVals[6] = time + Dstepval3 If cnt3 = Sustain3_level Then Clear Decay3_tog ' becomes 0 Set Sustain3_flag ' becomes 16 Set TimVals[6] EndIf Case 64 ' release flag is set cnt3 = Sustain3_level Set Release3_tog ' becomes 192 TimVals[6] = time + Rstepval3 Case 192 ' release-phase If cnt3 > 0 Then Dec cnt3 PDC3 = Ont[cnt3] TimVals[6] = time + Rstepval3 Else ' if we get here, release time has passed Clear ADSR3_flags ' Release1_flag Clear PDC3 ' so we can switch off the volume Clear TMR5 ' stop tone generator Clear IEC1bits_T5IE ' disable timer5 interrupt Clear IFS1bits_T5IF ' clear interrupt flag Clear Note_Port3 Set TimVals[6] EndIf EndSelect 'Case Else ' ' in dit geval is idx geset ' GoTo jumpout EndSelect GoSub SortTimers ' find a new nxt and idx EndIf ' beveiliging tegen overflow crashes... If maxtim = 1 Then Clear time Clear TMR2 Clear TMR3 Clear notes Set TimVals EndIf Else ' no timers running, so to avoid overflows, we can reset the loop timer If maxtim = 1 Then Clear time ' 16.06.2015 Clear TMR2 ' 07.08.2016 Clear TMR3 EndIf EndIf $ifdef Enable_UART_TX Midi_OutPut: If OutIdxOut <> OutIdxIn Then ' in dit geval is er een byte te versturen If IFS0bits_U1TXIF = 0 Then Inc OutIdxOut U1TXREG = Outbuffer[OutIdxOut] EndIf EndIf $endif 'Toggle loopcnt ' for loopspeed measurement: 1.3us now ' 10.08.2016: 366kHz met alle taken aan, 440kHz onbelast Wend 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 For i = 0 To NrTasks - 1 If TimVals[i] < Nxt Then Nxt = TimVals[i] ' 8 dword comparisons idx = i EndIf Next i Clear resort_flag Return ' ************************************************************************************** ' procedures for midi receiver: KeyPres: ' used for flashing speed ' can also be used to modulate sustain_level ' Select notePres ' Case 120 ' pres0 = pres ' Case 121 ' pres1 = pres ' Case 122 ' pres2 = pres ' Case 123 ' pres3 = pres ' EndSelect Set notePres '= 255 Return ProgChange: ' not implemented here. Set prog '= 255 'this is not realy required Return Pitchbend: Set pblsb Set pbmsb Return Aftertouch: 'this is the channel aftertouch, affecting any playing note 'not implemented here. Set aft ' reset Return Controller: Select Ctrl Case 7 ' volume controller 'CC7 = value ' needs remapping on a 16-bit log scale Sustain1_level = value Sustain2_level = value Sustain3_level = value 'Volume = CC7 Case 16 ' waveform control Inc value ' 0 crashes the system... dutcy1 = value / 256 Case 17 Attack1_time = value * 947 'CC17 Case 18 Decay1_time = value * 947 ' sustain level set with CC7 Case 19 Release1_Time = value * 947 ' can also be set with the note-off release value 'Case 20 ' should be tuning Case 26 Inc value dutcy2 = value / 256 Case 27 Attack2_time = value * 947 Case 28 Decay2_time = value * 947 Case 29 Release2_Time = value * 947 Case 30 ' can be used for global repeat frequency pres0 = value ' repeat rates pres1 = value Case 36 Inc value dutcy3 = value / 256 Case 37 Attack3_time = value * 947 Case 38 Decay3_time = value * 947 Case 39 Release3_Time = value * 947 Case 66 'on/off for the robot If value = 0 Then GoSub PowerDown 'CLEAR PowerOn 'CC66.0 =0 ' GoSub PowerDown 'Else ' 'SET PowerOn 'CC66.0 =1 'EndIf ' Case 100 ' ' this controller steers the PWM value for PWM1 ' velo100 = value ' Select Case PWMmodus ' Case 0 ' same period for all channels: PTPER ' dutcy1 = velo100 / 128 ' pwm1value = PTPER * dutcy1 ' PDC1 = pwm1value ' Case 1 ' dutcy1 = velo100 / 128 ' float 0.0 - 0.99 ' PHASE1 = pwm1freq ' steers periods ' pwm1value = pwm1freq * dutcy1 ' PDC1 = pwm1value ' Case 2 ' ' pwm common to all three channels ' dutcy1 = velo100 / 128 ' float ' pwm1value = PTPER * dutcy1 ' MDC = pwm1value ' Clear PHASE1 ' PHASE2 = PTPER / 3 ' PHASE3 = (PTPER / 3) << 1 ' Case 3 ' dutcy1 = velo100 / 128 ' pwm1value = PTPER * dutcy1 ' MDC = pwm1value ' Clear PHASE1 ' PHASE2 = PTPER >> 2 ' 90 degrees ' EndSelect ' Case 101 ' ' this note steers the period/frequency for PWM1 ' ' in pwmmodus0 it steers the phase ' velo101 = value ' Select Case PWMmodus ' Case 0 ' 'pwm1phase = velo101 << 9 ' 'PHASE1 = pwm1phase ' in deze modus sturen we de faze ' ' phase must also be a function of period! ' angle1 = velo101 / 128 ' pwm1phase = PTPER * angle1 ' PHASE1 = pwm1phase ' Case 1 ' ' geval PWMmodus = 1 phase register steers period ' pwm1freq.Byte1 = velo101 ' pwm1freq = pwm1freq << 1 ' sturing van de periode ' PHASE1 = pwm1freq ' dutcy1 = velo100 / 128 ' recalculate ' PDC1 = pwm1freq * dutcy1 ' Case 2 ' pwm1freq = velo101 << 9 ' PTPER = pwm1freq ' dit werkt o.k. sturing van de gemeenschappelijke fPWM ' dutcy1 = velo100 / 128 ' MDC = pwm1value * dutcy1 ' Clear PHASE1 ' PHASE2 = pwm1freq / 3 ' PHASE3 = (pwm1freq / 3) << 1 ' Case 3 ' pwm1freq = velo101 << 9 ' PTPER = pwm1freq ' dutcy1 = velo100 / 128 ' pwm1value = pwm1freq * dutcy1 ' MDC = pwm1value ' Clear PHASE1 ' PHASE2 = pwm1freq >> 2 ' 90 degrees ' EndSelect ' Case 102 ' velo102 = value ' Select Case PWMmodus ' Case 0 ' dutcy2 = velo102 / 128 ' pwm2value = PTPER * dutcy2 ' PDC2 = pwm2value ' Case 1 ' dutcy2 = velo102 / 128 ' PHASE2 = pwm2freq ' pwm2value = pwm2freq * dutcy2 ' PDC2 = pwm2value ' 'Case 2, 3 ' ' not requited ' EndSelect ' Case 103 ' velo103 = value ' Select Case PWMmodus ' Case 0 ' angle2 = velo103 / 128 ' pwm2phase = PTPER * angle2 ' PHASE2 = pwm2phase ' Case 1 ' pwm2freq.Byte1 = velo103 ' pwm2freq = pwm2freq << 1 ' PHASE2 = pwm2freq ' dutcy2 = velo102 / 128 ' recalculate ' PDC2 = pwm2freq * dutcy2 ' 'Case 2, 3 ' ' not required ' EndSelect ' Case 104 ' pwm steering note 3 ' velo104 = value ' Select Case PWMmodus ' Case 0 ' dutcy3 = velo104 / 128 ' pwm3value = PTPER * dutcy3 ' PDC3 = pwm3value ' Case 1 ' dutcy3 = velo / 128 ' PHASE3 = pwm3freq ' pwm3value = pwm3freq * dutcy3 ' PDC3 = pwm3value ' 'Case 2, 3 ' ' not required ' EndSelect ' Case 105 ' velo105 = value ' Select Case PWMmodus ' Case 0 ' angle3 = velo105 / 128 ' pwm3phase = PTPER * angle3 ' PHASE3 = pwm3phase ' Case 1 ' phase controls period here! ' pwm3freq.Byte1 = velo ' pwm3freq = pwm3freq << 1 ' PHASE3 = pwm3freq ' PDC3 = pwm3freq * dutcy3 ' 'Case 2, 3 ' ' not required ' EndSelect Case 123 ' all notes off - no controller resets If PWMmodus = 1 Then Clear PDC1 Clear PDC2 Clear PDC3 Clear Note_Port1 Clear Note_Port2 Clear Note_Port3 Clear ADSR1_flags Clear ADSR2_flags Clear ADSR3_flags Clear IEC0bits_T1IE ' disable the Timer1 interrupt Clear IEC1bits_T4IE ' disable timer4 Clear IEC1bits_T5IE ' disable timer5 EndIf Clear notes Clear VelFlags Set resort_flag For i = 0 To NrTasks -1 Set TimVals[i] ' stop timers Next i Case 126 ' test for midi-out Inc OutIdxIn Outbuffer[OutIdxIn] = Control_Status Inc OutIdxIn Outbuffer[OutIdxIn] = 126 Inc OutIdxIn Outbuffer[OutIdxIn] = value EndSelect Set Ctrl 'mandatory reset Return PowerDown: Low lite0_port Low lite1_port Low lite2_port Low lite3_port Low lite4_port Low lite5_port Clear VelFlags 'stop all running timers Clear notes Set resort_flag Clear velo0 Clear velo1 Clear velo2 Clear velo3 Clear pres0 Clear pres1 Clear pres2 Clear pres3 For i =0 To NrTasks -1 Set TimVals[i] Next i Clear PDC1 Clear PDC2 Clear PDC3 ' If PWMmodus = 1 Then Low Note_Port1 Low Note_Port2 Low Note_Port3 Clear ADSR1_flags Clear ADSR2_flags Clear ADSR3_flags Clear IEC0bits_T1IE ' disable the Timer1 interrupt Clear IEC1bits_T4IE ' disable Timer4 irq Clear IEC1bits_T5IE ' disable Timer5 irq ' EndIf Return Dur_Lookup: 'lookup for experiment. 1 dur unit is now 2.3us with loopcounter 'using timer23, 1 dur unit is 4.224 us Set Dur[0] Dur[1]= 23674 ' 03.08.2016: 56ms ' 04.08/2016: 66.2ms - 7.55 Hz ' 07.08.2016: 2x100ms = 200ms full period --> 5Hz [o.k.14.08.2016] Dur[2]= 22917 ' freq= 2.18178644674259 Dur[3]= 22548 ' freq= 2.21749157353202 Dur[4]= 22185 ' freq= 2.25377507324769 Dur[5]= 21827 ' freq= 2.29074082558299 Dur[6]= 21475 ' freq= 2.32828870779977 Dur[7]= 21129 ' freq= 2.36641582658905 Dur[8]= 20789 ' freq= 2.40511809129828 Dur[9]= 20454 ' freq= 2.44450963136795 Dur[10]= 20124 ' freq= 2.48459550785132 Dur[11]= 19800 ' freq= 2.52525252525252 Dur[12]= 19481 ' freq= 2.56660335711719 Dur[13]= 19167 ' freq= 2.60865028434288 Dur[14]= 18858 ' freq= 2.65139463357726 Dur[15]= 18554 ' freq= 2.69483669289641 Dur[16]= 18255 ' freq= 2.73897562311695 Dur[17]= 17961 ' freq= 2.7838093647347 Dur[18]= 17672 ' freq= 2.82933454051607 Dur[19]= 17387 ' freq= 2.87571173865532 Dur[20]= 17107 ' freq= 2.92278014847723 Dur[21]= 16831 ' freq= 2.97070881112233 Dur[22]= 16560 ' freq= 3.01932367149758 Dur[23]= 16293 ' freq= 3.06880255324372 Dur[24]= 16030 ' freq= 3.11915159076731 Dur[25]= 15772 ' freq= 3.17017499365965 Dur[26]= 15518 ' freq= 3.22206469905916 Dur[27]= 15268 ' freq= 3.27482315954938 Dur[28]= 15022 ' freq= 3.32845160431367 Dur[29]= 14780 ' freq= 3.382949932341 Dur[30]= 14542 ' freq= 3.43831660019254 Dur[31]= 14307 ' freq= 3.4947927587894 Dur[32]= 14077 ' freq= 3.55189315905378 Dur[33]= 13850 ' freq= 3.6101083032491 Dur[34]= 13627 ' freq= 3.66918617450649 Dur[35]= 13407 ' freq= 3.72939509211606 Dur[36]= 13191 ' freq= 3.79046319460238 Dur[37]= 12978 ' freq= 3.85267375558638 Dur[38]= 12769 ' freq= 3.91573341686898 Dur[39]= 12564 ' freq= 3.97962432346386 Dur[40]= 12361 ' freq= 4.04498017959712 Dur[41]= 12162 ' freq= 4.1111659266568 Dur[42]= 11966 ' freq= 4.17850576633796 Dur[43]= 11773 ' freq= 4.24700586086809 Dur[44]= 11583 ' 07.08.2016: geeft 10.1177 Hz Dur[45]= 11397 ' freq= 4.38711941739054 Dur[46]= 11213 ' freq= 4.45910996165165 Dur[47]= 11032 ' freq= 4.53226976069616 Dur[48]= 10855 ' freq= 4.60617227084293 Dur[49]= 10680 ' freq= 4.6816479400749 Dur[50]= 10508 ' freq= 4.75827940616673 Dur[51]= 10338 ' freq= 4.83652544012381 Dur[52]= 10172 ' freq= 4.91545418796697 Dur[53]= 10008 ' freq= 4.99600319744204 Dur[54]= 9846 ' freq= 5.07820434694292 Dur[55]= 9688 ' freq= 5.16102394715111 Dur[56]= 9532 ' freq= 5.24548887956357 Dur[57]= 9378 ' freq= 5.33162721262529 Dur[58]= 9227 ' freq= 5.4188793757451 Dur[59]= 9078 ' freq= 5.50782110597048 Dur[60]= 8932 ' freq= 5.59785042543663 Dur[61]= 8788 ' freq= 5.68957669549385 Dur[62]= 8646 ' freq= 5.78302105019662 Dur[63]= 8507 ' 04.08.2016: 21Hz pulse duur = 23.8ms Dur[64]= 8370 ' geeft nu 20ms pulsen freq= 25Hz 03.08.2016 ' 14.0017Hz 07.08.2016 Dur[65]= 8235 ' freq= 6.07164541590771 Dur[66]= 8102 ' freq= 6.17131572451246 Dur[67]= 7972 ' freq= 6.27195183140993 Dur[68]= 7843 ' freq= 6.37511156445238 Dur[69]= 7717 ' freq= 6.47920176234288 Dur[70]= 7593 ' freq= 6.58501251152377 Dur[71]= 7470 ' freq= 6.69344042838019 Dur[72]= 7350 ' freq= 6.80272108843537 Dur[73]= 7231 ' freq= 6.91467293597013 Dur[74]= 7115 ' freq= 7.02740688685875 Dur[75]= 7000 ' freq= 7.14285714285714 Dur[76]= 6888 ' freq= 7.25900116144018 Dur[77]= 6777 ' freq= 7.37789582411096 Dur[78]= 6667 ' freq= 7.49962501874906 Dur[79]= 6560 ' freq= 7.62195121951219 Dur[80]= 6454 ' freq= 7.74713356058258 Dur[81]= 6350 ' freq= 7.8740157480315 Dur[82]= 6248 ' freq= 8.00256081946223 Dur[83]= 6147 ' freq= 8.13404912965674 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 ' 03.08.2016: 6.9ms nu = 144Hz ' 04.08.2016: 8.35ms - 59.5Hz Set Dur5[0] ' not used Dur5[1]= 41667 ' freq= .999992000063999 Dur5[2]= 39494 ' freq= 1.0550125757499 Dur5[3]= 38450 ' freq= 1.08365843086259 Dur5[4]= 37434 ' freq= 1.11307011451265 Dur5[5]= 36445 ' freq= 1.14327525495038 Dur5[6]= 35482 ' freq= 1.17430434210774 Dur5[7]= 34544 ' freq= 1.20619113787247 Dur5[8]= 33631 ' freq= 1.23893629885126 Dur5[9]= 32743 ' freq= 1.27253662360403 Dur5[10]= 31877 ' freq= 1.30710752789367 Dur5[11]= 31035 ' freq= 1.34257021642232 Dur5[12]= 30215 ' freq= 1.37900601246621 Dur5[13]= 29416 ' freq= 1.41646269603844 Dur5[14]= 28639 ' freq= 1.45489251254117 Dur5[15]= 27882 ' freq= 1.49439303732396 Dur5[16]= 27146 ' freq= 1.53490999287802 Dur5[17]= 26428 ' freq= 1.57661066545583 Dur5[18]= 25730 ' freq= 1.61938074880166 Dur5[19]= 25050 ' freq= 1.66333998669328 Dur5[20]= 24388 ' freq= 1.70849051446066 Dur5[21]= 23743 ' freq= 1.75490319953951 Dur5[22]= 23116 ' freq= 1.8025033166061 Dur5[23]= 22505 ' freq= 1.85144042064726 Dur5[24]= 21910 ' freq= 1.90171915411532 Dur5[25]= 21331 ' freq= 1.95333864641445 Dur5[26]= 20768 ' freq= 2.006291730868 Dur5[27]= 20219 ' freq= 2.06076792455941 Dur5[28]= 19685 ' freq= 2.11667090000847 Dur5[29]= 19164 ' freq= 2.17421554303207 Dur5[30]= 18658 ' freq= 2.23317969057062 Dur5[31]= 18165 ' freq= 2.29378842095605 Dur5[32]= 17685 ' freq= 2.35604561304307 Dur5[33]= 17218 ' freq= 2.41994811631239 Dur5[34]= 16763 ' freq= 2.48563304102289 Dur5[35]= 16320 ' freq= 2.5531045751634 Dur5[36]= 15888 ' freq= 2.62252433702585 Dur5[37]= 15469 ' freq= 2.69355916133342 Dur5[38]= 15060 ' freq= 2.76671093404161 Dur5[39]= 14662 ' freq= 2.84181330423316 Dur5[40]= 14274 ' freq= 2.91906029610948 Dur5[41]= 13897 ' freq= 2.99824902257082 Dur5[42]= 13530 ' freq= 3.07957625030796 Dur5[43]= 13172 ' freq= 3.16327563518575 Dur5[44]= 12824 ' freq= 3.24911624038262 Dur5[45]= 12485 ' freq= 3.33733813910025 Dur5[46]= 12155 ' freq= 3.42794460441519 Dur5[47]= 11834 ' freq= 3.52092839840009 Dur5[48]= 11522 ' freq= 3.61627032343922 Dur5[49]= 11217 ' freq= 3.71459986330272 Dur5[50]= 10921 ' freq= 3.81527943106553 Dur5[51]= 10632 ' freq= 3.91898670679709 Dur5[52]= 10351 ' freq= 4.02537597011561 Dur5[53]= 10078 ' freq= 4.13441820467024 Dur5[54]= 9811 ' freq= 4.24693371385859 Dur5[55]= 9552 ' freq= 4.36208821887214 Dur5[56]= 9300 ' freq= 4.48028673835125 Dur5[57]= 9054 ' freq= 4.60201752448273 Dur5[58]= 8815 ' freq= 4.72679145396105 Dur5[59]= 8582 ' freq= 4.85512312592247 Dur5[60]= 8355 ' freq= 4.9870337123479 Dur5[61]= 8134 ' freq= 5.12253094008688 Dur5[62]= 7919 ' freq= 5.26160710527423 Dur5[63]= 7710 ' freq= 5.40423692174665 Dur5[64]= 7506 ' freq= 5.5511146638245 Dur5[65]= 7308 ' freq= 5.70151432220398 Dur5[66]= 7115 ' freq= 5.85617240571562 Dur5[67]= 6927 ' freq= 6.01510995621 Dur5[68]= 6744 ' freq= 6.1783313562673 Dur5[69]= 6565 ' freq= 6.34678852500635 Dur5[70]= 6392 ' freq= 6.51856487275761 Dur5[71]= 6223 ' freq= 6.69559162247576 Dur5[72]= 6059 ' freq= 6.87682235792485 Dur5[73]= 5898 ' freq= 7.06454165253758 Dur5[74]= 5743 ' freq= 7.25520924023449 Dur5[75]= 5591 ' freq= 7.45245334764204 Dur5[76]= 5443 ' freq= 7.65509216730969 Dur5[77]= 5299 ' freq= 7.86311882745172 Dur5[78]= 5159 ' freq= 8.07650061381405 Dur5[79]= 5023 ' freq= 8.29517552591413 Dur5[80]= 4890 ' freq= 8.52079072937969 Dur5[81]= 4761 ' freq= 8.75166281593503 Dur5[82]= 4635 ' freq= 8.98957209636821 Dur5[83]= 4513 ' freq= 9.23258734027624 Dur5[84]= 4393 ' freq= 9.48478640261021 Dur5[85]= 4277 ' freq= 9.74203101862676 Dur5[86]= 4164 ' freq= 10.0064040986231 Dur5[87]= 4054 ' freq= 10.277914816642 Dur5[88]= 3947 ' freq= 10.5565408326999 Dur5[89]= 3843 ' freq= 10.842223956978 Dur5[90]= 3741 ' freq= 11.1378419317473 Dur5[91]= 3642 ' freq= 11.4406004027091 Dur5[92]= 3546 ' freq= 11.7503290092122 Dur5[93]= 3452 ' freq= 12.0702974121282 Dur5[94]= 3361 ' freq= 12.3971040364971 Dur5[95]= 3272 ' freq= 12.7343113284434 Dur5[96]= 3186 ' freq= 13.0780498012136 Dur5[97]= 3102 ' freq= 13.4321942832581 Dur5[98]= 3020 ' freq= 13.7969094922737 Dur5[99]= 2940 ' freq= 14.172335600907 Dur5[100]= 2862 ' freq= 14.5585837409737 Dur5[101]= 2787 ' freq= 14.9503647889008 Dur5[102]= 2713 ' freq= 15.3581521071385 Dur5[103]= 2641 ' freq= 15.7768522024486 Dur5[104]= 2571 ' freq= 16.2064047711656 Dur5[105]= 2504 ' freq= 16.640042598509 Dur5[106]= 2437 ' freq= 17.0975242784845 Dur5[107]= 2373 ' freq= 17.5586458772299 Dur5[108]= 2310 ' freq= 18.037518037518 Dur5[109]= 2249 ' freq= 18.5267526307989 Dur5[110]= 2190 ' freq= 19.0258751902588 Dur5[111]= 2132 ' freq= 19.5434646654159 Dur5[112]= 2076 ' freq= 20.0706486833654 Dur5[113]= 2021 ' freq= 20.616856341745 Dur5[114]= 1967 ' freq= 21.182850364345 Dur5[115]= 1915 ' freq= 21.7580504786771 Dur5[116]= 1865 ' freq= 22.3413762287757 Dur5[117]= 1815 ' freq= 22.9568411386593 Dur5[118]= 1767 ' freq= 23.5804565176382 Dur5[119]= 1721 ' freq= 24.2107301956227 Dur5[120]= 1675 ' freq= 24.8756218905473 Dur5[121]= 1631 ' freq= 25.5466993664418 Dur5[122]= 1588 ' freq= 26.2384550797649 Dur5[123]= 1546 ' freq= 26.9512721000431 Dur5[124]= 1505 ' freq= 27.6854928017719 Dur5[125]= 1465 ' freq= 28.4414106939704 Dur5[126]= 1427 ' freq= 29.1987853305302 Dur5[127]= 1389 ' freq= 29.9976001919846 For i = 0 To 127 Dur5[i] = Dur5[i] >> 3 'so range becomes 8Hz to 240Hz Next i Return ' midi-note to period lookup for PIC24 with 120MHz clock ' time_unit = 8.33333333333333E-9 ' divider set to = 64 ' lowest note = midi 22 (Sib) , freq = 29.1355235 Hz Period_Lookup_Table: Period[22]= 64355 ' soll frequency = 29.13523 real frequency = 29.13526 Period[23]= 60743 ' soll frequency = 30.86771 real frequency = 30.86775 Period[24]= 57334 ' soll frequency = 32.70319 real frequency = 32.70311 Period[25]= 54116 ' soll frequency = 34.64783 real frequency = 34.64779 Period[26]= 51079 ' soll frequency = 36.7081 real frequency = 36.70784 Period[27]= 48212 ' soll frequency = 38.89087 real frequency = 38.89073 Period[28]= 45506 ' soll frequency = 41.20344 real frequency = 41.20336 Period[29]= 42952 ' soll frequency = 43.65353 real frequency = 43.65338 Period[30]= 40541 ' soll frequency = 46.2493 real frequency = 46.24948 Period[31]= 38266 ' soll frequency = 48.99943 real frequency = 48.99911 Period[32]= 36118 ' soll frequency = 51.91308 real frequency = 51.91317 Period[33]= 34091 ' soll frequency = 55 real frequency = 54.99986 Period[34]= 32178 ' soll frequency = 58.27047 real frequency = 58.26963 Period[35]= 30372 ' soll frequency = 61.73541 real frequency = 61.73449 Period[36]= 28667 ' soll frequency = 65.40639 real frequency = 65.40622 Period[37]= 27058 ' soll frequency = 69.29565 real frequency = 69.29558 Period[38]= 25539 ' soll frequency = 73.41619 real frequency = 73.41713 Period[39]= 24106 ' soll frequency = 77.78174 real frequency = 77.78146 Period[40]= 22753 ' soll frequency = 82.40689 real frequency = 82.40672 Period[41]= 21476 ' soll frequency = 87.30706 real frequency = 87.30676 Period[42]= 20271 ' soll frequency = 92.4986 real frequency = 92.49667 Period[43]= 19133 ' soll frequency = 97.99886 real frequency = 97.99822 Period[44]= 18059 ' soll frequency = 103.8262 real frequency = 103.8263 Period[45]= 17045 ' soll frequency = 110 real frequency = 110.0029 Period[46]= 16089 ' soll frequency = 116.5409 real frequency = 116.5392 Period[47]= 15186 ' soll frequency = 123.4708 real frequency = 123.469 Period[48]= 14333 ' soll frequency = 130.8128 real frequency = 130.817 Period[49]= 13529 ' soll frequency = 138.5913 real frequency = 138.5912 Period[50]= 12770 ' soll frequency = 146.8324 real frequency = 146.8285 Period[51]= 12053 ' soll frequency = 155.5635 real frequency = 155.5629 Period[52]= 11376 ' soll frequency = 164.8138 real frequency = 164.8207 Period[53]= 10738 ' soll frequency = 174.6141 real frequency = 174.6135 Period[54]= 10135 ' soll frequency = 184.9972 real frequency = 185.0025 Period[55]= 9566 ' soll frequency = 195.9977 real frequency = 196.0067 Period[56]= 9030 ' soll frequency = 207.6523 real frequency = 207.6412 Period[57]= 8523 ' soll frequency = 220 real frequency = 219.993 Period[58]= 8044 ' soll frequency = 233.0819 real frequency = 233.093 Period[59]= 7593 ' soll frequency = 246.9416 real frequency = 246.938 Period[60]= 7167 ' soll frequency = 261.6255 real frequency = 261.6158 Period[61]= 6764 ' soll frequency = 277.1826 real frequency = 277.2028 Period[62]= 6385 ' soll frequency = 293.6648 real frequency = 293.657 Period[63]= 6026 ' soll frequency = 311.127 real frequency = 311.1517 Period[64]= 5688 ' soll frequency = 329.6276 real frequency = 329.6414 Period[65]= 5369 ' soll frequency = 349.2282 real frequency = 349.227 Period[66]= 5068 ' soll frequency = 369.9944 real frequency = 369.9684 Period[67]= 4783 ' soll frequency = 391.9954 real frequency = 392.0134 Period[68]= 4515 ' soll frequency = 415.3047 real frequency = 415.2824 Period[69]= 4261 ' soll frequency = 440 real frequency = 440.0375 Period[70]= 4022 ' soll frequency = 466.1638 real frequency = 466.186 Period[71]= 3796 ' soll frequency = 493.8833 real frequency = 493.941 Period[72]= 3583 ' soll frequency = 523.2511 real frequency = 523.3045 Period[73]= 3382 ' soll frequency = 554.3652 real frequency = 554.4057 Period[74]= 3192 ' soll frequency = 587.3295 real frequency = 587.406 Period[75]= 3013 ' soll frequency = 622.254 real frequency = 622.3033 Period[76]= 2844 ' soll frequency = 659.2551 real frequency = 659.2827 Period[77]= 2684 ' soll frequency = 698.4565 real frequency = 698.5842 Period[78]= 2534 ' soll frequency = 739.9888 real frequency = 739.9368 Period[79]= 2392 ' soll frequency = 783.9908 real frequency = 783.8628 Period[80]= 2257 ' soll frequency = 830.6094 real frequency = 830.7488 Period[81]= 2131 ' soll frequency = 880 real frequency = 879.8686 Period[82]= 2011 ' soll frequency = 932.3275 real frequency = 932.3719 Period[83]= 1898 ' soll frequency = 987.7666 real frequency = 987.882 Period[84]= 1792 ' soll frequency = 1046.502 real frequency = 1046.317 Period[85]= 1691 ' soll frequency = 1108.73 real frequency = 1108.811 Period[86]= 1596 ' soll frequency = 1174.659 real frequency = 1174.812 Period[87]= 1507 ' soll frequency = 1244.508 real frequency = 1244.194 Period[88]= 1422 ' soll frequency = 1318.51 real frequency = 1318.565 Period[89]= 1342 ' soll frequency = 1396.913 real frequency = 1397.168 Period[90]= 1267 ' soll frequency = 1479.978 real frequency = 1479.874 Period[91]= 1196 ' soll frequency = 1567.982 real frequency = 1567.726 Period[92]= 1129 ' soll frequency = 1661.219 real frequency = 1660.762 Period[93]= 1065 ' soll frequency = 1760 real frequency = 1760.563 Period[94]= 1006 ' soll frequency = 1864.655 real frequency = 1863.817 Period[95]= 949 ' soll frequency = 1975.533 real frequency = 1975.764 Period[96]= 896 ' soll frequency = 2093.004 real frequency = 2092.634 Period[97]= 846 ' soll frequency = 2217.461 real frequency = 2216.312 Period[98]= 798 ' soll frequency = 2349.318 real frequency = 2349.624 Period[99]= 753 ' soll frequency = 2489.016 real frequency = 2490.04 Period[100]= 711 ' soll frequency = 2637.02 real frequency = 2637.131 Period[101]= 671 ' soll frequency = 2793.826 real frequency = 2794.337 Period[102]= 633 ' soll frequency = 2959.955 real frequency = 2962.085 Period[103]= 598 ' soll frequency = 3135.963 real frequency = 3135.451 Period[104]= 564 ' soll frequency = 3322.438 real frequency = 3324.468 Period[105]= 533 ' soll frequency = 3520 real frequency = 3517.824 Period[106]= 503 ' soll frequency = 3729.31 real frequency = 3727.634 Period[107]= 475 ' soll frequency = 3951.066 real frequency = 3947.368 Period[108]= 448 ' soll frequency = 4186.009 real frequency = 4185.268 Period[109]= 423 ' soll frequency = 4434.922 real frequency = 4432.624 Period[110]= 399 ' soll frequency = 4698.636 real frequency = 4699.248 Period[111]= 377 ' soll frequency = 4978.032 real frequency = 4973.475 Period[112]= 356 ' soll frequency = 5274.041 real frequency = 5266.854 Period[113]= 336 ' soll frequency = 5587.652 real frequency = 5580.357 Period[114]= 317 ' soll frequency = 5919.911 real frequency = 5914.827 Period[115]= 299 ' soll frequency = 6271.927 real frequency = 6270.903 Period[116]= 282 ' soll frequency = 6644.875 real frequency = 6648.936 Period[117]= 266 ' soll frequency = 7040 real frequency = 7048.872 Period[118]= 251 ' soll frequency = 7458.62 real frequency = 7470.12 Period[119]= 237 ' soll frequency = 7902.133 real frequency = 7911.392 Period[120]= 224 ' soll frequency = 8372.018 real frequency = 8370.536 Period[121]= 211 ' soll frequency = 8869.844 real frequency = 8886.256 Period[122]= 200 ' soll frequency = 9397.272 real frequency = 9375 Period[123]= 188 ' soll frequency = 9956.063 real frequency = 9973.404 Period[124]= 178 ' soll frequency = 10548.08 real frequency = 10533.71 Period[125]= 168 ' soll frequency = 11175.3 real frequency = 11160.71 Period[126]= 158 ' soll frequency = 11839.82 real frequency = 11867.09 Period[127]= 149 ' soll frequency = 12543.85 real frequency = 12583.89 Return ' pwm on/off values for PIC24 with 120MHz clock ' time_unit = 8.33333333333333E-9 ' divider set to = 8 ' using a 16 bit timers (timer1, 4, 5) ' PWM base frequency = 15000 ' with divider set to 1 pwm base freq becomes 120kHz ' so with the 16-bit values below we would get an audible 915Hz pitch... ' divider set to 1 does not work, it freezes the PIC, ' so we must use :8 PWM_Lookup_Table: Ont[0]= 64 : Oft[0]= 63936 ' db= -60 Ont[1]= 68 : Oft[1]= 63932 ' db= -59 Ont[2]= 71 : Oft[2]= 63929 ' db= -59 Ont[3]= 75 : Oft[3]= 63925 ' db= -59 Ont[4]= 80 : Oft[4]= 63920 ' db= -58 Ont[5]= 84 : Oft[5]= 63916 ' db= -58 Ont[6]= 89 : Oft[6]= 63911 ' db= -57 Ont[7]= 94 : Oft[7]= 63906 ' db= -57 Ont[8]= 99 : Oft[8]= 63901 ' db= -56 Ont[9]= 104 : Oft[9]= 63896 ' db= -56 Ont[10]= 110 : Oft[10]= 63890 ' db= -55 Ont[11]= 116 : Oft[11]= 63884 ' db= -55 Ont[12]= 123 : Oft[12]= 63877 ' db= -54 Ont[13]= 130 : Oft[13]= 63870 ' db= -54 Ont[14]= 137 : Oft[14]= 63863 ' db= -53 Ont[15]= 145 : Oft[15]= 63855 ' db= -53 Ont[16]= 153 : Oft[16]= 63847 ' db= -52 Ont[17]= 161 : Oft[17]= 63839 ' db= -52 Ont[18]= 170 : Oft[18]= 63830 ' db= -52 Ont[19]= 180 : Oft[19]= 63820 ' db= -51 Ont[20]= 190 : Oft[20]= 63810 ' db= -51 Ont[21]= 201 : Oft[21]= 63799 ' db= -50 Ont[22]= 212 : Oft[22]= 63788 ' db= -50 Ont[23]= 224 : Oft[23]= 63776 ' db= -49 Ont[24]= 236 : Oft[24]= 63764 ' db= -49 Ont[25]= 249 : Oft[25]= 63751 ' db= -48 Ont[26]= 263 : Oft[26]= 63737 ' db= -48 Ont[27]= 278 : Oft[27]= 63722 ' db= -47 Ont[28]= 293 : Oft[28]= 63707 ' db= -47 Ont[29]= 310 : Oft[29]= 63690 ' db= -46 Ont[30]= 327 : Oft[30]= 63673 ' db= -46 Ont[31]= 346 : Oft[31]= 63654 ' db= -45 Ont[32]= 365 : Oft[32]= 63635 ' db= -45 Ont[33]= 385 : Oft[33]= 63615 ' db= -44 Ont[34]= 407 : Oft[34]= 63593 ' db= -44 Ont[35]= 429 : Oft[35]= 63571 ' db= -43 Ont[36]= 453 : Oft[36]= 63547 ' db= -43 Ont[37]= 479 : Oft[37]= 63521 ' db= -43 Ont[38]= 506 : Oft[38]= 63494 ' db= -42 Ont[39]= 534 : Oft[39]= 63466 ' db= -42 Ont[40]= 564 : Oft[40]= 63436 ' db= -41 Ont[41]= 595 : Oft[41]= 63405 ' db= -41 Ont[42]= 629 : Oft[42]= 63371 ' db= -40 Ont[43]= 664 : Oft[43]= 63336 ' db= -40 Ont[44]= 701 : Oft[44]= 63299 ' db= -39 Ont[45]= 740 : Oft[45]= 63260 ' db= -39 Ont[46]= 781 : Oft[46]= 63219 ' db= -38 Ont[47]= 825 : Oft[47]= 63175 ' db= -38 Ont[48]= 871 : Oft[48]= 63129 ' db= -37 Ont[49]= 920 : Oft[49]= 63080 ' db= -37 Ont[50]= 971 : Oft[50]= 63029 ' db= -36 Ont[51]= 1025 : Oft[51]= 62975 ' db= -36 Ont[52]= 1083 : Oft[52]= 62917 ' db= -35 Ont[53]= 1143 : Oft[53]= 62857 ' db= -35 Ont[54]= 1207 : Oft[54]= 62793 ' db= -34 Ont[55]= 1275 : Oft[55]= 62725 ' db= -34 Ont[56]= 1346 : Oft[56]= 62654 ' db= -34 Ont[57]= 1421 : Oft[57]= 62579 ' db= -33 Ont[58]= 1501 : Oft[58]= 62499 ' db= -33 Ont[59]= 1584 : Oft[59]= 62416 ' db= -32 Ont[60]= 1673 : Oft[60]= 62327 ' db= -32 Ont[61]= 1767 : Oft[61]= 62233 ' db= -31 Ont[62]= 1865 : Oft[62]= 62135 ' db= -31 Ont[63]= 1970 : Oft[63]= 62030 ' db= -30 Ont[64]= 2080 : Oft[64]= 61920 ' db= -30 Ont[65]= 2196 : Oft[65]= 61804 ' db= -29 Ont[66]= 2319 : Oft[66]= 61681 ' db= -29 Ont[67]= 2448 : Oft[67]= 61552 ' db= -28 Ont[68]= 2585 : Oft[68]= 61415 ' db= -28 Ont[69]= 2730 : Oft[69]= 61270 ' db= -27 Ont[70]= 2882 : Oft[70]= 61118 ' db= -27 Ont[71]= 3043 : Oft[71]= 60957 ' db= -26 Ont[72]= 3213 : Oft[72]= 60787 ' db= -26 Ont[73]= 3393 : Oft[73]= 60607 ' db= -26 Ont[74]= 3583 : Oft[74]= 60417 ' db= -25 Ont[75]= 3783 : Oft[75]= 60217 ' db= -25 Ont[76]= 3994 : Oft[76]= 60006 ' db= -24 Ont[77]= 4218 : Oft[77]= 59782 ' db= -24 Ont[78]= 4453 : Oft[78]= 59547 ' db= -23 Ont[79]= 4702 : Oft[79]= 59298 ' db= -23 Ont[80]= 4965 : Oft[80]= 59035 ' db= -22 Ont[81]= 5243 : Oft[81]= 58757 ' db= -22 Ont[82]= 5536 : Oft[82]= 58464 ' db= -21 Ont[83]= 5845 : Oft[83]= 58155 ' db= -21 Ont[84]= 6172 : Oft[84]= 57828 ' db= -20 Ont[85]= 6517 : Oft[85]= 57483 ' db= -20 Ont[86]= 6881 : Oft[86]= 57119 ' db= -19 Ont[87]= 7266 : Oft[87]= 56734 ' db= -19 Ont[88]= 7672 : Oft[88]= 56328 ' db= -18 Ont[89]= 8101 : Oft[89]= 55899 ' db= -18 Ont[90]= 8554 : Oft[90]= 55446 ' db= -17 Ont[91]= 9032 : Oft[91]= 54968 ' db= -17 Ont[92]= 9537 : Oft[92]= 54463 ' db= -17 Ont[93]= 10070 : Oft[93]= 53930 ' db= -16 Ont[94]= 10633 : Oft[94]= 53367 ' db= -16 Ont[95]= 11227 : Oft[95]= 52773 ' db= -15 Ont[96]= 11855 : Oft[96]= 52145 ' db= -15 Ont[97]= 12518 : Oft[97]= 51482 ' db= -14 Ont[98]= 13217 : Oft[98]= 50783 ' db= -14 Ont[99]= 13956 : Oft[99]= 50044 ' db= -13 Ont[100]= 14736 : Oft[100]= 49264 ' db= -13 Ont[101]= 15560 : Oft[101]= 48440 ' db= -12 Ont[102]= 16430 : Oft[102]= 47570 ' db= -12 Ont[103]= 17348 : Oft[103]= 46652 ' db= -11 Ont[104]= 18318 : Oft[104]= 45682 ' db= -11 Ont[105]= 19342 : Oft[105]= 44658 ' db= -10 Ont[106]= 20423 : Oft[106]= 43577 ' db= -10 Ont[107]= 21564 : Oft[107]= 42436 ' db= -9 Ont[108]= 22770 : Oft[108]= 41230 ' db= -9 Ont[109]= 24043 : Oft[109]= 39957 ' db= -9 Ont[110]= 25387 : Oft[110]= 38613 ' db= -8 Ont[111]= 26806 : Oft[111]= 37194 ' db= -8 Ont[112]= 28304 : Oft[112]= 35696 ' db= -7 Ont[113]= 29886 : Oft[113]= 34114 ' db= -7 Ont[114]= 31557 : Oft[114]= 32443 ' db= -6 Ont[115]= 33321 : Oft[115]= 30679 ' db= -6 Ont[116]= 35183 : Oft[116]= 28817 ' db= -5 Ont[117]= 37150 : Oft[117]= 26850 ' db= -5 Ont[118]= 39227 : Oft[118]= 24773 ' db= -4 Ont[119]= 41419 : Oft[119]= 22581 ' db= -4 Ont[120]= 43735 : Oft[120]= 20265 ' db= -3 Ont[121]= 46179 : Oft[121]= 17821 ' db= -3 Ont[122]= 48761 : Oft[122]= 15239 ' db= -2 Ont[123]= 51486 : Oft[123]= 12514 ' db= -2 Ont[124]= 54364 : Oft[124]= 9636 ' db= -1 Ont[125]= 57403 : Oft[125]= 6597 ' db= -1 Ont[126]= 60612 : Oft[126]= 3388 ' db= 0 Ont[127]= 64000 : Oft[127]= 64 ' db= 0 For i = 0 To 127 Ont[i] = Ont[i] >> 6 '5 ' geeft pwm freq = 126Hz nu Oft[i] = Oft[i] >> 6 '5 ' :64 :32 Next i Return ' EOF