Pommie said:Another thought, how are you listening to the signals. If it's through your PC then the sample frequency could be interfering with the playback frequency. The glitch is very distinctive, can you see it on a scope?
Mike.
3dluvr said:Turns out the problem is not just with the computation of the figures but with their values and the timer itself.
There seems to be a point after which the jitter disappears, perhaps after 835 or 840, so the PortA which is always on 868 sounds fine because the tone is above (some?) threshold.
So the idea is to use a higher frequency on the PortB instead of lower. Fine, I tried that but then a totally new problem occurs. The numbers computed do not correspond to the frequencies generated.
For example, 934 should make 228.02Hz but output is closer to 226.2Hz and I somehow do not believe it is my scope that's broken. The base 868 produces 210.3Hz while it should be 211.9Hz.
Is there a way to increase stability and resolution by perhaps using Timer1 instead, it being a 16bit timer?
LIST p=16F88
#INCLUDE <P16F88.INC>
errorlevel -302
;------------------------------------------------------------------------------
__CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
;------------------------------------------------------------------------------
CBLOCK 0x20 ; Sample GPR variable registers allocated contiguously
Position:2
Step:2
TempB
ENDC
W_TEMP EQU 0x7D ; w register for context saving (ACCESS)
STATUS_TEMP EQU 0x7E ; status used for context saving (ACCESS)
PCLATH_TEMP EQU 0x7F ; variable used for context saving
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------
RESET ORG 0x0000 ; processor reset vector9
PAGESEL START
GOTO START ; go to beginning of program
;------------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------
ISR ORG 0x0004 ; interrupt vector location
; Context saving for ISR
MOVWF W_TEMP ; save off current W register contents
MOVF STATUS,W ; move status register into W register
MOVWF STATUS_TEMP ; save off contents of STATUS register
MOVF PCLATH,W ; move pclath register into W register
MOVWF PCLATH_TEMP ; save off contents of PCLATH register
;------------------------------------------------------------------------------
; USER INTERRUPT SERVICE ROUTINE GOES HERE
;------------------------------------------------------------------------------
movfw Step ;Position+=Step
addwf Position,F
movfw Step+1
btfsc STATUS,C
addlw 1
addwf Position+1,F
movlw high GetSine ;Prepare to get sine value
movwf PCLATH
rlf Position,W
rlf Position+1,W
andlw .31 ;TempB=(Position>>7)&31
call GetSine
movwf TempB
movwf PORTB
bcf PIR1,TMR2IF
; Restore context before returning from interrupt
MOVF PCLATH_TEMP,W ; retrieve copy of PCLATH register
MOVWF PCLATH ; restore pre-isr PCLATH register contents
MOVF STATUS_TEMP,W ; retrieve copy of STATUS register
MOVWF STATUS ; restore pre-isr STATUS register contents
SWAPF W_TEMP,F
SWAPF W_TEMP,W ; restore pre-isr W register contents
RETFIE ; return from interrupt
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
START
bsf STATUS,RP0
movlw 0xf0
movwf TRISA
movwf TRISB
movlw b'00000111' ; disable comparator
movwf CMCON
movlw B'01110000' ;select 8MHz clock
movwf OSCCON
clrf ANSEL ;no ADCs
bcf STATUS,RP0
movlw 1<<TMR2ON|b'01'<<T2CKPS0
movwf T2CON
bsf STATUS,RP0
movlw .124
movwf PR2
bsf PIE1,TMR2IE
bcf STATUS,RP0
movlw low(.819)
movwf Step
movlw high(.819)
movwf Step+1
movlw (1<<GIE|1<<PEIE|0<<TMR0IE|0<<INTE|0<<RBIE|0<<TMR0IF|0<<INTF|0<<RBIF)
movwf INTCON ; enable Peripheral interupts
;------------------------------------------------------------------------------
; PLACE USER PROGRAM HERE
;------------------------------------------------------------------------------
GOTO $
org 0x0400
GetSine addwf PCL,F
dt .7,.8,.10,.11,.12,.13,.13,.14,.14,.14,.13,.13,.12,.11,.10,.8
dt .7,.6,.4,.3,.2,.1,.1,.0,.0,.0,.1,.1,.2,.3,.4,.6
END
LIST p=16F88
#INCLUDE <P16F88.INC>
errorlevel -302
;------------------------------------------------------------------------------
__CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
;------------------------------------------------------------------------------
CBLOCK 0x20 ; Sample GPR variable registers allocated contiguously
Position:2
Step:2
TempB
ENDC
W_TEMP EQU 0x7D ; w register for context saving (ACCESS)
STATUS_TEMP EQU 0x7E ; status used for context saving (ACCESS)
PCLATH_TEMP EQU 0x7F ; variable used for context saving
;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------
RESET ORG 0x0000 ; processor reset vector9
PAGESEL START
GOTO START ; go to beginning of program
;------------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------
ISR ORG 0x0004 ; interrupt vector location
; Context saving for ISR
MOVWF W_TEMP ; save off current W register contents
MOVF STATUS,W ; move status register into W register
MOVWF STATUS_TEMP ; save off contents of STATUS register
MOVF PCLATH,W ; move pclath register into W register
MOVWF PCLATH_TEMP ; save off contents of PCLATH register
;------------------------------------------------------------------------------
; USER INTERRUPT SERVICE ROUTINE GOES HERE
;------------------------------------------------------------------------------
movfw Step ;Position+=Step
addwf Position,F
movfw Step+1
btfsc STATUS,C
addlw 1
addwf Position+1,F
movlw high GetSine ;Prepare to get sine value
movwf PCLATH
rrf Position+1,W
andlw .31 ;TempB=(Position>>9)&31
call GetSine
movwf TempB
movwf PORTB
bcf PIR1,TMR2IF
; Restore context before returning from interrupt
MOVF PCLATH_TEMP,W ; retrieve copy of PCLATH register
MOVWF PCLATH ; restore pre-isr PCLATH register contents
MOVF STATUS_TEMP,W ; retrieve copy of STATUS register
MOVWF STATUS ; restore pre-isr STATUS register contents
SWAPF W_TEMP,F
SWAPF W_TEMP,W ; restore pre-isr W register contents
RETFIE ; return from interrupt
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------
START
bsf STATUS,RP0
movlw 0xf0
movwf TRISA
movwf TRISB
movlw b'00000111' ; disable comparator
movwf CMCON
movlw B'01110000' ;select 8MHz clock
movwf OSCCON
clrf ANSEL ;no ADCs
bcf STATUS,RP0
movlw 1<<TMR2ON|b'01'<<T2CKPS0
movwf T2CON
bsf STATUS,RP0
movlw .124
movwf PR2
bsf PIE1,TMR2IE
bcf STATUS,RP0
movlw low(.819)
movwf Step
movlw high(.819)
movwf Step+1
movlw (1<<GIE|1<<PEIE|0<<TMR0IE|0<<INTE|0<<RBIE|0<<TMR0IF|0<<INTF|0<<RBIF)
movwf INTCON ; enable Peripheral interupts
;------------------------------------------------------------------------------
; PLACE USER PROGRAM HERE
;------------------------------------------------------------------------------
GOTO $
org 0x0400
GetSine addwf PCL,F
dt .7,.8,.10,.11,.12,.13,.13,.14,.14,.14,.13,.13,.12,.11,.10,.8
dt .7,.6,.4,.3,.2,.1,.1,.0,.0,.0,.1,.1,.2,.3,.4,.6
END
#include <16F88.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=20000000)
int timeCount; //int = int8
long TempA, TempB; //long = int16
int32 step, step2, position, position2;
CONST unsigned int SineTab[32] = {
7,8,10,11,12,13,13,14,14,14,13,13,12,11,10,8,
7,6,4,3,2,1,1,0,0,0,1,1,2,3,4,6};
#INT_TIMER2
void interrupt(){
position+=step;
TempB=SineTab[(position>>16)&31];
output_b(TempB);
position2+=step2;
TempA=SineTab[(position2>>16)&31];
output_a(TempA);
}
void main(void) {
setup_oscillator(OSC_8MHZ | OSC_INTRC); // Use internal 8MHz oscillator
set_timer2(0);
setup_timer_2(T2_DIV_BY_4, 249, 1); // 200us = (1/20000000 * 4 * 4 * 249+1)
// N = F * 200*10-6*32*65536
// N = F * 419.42
// For 200Hz N = 83886
step = 83886; // changing frequency
// For 211.4 N = 88665
step2 = 88665; // base frequency
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(TRUE)
{
delay_us(1);
}
disable_interrupts(INT_TIMER2);
}
#include <16F88.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=10000000)
int timeCount;
long TempA, TempB, step, step2, hundreths, position, position2;
CONST unsigned int SineTab[32] = {
7,8,10,11,12,13,13,14,14,14,13,13,12,11,10,8,
7,6,4,3,2,1,1,0,0,0,1,1,2,3,4,6};
#INT_TIMER2
void interrupt(){
position+=step;
TempB=SineTab[(position>>8)&31];
output_b(TempB);
position2+=step2;
TempA=SineTab[(position2>>8)&31];
output_a(TempA);
//if((TempA-7)+(TempB-7)>0){
if((TempA&7)!=(TempB&7)){
output_bit(PIN_A4, 0);
}
else{
output_bit(PIN_A4, 1);
}
if(timeCount++ == 50){
timeCount=0;
hundreths++;
}
}
void PlayTone(long Freq1, long Freq2, long Duration) {
signed long long work;
hundreths=0;
While(hundreths<Duration){
//work=Freq2-Freq1;
//work*=hundreths;
//work/=Duration;
//step=work+Freq1;
if (Freq2 >= Freq1) { // ramp up
work = Freq2 - Freq1;
work *= hundreths;
work /= Duration;
step = work + Freq1;
} else { // ramp down
work = Freq1 - Freq2;
work *= hundreths;
work /= Duration;
step = Freq1 - work;
}
}
}
void main(void) {
setup_comparator(NC_NC_NC_NC);
set_timer2(0);
setup_timer_2(T2_DIV_BY_4, 124, 1); // 200us = (1/10000000 * 4 * 4 * 124+1)
// N = F * 1.6384
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(TRUE)
{
PlayTone(360,360,500);
PlayTone(360,450,500);
PlayTone(450,360,500);
}
disable_interrupts(INT_TIMER2);
}
3dluvr said:I just tried the new code and there's jitter if I change the frequencies from your default parameters, ugghh. Should I be looking to switch to AVR and give up PIC?
3dluvr said:N = F * 419.42, N = F * 200*10-6*32*65536 // for 20MHz, 200us period, 16.16bits (32bit)
I know that 200*10e-6 is the 200us period, 65536 is the max value but where does that 32 come from, is that 4*prescaler, because prescaler is 4 not 8 in my timer2?
#include <16F88.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=10000000)
int timeCount; //int = int8
long TempA, TempB; //long = int16
int32 step, step2, position, position2;
CONST unsigned int SineTab[64] = {
7,8,8,9,10,10,11,11
12,12,13,13,13,14,14,14
14,14,14,14,13,13,13,12
12,11,11,10,10,9,8,8
7,6,6,5,4,4,3,3
2,2,1,1,1,0,0,0
0,0,0,0,1,1,1,2
2,3,3,4,4,5,6,6};
#INT_TIMER2
void interrupt(){
position+=step;
TempB=SineTab[(position>>16)&63];
output_b(TempB);
position2+=step2;
TempA=SineTab[(position2>>16)&63];
output_a(TempA);
}
void main(void) {
setup_comparator(NC_NC_NC_NC);
set_timer2(0);
setup_timer_2(T2_DIV_BY_4, 124, 1); // 200us = (1/10000000 * 4 * 4 * 124+1)
// N = F * 200*10-6*64*65536
// N = F * 838.86
// For 200Hz N = 167772
step = 167772; // changing frequency
// For 211.4 N = 177335
step2 = 177335; // base frequency
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(TRUE)
{
delay_us(1);
}
disable_interrupts(INT_TIMER2);
}
.................... TempB=SineTab[(position>>16)&63];
0089: MOVF 3A,W
008A: MOVWF 41
008B: MOVF 3B,W
008C: MOVWF 42
008D: CLRF 43
008E: CLRF 44
008F: MOVF 3A,W
0090: ANDLW 3F
0091: MOVWF 45
0092: CLRF 46
0093: CLRF 47
0094: CLRF 48
0095: MOVF 45,W
0096: MOVWF 77
0097: MOVF 46,W
0098: MOVWF 78
0099: MOVF 47,W
009A: MOVWF 79
009B: MOVF 48,W
009C: MOVWF 7A
009D: MOVF 45,W
009E: CALL 037
009F: MOVWF 78
00A0: CLRF 2D
00A1: MOVF 78,W
00A2: MOVWF 2C
3dluvr said:The iterations are spaced further apart and it sounds as if the frequency is getting higher, although the scope does not show any increase in frequency?!
When you say 500 cycles is not enough on a 10MHz clock, how many interrupts should I have instead so that it gives enough time to do 32-bit math?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?