Thanks, I will make some experiments with this code.
Thanks, I will make some experiments with this code.
Unfortuntely, it doesn't works.
The problem is that TimerReload variable overwrites TimerReload EXT constant, defined later in DT routine.
Code:' PIC initialization DEFINE OSC 40 DEFINE LCD_DREG PORTC DEFINE LCD_EREG PORTD DEFINE LCD_RSREG PORTD DEFINE LCD_EBIT 0 DEFINE LCD_RSBIT 1 DEFINE LCD_COMMANDUS 4000 DEFINE LCD_DATAUS 1000 ' BAS includes INCLUDE "DT_INTS-18.bas" INCLUDE "ReEnterPBP-18.bas" INCLUDE "Sine_table.bas" ' Port registers configuration TRISB=%11000000 ' PWM 0,1,2,3,4,5 outputs TRISC=%00110000 ' +/- buttons ' PCPWM registers configuration DTCON=%110 ' Deadtime (600ns) PTCON0=%0 ' 1:1 postscale, Fosc/4 1:1 prescale, free running mode PTCON1=%10000000 ' PWM time base is ON, counts up, 19.45kHz/4 PWMCON0=%1000000 ' PWM 0,1,2,3,4,5 set in pair mode PWMCON1=%1 ' PWM timer sync configuration ' PWM calculation variables ustep var byte vstep var byte wstep var byte uduty var word vduty var word wduty var word amplitude var word carrier VAR word flag var bit ' Variables definition ustep=90 ' 360 degrees phase angle vstep=60 ' 240 degrees phase angle wstep=30 ' 120 degrees phase angle amplitude=65535 ' Sinewave amplitude adjust (65535=max amplitude) carrier=1023 ' Carrier frequency adjust (1023=13kHz) flag=%0 ' Menu flag ' PWM carrier frequency register configuration PTPERL=carrier.lowbyte PTPERH=carrier.highbyte Dummy VAR WORD Dummy2 VAR WORD Dummy3 VAR WORD ReloadInstruction VAR BYTE TimerReload VAR WORD Frequency VAR WORD ReloadInstruction = 0 'Number of instructioncycles it takes to actually reload the timer. I don't know how many it is in this case. Tune later. 'For 40Mhz operation and 1:1 prescaler the timer ticks at 10Mhz Dummy2 = 10000 'These can not be constants because Dummy3 = 10000 'constants doesn't work with DIV32 Frequency = 5000 'Lowest possible frequency is ~153Hz. Don't go below that. Dummy = Dummy2 * Dummy3 'Intermediate result is now 10.000.000 TimerReload = DIV32 Frequency 'Divide 10.000.000 in Frequency (200 in this case) TimerReload = 65535 - TimerReload + 1 + ReloadInstruction ' =15536 for 200Hz ' Interrupt processors ASM INT_LIST macro INT_Handler TMR1_INT,ReloadTMR1,ASM,no INT_Handler TMR1_INT,_pwmint,PBP,yes endm INT_CREATE ENDASM ' Timers configuration @Freq=4050 @Prescaler=1 T1CON=$00 ' Interrupts enable @INT_ENABLE TMR1_INT GOSUB StartTimer ' Main program loop mainlp: ' Debug display if flag=0 then LCDOUT $FE,$2,"Freq. adjust :" LCDOUT $FE,$C0, DEC frequency if PORTC.4=1 then frequency=frequency-1 if PORTC.5=1 then frequency=frequency+1 IF PORTC.4 AND PORTC.5=1 then flag=%1 else LCDOUT $FE,$2,"Amp. adjust :" LCDOUT $FE,$C0,DEC4 amplitude if PORTC.4=1 then amplitude=amplitude-1 if PORTC.5=1 then amplitude=amplitude+1 endif goto mainlp ' PWM calculation and update interrupt (Timer 1) pwmint: ' PWM U phase calculation uduty=sine[ustep] uduty=uduty<<4**amplitude ' PWM V phase calculation vduty=sine[vstep] vduty=vduty<<4**amplitude ' PWM W phase calculation wduty=sine[wstep] wduty=wduty<<4**amplitude ' PWM U, V and W update PDC0L=uduty.lowbyte PDC0H=uduty.highbyte PDC1L=vduty.lowbyte PDC1H=vduty.highbyte PDC2L=wduty.lowbyte PDC2H=wduty.highbyte ' Phase angle calculation ustep=ustep-1 vstep=vstep-1 wstep=wstep-1 ' Phase angle reinitialization if ustep=0 then ustep=90 if vstep=0 then vstep=90 if wstep=0 then wstep=90 @INT_RETURN ' Timer1 interrupt handler ASM ReloadInst=8 MaxCount=65536+(ReloadInst/Prescaler) TimerReload=MaxCount-(OSC*1000000/4/Prescaler/Freq) ENDASM ' Timer1 variables @Timer1=TMR1L Timer1 VAR WORD EXT 'TimerReload VAR EXT TMR1ON VAR T1CON.0 ' Timer1 reload ASM ReloadTMR1 MOVE?CT 0,T1CON,TMR1ON MOVLW LOW(TimerReload) ADDWF TMR1L,F BTFSC STATUS,C INCF TMR1H,F MOVLW HIGH(TimerReload) ADDWF TMR1H,F MOVE?CT 1,T1CON,TMR1ON INT_RETURN ENDASM ' Timer1 start/stop control StartTimer: Timer1=TimerReload TMR1ON=1 RETURN StopTimer: TMR1ON=0 RETURN
Last edited by pxidr84; - 7th March 2011 at 20:30.
Yes of course it does. I thought we came to the conclusion that you couldn't use Darrels timer template because it calculated the reload value at build time and you wanted to calculate it at runtime. Now you're trying to use it anyway....I don't get it.
Code:INCLUDE "DT_INTS-18.bas" INCLUDE "ReEnterPBP-18.bas" InterruptFrequency VAR WORD Dummy VAR WORD Dummy2 VAR WORD Dummy3 VAR WORD TMRCopy VAR WORD TimerReloadValue VAR WORD Dummy2 = 10000 Dummy3 = 10000 InterruptFrequency = 5000 ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler TMR1_INT, _TimezUp, PBP, yes endm INT_CREATE ; Creates the interrupt processor ENDASM @ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts TRISB.3 = 0 ' Output to measure interrupt frequency CMCON = 7 ADCON1 = %00001111 ' No analog inputs. T1CON.0 = 1 ' Start TMR1 Dummy = Dummy2 * Dummy3 TimerReloadValue = Div32 InterruptFrequency TimerReloadValue = 65535 - TimerReloadValue + 1 LCDOUT $FE,1,"F: ", #InterruptFrequency, " Reload: ", #TimerReloadValue Main: Pause 20 Goto Main ' ---------- Interrupt handler ------------ TimezUp: T1CON.0 = 0 ' Stop TMR1 TMRCopy.HighByte = TMR1H ' Copy value of TMR1 registers TMRCopy.LowByte = TMR1L TMRCopy = TMRCopy + TimerReloadValue ' Add reload value (compensates for overhead) TMR1H = TMRCOPY.HighByte ' And back to TMR1 TMR1L = TMRCopy.LowByte T1CON.0 = 1 ' Restart Timer Toggle PortB.3 @ INT_RETURN
I've tested your code, and the results are quite encouraging.
Some tests I've done :
For each, INTF/Output=678, so it's "linear" now.INTF=38000 Output=56Hz
INTF=35000 Output=51.6Hz
INTF=30000 Output=44.3Hz
But when the interrupt frequency is above ~39060Hz, the ReloadTimer jumps from ~62975 to ~63405 ! Of course, the sines jumps ~10Hz upper.
Code:' PIC initialization DEFINE OSC 40 DEFINE LCD_DREG PORTC DEFINE LCD_EREG PORTD DEFINE LCD_RSREG PORTD DEFINE LCD_EBIT 0 DEFINE LCD_RSBIT 1 DEFINE LCD_COMMANDUS 4000 DEFINE LCD_DATAUS 1000 ' BAS includes INCLUDE "DT_INTS-18.bas" INCLUDE "ReEnterPBP-18.bas" INCLUDE "Sine_table.bas" ' Port registers configuration TRISB=%11000000 ' PWM 0,1,2,3,4,5 outputs TRISC=%00110000 ' +/- buttons ' PCPWM registers configuration DTCON=%110 ' Deadtime (600ns) PTCON0=%0 ' 1:1 postscale, Fosc/4 1:1 prescale, free running mode PTCON1=%10000000 ' PWM time base is ON, counts up, 19.45kHz/4 PWMCON0=%1000000 ' PWM 0,1,2,3,4,5 set in pair mode PWMCON1=%1 ' PWM timer sync configuration ' PWM calculation variables ustep var byte vstep var byte wstep var byte uduty var word vduty var word wduty var word amplitude var word carrier VAR word flag var bit ' Variables definition ustep=90 ' 360 degrees phase angle vstep=60 ' 240 degrees phase angle wstep=30 ' 120 degrees phase angle amplitude=65535 ' Sinewave amplitude adjust (65535=max amplitude) carrier=1023 ' Carrier frequency adjust (1023=13kHz) flag=0 ' Menu flag ' PWM carrier frequency register configuration PTPERL=carrier.lowbyte PTPERH=carrier.highbyte InterruptFrequency VAR WORD Dummy VAR WORD Dummy2 VAR WORD Dummy3 VAR WORD TMRCopy VAR WORD TimerReloadValue VAR WORD InterruptFrequency = 38000 ' Interrupt processors ASM INT_LIST macro INT_Handler TMR1_INT,_pwmint,PBP,yes endm INT_CREATE ENDASM ' Interrupts enable @INT_ENABLE TMR1_INT T1CON.0=1 recalc: Dummy2 = 10000 Dummy3 = 10000 Dummy = Dummy2 * Dummy3 TimerReloadValue = Div32 InterruptFrequency TimerReloadValue = 65535 - TimerReloadValue + 1 ' Main program loop mainlp: flag=0 LCDOUT $FE,2,"F: ", #InterruptFrequency lcdout $FE, $C0," R: ", #TimerReloadValue if PORTC.4=1 then InterruptFrequency=InterruptFrequency-1 : flag=1 if PORTC.5=1 then InterruptFrequency=InterruptFrequency+1 : flag=1 if flag=1 then goto recalc goto mainlp ' PWM calculation and update interrupt (Timer 1) pwmint: T1CON.0 = 0 ' Stop TMR1 TMRCopy.HighByte = TMR1H ' Copy value of TMR1 registers TMRCopy.LowByte = TMR1L TMRCopy = TMRCopy + TimerReloadValue ' Add reload value (compensates for overhead) TMR1H = TMRCOPY.HighByte ' And back to TMR1 TMR1L = TMRCopy.LowByte T1CON.0 = 1 ' Restart Timer ' PWM U phase calculation uduty=sine[ustep] uduty=uduty<<4**amplitude ' PWM V phase calculation vduty=sine[vstep] vduty=vduty<<4**amplitude ' PWM W phase calculation wduty=sine[wstep] wduty=wduty<<4**amplitude ' PWM U, V and W update PDC0L=uduty.lowbyte PDC0H=uduty.highbyte PDC1L=vduty.lowbyte PDC1H=vduty.highbyte PDC2L=wduty.lowbyte PDC2H=wduty.highbyte ' Phase angle calculation ustep=ustep-1 vstep=vstep-1 wstep=wstep-1 ' Phase angle reinitialization if ustep=0 then ustep=90 if vstep=0 then vstep=90 if wstep=0 then wstep=90 @INT_RETURN
Last edited by pxidr84; - 8th March 2011 at 21:03.
Hi,
Interrupt frequency of 39060Hz?
Previously you said you wanted an output of 120Hz and with 72 steps per sin-cycle that's 120*72=8640Hz interrupt frequency. The math is then like this
65535 - (10,000,000 / 8640) + 1 = 64378
64378 is what the timer reload value is and this means that there's 65536-64378=1158 cycles between interrupts. 1158 cycles times 100ns per cycle equals 115.8us between interrupts 1/115.8us = 8635Hz so it's pretty close.
This means that there's only 1158 cycles (or instructions if you will) between interrupts. In this time the PIC has to save all the PBP system variables, reload the timer, execute your interrupt service routine and then restore all the PBP system variables.
Why are you trying to interrupt at ~39kHz? That's only about 256 cycles between interrupts which I'm pretty sure won't be enough time to do all that needs to get done in the interrupt.
Finally, this line:Probably doesn't work like you think. Here, Flag gets set no matter what the state of of PortC.4 actually is. So you are always running the recalc routine. If you want Flag to be set only when PortC.4 is high you need to change it to:Code:If PortC.4 = 1 Then InterruptFrequency = InterruptFrequency -1 : Flag = 1Code:If PortC.4 = 1 THEN InterruptFrequency = InterruptFrequency - 1 Flag = 1 ENDIF
Well, for 120Hz, I need an interrupt frequency of 120*90=10800Hz.
If I configure this in my program, I get output sines of only ~16Hz.
So what's wrong?
The code :
The "flag" problem is corrected now, I can change frequency during runtime.Code:' PIC initialization DEFINE OSC 40 DEFINE LCD_DREG PORTC DEFINE LCD_EREG PORTD DEFINE LCD_RSREG PORTD DEFINE LCD_EBIT 0 DEFINE LCD_RSBIT 1 DEFINE LCD_COMMANDUS 4000 DEFINE LCD_DATAUS 1000 ' BAS includes INCLUDE "DT_INTS-18.bas" INCLUDE "ReEnterPBP-18.bas" INCLUDE "Sine_table.bas" ' Port registers configuration TRISB=%11000000 ' PWM 0,1,2,3,4,5 outputs TRISC=%00110000 ' +/- buttons ' PCPWM registers configuration DTCON=%110 ' Deadtime (600ns) PTCON0=%0 ' 1:1 postscale, Fosc/4 1:1 prescale, free running mode PTCON1=%10000000 ' PWM time base is ON, counts up, 19.45kHz/4 PWMCON0=%1000000 ' PWM 0,1,2,3,4,5 set in pair mode PWMCON1=%1 ' PWM timer sync configuration ' PWM calculation variables ustep var byte vstep var byte wstep var byte uduty var word vduty var word wduty var word amplitude var word carrier VAR word flag var bit Dummy VAR WORD Dummy2 VAR WORD Dummy3 VAR WORD InterruptFrequency VAR WORD TMRCopy VAR WORD TimerReloadValue VAR WORD ' Variables definition ustep=90 ' 360 degrees phase angle vstep=60 ' 240 degrees phase angle wstep=30 ' 120 degrees phase angle amplitude=65535 ' Sinewave amplitude adjust (65535=max amplitude) carrier=1023 ' Carrier frequency adjust (1023=13kHz) flag=0 ' Menu flag Dummy2 = 10000 Dummy3 = 10000 InterruptFrequency = 10800 ' PWM carrier frequency register configuration PTPERL=carrier.lowbyte PTPERH=carrier.highbyte ' Interrupt processors ASM INT_LIST macro INT_Handler TMR1_INT,_pwmint,PBP,yes endm INT_CREATE ENDASM ' Interrupts enable @INT_ENABLE TMR1_INT T1CON.0=1 recalc: Dummy = Dummy2 * Dummy3 TimerReloadValue = Div32 InterruptFrequency TimerReloadValue = 65535 - TimerReloadValue + 1 flag=0 ' Main program loop mainlp: LCDOUT $FE,2,"F: ",#InterruptFrequency lcdout $FE,$C0,"R: ",#TimerReloadValue if PORTC.4=1 then InterruptFrequency=InterruptFrequency-1 flag=1 ENDIF if PORTC.5=1 then InterruptFrequency=InterruptFrequency+1 flag=1 ENDIF if flag=1 then goto recalc goto mainlp ' PWM calculation and update interrupt (Timer 1) pwmint: T1CON.0 = 0 ' Stop TMR1 TMRCopy.HighByte = TMR1H ' Copy value of TMR1 registers TMRCopy.LowByte = TMR1L TMRCopy = TMRCopy + TimerReloadValue ' Add reload value (compensates for overhead) TMR1H = TMRCOPY.HighByte ' And back to TMR1 TMR1L = TMRCopy.LowByte T1CON.0 = 1 ' Restart Timer ' PWM U phase calculation uduty=sine[ustep] uduty=uduty<<4**amplitude ' PWM V phase calculation vduty=sine[vstep] vduty=vduty<<4**amplitude ' PWM W phase calculation wduty=sine[wstep] wduty=wduty<<4**amplitude ' PWM U, V and W update PDC0L=uduty.lowbyte PDC0H=uduty.highbyte PDC1L=vduty.lowbyte PDC1H=vduty.highbyte PDC2L=wduty.lowbyte PDC2H=wduty.highbyte ' Phase angle calculation ustep=ustep-1 vstep=vstep-1 wstep=wstep-1 ' Phase angle reinitialization if ustep=0 then ustep=90 if vstep=0 then vstep=90 if wstep=0 then wstep=90 @INT_RETURN
And there is my sine table (if needed) :
Code:' Sine table (4 degrees/step, 90*4=360 degrees) sine var byte[90] sine[1]=128 sine[2]=137 sine[3]=146 sine[4]=155 sine[5]=163 sine[6]=172 sine[7]=180 sine[8]=188 sine[9]=196 sine[10]=203 sine[11]=210 sine[12]=217 sine[13]=223 sine[14]=229 sine[15]=234 sine[16]=239 sine[17]=243 sine[18]=247 sine[19]=250 sine[20]=252 sine[21]=254 sine[22]=255 sine[23]=255 sine[24]=255 sine[25]=255 sine[26]=254 sine[27]=252 sine[28]=250 sine[29]=247 sine[30]=243 sine[31]=239 sine[32]=234 sine[33]=229 sine[34]=223 sine[35]=217 sine[36]=210 sine[37]=203 sine[38]=196 sine[39]=188 sine[40]=180 sine[41]=172 sine[42]=163 sine[43]=155 sine[44]=146 sine[45]=137 sine[46]=128 sine[47]=119 sine[48]=110 sine[49]=101 sine[50]=93 sine[51]=84 sine[52]=76 sine[53]=68 sine[54]=60 sine[55]=53 sine[56]=46 sine[57]=39 sine[58]=33 sine[59]=27 sine[60]=22 sine[61]=17 sine[62]=13 sine[63]=9 sine[64]=6 sine[65]=4 sine[66]=2 sine[67]=1 sine[68]=0 sine[69]=0 sine[70]=1 sine[71]=2 sine[72]=4 sine[73]=6 sine[74]=9 sine[75]=13 sine[76]=17 sine[77]=22 sine[78]=27 sine[79]=33 sine[80]=39 sine[81]=46 sine[82]=53 sine[83]=60 sine[84]=68 sine[85]=76 sine[86]=84 sine[87]=93 sine[88]=101 sine[89]=110 sine[90]=119
Last edited by pxidr84; - 9th March 2011 at 15:57.
Bookmarks