Author Topic: PIC Delay Loop Time Question (ASM)  (Read 8658 times)

0 Members and 1 Guest are viewing this topic.

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
PIC Delay Loop Time Question (ASM)
« on: March 13, 2013, 06:14:16 pm »
I have a delay loop from a Blinking LED tutorial and I am trying to understand the math behind it so I can effectively write my own delay loops.  For some odd reason I can't wrap my head around it.  Right now the delay is 1.579 seconds and I want to make it more accurate by decreasing the delay to 1 second.

I am not looking for an answer on how to do it I can write the code I am trying to understand the equation behind calculating the delay time.
The 2 loops for on and off are labeled as OnLoop and OffLoop.

If you have any tips on a better way to do the looping that is easier to calculate off of feel free to give tips.

Code: [Select]
; =============================================================================
; File: blink_test.asm
;
; Date: 3-13-2013
;
; The typical Hello World uC program.
; This is a simple program that uses a timed delay to blink a LED.
; The LED blinks at a rate of 1.579 seconds.
;
; PIC: 16F1829
; Assembler: MPASM v5.49
; IDE: MPLABX v1.70
; Board: Breadboard
; =============================================================================

    ; Include file containing register mappings for PIC16F1829
    #include <p16f1829.inc>

    ; Fuse configurations
    #define CFG_1_1 _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF
    #define CFG_1_2 _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF
    #define CFG_1_3 _IESO_OFF & _FCMEN_OFF

    __CONFIG _CONFIG1, (CFG_1_1 & CFG_1_2 & CFG_1_3)
    __CONFIG _CONFIG2, (_WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _LVP_OFF)

    ; Warning suppression
    errorlevel -302             ; not in bank0 warining

    ; User file registers
    cblock 0x70                 ; start of shared bank memory
        Dly1
        Dly2
    endc

    org 0                       ; start program at address 0

Start:
    banksel     OSCCON          ; move to bank1
    movlw       b'00111000'     ; set internal cpu clock to 500kHZ
    movwf       OSCCON          ; move contents of w to OSCCON
    bcf         TRISC, 0        ; make I/O pin RC0 and output
    banksel     LATC            ; move to bank2
    clrf        LATC            ; clr data latch for PORTC (set bits to 0)

Loop:
    bsf         LATC, 0         ; turn on pin RC0

OnLoop:
                                ; Outer Loop
    decfsz      Dly1, f         ; Decrement Dly1 store back in Dly1
    bra         OnLoop          ; branch to OnLoop
                                ; OnLoop takes 3 instructions per loop
                                ; * 256 iterations = 768 instructions.
                                ; Inner Loop
    decfsz      Dly2, f         ; Decrement Dly2 store back in Dly2
    bra         OnLoop          ; takes 3 more instructions
                                ; per iteration (768+3) * 256 = 197376
                                ; 197376 inst. / 125k inst. per sec = 1.570 sec
    bcf         LATC, 0         ; turn off pin RC0

OffLoop:                        ; same as OnLoop
    decfsz      Dly1, f
    bra         OffLoop
    decfsz      Dly2, f
    bra         OffLoop
    bra         Loop            ; start over

    end                         ; end of code
 

Offline Kaluriel

  • Contributor
  • Posts: 33
  • Country: 00
Re: PIC Delay Loop Time Question (ASM)
« Reply #1 on: March 13, 2013, 06:37:03 pm »
Looks like two for loops, wrapping around.

Code: [Select]
unsigned char Dly1 = 0;
unsigned char Dly2 = 0;

void Sleep()
{
do
{
do
{
--Dly1;
} while(Dly1 != 0);

--Dly2;
} while(Dly2 != 0);
}

void main()
{
while(true)
{
SetLEDOn(true);
Sleep();
SetLEDOn(false);
Sleep();
}
}

Each loop only takes 3 instructions to execute if it does nothing but decrement, compare to zero, and branch, a total cost of 256 iterations, so 3x256. But the internal one is executed 256x by the outer loop, so the outer loop cost 3x256 instructions plus its own 3 per loop, another 256 times.
Judging by the comment in the code, 125k instructions are executed per second, assuming you haven't changed the clock speed.
So
Inner Loop: 3 instructions x 256 iterations = 768 instructions
Outer Loop: (3 instructions + 768 instructions) x 256 iterations = 197376 instructions

