PIC Code Uncertainty: Why Does Placement Matter?

  • Thread starter Thread starter El Moriana
  • Start date Start date
  • Tags Tags
    Code Uncertainty
AI Thread Summary
The discussion centers on the placement of a Delay subroutine in PIC assembly code, which affects whether the code functions correctly. The first method, with the Delay subroutine placed before the main code, fails due to improper handling of the reset vector, leading to a stack overflow when executing the "retlw" instruction without a preceding "call." The second method works because the code structure inadvertently allows the program to execute correctly, despite the potential for uninitialized values. Participants emphasize the importance of starting the program at the correct reset vector (0x0000) to avoid issues. Proper organization of subroutines and understanding of the PIC architecture are crucial for successful coding.
El Moriana
Messages
33
Reaction score
0
Hi, I have just managed to make a PIC light blink. My question has to do with the syntax. In my code, I use a Delay subroutine that is called in between turning the LED on and turning it off.

I tried two codes. The first had my Delay subroutine being placed before my main code. The second had the subroutine placed after my main code (but before END). Only the second code worked. Why? What is the problem with the first method?

Below are the two codes I used:

************************************
1st METHOD
************************************

list p=16F690 ; defines chip that will be used
#include <p16F690.inc> ; imports instructions specific to PIC used

;================
;configuration

__CONFIG _CP_OFF & _CPD_OFF & _BOR_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _FCMEN_OFF & _IESO_OFF

;================
;declarations

org 1FFh ; reset
goto start ;
org 0 ;



count1 equ 20h ; general purpose registers used in the delay
counta equ 21h ;
countb equ 22h ;

;================
;subroutines

Init ; initialisation subroutine
clrf PORTA ; clears the port file registers
clrf PORTB ;
clrf PORTC ;

bsf STATUS,RP0 ; selects bank 1
bcf STATUS,RP1 ;

clrf TRISC ; sets all of portC to output

bcf STATUS,RP0 ; selects bank 0
bcf STATUS,RP1 ;

retlw 0

Delay movlw d'250' ;delay 250 ms (4 MHz clock)
movwf count1
d1 movlw 0xC7
movwf counta
movlw 0x01
movwf countb
Delay_0
decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0

decfsz count1, f
goto d1
retlw 0

;================
;main code

start call Init ; calls the intitialization subroutine

main bsf PORTC,0 ; LED on
call Delay
bcf PORTC,0 ; LED off
call Delay
goto main ; infinite loop
END ; end of program

;================



************************************
2nd METHOD
************************************

list p=16F690 ; defines chip that will be used
#include <p16F690.inc> ; imports instructions specific to PIC used

;================
;configuration

__CONFIG _CP_OFF & _CPD_OFF & _BOR_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _FCMEN_OFF & _IESO_OFF

;================
;declarations

org 1FFh ; reset
goto start ;
org 0 ;



count1 equ 20h ; general purpose registers used in the delay
counta equ 21h ;
countb equ 22h ;

;================
;subroutines

Init ; initialisation subroutine
clrf PORTA ; clears the port file registers
clrf PORTB ;
clrf PORTC ;

bsf STATUS,RP0 ; selects bank 1
bcf STATUS,RP1 ;

clrf TRISC ; sets all of portC to output

bcf STATUS,RP0 ; selects bank 0
bcf STATUS,RP1 ;

retlw 0

;================
;main code

start call Init ; calls the intitialization subroutine

main bsf PORTC,0 ; LED on
call Delay
bcf PORTC,0 ; LED off
call Delay
goto main ; infinite loop

Delay movlw d'250' ;delay 250 ms (4 MHz clock)
movwf count1
d1 movlw 0xC7
movwf counta
movlw 0x01
movwf countb
Delay_0
decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0

decfsz count1, f
goto d1
retlw 0

END ; end of program

;================
 
Engineering news on Phys.org
I can't see how either of your two codes would work
since the reset vector for all PIC's is 0x0000, not 0x01FF.

The PIC will execute the init method without being called, and when it reaches the
'retlw' instruction that will cause a stack overflow reset.
 
That may be. I am only beginning to code PICs and know very little on the subject.

However I have written both those exact codes to a PIC16F690 and the second code worked, with the LED physically turning on and off.

I will keep in mind for future that the reset vector is 0x0000, but is there anything else that could cause the difference?
 
JimmyAlz said:
I can't see how either of your two codes would work
since the reset vector for all PIC's is 0x0000, not 0x01FF.

The PIC will execute the init method without being called, and when it reaches the
'retlw' instruction that will cause a stack overflow reset.

Possibly what I have done is (quite uselessly) placed the instruction "goto start" at 0x01FF and mislabeled it "reset", which has little overall bearing on the working of the code... does this sound correct?
 
I'm sorry it sounded like I didn't believe you. (English is not my first language)

I'm still leaning towards the reset vector. It is a clear problem.
What happens if you rewrite using 0x0000 as reset vector?
 
Possibly what I have done is (quite uselessly) placed the instruction "goto start" at 0x01FF and mislabeled it "reset", which has little overall bearing on the working of the code... does this sound correct?

Yes this sound correct. And would not affect the code. Executing "retlw" without first executing "call" is I think what causes the problems.
 
Firstly,coding:

org 0x0000
goto start
org 0

Does indeed give me an error:

Error[118] G:\...\MYFILE.ASM 61 : Overwriting previous address contents (0000)

Secondly:
JimmyAlz said:
Executing "retlw" without first executing "call" is I think what causes the problems.

In this case, why is it that I am able to call the 'Init' subroutine (which is placed before the call) successfully, as I do in the 2nd method?
 
Checked the data sheet ... 16F690 doesn't *have* stack overflow reset ... :/

So what happens is that the "retlw" instruction fetches an uninitialized value from the stack and jumps to it.
So your code #2 works because you are "lucky".
The uninitialized value just happens to point inside your program code in #2.
 
JimmyAlz said:
The uninitialized value just happens to point inside your program code in #2.

Ok, this makes sense. =) So what do I need to change to code this properly?
 
  • #10
In this case, why is it that I am able to call the 'Init' subroutine (which is placed before the call) successfully, as I do in the 2nd method?
I'm confused, what do you mean by "(which is placed before the call)"?
The placement of the code does not matter.

this will work:

org 0 ; or 0x0000 or 000h (all mean the same thing)
goto start

init
<some code>
retlw

start
call init
main
call something_else
goto main


this will not work:

org 0

init
<some code>
retlw

start
call init
main
call something_else
goto main


I hope I have helped somewhat, going to bed now ... it's 3am here in Sweden.
 
  • #11
Ah, I see! It all makes sense now =), thank you *very* much for your help. Go well.
 
Back
Top