PDA

View Full Version : Fast Loop in PICBASIC Pro



Bonaparte
- 15th December 2006, 17:54
Hi guys,

I'm new to PICBasic!! I'm programming PIC16F877A using PICBASIC Pro & MicroStudio...

What's the FASTEST way to implement a simple loop with a loop counter (initially positive) which decrements & stops when it reaches zero...


Again, i'm talking about the FASTEST (in decrementing counter & repeating itself) way?!!!


Thx...

skimask
- 15th December 2006, 19:20
Hi guys,

I'm new to PICBasic!! I'm programming PIC16F877A using PICBASIC Pro & MicroStudio...

What's the FASTEST way to implement a simple loop with a loop counter (initially positive) which decrements & stops when it reaches zero...


Again, i'm talking about the FASTEST (in decrementing counter & repeating itself) way?!!!


Thx...




LOOP: For I=10 TO 1 STEP -1:NEXT I:GOTO LOOP

That's not so hard now is it? It's just like in the PBP manual, with a couple of very small changes.

sayzer
- 16th December 2006, 10:59
There are ten cars in front of you.

And someone is asking which one is the fastest.

Then you look at each one and say "that one".

But the fastest car you found is the fastest car among the ones in front of you.

There are other fastest cars around.

Now, "fastest" changes from one perspective to another.

The fastest for you may be the slowest for me.

Take Skimask's example:
LOOP: For I=10 TO 1 STEP -1:NEXT I:GOTO LOOP

if you run this with 4mhz, you get the "fastest" loop.

If you run the same loop at 20Mhz, you get the "fastest", too, but faster then
4mhz.

If you run it at 40Mhz, you still get "fastest" but faster then 20Mhz.

Now, you do the math.

-------------------------------------

Bruce
- 16th December 2006, 15:17
I VAR BYTE SYSTEM

LOOP1: ; 150 cycles. Not very fast
For I=10 TO 1 STEP -1
NEXT I

LOOP2: ; 90 cycles. A lot better
I = 10
REPEAT
I=I-1
UNTIL I=0

ASM ; 31 cycles. Pretty fast
LOOP3
MOVLW 0xA
MOVWF I ; I=10
INNER
DECFSZ I,F ; I=I-1. IF I=0 skip next instruction
GOTO INNER ; Loop until I=0
ENDASM

FINISH:
GOTO FINISH

sayzer
- 16th December 2006, 16:15
I VAR BYTE SYSTEM

LOOP1: ; 150 cycles. Not very fast
For I=10 TO 1 STEP -1
NEXT I

LOOP2: ; 90 cycles. A lot better
I = 10
REPEAT
I=I-1
UNTIL I=0
ASM ; 31 cycles. Pretty fast
LOOP3
MOVLW 0xA
MOVWF I ; I=10
INNER
DECFSZ I,F ; I=I-1. IF I=0 skip next instruction
GOTO INNER ; Loop until I=0
ENDASM

FINISH:
GOTO FINISH


...and, there is also the expert approach!

You know, we kiss the hand of the experts here.



------------------------------------

skimask
- 16th December 2006, 19:38
...and, there is also the expert approach!

You know, we kiss the hand of the experts here.



------------------------------------



Or the keyboard of the experts... :)

However, I saw the original poster's first line
------------------
Hi guys,

I'm new to PICBasic!!
-----------------------
which says to me 'not fluent in any sort of asm', so he's probably not going to get much better than 90 cycles :)
JDG

Bonaparte
- 17th December 2006, 18:56
I VAR BYTE SYSTEM

LOOP1: ; 150 cycles. Not very fast
For I=10 TO 1 STEP -1
NEXT I

LOOP2: ; 90 cycles. A lot better
I = 10
REPEAT
I=I-1
UNTIL I=0

ASM ; 31 cycles. Pretty fast
LOOP3
MOVLW 0xA
MOVWF I ; I=10
INNER
DECFSZ I,F ; I=I-1. IF I=0 skip next instruction
GOTO INNER ; Loop until I=0
ENDASM

FINISH:
GOTO FINISH


I will probably go for Loop 2 implementation..