A total of 197376 instructions before both Dly1 and Dly2 are both 0.

If it takes one second to perform 125k instructions, 197376 / 125000 = 1.579008 seconds
« Last Edit: March 13, 2013, 06:58:48 pm by Kaluriel »
 

Offline brainwash

  • Frequent Contributor
  • **
  • Posts: 463
  • Country: de
    • Hack Correlation
Re: PIC Delay Loop Time Question (ASM)
« Reply #2 on: March 13, 2013, 06:40:25 pm »
You might try to initialize Dly1 with value 162, it is by default initialized to 0 which causes 256 cycles to occur
 

Offline Kaluriel

  • Contributor
  • Posts: 33
  • Country: 00
Re: PIC Delay Loop Time Question (ASM)
« Reply #3 on: March 13, 2013, 07:11:16 pm »
As brainwash said, changing the initial value of Dly1 and Dly2 will change the timing.
(3 + (3 * Dly1)) * Dly2 = timeInSeconds * 125000
Where Dly1 and Dly2 are a number between 0 and 255, with 0 being treated as 256, and the rest being treated as their respective value.

Keep Dly1 as a low number for more precision, and choose Dly2 as your multiplier to scale up to the time you require. Without more loops, 1.5 seconds is your maximum.
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: PIC Delay Loop Time Question (ASM)
« Reply #4 on: March 13, 2013, 07:23:51 pm »
As brainwash said, changing the initial value of Dly1 and Dly2 will change the timing.
(3 + (3 * Dly1)) * Dly2 = timeInSeconds * 125000
Where Dly1 and Dly2 are a number between 0 and 255, with 0 being treated as 256, and the rest being treated as their respective value.

Keep Dly1 as a low number for more precision, and choose Dly2 as your multiplier to scale up to the time you require. Without more loops, 1.5 seconds is your maximum.

ok thanks a bunch that is what I was looking for a solid equation.
((3 + (3 * Dly1)) * Dly2) / ips

I was not sure where the delay variables went into the equation and it was messing up my calculations I guess.

I should be able to easily modify the blink speed and get it very accurate.
 

Offline SebG

  • Regular Contributor
  • *
  • Posts: 66
  • Country: ca
  • Currently looking for an EE Job
Re: PIC Delay Loop Time Question (ASM)
« Reply #5 on: March 13, 2013, 07:28:34 pm »
Hi
The delay loops are pretty common.  Let's look at OnLoop first.  The first decfsz and bra pair creates a stand alone loop and the second decfsz and bra pair creates a loop that includes the delay of the first pair.  That is the first pair loops until Dly1 == 0, then the second decfsz instruction decrements Dly2 and loops (bra OnLoop) back to the start (assuming Dly is not Zero).  At the start, the first decfsz and bra pair loops AGAIN until Dly1 == 0 and then the second decfsz instruction decrements Dly2 and so on until Dly2 == 0.

The first pair works like this:
1: decrement Dly1 which takes 1 instruction cycle if it does not skip (i.e. Dly1 != 0)
2: branch back to decfsz instruction which takes 2 instruction cycles
So each decrement step takes 3 instruction cycles.  However, when decrement results in Dly1 == 0 then a skip will occur which will take 2 instruction cycles so the last decrement step will be 2 instead of 3 instruction cycles. 
The time it takes is as follows: the starting value of Dly1 is the number of times the loop will step.  Since decfsz first decrements and then compares (to determine if zero) a value of Dly1 = 0 will loop 256 times. So the total time (in instruction cycles) is T1 = (Dly1 * 3) - 1 so if Dly1 = 0 then T1 = (256 * 3) - 1 = 767 instruction Cycles. Note: the minus 1 is there since the last step is 2 instruction cycles.

