CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

40MHz just ISN'T fast enough!

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Guest








40MHz just ISN'T fast enough!
PostPosted: Thu Jul 01, 2004 8:49 am     Reply with quote

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!
PostPosted: Thu Jul 01, 2004 9:12 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

PostPosted: Thu Jul 01, 2004 9:17 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

PostPosted: Thu Jul 01, 2004 9:23 am     Reply with quote

Me again,
I now have 8kHz Very Happy

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

View user's profile Send private message

PostPosted: Thu Jul 01, 2004 9:42 am     Reply with quote

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







PostPosted: Thu Jul 01, 2004 10:14 am     Reply with quote

Will Reeve wrote:
Me again,
I now have 8kHz Very Happy

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







PostPosted: Thu Jul 01, 2004 10:30 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jul 01, 2004 12:16 pm     Reply with quote

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








PostPosted: Thu Jul 01, 2004 2:31 pm     Reply with quote

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







PostPosted: Thu Jul 01, 2004 3:02 pm     Reply with quote

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

View user's profile Send private message

cycles times
PostPosted: Thu Jul 01, 2004 4:47 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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