|
|
View previous topic :: View next topic |
Author |
Message |
Guest
|
40MHz just ISN'T fast enough! |
Posted: Thu Jul 01, 2004 8:49 am |
|
|
I’ve moved to the 40MHz part. My code is extremely simple. I have a R2D ladder connected to port D, mapped to C variable AD . I need to bit bash a waveform out. The waveform is sampled at a rate of 48 samples per cycle. I need to output the waveform for precise amounts of time hence the 16bit “timer” loop variable. It all works superbly, just my PIC is a touch slow!
My code is very simple:
loop = 7600;
while(loop--) {
AD = triangle48[counter++];
if (counter==48) counter = 0;
} //while(loop--)
This generates:
.................... while(loop--) {
0096: MOVF 07,W
0098: MOVWF 03
009A: MOVF 06,W
009C: BTFSC FD8.2
009E: DECF 07,F
00A0: DECF 06,F
00A2: IORWF 03,W
00A4: BTFSC FD8.2
00A6: GOTO 00C6
.................... AD = triangle48[counter++];
00AA: MOVF 05,W
00AC: INCF 05,F
00AE: CLRF 03
00B0: CALL 0004
00B4: MOVWF 01
00B6: MOVFF 01,F8C
.................... if (counter==48) counter = 0;
00BA: MOVF 05,W
00BC: SUBLW 30
00BE: BTFSC FD8.2
00C0: CLRF 05
.................... } //while(loop--)
00C2: GOTO 0096
I am close; at 40MHz this gives me a frequency of 6.133kHz. I would really like 6.3kHz, so would like to trim a single instruction! Is this the most efficient code for the job? It looks quite compact to me, but hopefully some of you compact C hackers will spot a shortcut I don’t know! |
|
|
Ttelmah Guest
|
Re: 40MHz just ISN'T fast enough! |
Posted: Thu Jul 01, 2004 9:12 am |
|
|
Anonymous wrote: | I’ve moved to the 40MHz part. My code is extremely simple. I have a R2D ladder connected to port D, mapped to C variable AD . I need to bit bash a waveform out. The waveform is sampled at a rate of 48 samples per cycle. I need to output the waveform for precise amounts of time hence the 16bit “timer” loop variable. It all works superbly, just my PIC is a touch slow!
My code is very simple:
loop = 7600;
while(loop--) {
AD = triangle48[counter++];
if (counter==48) counter = 0;
} //while(loop--)
This generates:
.................... while(loop--) {
0096: MOVF 07,W
0098: MOVWF 03
009A: MOVF 06,W
009C: BTFSC FD8.2
009E: DECF 07,F
00A0: DECF 06,F
00A2: IORWF 03,W
00A4: BTFSC FD8.2
00A6: GOTO 00C6
.................... AD = triangle48[counter++];
00AA: MOVF 05,W
00AC: INCF 05,F
00AE: CLRF 03
00B0: CALL 0004
00B4: MOVWF 01
00B6: MOVFF 01,F8C
.................... if (counter==48) counter = 0;
00BA: MOVF 05,W
00BC: SUBLW 30
00BE: BTFSC FD8.2
00C0: CLRF 05
.................... } //while(loop--)
00C2: GOTO 0096
I am close; at 40MHz this gives me a frequency of 6.133kHz. I would really like 6.3kHz, so would like to trim a single instruction! Is this the most efficient code for the job? It looks quite compact to me, but hopefully some of you compact C hackers will spot a shortcut I don’t know! |
How is 'triangle48' stored?.
Most of the time is being taken up in doing the 'lookup' for this (the call to 0004). This will differ according to whether this is in ROM or RAM. The code as shown (excluding this lookup), will execute at around 45Khz, so the lookup is adding an enormous amount (more than I'd typically expect...). So post the declarations of this.
Best Wishes |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Thu Jul 01, 2004 9:17 am |
|
|
It's stored in ROM, using a
unsigned int8 const triagle[48] {
...
};
statment which does not compile to "code" in the list file as far as I can see! It's one of those things I never thought about before a CCS black box I guess.
Keep well,
Will |
|
|
Will Reeve
Joined: 30 Oct 2003 Posts: 209 Location: Norfolk, England
|
|
Posted: Thu Jul 01, 2004 9:23 am |
|
|
Me again,
I now have 8kHz
simple:
for (loop=0;loop<49;loop++)
ramlookup[loop] = triangle48[loop];
to move from ROM to RAM.
Which now gives me:
.................... while(loop--) {
00D2: MOVF 07,W
00D4: MOVWF 03
00D6: MOVF 06,W
00D8: BTFSC FD8.2
00DA: DECF 07,F
00DC: DECF 06,F
00DE: IORWF 03,W
00E0: BTFSC FD8.2
00E2: GOTO 0106
.................... AD = ramlookup[counter++];
00E6: MOVF 05,W
00E8: INCF 05,F
00EA: CLRF 03
00EC: ADDLW 08
00EE: MOVWF FE9
00F0: MOVLW 00
00F2: ADDWFC 03,W
00F4: MOVWF FEA
00F6: MOVF FEF,W
00F8: MOVWF F8C
.................... if (counter==48) counter = 0;
00FA: MOVF 05,W
00FC: SUBLW 30
00FE: BTFSC FD8.2
0100: CLRF 05
.................... } //while(loop--)
0102: GOTO 00D2
I can fine tune the frequency with the addition of a delay_cycles(x). Superb. Thanks alot. I wouldn't have thought of that! You have saved me a lot of head scratching! |
|
|
SteveS
Joined: 27 Oct 2003 Posts: 126
|
|
Posted: Thu Jul 01, 2004 9:42 am |
|
|
I'm not real hot at PIC assembly (which is why I use CCS!), but couldn't the "while(loop--)" code be replaced with assembly like this:
Code: |
decfsz loop_l // loop_l is the low order byte of loop counter
goto notdone // if loop_l is not zero just go on
decfsnz loop_h // if it was, dec the high order byte (loop_h)
goto done // if if hob is zero, then while loop is done
notdone:
//
// rest of while loop
//
done: // endwhile
|
You need to set loop_l and loop_h, use proper asm directives, etc
I think loop_h needs to be 1 greater than what you want since it decrements when loop_l reaches 0 not when it rolls over to 0xff.
Now it's 4 cycles instead of 9 or so. Actually you could place this at the end of the while and have "notdone" be a label at the start - saves the goto at the end - another 2 cycles saved. Like this:
Code: |
notdone:
//
// loop code goes here
//
decfsz loop_l // loop_l is the low order byte of loop counter
goto notdone // if loop_l is not zero just go on
decfsz loop_h // if it was, dec the high order byte (loop_h)
goto notdone // if if hob not zero, then loop again
done: // endwhile
|
On the other hand I may be completely wrong.
- SteveS[/code] |
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 01, 2004 10:14 am |
|
|
Will Reeve wrote: | Me again,
I now have 8kHz
simple:
for (loop=0;loop<49;loop++)
ramlookup[loop] = triangle48[loop];
to move from ROM to RAM.
Which now gives me:
.................... while(loop--) {
00D2: MOVF 07,W
00D4: MOVWF 03
00D6: MOVF 06,W
00D8: BTFSC FD8.2
00DA: DECF 07,F
00DC: DECF 06,F
00DE: IORWF 03,W
00E0: BTFSC FD8.2
00E2: GOTO 0106
.................... AD = ramlookup[counter++];
00E6: MOVF 05,W
00E8: INCF 05,F
00EA: CLRF 03
00EC: ADDLW 08
00EE: MOVWF FE9
00F0: MOVLW 00
00F2: ADDWFC 03,W
00F4: MOVWF FEA
00F6: MOVF FEF,W
00F8: MOVWF F8C
.................... if (counter==48) counter = 0;
00FA: MOVF 05,W
00FC: SUBLW 30
00FE: BTFSC FD8.2
0100: CLRF 05
.................... } //while(loop--)
0102: GOTO 00D2
I can fine tune the frequency with the addition of a delay_cycles(x). Superb. Thanks alot. I wouldn't have thought of that! You have saved me a lot of head scratching! |
A big improvement.
However it should be faster.
What is the processor?. The reason is that the 18F family, use a fast 'read_program_eeprom' call to fetch data from ROM, and I'd have not expected it to be as slow as it was. I'm slightly suprised that any of the processors that support 40MHz would be quite this bad!. Are you genuinely sure the processor is running at 40MHz, not perhaps a some lower speed?. How is the clock generated/fed?. The code you post, should now be looping about 50* faster than you describe (the loop time is about 1/400000th second.....
Best Wishes |
|
|
Aware Guest
|
|
Posted: Thu Jul 01, 2004 10:30 am |
|
|
If you use pointers instead of table lookup, it is even more faster.
Just store the variables in an array. And do the table lookup starting with the address of the variable and increment it when you need the next variable.
grt. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Thu Jul 01, 2004 12:16 pm |
|
|
Will Reeve wrote: | It's stored in ROM, using a
unsigned int8 const triagle[48] {
...
};
statment which does not compile to "code" in the list file as far as I can see! It's one of those things I never thought about before a CCS black box I guess.
Keep well,
Will |
You can keep it a black box by removing the const keyword. That will allow it to compile better. It also helps to manualy locate the array at the beginning of a bank boundry if the compiler has not already done so. All the variables that are not part of the arrau should be located in the same bank of memory to reduce the number of bank jumps. |
|
|
Guest
|
|
Posted: Thu Jul 01, 2004 2:31 pm |
|
|
I am using a PIC18F422 running directly from a 40MHz crystal which. I have a 40MHz signal on the OSC pins. The ICD debugger also reports the PIC to be running at 40MHz.
The following code:
.................... output_high(PIN_A0);
00CA: BCF F92.0
00CC: BSF F89.0
.................... output_low(PIN_A0);
00CE: BCF F92.0
00D0: BCF F89.0
Produces a square wave of frequency 1.666MHz on pin A0. According to my scope the “on” period is 200.0ns (5.000MHz)
I thought that a PIC running at 40MHz, has an instruction clock at 10MHz, so that’s right as it’s a two instruction job to turn on and off? Instruction 00CC sets it high; 00D0 sets it low, with one instruction in between? I can understand that.
Back to my waveform code; so each instruction takes 100.0ns. So the quickest I could ever hope to get the 48 (1 cycle of waveform) settings of PORTD would be 200ns x 48 = 9600ns = 104kHz?
Now I have 23 instructions x 48 = 1 cycle of my waveform so that takes 1104 instructions = 110400ns which should equal I should be getting 9.057kHz but I max out at 8kHz, 1kHz out?
Have I done that calculation correctly?
I am going to try pointers tomorrow and will let you all know how I get on, bedtime here in the UK!
Thanks everyone for your help. This forum is, as always, fantastic. My last job was a large Delphi program and it was a struggle without the support!
Keep well,
Will |
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 01, 2004 3:02 pm |
|
|
Anonymous wrote: | I am using a PIC18F422 running directly from a 40MHz crystal which. I have a 40MHz signal on the OSC pins. The ICD debugger also reports the PIC to be running at 40MHz.
The following code:
.................... output_high(PIN_A0);
00CA: BCF F92.0
00CC: BSF F89.0
.................... output_low(PIN_A0);
00CE: BCF F92.0
00D0: BCF F89.0
Produces a square wave of frequency 1.666MHz on pin A0. According to my scope the “on” period is 200.0ns (5.000MHz)
I thought that a PIC running at 40MHz, has an instruction clock at 10MHz, so that’s right as it’s a two instruction job to turn on and off? Instruction 00CC sets it high; 00D0 sets it low, with one instruction in between? I can understand that.
Back to my waveform code; so each instruction takes 100.0ns. So the quickest I could ever hope to get the 48 (1 cycle of waveform) settings of PORTD would be 200ns x 48 = 9600ns = 104kHz?
Now I have 23 instructions x 48 = 1 cycle of my waveform so that takes 1104 instructions = 110400ns which should equal I should be getting 9.057kHz but I max out at 8kHz, 1kHz out?
Have I done that calculation correctly?
I am going to try pointers tomorrow and will let you all know how I get on, bedtime here in the UK!
Thanks everyone for your help. This forum is, as always, fantastic. My last job was a large Delphi program and it was a struggle without the support!
Keep well,
Will |
Thank heavens for that.
You are talking about the total loop time as your 'frequency', rather than the individual loop. Hence the about 50* discrepancy. The actual loop frequency is as I thought.
Best Wishes |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
cycles times |
Posted: Thu Jul 01, 2004 4:47 pm |
|
|
Anonymous wrote: |
Now I have 23 instructions x 48 = 1 cycle of my waveform so that takes 1104 instructions = 110400ns which should equal I should be getting 9.057kHz but I max out at 8kHz, 1kHz out?
Will |
23 Instructions x 48 does not equal 1104....
Look at the data sheet and you should see some of your instructions are 2 or 3 cycles.
Example:
BTFSC can take 1,2 or 3 cycles.
GOTO 2 cycles.
So you should consider this, it could cause jitter in the output waveform.
Hans W
Your 28 instructions:
Which now gives me:
.................... while(loop--) {
00D2: MOVF 07,W
00D4: MOVWF 03
00D6: MOVF 06,W
00D8: BTFSC FD8.2
00DA: DECF 07,F
00DC: DECF 06,F
00DE: IORWF 03,W
00E0: BTFSC FD8.2
00E2: GOTO 0106
.................... AD = ramlookup[counter++];
00E6: MOVF 05,W
00E8: INCF 05,F
00EA: CLRF 03
00EC: ADDLW 08
00EE: MOVWF FE9
00F0: MOVLW 00
00F2: ADDWFC 03,W
00F4: MOVWF FEA
00F6: MOVF FEF,W
00F8: MOVWF F8C
.................... if (counter==48) counter = 0;
00FA: MOVF 05,W
00FC: SUBLW 30
00FE: BTFSC FD8.2
0100: CLRF 05
.................... } //while(loop--)
0102: GOTO 00D2 |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|