'**************************************************************************** '* * '* 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. '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 '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 '13.08.2016: metacompiler statements for UART-TX and UART-RX added. ' Buffered midi-out fully implemented. '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... '-------------------------------------------------------------------------------------- '23.08.2016: Start delopment of specific HybrLo code. ' This code implements notes 22, 23 and 24 and their octaves. ' Now with 40dB scalings. ' 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. '------------------------------------------------------------------------------- ' 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% '-------------------------------------------------------------------------------------------------------------- ' 20.05.2017: Start coding for thunderwood ' 21.05.2017: further coding for the motor controller ' 23.05.2017: crashes as soon as we switch storm on... ' not enough processing speed to handle the tim1 IRQ was the cause ' In principle it seems to work now. Motor speeds are too slow though. ' PCB produced. ' 24.05.2017: First tests on PCB ' Version 000: ' This version makes a 1 -90Hz motor controller, 3-phase, triangle connected. '------------------------------------------------------------------------------------------------------------- ' 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 ' port-assignments - hardware specifics '************************************** Symbol watchdog_led PORTB.7 ' red LED - pin 16 Symbol motor_enable PORTB.6 ' pin 15 Symbol OnOff1 PORTB.5 Symbol OnOff2 PORTA.4 Symbol OnOff3 PORTB.4 Symbol Orange_led PORTA.0 Symbol Green_led PORTA.1 Symbol Yellow_led PORTB.0 Symbol Red_Led PORTB.1 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 'constant initialisations for the midi input parser: Symbol Midichannel 5 ' Thunderwood_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 6 ' used for gesture input to rodo command tasks Symbol LastTask 5 ' = NrTasks - 1 ' midi-note mapping Symbol Stormnote 25 Symbol OnOff1note 120 ' green Symbol OnOff2note 121 ' red Symbol OnOff3note 122 ' yellow '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. ' Storm needs the 3-phase motor controller setting. 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 ' we start-up with 90 degree phase shifts. TRISA = %100000 ' set to output - for debugging TRISB = %0101011100000000 Output watchdog_led Output motor_enable ' Stormnote Output OnOff1 ' OnOff1note Output OnOff2 ' OnOff2note Output OnOff3 ' OnOff3note Output Orange_led Output Green_led Output Yellow_led Output Red_Led Variables: ' variable declarations: ' variables for midi reception and parsing: ' if buffers are > 255, indexes must be word! Dim RCIdxIn As Byte 'Word ' Pointer to the next empty location in the buffer Dim RCIdxOut As Byte '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 RCbuffer[256] As Byte ' 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 Dim pwm1value As Float 'Word Dim pwm2value As Float 'Word Dim pwm3value As Float '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 angle As Float Dim PWM_reset As Float Dim Srate As Word Dim Scnt As Byte ' must be byte! this is the sample clock Dim OldScnt As Byte Dim Scnt1 As Byte ' 120 degree phase shifted Dim Scnt2 As Byte ' 240 degree phase shifted Dim Amplitude_Factor As Float Dim Velfak As Word Dim stap As Word 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 Dur2[128] As Word ' durations for tasks Dim Dur[128] As Word ' chromatic mapping ' Dim Wave[256] As Word ' sine wave lookup - 1 period Dim SampRate[128] As Word ' motor frequency lookup Dim WaveFlt[256] As Float ' 4-period sine wave lookup Variable_Inits: GoSub Dur_Lookup1 GoSub Dur_Lookup2 ' GoSub Wave_Lookup ' sinewave 16-bit GoSub Period_Lookup_Table ' samprates GoSub Wave_Lookup_64 ' 4 sinewaves - 6 bit resolution Clear RCbuffer ' Rx Clear RCIdxIn ' Clear the buffer internal pointer Clear RCIdxOut ' Clear the buffer external pointer Clear time ' Clear TXBuffer ' Tx ' Clear TXIdxIn ' Clear TXIdxOut Set TimVals ' array Clear velflags Clear lites $ifdef Enable_Timer1 ' in the Thunderwood - Storm motorcontroller, this timer ' is used for the sample rate of the motor frequency. (sine wave lookup) ' used as sample frequency generator IPC0bits_T1IP0 = 0 ' set priority - this is very critical! IPC0bits_T1IP1 = 0 ' 5 = 101 IPC0bits_T1IP2 = 1 ' 6 = 011 Set TMR1 'set PR1 ' PR1 = 4800 'PR1 = 1310 - geeft 22kHz ---> / 256 = 86Hz sinewave 'PR1 = 2400 PR1 = 9600 '4800 ' prescaler: set to 01 for :8 ' with a 00 setting (:1) we supper up all machine cycles and the system freezes ' with PR1 = 9600 we measure freq = 2.85kHz corresponding with a motor frequency = 44Hz T1CON.5 = 0 ' set prescaler to :8 = 01 , :64 = 10 , :256 = 11 T1CON.4 = 1 ' prescaler :1 = 00 T1CON.15 = 1 ' start IFS0bits_T1IF = 0 ' clear Timer1 interrupt flag IEC0bits_T1IE = 1 ' Enable the Timer1 interrupt $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 TMR3 = 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 ' 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 ' 65536 would give 1836 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) ' for the ADSR implementation we should set this as fast as possible! PTPER = 256 ' 8 bit resolution '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 'Set PTPER ' set to 16-bit resolution = 1831.16 Hz = lowest freq. ' no divider, maximum timing resolution: Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Set PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 ' should be divide by 4 Clear PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 ' this gives 116kHz base frequency with PTPER set to 256 PDC1 = 127 'Clear PDC1 PDC2 = 127 'Clear PDC2 PDC3 = 127 'Clear PDC3 ' Clear PHASE1 ' Clear PHASE2 ' Clear PHASE3 Clear PHASE1 ' 0 graden PHASE2 = 21 '21845 ' 120 graden PHASE3 = 43 '43690 ' 240 graden 'Set MDC ' set to longest period - check this MDC = 256 ' seems to make no difference ' 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 outputs: IOCON1.11 = 0 ' 10 = push pull mode, 01 = redundant mode, 00 = complimentary IOCON1.10 = 0 ' IOCON1.9 = 0 ' no override IOCON1.8 = 0 'id. IOCON1.1 = 0 ' 1= swap pins, 0 = no pin swaps ' IOCON1 = %1100 0000 0000 0000 = &HC000 %1100 0100 0000 0010 = &HC402 IOCON2.15 = 1 IOCON2.14 = 1 IOCON2.13 = 0 IOCON2.12 = 0 IOCON2.11 = 0 IOCON2.10 = 0 IOCON2.9 = 0 IOCON2.8 = 0 ' IOCON2 = %1100 0000 0000 0000 = &HC000 IOCON3.15 = 1 IOCON3.14 = 1 IOCON3.13 = 0 IOCON3.12 = 1 IOCON3.11 = 0 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 #0xC000, w0 ' 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 #0xC000, w0 '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 #0xC000, w0 ' Mov #0xC800, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 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 - this is the setting for Thunderwood ' 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. - 16 bit period PTPER = 1024 ' should give 117kHz base frequency 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 GoTo MAIN ' jump over interrupt handlers Interrupt_handling: Isr- T1Interrupt ' timer1 interrupt Clear IFS0bits_T1IF ' Reset the Timer1 interrupt flag ' used for sampling rate as in Bug. Clear TMR1 ' this is required! ' PR1 = Srate ' SampRate[velo] = Srate set on reception of a note-on ' these float's should be removed from the IRQ: ' PDC1 = 128 + (WaveFlt[Scnt] * velfak ) 'Wave[Scnt] '* Amplitude_Factor ' waveform lookup table to PWM1 ' PDC2 = 128 + (WaveFlt[Scnt + 21] * velfak) 'Wave[Scnt + 85] '* Amplitude_Factor ' PDC3 = 128 + (WaveFlt[Scnt + 43] * velfak) 'Wave[Scnt + 171] '* Amplitude_Factor PDC1 = 128 + pwm1value PDC2 = 128 + pwm2value PDC3 = 128 + pwm3value Inc Scnt ' cleared on entry Orange_led = Scnt.0 ' speed neasurement debug - motor frequency is this frequency : 64 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 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 PortA.1 'debug this works fine 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 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 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 Inc RCIdxOut ' RCIdxOut = RCIdxOut & RCBufSize Bytein = RCbuffer[RCIdxOut] 'Toggle PORTB.0 'not working...- gives just a 1us spike Else Set Bytein EndIf 'Toggle PORTB.0 ' = 460kHz 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 MAIN: While ' timer23 version: ' overflows after 5 hours. time.Word1 = TMR3 ' resolution is 4.224 us time.Word0 = TMR2 ' time is a dword var $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 'toggle PORTB.0 ' debug ok 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 Stormnote Clear motor_enable Clear Scnt Clear T1CON.15 ' stop timer 'Clear PDC1 ' beter do: = PWM_reset 'Clear PDC2 'Clear PDC3 PDC1 = 127 PDC2 = 127 PDC3 = 127 Clear Velfak 'Clear IEC0bits_T1IE ' disable timer interrupt Case OnOff1note Clear OnOff1 Case OnOff2note Clear OnOff2 Case OnOff3note Clear OnOff3 EndSelect Set noteUit 'reset EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein ' toggle portB.0 ok. Else velo = Bytein If velo = 0 Then ' note off via velo=0 Select noteAan Case Stormnote Clear motor_enable Clear Scnt Clear T1CON.15 ' stop timer PDC1 = 127 'Clear PDC1 PDC2 = 127 'Clear PDC2 PDC3 = 127 'Clear PDC3 Clear Velfak 'clear IEC0bits_T1IE ' disable timer interrupt Case OnOff1note Clear OnOff1 Case OnOff2note Clear OnOff2 Case OnOff3note Clear OnOff3 EndSelect Else Select noteAan Case Stormnote Set motor_enable 'Srate = SampRate[velo] ' sets motor speed PR1 = SampRate[velo] ' Srate Set T1CON.15 ' start timer Clear IFS0bits_T1IF ' clear irq flag Set IEC0bits_T1IE ' enable irq Clear Scnt Velfak = velo ' for amplitude correction Case OnOff1note Set OnOff1 Case OnOff2note Set OnOff2 Case OnOff3note Set OnOff3 EndSelect EndIf Set noteAan EndIf Case Keypres_Status If notePres = 255 Then notePres = Bytein Else pres = Bytein Select notePres Case Stormnote If motor_enable = 1 Then Clear Scnt Velfak = pres PR1 = SampRate[pres] EndIf 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 Set Ctrl EndIf Case ProgChange_Status If prog = 255 Then 'single byte message prog = Bytein Set prog EndIf Case Aftertouch_Status If aft = 255 Then aft = Bytein Set aft EndIf Case Pitchbend_Status If pblsb = 255 Then pblsb = Bytein Else pbmsb = Bytein Set pblsb 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 Set TimVals[0] ' cancel repetitions Case 1 Set TimVals[1] Case 2 Set TimVals[2] Case 3 Set TimVals[3] Case 4 Set TimVals[4] Case 5 Clear velflags.5 Set TimVals[5] '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 TMR3 Clear time Set TimVals ' reboot: 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 TMR3 ' this resets maxtim 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 ' these float's removed from the timer 1 IRQ: ' the sample clock, Scnt, is incremented in the Timer1 ISR If Scnt <> OldScnt Then pwm1value = WaveFlt[Scnt] * Velfak Scnt1 = Scnt + 21 pwm2value = WaveFlt[Scnt1] * Velfak Scnt2 = Scnt + 43 pwm3value = WaveFlt[Scnt2] * Velfak OldScnt = Scnt EndIf ' 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 watchdog_led = time.17 ' 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 Clear resort_flag Return ' ************************************************************************************** ' procedures for midi receiver: Controller: Select Ctrl Case 66 '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 motor_enable Clear OnOff1 Clear OnOff2 Clear OnOff3 Clear Green_led Else Set Green_led EndIf Case 123 Clear motor_enable Clear OnOff1 Clear OnOff2 Clear OnOff3 EndSelect Set Ctrl 'mandatory reset 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 'Wave_Lookup: ' angle = 6.28318530717 / 256 ' PWM_reset = 32767.0 ' 'this is a pure sinewave 256 datapoints - 16 bit - unipolar 'For i = 0 To 255 ' Wave[i] = (1.0 + Sin(angle * i)) * PWM_reset 'Next i 'Return Wave_Lookup_64: ' four periods such that we still have 256 datapoints: angle = 6.28318530717 / 64 For i = 0 To 255 WaveFlt[i] = Sin(angle * i) ' bipolar -1 to + 1 Next i ' this brings the sampling rate down a factor 4 ' for PWM scaling we have to multiply this with the velo value and add 128 to obtain unipolar 8-bit PWM values Return Period_Lookup_Table: ' for the storm motor the range should be up to max. 400Hz ' the index is derived from the velo byte here. ' the period range should be 64355 --> ' Period[0] = 65535 ' Period[127] = 1200 (voor ca. 400Hz) SampRate[0] = 65535 stap = (65535 - 1200) / 127 For i = 1 To 127 ' inline calculation on startup: 'SampRate[i] = 65535.0 / (50.0 ^ (i/127.0)) ' linear scaling: SampRate[i] = 65535 - (stap * i) Next i Return '[EOF]