The second pair works like this (and OnLoop overall):
1: The first delay of 767 instruction cycles (T1) occurs
2: Dly2 is decremented which takes 1 instruction cycle (assuming it does not skip)
3: branch to OnLoop label and repeat it all again.  The branch takes 2 instruction cycles.
So The math is this: Total instruction cycles = [(T1 + 3) * Dly2] - 1.  Why?  Each time, from OnLoop label, that Dly2 is decremented it takes T1 and the 3 instruction cycles to go back to OnLoop label.  Again -1 since when Dly2 == 0 a skip will occur which is 2 instruction cycles

To get more precision on the delay you need assign a value to Dly2 before OnLoop label (you may also include the instruction time it takes to assign the value by simply adding to the total time equation).  Even more precession you can get if you assign a value to Dly1 but that would change the Total Time formula a bit.

Furthermore, since the Oscillator is set to 500kHz so each instruction cycle takes 1 / (500k/4) = 8e-6 = 8 us and the total time of OnLoop is {[(767 + 3) * 256] - 1} * 8us = 1.576952 seconds.

I've noticed that the code you have doesn't accurately calculate the time as I have shown here.  But if you want accuracy then you need to consider the "-1" in the calculations.
Sebastian
 

Offline brainwash

  • Frequent Contributor
  • **
  • Posts: 463
  • Country: de
    • Hack Correlation
Re: PIC Delay Loop Time Question (ASM)
« Reply #6 on: March 13, 2013, 07:41:19 pm »
Anyway the oscillator is set to internal so you will not get a whole lot of precision.
 

Offline SebG

  • Regular Contributor
  • *
  • Posts: 66
  • Country: ca
  • Currently looking for an EE Job
Re: PIC Delay Loop Time Question (ASM)
« Reply #7 on: March 13, 2013, 07:47:50 pm »
Ok so I wrote the whole description and all but few posts came up in the time all of which are not quite accurate since ... well read my post above.  But if you just need a way to control roughly the delay between toggling the light then it should be ok.
Keep this in mind.  Setting Dly2 is needed only once since the OnLoop or OffLoop is done when Dly2 == 0 but setting Dly1 needs to happen every time the fist (inner loop) is executed.  Here is an example:

Code: [Select]
movlw 0x00
movwf Dly2
OnLoop:
movlw 0x00
movwf Dly1
OnLoopInnerLoop:
decfsz Dly1, f
bra OnLoopInnerLoop

decfsz Dly2, f
bra OnLoop

The equation for Instruction Cycle Delay is (accurately):  ({[(Dly1 * 3) - 1] + 2 + 3} * Dly2) - 1 + 2 = ({[(Dly1 * 3) + 4] * Dly2} + 1 = Instruction Cycles.  Multiply that by 8us to get the time of the loop.

Also the precision of the internal oscillator is +/- 2% at Room Temperature
Sebastian
 

Offline brainwash

  • Frequent Contributor
  • **
  • Posts: 463
  • Country: de
    • Hack Correlation
Re: PIC Delay Loop Time Question (ASM)
« Reply #8 on: March 13, 2013, 07:56:00 pm »
I agree with SebG, I didn't analyze the code throughly before saying about the Dly1 modification. Also, setting Dly1 will eat some extra cycles and the formula would need to be revised.
But I actually meant setting Dly2 to 162, that would give you 1.00052 seconds.
Nevertheless, you might need a combination of Dly1 and Dly2 setting to achieve the value closest to 1 second.
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: PIC Delay Loop Time Question (ASM)
« Reply #9 on: March 13, 2013, 08:00:59 pm »
Thanks a bunch SebG very informative.  Yes dealing with the resetting of Dly1 would add 2 extra instructions per loop and for accuracy would modify the formula.  Again thanks for all the info I learned a lot here and now I can modify the tutorial to be a tiny bit more accurate.  It is really amazing how complex assembler can become great learning experience for me.  These tiny details will make me a much better programmer in the long run for these little devices.
 

Offline croberts

  • Regular Contributor
  • *
  • Posts: 94
  • Country: us
Re: PIC Delay Loop Time Question (ASM)
« Reply #10 on: March 13, 2013, 08:20:55 pm »
You may want to consider interrupt driven software timers. Please see the code in my post
https://www.eevblog.com/forum/microcontrollers/a-simple-state-machine/
 

Offline SebG

  • Regular Contributor
  • *
  • Posts: 66
  • Country: ca
  • Currently looking for an EE Job
Re: PIC Delay Loop Time Question (ASM)
« Reply #11 on: March 13, 2013, 08:43:22 pm »
I'm glad it was beneficial to you.  Programming in assembly is fun and gives you greater insight into programming, especially when working with hardware.
Sebastian
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: PIC Delay Loop Time Question (ASM)
« Reply #12 on: March 14, 2013, 01:35:16 pm »
Ok the new math seems to work out and I got to about a 1% accuracy level I believe off of a 500kHZ internal clock.  I made some modifications to the formula to take into account the extra 2 instructions cycles to reset Dly1.  So lets run through this and see if I am correct in this.  Been a while since I had to modify math formulas.

So to take into account the extra 2 instructions cycles I modified the formula to be:
T = ({[(Dly1 * 3) - 1] + 2 + 2 + 3} - 1 + 4) * 8uS = ({[(Dly1 * 3) + 5] * Dly2} + 3) * 8uS

So if:

Dly1 = 160
Dly2 = 256

T = ({[160 * 3) + 5] * 256} + 3) * 8uS = [(485 * 256) + 3] * 8uS = 124163 * 8uS = 0.993304 seconds of delay