(Assembly isn't an appealing choice!!)

However, is there any way to estimate the time required to implement this Loop (2). I need to calculate the time needed to decrement the counter, compare its current value to the end value & the repetition (go back to start of loop) of the body time...

I'm using a 20 MHz crystal as clock....

if it can't be estimated from BASIC code... can the .asm file generated by compiler in assembly help me estimate delay time in executing loop knowing the time for each assembly line code???

This is what i'm trying to do; generation of 40kHz pulses (25us)

Loop:

counter = 16

(set one o/p pin high
pause (delay) by 11 us
set o/p pin to low (zero)
puse (delay) by 10 us

decrement counter & compare it

repeat loop again

i need the total time of loop to be 25 microseconds....

HELP PLEASE!!!

mister_e
- 17th December 2006, 20:55
Why not using the internal PWM module instead? it will run in background and you don't need to care about latency etc etc.

use something like this...


DEFINE OSC 20
TRISC=0
duty var word
duty = 250 ' duty value for 50% duty cycle
PR2 = 124 ' period for 40KHZ
T2CON = %00000100 ' timer2 on, prescale 1:1
CCPR1L = duty>>2 ' eight MSB of duty cycle value
CCP1CON = (duty.lowbyte&3)<<5 | %00001100 ' store 2 LSB of duty
' & set PWM mode

START:
PAUSE 1
GOTO START

and look what happen on PORTC.2 pin.

Need to start it and stop it ? here's something using PORTB.0 as trigger source


DEFINE OSC 20
TRISC=0
duty var word
PWMMode var byte
StartStop var bit

duty = 250 ' duty value for 50% duty cycle
PR2 = 124 ' period for 40KHZ
T2CON = %00000100 ' timer2 on, prescale 1:1
CCPR1L = duty>>2 ' eight MSB of duty cycle value
PWMMode = (duty.lowbyte&3)<<5 | %00001100 ' store 2 LSB of duty
' & set PWM mode

START:
IF PORTB.0=0 then '
startstop=startstop ^ 1 ' toggle between start/stop
if startstop=1 then '
CCP1CON=PWMMODE ' Start PWM
ELSE '
CCP1CON=0 ' Stop PWM
PORTC.2=0 ' make sure the pin is low
ENDIF '
WHILE PORTB.0=0 : WEND ' wait until trigger release
PAUSE 100 ' debounce delay
ENDIF
GOTO START

How to calculate those value easy? PicMultiCalc software available bellow for FREE
http://mister-e.org/pages/utilitiespag.html

ScreenShot

<img src="http://www.picbasic.co.uk/forum/attachment.php?attachmentid=1280&stc=1&d=1166390984">
HTH

paul borgmeier
- 18th December 2006, 04:24
I agree with Steve (and everyone else) that the hardware PWM sounds best for what you described. But, if it will not work for you consider "unrolling" your loops like that shown below. You lose no time in looping but it does cost you more code space (16 repeats is not huge considering the amount of memory in the 877A).

DEFINE OSC 20
TRISB.0 = 0
PORTB = 0

PORTB.0 = 1 ' I = 1 (on for 12.6 uS)
@ nop
Pauseus 12
PORTB.0 = 0 ' (off for 12.4 uS)
PAUSEUS 12

PORTB.0 = 1 ' I = 2
@ nop
Pauseus 12
PORTB.0 = 0
PAUSEUS 12

;(more of the same here)

PORTB.0 = 1 ' I = 16
@ nop
Pauseus 12
PORTB.0 = 0
PAUSEUS 12

Endhere:
goto Endhere
END

mister_e
- 18th December 2006, 04:33
could be...


DEFINE OSC 20
TRISB.0 = 0
PORTB = 0
pauseus 0 ' do nothing good but include PAUSEUS?C macro
TRISB.0 = 0
PORTB = 0
start:
asm
CHK?RP PORTB
local a=0
while a<16
BSF PORTB,0
nop
PAUSEUS?C 12
BCF PORTB,0
nop
PAUSEUS?C 12
a+=1
endw
endasm
pause 100
goto start

now play with the a < x value, and look what happen to your code size.. interesting eh?

Now compare the code size of


PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12
copy and pasted 16 times, with the one generated with my solution... mmm interesting ;)

Sometime MPASM directive are really handy!

EDIT: you could also use


@ local a=0
@ while a<16
PORTB.0=1
@ nop
PAUSEUS 12
PORTB.0=0
@ nop
PAUSEUS 12
@a+=1
@ endw

If you don't like the PAUSE?C, BSF, BCF option... both generate the same code.

paul borgmeier
- 18th December 2006, 05:07
Steve, I did compare code space

171 for 16X of my block (MPASM)

211 for your code as posted
191 (with the second nop removed from yours - which makes T = 25 uS)

it is interesting.

Now, the question for me is how the ASM while directive checks without adding time???

EDIT (after looking up while) - I see .... it doesn't check .... now I understand your comment about code space and it is a handy directive :-) THANKS

mister_e
- 18th December 2006, 05:13
MIIP, there's something weird... if i use a 16F877 and this....


DEFINE OSC 20
DEFINE LOADER_USED 1
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 129 ' 9600 Baud @ 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically


pauseus 0
TRISB.0 = 0
PORTB = 0
start:
asm
CHK?RP PORTB
local a=0
while a<16
BSF PORTB,0
nop
PAUSEUS?C 12
BCF PORTB,0
nop
PAUSEUS?C 12
a+=1
endw
endasm

pause 100
goto start
it compile 207 Word

if i use...


DEFINE OSC 20
DEFINE LOADER_USED 1
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 129 ' 9600 Baud @ 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically


pauseus 0
TRISB.0 = 0
PORTB = 0
start:
' #1
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #2
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #3
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #4
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #5
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #6
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #7
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #8
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #9
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #10
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #11
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #12
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #13
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #14
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #15
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

' #16
PORTB.0 = 1
@ nop
Pauseus 12
PORTB.0 = 0
@ nop
PAUSEUS 12

pause 100
goto start
Still 207 words...

EDIT: OK DUDE we hit the button at the same time or...so. :D