'**************************************************************************** '* * '* 16 bit 24EP128MC202 microcontroller * '* Godfried-Willem Raes * '* 16-bit PWM and PWM base frequency 1.8kHz * '* 64-point sinewave * '* with ramping and braking implemented * '* 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. ' 20.05.2017: Start coding for thunderwood : 3-phase 400Hz airplane fan motor ' 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. ' 25.05.2017: Version 001: ' 50Hz - 400Hz version using 8-bit pwm at 100kHz ' with a 8-bit sine-wave in 64-points per period. ' Braking implemented now ' 26.05.2017: Getting stuck in the main loop and thus missing midi commands... ' Try getting rid of floats. ' 1nF snubber caps added over motor windings. ' This be version 002. ' 26.05.2017: Integer math applied. Amplitude now controlled by phase shifting the sinewave. ' This works fine, but we are still missing midi commands when the motor runs at full ' speed. We note a lot of spikes on the midi data-input line... so we may have to add ' a small choke here. ' 27.05.2017: Code seems to run fine now. Hardware needed snubbers and Pi-filters. ' Loopspeed is now 434kHz with no load and drops to 363kHz worst case (Brake-condition). ' Brake time is now 0-1 second. ' instead of BUK454 we would better use IPP60R180C7XKSA1 mosfets. ' -------------------------------------------------------------------------------------------------- ' 29.08.2017: Starting from the code for Thunderwood storm. ' This should be a 0-50Hz motor controller for 3-phase induction motors. ' This uses a special PCB, with IPP60R180C7 power Mosfets. ' 30.08.2017: Back to a 64-points per period sinewave lookup ' PWM base frequency lowered to 29 kHz, still using 8 bit PWM resolution ' 31.08.2017: ADC working at 100 S/s sampling rate. This is for manual setting of motor speed. ' Afters hours of experimenting with settings, finally the ADC seems to work now... ' 01.09.2017: Continued research. ' 02.09.2017: Start-up problem detected... ' Flow chart bugs removed. ' Tacho not yet implemented. ' 03.09.2017: Tests with Siemens 3-phase motor. ' Problem: motor enable goes low when we raise the power supply voltage for the motor... ' 04.09.2017: Further testing, debugging and measurement. We suffer from motorboating. ' 06.09.2017: All mosfets burned out in the circuit. Driver chips and processor as well... ' 08.09.2017: PWM base frequency lowered to 7.6kHz, strict V/f scaling applied. ' Still not working on higher voltages than 40V... ' This version saved as Balsi_Motor_000.bas ' 10.09.2017: Attempting to recode for 16-bit PWM resolution and low PWM base frequency. ' nothing works amymore... ' Working at base freq 1.8 kHz now. ' Ramping added, not yet working well... ' 11.09.2017: Ramping now works with midi control. ' to be added: ramping with potmeter control. ' declared constant or parameter for ramping speed. ' Ramping added for potmeter control and for key pressure commands. ' The circuit still is not working with voltages higher than 40V... We are blowing ' IR2104 chips all the time... Erlarge the bootstrap capacitor? (now 47nF) ' 15.09.2017: New board made, using 7667 drivers and 1:1:1 transformers. ' This works best with PCM base frequencies between 20kHz and 40kHz. '------------------------------------------------------------------------------------------------------------- ' 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.5 ' red LED - pin 14 Symbol motor_enable PORTB.6 ' pin 15 Symbol Orange_led PORTB.1 Symbol Green_led PORTA.1 ' follows CTRL #66: If ON midi control is active, if OFF potentiometer controls speed Symbol Yellow_led PORTB.0 ' ON when the motor is running. ' note: RB7 used as input for tacho, via IRQ ' RA0 used as analog input for potentiometer speed control 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 - sampling rate 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 - for ADC sampler 100 S/s '$define Enable_Int0 ' enable external interrupt - for tacho '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 13 ' Balsi_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 2 ' used for braking and ramping Symbol LastTask 1 ' = NrTasks - 1 Symbol Brake_time 2048 ' multiplied with release value on note-off's - this gives 1 second max. Symbol RampUp_time 400 '3008 ' periods for ramping up and down Symbol RampDown_time 500 '3008 ' slowing down ramp period ' midi-note mapping Symbol Sirennote 24 ' for TRISA = %100001 TRISB = %0101011110000000 Output watchdog_led Output motor_enable Output Orange_led Output Green_led Output Yellow_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 ' must be word: used in lookups Dim idx As Byte ' index for task-timers 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 pw1 As Word ' 16-bit unsigned Dim pw2 As Word Dim pw3 As Word Dim angle As Float Dim sine As Float Dim OldScnt As Byte Dim Scnt1 As Byte ' sample clock Dim Scnt2 As Byte ' 120 degree phase shifted Dim Scnt3 As Byte ' 240 degree phase shifted Dim Scnt1s As Byte ' shifted version for amplitude control Dim Scnt2s As Byte Dim Scnt3s As Byte Dim Velfak As Byte Dim stap As Word Dim Braking As Word Dim Brake As Braking.0 Dim SpdIdx As Byte ' speedindex for the Samprate array. Set to velo on note-on Dim PerIdx As Byte ' speedindex for ramping Dim seinperiod As Word ' always = Srate Dim sollperiod As Word Dim Srate As Word ' for manual speed control via potmeter (or... sensor) Dim sample As Word ' holds the ADC value - 12 bits Dim Potflags As Byte Dim PotTog As Potflags.0 ' for periodicity timer Dim MotorRunning As Potflags.1 Dim Potvalue As Byte ' 7-bit value for spdidx ' Lookup tables: Dim SampRate[128] As Word ' motor frequency lookup (periods for timer1) ' Dim VelFaks[128] As Byte ' voltage correction factors Dim WaveWrd[256] As Word ' changed to unsigned word 10.09.2017 Dim Dur2[128] As Word ' durations for tasks Dim Dur[128] As Word ' chromatic mapping Dim Velperiod[4096] As Byte ' Velperiod[Srate] = PerIdx Variable_Inits: GoSub Dur_Lookup1 GoSub Dur_Lookup2 ' GoSub Wave_Lookup ' sinewave 16-bit GoSub Period_Lookup_Table ' samprates ' for Balsi motor controller we try: GoSub Wave_Lookup_64 ' 4 sinewaves ' for thunderwood storm-motor we had: ' GoSub Wave_Lookup_32 ' 8 sinewaves 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 Low motor_enable ' motor off Clear MotorRunning Clear Braking 'Clear lites $ifdef Enable_Timer1 ' This is our coding for : ' in the motorcontroller, this timer ' is used for the sample rate of the motor frequency. (sine wave lookup) ' used as sample frequency generator IPC0bits_T1IP0 = 1 ' set priority - this is very critical! IPC0bits_T1IP1 = 0 ' 4 = 100 , 5 = 101 IPC0bits_T1IP2 = 1 ' 6 = 110 Set TMR1 PR1 = SampRate[0] ' just for init. The values used are stored in Samprate[] Srate = SampRate[0] ' prescaler: set to 10 for :64 - for balsi motor. ' with a 00 setting (:1) we supper up all machine cycles and the system freezes T1CON.5 = 1 ' set prescaler to :8 = 01 , :64 = 10 , :256 = 11 T1CON.4 = 0 ' prescaler :1 = 00 T1CON.15 = 1 ' start timer 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 Set PR3 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 ' not used here ' 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 clock generator in to read the potmeter T5CON.15 = 1 ' start timer in 16 bit mode T5CON.13 = 0 T5CON.6 = 0 ' prescaler: 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. PR5 = 2340 ' should give 100 S/s 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 ' 29.08.2017: In the motor controller firmware used to read the value of the speed potmeter 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 format 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 = 1'0 ' 1'0 '1 ' auto-convert mode - internal counter ends sampling and starts conversion AD1CON1.6 = 1'0 '1'0 '1 ' id. AD1CON1.5 = 1'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 $endif $ifdef Enable_Int0 ' can be used to measure the rpm of the motor, a tacho ' 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 = 0 ' 0 = irq on positive edge INT0EP bit ' 1 = irq on negative edge ' 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 ' 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 'PTPER = 256 ' 8 bit resolution for PWM values - version Balsi_000 Set PTPER ' 16 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, if we clear all bits: Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Clear PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Clear PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 ' with PTPER set to 65535 this gives 1831 Hz as base frequency ' try halving the PWM frequency once more: (:8) ' we tried this to keep temperature on mosfets lower. the base frequency for the PWM ' should become 58.36kHz - measured o.k. 30.08.2017 ' set PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 ' Set PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 ' should be divide by 8 ' Clear PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 ' we can also go down to 29KHz by dividing by 16: ' measurement 31.08.2017: 29183Hz with PTPER set to 256 ' Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 ' Clear PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 ' should be divide by 16 ' Set PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 ' as all mosfet's burned out at this frequency, let get further down with the frequency: ' this should give 7296 Hz, the lowest possible setting for 8 bit resolution ' measured 07.09.2017: 7600 Hz ' CleaR PTCON2BITS_PCLKDIV0 ' BIT 0 ' SET PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 ' should be divide by 64 ' Set PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 PDC1 = 32768 '127 'Clear PDC1 PDC2 = 32768 '127 'Clear PDC2 PDC3 = 32768 '127 'Clear PDC3 Clear PHASE1 Clear PHASE2 Clear PHASE3 ' Clear PHASE1 ' 0 graden ' PHASE2 = 85 '21845 ' 120 graden ' PHASE3 = 171 '43690 ' 240 graden Set MDC ' set to longest period irrelevant here. 'MDC = 256 ' seems to make no difference ' could we use it for master duty cycle control? --> NO ' 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 ' polarity bits: 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 = 1 ' we used redundant mode here, for measurement purposes in Balsi 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 ' IOCON1 = %1100 0100 0000 0000 = &HC400 for Balsi IOCON2.15 = 1 IOCON2.14 = 1 IOCON2.13 = 0 IOCON2.12 = 0 IOCON2.11 = 0 IOCON2.10 = 1 ' redundant mode IOCON2.9 = 0 IOCON2.8 = 0 ' IOCON2 = %1100 0000 0000 0000 = &HC000 ' &HC400 for Balsi IOCON3.15 = 1 IOCON3.14 = 1 IOCON3.13 = 0 IOCON3.12 = 1 IOCON3.11 = 0 IOCON3.10 = 1 ' redundant mode ' 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 #0xC400, 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 #0xC400, w0 'Mov #0xC800, w0 ' required value for IOCON2 - redundant 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 #0xC400, w0 ' Mov #0xC800, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 ' 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 ' dead time is guaranteed by the specs of the IR2104 driver chips. PWMCON3.7 = 1 ' if we use all 6-outputs to drive transformers or optocouplers, we need to implement a dead time here! ' 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 ' Sampling rate timer interrupt Clear IFS0bits_T1IF ' Reset the Timer1 interrupt flag ' used for sampling rate as in Bug, Thunderwood... Clear TMR1 ' this is required! PR1 = Srate ' SampRate[velo] = Srate set on reception of a note-on 'seinperiod = Srate ' or a non-zero reading on the potmeter. ' changed to full 16-bits 10.09.2017 PDC1 = pw1 ' set the values for the PWM output channels PDC2 = pw2 ' pw1, pw2, pw3 must be unsigned word variables PDC3 = pw3 Inc Scnt1 ' this is the sample counter, a byte overflowing on 256. ' Toggle Orange_led ' = Scnt.0 ' speed neasurement debug - motor frequency is this frequency :32 in Balsi 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 ' 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 ' shouldn't we set AD1CON1.1 instead??? Set AD1CON1.1 'Toggle yellow_led ' for debug, measurement of sampling rate ' 31.08.2017: 50Hz, so 100 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 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 ' use of floats here crashes the compiler. ' even using a multiply seems impossible ' 31.08.2017: sampling rate down to 100 S/s sample = ADC1BUF0 ' 12-bit value format 0000 xxxx xxxx xxxx Clear IFS0.13 ' clear AD1 interrupt flag Clear AD1CON1.0 ' clear the conversion-done flag ' Toggle Yellow_led ' for debugging - gives 50Hz, so 100 S/s 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] Else Set Bytein EndIf 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: ' maybe only here we should start timer 1... Set T1CON.15 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 Potmeter_Control 'Midi_Parse_done 'throw away... EndIf If StBit = 1 Then 'should be faster than If Bytein > 127 Then 'status byte received, bit 7 is set Clear statusbyte 'if on another channel, the statusbyte needs a reset Select Bytein 'eqv to Select case ByteIn Case NoteOff_Status statusbyte = Bytein Set noteUit 'reset value. Cannot be 0 !!! Set release '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan Set velo Case Keypres_Status statusbyte = Bytein Set notePres Set pres Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status ' tuning and piece selection statusbyte = Bytein Set prog Case Aftertouch_Status ' used by Radar 1 to send messages to Radar 2 statusbyte = Bytein Set aft Case Pitchbend_Status statusbyte = Bytein Set pblsb Set pbmsb EndSelect Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Potmeter_Control '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 Sirennote ' = note 24 ' we use the release byte here to implement braking ' this involves a timer task, ' during braking, the direction of rotation is inverted. If release = 0 Then ' stop without braking Clear motor_enable ' Clear T1CON.15 ' stop timer - not required ' PDC1 = 32768 '128 ' done in timer irq ' PDC2 = 32668 '128 ' PDC3 = 32768 '128 pw1 = 32768 pw2 = 32768 pw3 = 32768 Clear Velfak Clear Brake If velflags.0 = 1 Then Set TimVals[0] Set resort_flag Clear velflags.0 EndIf Clear Yellow_led If velflags.1 = 1 Then Set TimVals[1] Set resort_flag Clear velflags.1 EndIf sollperiod = SampRate[0] Srate = sollperiod Else ' stop with braking. Brake duration proportional to release value ' we reverse the direction of rotation on the motor here. ' as an alternative we could also slowdown to 0 using task1 If Green_led = 1 Then ' power must be ON Set Brake ' Set T1CON.15 ' start timer 1 TimVals[0] = release * Brake_time ' = 2048 ' 4096 'Timvals[0] = Timvals[0] << 11 - gives assembler error TimVals[0] = TimVals[0] + time ' braking time is now ca. 1 second maximum Set velflags.0 Set resort_flag If velflags.1 = 1 Then Set TimVals[1] Clear velflags.1 EndIf Clear Yellow_led 'Set Red_Led ' indicate braking operation EndIf 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 Sirennote ' stop motor without braking Clear motor_enable ' Clear T1CON.15 ' stop timer ' PDC1 = 32768 '128 ' PDC2 = 32768 '128 ' PDC3 = 32768 '128 pw1 = 32768 pw2 = 32768 pw3 = 32768 Clear Brake If velflags.0 = 1 Then Set TimVals[0] Set resort_flag Clear velflags.0 'Clear Red_Led EndIf If velflags.1 = 1 Then Set TimVals[1] Clear velflags.1 EndIf sollperiod = SampRate[0] 'seinperiod = Sollperiod Srate = sollperiod Clear Yellow_led EndSelect Else Select noteAan Case Sirennote SpdIdx = velo ' here we should add code for ramping. If Green_led = 1 Then ' #66 must be ON! ' ' code without ramping: ' PR1 = SampRate[SpdIdx] ' Srate - for timer1 ' Set T1CON.15 ' start timer ' Clear IFS0bits_T1IF ' clear irq flag ' Set IEC0bits_T1IE ' enable irq ' ' for amplitude correction using phase addition ' ' This was for Thunderwood: ' ' Velfak = 8 - (SpdIdx / 16) ' 0 - 7 ' ' for Balsi we use a 64 point lookup and thus we should write: ' ' a full period is 64 points, so shifting 32 points and adding ' ' would give zero output voltage. ' 'Velfak = 16 - (SpdIdx / 8) ' for velo = 1 to 127, runs from 16 to 0 ' ' so amplitude should go down by 50% ' ' strictly V/f: ' Velfak = 32 - (SpdIdx / 4) ' ramping code: sollperiod = SampRate[SpdIdx] If sollperiod = Srate Then 'Srate = SampRate[SpdIdx] ' Srate - for timer1 - PR1 ' for amplitude correction using phase addition ' strictly V/f Velfak = 32 - (SpdIdx / 4) If velflags.1 = 1 Then ' stop ramping Clear velflags.1 Set TimVals[1] Set resort_flag EndIf Else ' start a timer for ramping ' start a task to increment/decrement Srate until sollspeed is reached PerIdx = Velperiod[Srate] 'Srate = Samprate[Peridx] ' for PR1 If sollperiod > Srate Then ' in this case we must slowdown TimVals[1] = time + RampDown_time '3008 ' ramping speed Else ' in this case we must speedup TimVals[1] = time + RampUp_time EndIf Set velflags.1 Set resort_flag EndIf ' Set T1CON.15 ' start timer ' Clear IFS0bits_T1IF ' clear irq flag ' Set IEC0bits_T1IE ' enable irq Clear Brake If velflags.0 = 1 Then Set TimVals[0] ' cancel brake timer Set resort_flag Clear velflags.0 EndIf Set motor_enable Set Yellow_led Else ' no midi operation - CC66 is off Clear motor_enable Clear Yellow_led Velfak = 32 ' gives 0 output EndIf EndSelect EndIf Set noteAan EndIf Case Keypres_Status If notePres = 255 Then notePres = Bytein Else pres = Bytein Select notePres Case Sirennote If motor_enable = 1 Then High motor_enable ' confirm If Brake = 0 Then ' if braking, the command will be refused. 'Velfak = 16 - (pres / 8) ' reducing amplitude to 50% for lower speeds ' strictly V/f (so 0 amplitude for pres = 0): 'Velfak = 32 - (pres / 4) 'Srate = SampRate[pres] ' no ramping. (to be added!) ' with ramping: sollperiod = SampRate[pres] If sollperiod = Srate Then ' for amplitude correction using phase addition ' strictly V/f Velfak = 32 - (pres / 4) If velflags.1 = 1 Then ' stop ramping Clear velflags.1 Set TimVals[1] Set resort_flag EndIf Else ' start a task to increment/decrement Srate until sollspeed is reached PerIdx = Velperiod[Srate] If sollperiod > Srate Then ' in this case we must slowdown TimVals[1] = time + RampDown_time '3008 ' ramping speed Else ' in this case we must speedup TimVals[1] = time + RampUp_time EndIf Set velflags.1 Set resort_flag EndIf 'else ' evt. kode toevoegen voor het geval de rem nog aanstaat... EndIf 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 Potmeter_Control: ' procedure for manual potmeter-motor control: ' procedure to read the potmeter and set speed according to it. ' This should only work on the condition that no midi note is received for ' motor control. ' Hence, it should also work when CC66 is OFF. ' maybe it would be best to let it work only when CC66 is OFF. If Green_led = 0 Then If time.15 <> PotTog Then PotTog = time.15 ' flipflop Potvalue = sample >> 5 ' reduce the ADC 12 bit value to 7 bits ' potvalue must be byte ' here we can add an integrator. If Potvalue > 0 Then ' run motor If MotorRunning = 0 Then ' we have to start the motor from standstill in this case ' without ramping: Srate = SampRate[Potvalue] ' Srate - for timer1 ' with ramping: sollperiod = SampRate[Potvalue] If sollperiod = Srate Then 'Srate = SampRate[SpdIdx] ' Srate - for timer1 - PR1 ' for amplitude correction using phase addition ' strictly V/f Velfak = 32 - (Potvalue / 4) If velflags.1 = 1 Then ' stop ramping Clear velflags.1 Set TimVals[1] Set resort_flag EndIf Else ' start a timer for ramping ' start a task to increment/decrement Srate until sollspeed is reached PerIdx = Velperiod[Srate] ' dus Srate = Samprate[Peridx] ' for PR1 Velfak = 32 - (PerIdx / 4) If sollperiod > Srate Then ' in this case we must slowdown TimVals[1] = time + RampDown_time '3008 ' ramping speed Else ' in this case we must speedup TimVals[1] = time + RampUp_time EndIf Set velflags.1 Set resort_flag EndIf ' Velfak is for amplitude correction using phase addition ' for Balsi we use a 64 point lookup and thus we should write: ' a full period is 64 points, so shifting 32 points and adding ' would give zero output voltage. Clear Brake If velflags.0 = 1 Then Set TimVals[0] ' cancel brake timer Set resort_flag Clear velflags.0 EndIf Set MotorRunning ' flag Else ' in this case the motor is already running ' set motor-enable ' added, as we noticed it gets switched off for some reason... ' we just have to adjust the speed: ' without ramping: 'Srate = SampRate[Potvalue] ' Srate - for timer1 PR1 'Velfak = 32 - (Potvalue / 4) ' with ramping: sollperiod = SampRate[Potvalue] If sollperiod = Srate Then 'Srate = SampRate[SpdIdx] ' Srate - for timer1 - PR1 ' for amplitude correction using phase addition ' strictly V/f Velfak = 32 - (Potvalue / 4) If velflags.1 = 1 Then ' stop ramping Clear velflags.1 Set TimVals[1] Set resort_flag EndIf Else ' start a timer for ramping ' start a task to increment/decrement Srate until sollspeed is reached PerIdx = Velperiod[Srate] 'Srate = Samprate[Peridx] ' for PR1 Velfak = 32 - (PerIdx / 4) If sollperiod > Srate Then ' in this case we must slowdown TimVals[1] = time + RampDown_time '3008 ' ramping speed Else ' in this case we must speedup TimVals[1] = time + RampUp_time EndIf Set velflags.1 Set resort_flag EndIf EndIf Set motor_enable ' so we confirm motor start after setting the timer. Set Yellow_led Else ' stop motor without braking ' we could add code for braking as well. Clear motor_enable ' Clear T1CON.15 ' stop timer pw1 = 32768 pw2 = 32768 pw3 = 32768 Clear Velfak Clear Brake ' no braking flag here. If velflags.0 = 1 Then Set TimVals[0] Set resort_flag Clear velflags.0 EndIf Clear Yellow_led Clear MotorRunning EndIf 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 ' used to implement motor braking. ' stop the motor: Clear motor_enable ' Clear T1CON.15 ' stop timer 1 pw1 = 32768 pw2 = 32768 pw3 = 32768 Velfak = 32 '16 Set TimVals[0] ' cancel timer Clear Brake ' clear brake flag Clear velflags.0 Clear MotorRunning 'Clear Red_Led sollperiod = SampRate[0] Srate = sollperiod Case 1 ' slowdown/speedup ramping Select Srate ' = seinperiod Case sollperiod ' goal reached ' stop ramping ' Srate = sollperiod Set TimVals[1] ' cancel timer Clear velflags.1 PerIdx = Velperiod[sollperiod] Case < sollperiod ' slowdown Inc Srate ' = seinperiod 'Srate = seinperiod PerIdx = Velperiod[Srate] TimVals[1] = time + RampDown_time ' 3008 Case > sollperiod ' speedup Dec Srate 'Srate = seinperiod TimVals[1] = time + RampUp_time ' 3008 PerIdx = Velperiod[Srate] EndSelect ' strictly V/f: Velfak = 32 - (PerIdx / 4) '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 ' the sample clock, Scnt1, is incremented in the Timer1 ISR ' of course there is a risk that a timer1 interrupt happens during this proc... If Scnt1 <> OldScnt Then ' thus this proc. is performed at the sampling rate. ' disable irq1: IEC0bits_T1IE = 0 ' disable the Timer1 interrupt If Brake = 0 Then ' normal direction of rotation ' integer version: ' we can avoid the multiply here by adding two sines wave with a phase shift in function of Velfak Scnt1s = Scnt1 + Velfak ' it's essential to use a byte variable here! ' doing WaveWrd[Scnt1 + Velfak] leads to serious glitches! pw1 = WaveWrd[Scnt1] + WaveWrd[Scnt1s] ' 10.09.2017: now unsigned ' 0 - 65535 centered around 32768 Scnt2 = Scnt1 + 21 ' 120 degrees phase shift for a 64 point sinewave (Balsi) Scnt2s = Scnt2 + Velfak pw2 = WaveWrd[Scnt2] + WaveWrd[Scnt2s] Scnt3 = Scnt1 + 43 ' 240 degrees phase shift Scnt3s = Scnt3 + Velfak pw3 = WaveWrd[Scnt3] + WaveWrd[Scnt3s] ' the pw values are sent to the PWM system in the timer 1 interrupt Else ' inverted direction of rotation, used for braking only: If velflags.0 = 1 Then ' this means braking is active pw1 = WaveWrd[Scnt1] + WaveWrd[Scnt1] Scnt2 = Scnt1 - 21 ' - 120 degrees pw2 = WaveWrd[Scnt2] + WaveWrd[Scnt2] Scnt3 = Scnt1 - 43 ' - 240 degrees pw3 = WaveWrd[Scnt3] * WaveWrd[Scnt3] Else pw1 = 32768 pw2 = 32768 pw3 = 32768 EndIf EndIf OldScnt = Scnt1 IEC0bits_T1IE = 1 ' Enable the Timer1 interrupt EndIf ' Toggle Orange_led ' for loopspeed measurement: 434kHz 29.08.2017 - at no load ' ca. 1us per cycle ' drops to 363kHz at full load 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 '11.09.2017: we now leave timer1 running at all times If value = 0 Then ' power down For i = 0 To LastTask Set TimVals[i] Next i ' Clear T1CON.15 ' stop timer Clear velflags Set resort_flag Clear motor_enable ' this stops the motor Clear Green_led pw1 = 32768 pw2 = 32768 pw3 = 32768 Clear PerIdx sollperiod = SampRate[0] Srate = SampRate[0] Else Set Green_led EndIf Case 123 Clear motor_enable pw1 = 32768 pw2 = 32768 pw3 = 32768 Set TimVals[0] Set TimVals[1] Clear velflags Clear PerIdx sollperiod = SampRate[0] Srate = SampRate[0] 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_128: ' ' two periods such that we still have 256 datapoints: ' angle = 6.28318530717 / 128.0 ' ' integer version: ' For i = 0 To 255 ' sine = Sin(angle * i) ' WaveWrd[i] = 16384 * sine ' bipolar 15 bits: - 16384 to + 16383 ' Next i 'Return Wave_Lookup_64: ' four periods such that we still have 256 datapoints: ' this one in use for Balsi 31.08.2017 angle = 6.28318530717 / 64.0 ' integer version: For i = 0 To 255 sine = Sin(angle * i) ' unsigned coding: WaveWrd[i] = (1.0 + sine) * 16383.00 ' 0 --> 32768 , zero = 16384 Next i Return 'Wave_Lookup_32: ' ' eight periods such that we still have 256 datapoints ' ' this brings the sampling rate down a factor 8 ' ' so if we use this, the sample-rate values in the lookup have to be multiplied by 2 ' angle = 6.28318530717 / 32.0 ' ' For i = 0 To 255 ' ' sine = Sin(angle * i) ' ' WaveWrd[i] = 255.99 * sine ' bipolar -256 to + 255 - 9 bits ' ' Next i ' ' for version 002: 26.05.2017: - Thunderwood storm. ' For i = 0 To 255 ' sine = Sin(angle * i) ' WaveWrd[i] = 16383.99 * sine ' bipolar 15 bits: -16384 to + 16383 ' Next i 'Return Period_Lookup_Table: ' values for 3-phase motor ' Samprate[] is a word-array (16 bits) ' 250 geeft 58.4Hz SampRate[127] = 292 ' frequency = should be 50Hz SampRate[126] = 300 SampRate[125] = 310 SampRate[124] = 315 SampRate[123] = 320 SampRate[122] = 325 SampRate[121] = 331 SampRate[120] = 336 SampRate[119] = 342 SampRate[118] = 347 SampRate[117] = 353 SampRate[116] = 359 SampRate[115] = 365 SampRate[114] = 371 SampRate[113] = 377 ' frequency = 313 SampRate[112] = 383 ' frequency = 308 SampRate[111] = 389 ' frequency = 303 SampRate[110] = 395 ' frequency = 299 SampRate[109] = 402 ' frequency = 294 SampRate[108] = 408 ' frequency = 289 SampRate[107] = 415 ' frequency = 284 SampRate[106] = 422 ' frequency = 280 SampRate[105] = 429 ' frequency = 275 SampRate[104] = 436 ' frequency = 271 SampRate[103] = 443 ' frequency = 266 SampRate[102] = 450 ' frequency = 262 SampRate[101] = 458 ' frequency = 258 SampRate[100] = 465 ' frequency = 254 SampRate[99] = 473 ' frequency = 250 SampRate[98] = 481 ' frequency = 246 SampRate[97] = 488 ' frequency = 242 SampRate[96] = 496 ' frequency = 238 SampRate[95] = 505 ' frequency = 234 SampRate[94] = 513 ' frequency = 230 SampRate[93] = 521 ' frequency = 227 SampRate[92] = 530 ' frequency = 223 SampRate[91] = 538 ' frequency = 219 SampRate[90] = 547 ' frequency = 216 SampRate[89] = 556 ' frequency = 212 SampRate[88] = 565 ' frequency = 209 SampRate[87] = 575 ' frequency = 205 SampRate[86] = 584 ' frequency = 202 SampRate[85] = 594 ' frequency = 199 SampRate[84] = 603 ' frequency = 196 SampRate[83] = 613 ' frequency = 193 SampRate[82] = 623 ' frequency = 189 SampRate[81] = 633 ' frequency = 186 SampRate[80] = 644 ' frequency = 183 SampRate[79] = 654 ' frequency = 180 SampRate[78] = 665 ' frequency = 178 SampRate[77] = 676 ' frequency = 175 SampRate[76] = 687 ' frequency = 172 SampRate[75] = 698 ' frequency = 169 SampRate[74] = 710 ' frequency = 166 SampRate[73] = 721 ' frequency = 164 SampRate[72] = 733 ' frequency = 161 SampRate[71] = 745 ' frequency = 158 SampRate[70] = 757 ' frequency = 156 SampRate[69] = 770 ' frequency = 153 SampRate[68] = 782 ' frequency = 151 SampRate[67] = 795 ' frequency = 148 SampRate[66] = 808 ' frequency = 146 SampRate[65] = 821 ' frequency = 144 SampRate[64] = 835 ' frequency = 141 SampRate[63] = 849 ' frequency = 139 SampRate[62] = 862 ' frequency = 137 SampRate[61] = 877 ' frequency = 135 SampRate[60] = 891 ' frequency = 133 SampRate[59] = 905 ' frequency = 130 SampRate[58] = 920 ' frequency = 128 SampRate[57] = 935 ' frequency = 126 SampRate[56] = 951 ' frequency = 124 SampRate[55] = 966 ' frequency = 122 SampRate[54] = 982 ' frequency = 120 SampRate[53] = 998 ' frequency = 118 SampRate[52] = 1015 ' frequency = 116 SampRate[51] = 1031 ' frequency = 114 SampRate[50] = 1048 ' frequency = 113 SampRate[49] = 1065 ' frequency = 111 SampRate[48] = 1083 ' frequency = 109 SampRate[47] = 1100 ' frequency = 107 SampRate[46] = 1118 ' frequency = 106 SampRate[45] = 1137 ' frequency = 104 SampRate[44] = 1155 ' frequency = 102 SampRate[43] = 1174 ' frequency = 101 SampRate[42] = 1194 ' frequency = 99 SampRate[41] = 1213 ' frequency = 97 SampRate[40] = 1233 ' frequency = 96 SampRate[39] = 1253 ' frequency = 94 SampRate[38] = 1274 ' frequency = 93 SampRate[37] = 1295 ' frequency = 91 SampRate[36] = 1316 ' frequency = 90 SampRate[35] = 1337 ' frequency = 88 SampRate[34] = 1359 ' frequency = 87 SampRate[33] = 1381 ' frequency = 85 SampRate[32] = 1404 ' frequency = 84 SampRate[31] = 1427 ' frequency = 83 SampRate[30] = 1450 ' frequency = 81 SampRate[29] = 1474 ' frequency = 80 SampRate[28] = 1498 ' frequency = 79 SampRate[27] = 1523 ' frequency = 78 SampRate[26] = 1548 ' frequency = 76 SampRate[25] = 1573 ' frequency = 75 SampRate[24] = 1599 ' frequency = 74 SampRate[23] = 1625 ' frequency = 73 SampRate[22] = 1652 ' frequency = 71 SampRate[21] = 1679 ' frequency = 70 SampRate[20] = 1706 ' frequency = 69 SampRate[19] = 1734 ' frequency = 68 SampRate[18] = 1763 ' frequency = 67 SampRate[17] = 1791 ' frequency = 66 SampRate[16] = 1821 ' frequency = 65 SampRate[15] = 1851 ' frequency = 64 SampRate[14] = 1881 ' frequency = 63 SampRate[13] = 1912 ' frequency = 62 SampRate[12] = 1943 ' frequency = 61 SampRate[11] = 1975 ' frequency = 60 SampRate[10] = 2007 ' frequency = 59 SampRate[9] = 2040 ' frequency = 58 SampRate[8] = 2074 ' frequency = 57 SampRate[7] = 2108 ' frequency = 56 SampRate[6] = 2142 ' frequency = 55 SampRate[5] = 2177 ' frequency = 54 SampRate[4] = 2213 SampRate[3] = 2249 SampRate[2] = 2286 SampRate[1] = 2323 SampRate[0] = 2361 ' 6 Hz ' Balsi: ' now we have 48Hz to 6 Hz for the motor frequency range: checked o.k. on Tektronix. ' inverse table, required for ramping: j = SampRate[0] ' bug 11/09/2017: j was byte - must be word!!! For i = 0 To 127 While SampRate[i] <= j Dec j Velperiod[j] = i Wend Next i Clear j Return '[EOF]