Baseline PIC 12F508 Delay Loop Goto Instruction

microcontroller

I have been experimenting with a PIC 12F508 and have just begun writing my own delay loops in assembler. Nothing fancy yet just toggling an LED connected to GP1 (set as an output) on and off to verify the code.

I finally got my loop to work but I don't understand why it has to be written a certain way for it to work.

I have copied part of the code that doesn't work below I omitted the input / output TRIS setup and configuration bits for clarity.

When the code is written as it is below and dly4 loops back on itself the LED doesn't flash it just stays on solid.

I can't understand why this is because according to the datasheet after the variable count4 reaches 0 the goto dly4 should be skipped. The next instruction goto main_loop should then be executed which returns to the start of the code toggles the led again and the process repeats.

main_loop

movf    sGPIO,w
xorlw   b'000010' ; toggle LED on GP1
movwf   sGPIO
movwf   GPIO

movlw   .80
movwf   count
movwf   count2
movwf   count3
movwf   count4

dly1    decfsz  count,f
        goto    dly1
dly2    decfsz count2,f
        goto    dly2
dly3    decfsz count3,f
        goto    dly3
dly4    decfsz  count4,f
        goto    dly4
        goto    main_loop
END

To make the code work I have to modify the goto at the end of the loop from:

goto    dly4   to    goto    dly1

Why would I want to go back through all four loops again? Wouldn't decrementing the variables from 0 by going through again reset them to 255? Even though the code works with the modification above I can't understand how the loop is even being exited.

Thanks For Any Help In Advance.

Best Answer

Well I did some digging for accurate information. The PIC12F508 is a 33-single-instruction-per-clock device... except for program branches, which take two clocks.

So if the oscillator frequency of this PIC were 4MHz, then the instruction rate is 1MIPS. The period of 1MIPS = 1uS. Each decfsz loop takes 80*3 (since there are two instructions and the branch takes two cycles) = 240uS. Four of those total 960uS. That's 0.000960 seconds.

"Persistence of vision" is a phenomena of human vision which essentially means that if something is moving fast enough, we can't see it and it appears "fluid" or non-jittery. Essentially, anything changing faster than 30 times per second (1s/30 = 0.0333s) is imperceptible to our eyes. So if the LED were toggling at a rate of 0.001s, then we would perceive it as constantly-on, even though it were in fact, blinking really fast.

However, when the final goto is changed to the first loop, remember count is zero, so decrementing it makes it 255. (decfsz decrements first, then skips if zero.) So after the initial three loops, this new first loop adds another 255*3 = 765uS. The next two also add 765uS each. But when it gets to the fourth one, it again decrements only once, and loops to the top again. Over and over, 78 more times. This is called a nested loop, and is very common to create larger delays.

The bottom line is that the first version does work as intended. But it happens so fast, you can't "see" it. The second version loops many, many times, so is much slower, and behaves in a way we can perceive with our eyes.

Also note that this PIC does have a hardware timer module, TMR0. This can also be used to create delays and intervals, and since it is implemented in hardware, leaves the rest of the device free to do other things while TMR0 increments. It may be a little finicky to setup and use, since it involves interrupts, however they are very useful in real-world applications. I'd recommend trying these also.