To me that is really close to the 1 second delay I am looking for and at 500 kHz I don't think I can get much closer due to the accuracy limits of the internal clock.

So how did I do on my formula modification?
 

Offline SebG

  • Regular Contributor
  • *
  • Posts: 66
  • Country: ca
  • Currently looking for an EE Job
Re: PIC Delay Loop Time Question (ASM)
« Reply #13 on: March 14, 2013, 04:00:59 pm »
It would be helpful if I saw the code that you have modified.  The formula I showed in my previous post above includes setting Dly1 and Dly2.
Sebastian
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: PIC Delay Loop Time Question (ASM)
« Reply #14 on: March 14, 2013, 04:48:32 pm »
Oh ok I did not realize you already included the resetting the modified code would look something like this without exact values...

Code: [Select]
; Dly2 is set to 0x00
OnLoop:
    movlw     0x00
    movwf     Dly1
    decfsz    Dly1, f   
    bra       $-1 
    decfsz    Dly2, f
    bra       OnLoop                             
    bcf       LATC, 0

OffLoop:
    ; ...
 

Offline SebG

  • Regular Contributor
  • *
  • Posts: 66
  • Country: ca
  • Currently looking for an EE Job
Re: PIC Delay Loop Time Question (ASM)
« Reply #15 on: March 14, 2013, 05:08:07 pm »
Ok so in your example the delay of OnLoop is: {[ (Dly1 * 3) - 1 + 2 + 3 ] * Dly2 - 1 + 1} * 8us  =   [(Dly1 * 3) + 4] * Dly2 * 8us
That is  (Dly1 * 3) - 1 is the inner loop, 2 instructions that load Dly1 and 3 instruction cycles that decrement Dly2 and branch (except the last decrement that skips so -1 at the end).  The last +1 is the bcf instruction.  What you have is a bit different.

I've copied your code in here since it is on the previous page:
Code: [Select]
; Dly2 is set to 0x00
OnLoop:
    movlw     0x00
    movwf     Dly1
    decfsz    Dly1, f   
    bra       $-1 
    decfsz    Dly2, f
    bra       OnLoop                             
    bcf       LATC, 0

OffLoop:
    ; ...
« Last Edit: March 14, 2013, 05:10:01 pm by SebG »
Sebastian
 

Offline blewisjrTopic starter

  • Frequent Contributor
  • **
  • Posts: 301
Re: PIC Delay Loop Time Question (ASM)
« Reply #16 on: March 14, 2013, 05:56:05 pm »
Ok I see where I screwed up on my equation I think I got this down now thanks a bunch again I finally see how the equation is heavily dependent on the code.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf