Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Program stack overflow error on Pic Simulator IDE

Status
Not open for further replies.

SkeeterB08

Newbie level 6
Joined
Sep 1, 2008
Messages
14
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Location
NorthEast Mississippi, USA
Activity points
1,397
Program Stack Overflow

can anyone help me? I've got a problem with the code I'm working on. For a while it was kicking out of the program when RA0 and RA1 were both low. I've played with it and now when RA0 and RA1 are low, it runs a bit then gives me a stack overflow error on Pic Simulator IDE. Where am I going wrong?? Oh, and that bit at the beginning with errorlevel throws me out when compiling, so I have it commented out.

Here is the Logic diagram of my circuit

(Operation)
Upper (RA0) + Lower Sensor (RA1) = 1 Then Operation (RB6) = 1; Warn (RB5) = 0; Refill (RB3, RB4) = 0
Upper Sensor = 0 + Lower Sensor = 1 Then Operation = 1; Warn = 1; Refill = 0

(Refilling)
Upper + Lower Sensor = 0 Then Operation = 0; Warn = Flashing; Refill = 1
If Upper Sensor = 0 Then Operation = 0, Warn = Flashing, Refill = 1
If Upper Sensor = 1 Then Operation = 1; Warn = 0; Refill = 0
(End Refilling)

Here's the code as it stands. Its for the PIC16F628

Code:
       list      p=16f628            ; list directive to define processor
       #include <p16f628.inc>        ; processor specific variable definitions
    ;   errorlevel   -302 ;hide banking message
    ;*****   
     __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_ON & _LVP_OFF
    ;*****
    ;internal osc settings
    ;*****
    ; '__CONFIG' directive is used to embed configuration data within .asm file.
    ; The lables following the directive are located in the respective .inc file.
    ; See respective data sheet for additional information on configuration word.

    ;***** VARIABLE DEFINITIONS
w_temp        EQU     0x70          ; variable used for context saving
status_temp   EQU     0x71          ; variable used for context saving
Count1        EQU     0X72          ; First Counter for Delay Loops
Count2        EQU     0X73          ; Second Counter for Delay Loops

    ;**********************************************************************
          ORG     0x000             ; processor reset vector
          goto    Start              ; go to beginning of program
    ;*****
          ORG     0x004             ; interrupt vector location
          movwf   w_temp            ; save off current W register contents
          movf   STATUS,w           ; move status register into W register
          movwf   status_temp       ; save off contents of STATUS register
          movf    status_temp,w     ; retrieve copy of STATUS register
          movwf   STATUS            ; restore pre-isr STATUS register contents
          swapf   w_temp,f
          swapf   w_temp,w          ; restore pre-isr W register contents
          retfie                    ; return from interrupt
          
    ;*****
Start
          clrf     PORTA
          clrf     PORTB
          MOVLW    B'00000111'
          MOVWF    CMCON             ; Turn off comparator
          bsf      STATUS,RP0        ; bank one
          movlw    0xFF
          movwf    PORTA            ; porta all Input
          movlw    0x00 
          movwf    PORTB            ; portb all Output
          bcf      STATUS,RP0        ; return to bank 0
    ;*****               
          movlw   b'00000000'       ;See datasheet for prefered
          movwf   OPTION_REG        ;settings of OPTION_REG
          bsf     PORTB,7           ; Turn on Power LED

          btfss   PORTA,0           ; Check if Upper Sensor = 1
          Goto    Prestart          ; If not go to prestart subroutine
          bsf     PORTB,6
          Goto    Run
    ;*****


Prestart
          bsf PORTB,5               ; Turn on Warning LED
          bsf PORTB,4               ; Turn on Refill LED
          bsf PORTB,3               ; Turn On Relay Sub-Circuit
          btfsc PORTA,0             ; If Upper Sensor = 1
          Goto Run                  ; Go to Operation Mode
          

Run
          
          btfss PORTA,0             ; If Upper Sensor = 0
          bsf PORTB,5               ; Then turn on Warning LED
          btfsc PORTA,0             ; If Upper Sensor = 1
          decfsz Count1,1           ; Don't Decrement Counter 1
          btfss PORTA,1             ; If Lower Sensor = 0
          call Refill               ; Go To Refill Subroutine
          btfsc PORTA,1             ; If Lower Sensor = 0
          decfsz Count2,1           ; Don't Decrement Counter2
          goto Run

Refill
         bsf PORTB,4                ; Turn on Refill LED
         bsf PORTB,3                ; Turn on Refill Sub-Circuit
         btfsc PORTA,0              ; If Upper Sensor = 1
         bcf PORTB,3                ; Turn Off Refill Sub-Circuit
         btfsc PORTA,0              ; If Upper Sensor = 1
         bcf PORTB,4                ; Turn off Refill LED
         btfsc PORTA,0              ; If Upper Sensor = 1
         bcf PORTB,5                ; Turn off Warning LED
         bsf PORTB,6
         goto Run

     ;*****
          END
[/img]
 

Re: Program Stack Overflow

The first thing you need to do when an interrupt occurs, is to disable interrupts by clearing the "GIE" flag. If you don't, while you are in an interrupt routine (Program Counter value stored on one Stack level), it may happen that another interrupt condition occurs, in which case the new PC value will be stored in the Stack. If that happens more than 8 times (on a Mid-Range MCU) or 32 times on PIC18F (and similar) MCU a stack overflow will occur. Your interrupt routine doesn't seem to be doing anything (other than saving W and Status and then retrieving it) but that's still something you should always implement when using interrupts.

Ahh, actually, I think the issue is with the "Refill" routine. You are CALL-ing "Refill" but then instead of using RETURN, you use "GOTO" which doesn't pop the stack. Therefore, after 8 calls to "Refill" your stack will overflow. You MUST make sure that you always end a routine with RETURN if you are CALL-ing it.
 

Re: Program Stack Overflow

I figured it was the refill subroutine, I'm still having trouble getting the code right and that bug was created when I created that subroutine. I'm a total newbie, and don't know crap about this, but I'm trying to write code, but its slow going. Earlier versions of my program somewhat worked but the lights on the display tended to blink, because of my faulty code. I think I'm slowly getting it, but it takes time, and a lot of work.
 

Re: Program Stack Overflow

Skeeter, you just need to replace "GOTO Run" with "RETURN".

Simply put, RETURN is the opposite of CALL. When you CALL a routine, the MCU actually "saves" the present location (of the program counter) in the stack, and then proceeds to do what the routine does. Then, when it comes to RETURN, it will revert back to the saved value of program counter, thus clearing the stack.

You are constantly CALL-ing, but never actually returning (instead, you are using GOTO Run).

There are two ways to solve this. Either replace "CALL Refill" with "GOTO Refill" or replace "GOTO Run" with "RETURN". If you do the latter, you must note that the "main" bit of program will continue from where it was before the CALL statement. In the first solution, it will re-start from "Run" and onwards.


Here's a graphic that explains how "subroutines" work. Just look at the first two columns. Imagine that SUB1 is "Refill" and Main is "Run"
Credit goes to PicList.com website
pic2_3.gif
 

    SkeeterB08

    Points: 2
    Helpful Answer Positive Rating
Re: Program Stack Overflow

So that is where I was going wrong? Ok, I will make those changes to my program and test them using OshonSoft's Pic Simulator IDE. My first attempt of creating this circuit without using a microcontroller was an utter failure. It used a 4093 and 4011 CMOS ICs. It prompted me to try the PIC when I failed to get the desired results. It's been a while, but I think I'm getting somewhere with this program. Most of the code was written by me but some of it came from the help that I've gotten over time. Some of it is more recent but its help none the less. Thank you everyone, for your help. But I may require more help if I do run into any more problems

Added after 12 minutes:

Ok that's weird, I've now got a stack underflow error. I was going through the program step-by-step, and I had just deactivated the input representing the Lower Sensor and a few steps later I got a Stack Underflow error. Ok, that's another bug I gotta squash with a little help from y'all.

Edit: I found the problem, changing the Call to Goto in the main program, calling the Refill subroutine was giving me that error. It disappeared when I replaced the goto with call. I'm still having trouble getting outputs turned off when the requirements are fulfilled in the Prefill section. It instead jumps to the main program instead of turning off the outputs when I made the inputs high. Where am I going wrong??? What would I do to correct it?
 

Re: Program Stack Overflow

SkeeterB08, stack underflow is the opposite of a stack overflow. Before the changes, you were CALL-ing but never RETURN-ing so the stack always got full. Now, you have removed all the CALLs but kept the RETURNs which means it's trying to take data from an empty stack - which doesn't work either :)

You did eventually come up with the correct solution, but I would really suggest you take a closer look at those things if you intend to continue developing firmware with PIC MCUs. It's a LOT easier and time conserving if you KNOW how to make something, rather than using the trial and error method :)




EDIT: Oshonsoft's PIC Simulator is one of the best tools I found when I was starting out with PIC MCUs. Great for developing stuff when you aren't 100% confident you got it right the first time. You should go through the "Tools" menu, because there are many things in there that you might find useful, among others - a STACK monitor which can help you determine just how many stack "LEVELS" are you using at any given time.
 

Re: Program Stack Overflow

Thanks for your support. :) Bugs keep on popping up on me, especially the jump out bug, where the MCU jumps out of my program occasionally. I'm still trying work out how to make the outputs return low when the Upper Sensor returns to its high state.

Added after 5 hours 32 minutes:

I've got the stack errors cleared now I'm having trouble with it wanting to either stay in the wrong section or jumping back to the main program before completing other tasks. I've been playing with using binary to set the status of PORTB, and I think that I've figured out the binary code needed for Operation mode, Warning, and Refill mode.

Code:
Operation Mode
  0 1 2 3 4 5 6 7
  0 0 0 0 0 0 1 1

Warning
 0 1 2 3 4 5 6 7
 0 0 0 0 0 1 1 1

Refill Mode
 0 1 2 3 4 5 6 7
 0 0 0 1 1 1 0 1

Here's the code as it stands with the changes I've made

Code:
       list      p=16f628            ; list directive to define processor
       #include <p16f628.inc>        ; processor specific variable definitions
       errorlevel   -302             ;hide banking message
    ;*****   
     __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _LVP_OFF
    ;*****
    ;internal osc settings
    ;*****
    ; '__CONFIG' directive is used to embed configuration data within .asm file.
    ; The lables following the directive are located in the respective .inc file.
    ; See respective data sheet for additional information on configuration word.

    ;***** VARIABLE DEFINITIONS
w_temp        EQU     0x70          ; variable used for context saving
status_temp   EQU     0x71          ; variable used for context saving
Count1        EQU     0X20          ; First Counter for Delay 
Count2        EQU     0X21          ; Second Counter for Delay 
Count3        EQU     0X22          ; Third Counter for Delay

    ;**********************************************************************
          ORG     0x000             ; processor reset vector
          goto    Start             ; go to beginning of program
          ORG     0x004             ; interrupt vector location
          movwf   w_temp            ; save off current W register contents
          movf   STATUS,w           ; move status register into W register
          movwf   status_temp       ; save off contents of STATUS register
          movf    status_temp,w     ; retrieve copy of STATUS register
          movwf   STATUS            ; restore pre-isr STATUS register contents
          swapf   w_temp,f
          swapf   w_temp,w          ; restore pre-isr W register contents
          retfie                    ; return from interrupt
          
Start
          clrf     PORTA
          clrf     PORTB
          MOVLW    B'00000111'
          MOVWF    CMCON            ; Turn off comparator
          bsf      STATUS,RP0       ; bank one
          movlw    0xFF
          movwf    TRISA            ; porta all Input
          movlw    0x00 
          movwf    TRISB            ; portb all Output
          bcf      STATUS,RP0       ; return to bank 0

          movlw   b'00000000'       ;See datasheet for prefered
          movwf   OPTION_REG        ;settings of OPTION_REG
          bsf     PORTB,7           ; Turn on Power LED

          btfss   PORTA,0           ; Check if Upper Sensor = 1
          Call    Prestart          ; If not go to prestart subroutine
          btfsc   PORTA,0           ; Check if Upper Sensor = 1
          Goto    Run               ; Then go to Operation Mode

Prestart
          movlw b'00011101'
          btfsc PORTA,0
          movlw b'00000011'
          movwf PORTB        
          btfsc PORTA,0             ; If Upper Sensor = 1
          Return                    ; Return to Startup Section
          goto Prestart
Run
          
          btfss PORTA,0             ; If Upper Sensor = 0
          bsf PORTB,5               ; Then turn on Warning LED
          btfsc PORTA,0             ; If Upper Sensor = 0
          decfsz Count1,1           ; Don't Decrement Counter 1
          btfss PORTA,1             ; If Lower Sensor = 0
          Call Refill               ; Go To Refill Subroutine
          goto Run

Refill
          movlw b'00011101'
          btfsc PORTA,0
          movlw b'00000011'
          movfw PORTB
          btfss PORTA,0
          goto Refill
          btfsc PORTA,0
          Return
          
          END
 

Re: Program Stack Overflow

I don't know if your comments are what you want happening, but if they are, one of the errors I spotted was:

Code:
Refill
1          movlw b'00011101'
2          btfsc PORTA,0            ; If Upper Sensor = 0
3          movlw b'00000011'     ; Output "Operation Mode"
4          movfw PORTB            ; else, "Refill mode"
5          btfss PORTA,0            ; If upper sensor = 0
6          goto Refill                  ; Continue re-filling
7          movlw b'00011101'
8          movwf PORTB
9          Return                       ; Return back to Run
         
          END

One of the things that you don't need to put is "BTFSC PORTA,0" on line 7 {see code}. If Upper Sensor is 0, it will skip the "GOTO Refill" command and land straight on "Return" which is what you want. If the sensor is NOT 0, the only other thing it can be is 1.

Also, when you return from Refill, you don't re-set PORTB, so it still shows "Refill Mode" even though it's actually in Run. Look at what I've edited on lines 7 and 8.

Another important thing to keep in mind is to ALWAYS make sure you have at least two lines of code following any BTFSS or BTFSC commands. Here's why: let's assume you're testing the lower sensor. In your original code, you had:

If sensor is 0 continue refilling
Else if sensor is 1 return to normal ops

But, what would happen if the sensor went from 1 to 0 between the two "IFs"? You wouldn't continue filling and you wouldn't return to normal ops.
 

Re: Program Stack Overflow

I try to comment the lines, but sometimes I forget to put the comments when I post the code. For my binary code I had to create a crib sheet for both Port A and B. What I posted came straight from my Binary crib sheet I had to make to figure out the coding in binary. Testing it, I noticed how some of the LEDs didn't come on and had to rework the binary by reversing it from 0 1 2 3 4 5 6 7 to 7 6 5 4 3 2 1 0. I'm still working on trying it out but I'm getting it bit by bit. (LOL, notice the joke?)

Added after 57 minutes:

I realized something after I posted the previous reply you responded to, that I had the binary code reversed.


It should be:

1 0 1 1 1 0 0 0

instead of:

0 0 0 1 1 1 0 1

I noticed it when I tested the program and the Operation LED and Power LEDs didn't come on when it entered run mode and it would probably be the same way in refill mode.
 

Re: Program Stack Overflow

EUREKA!!!!! I've Done it! I've gotten the program working!!!! I got the Prefill section working and then copied/pasted the prefill section into the refill section and got it working, I've tested it and no errors and no kicking out of the program by the MCU. I've run it at different speeds from step-by-step up to ultimate in PIC Simulator and no problems. I'm attaching the code below

Code:
       list      p=16f628            ; list directive to define processor
       #include <p16f628.inc>        ; processor specific variable definitions
       errorlevel   -302             ;hide banking message
    ;*****   
     __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _LVP_OFF
    ;*****
    ;internal osc settings
    ;*****
    ; '__CONFIG' directive is used to embed configuration data within .asm file.
    ; The lables following the directive are located in the respective .inc file.
    ; See respective data sheet for additional information on configuration word.

    ;***** VARIABLE DEFINITIONS
w_temp        EQU     0x70          ; variable used for context saving
status_temp   EQU     0x71          ; variable used for context saving
Count1        EQU     0X20          ; First Counter for Delay 
Count2        EQU     0X21          ; Second Counter for Delay 
Count3        EQU     0X22          ; Third Counter for Delay

    ;**********************************************************************
          ORG     0x000             ; processor reset vector
          goto    Start             ; go to beginning of program
          ORG     0x004             ; interrupt vector location
          movwf   w_temp            ; save off current W register contents
          movf   STATUS,w           ; move status register into W register
          movwf   status_temp       ; save off contents of STATUS register
          movf    status_temp,w     ; retrieve copy of STATUS register
          movwf   STATUS            ; restore pre-isr STATUS register contents
          swapf   w_temp,f
          swapf   w_temp,w          ; restore pre-isr W register contents
          retfie                    ; return from interrupt
          
Start
          clrf     PORTA
          clrf     PORTB
          MOVLW    B'00000111'
          MOVWF    CMCON            ; Turn off comparator
          bsf      STATUS,RP0       ; bank one
          movlw    0xFF
          movwf    TRISA            ; porta all Input
          movlw    0x00 
          movwf    TRISB            ; portb all Output
          bcf      STATUS,RP0       ; return to bank 0

          movlw   b'00000000'       ;See datasheet for prefered
          movwf   OPTION_REG        ;settings of OPTION_REG
          
          btfss   PORTA,0           ; Check if Upper Sensor = 1
          Call    Prestart          ; If not go to Prestart Subroutine
          Goto    Run               ; Then go to Operation Mode

Prestart
          movlw b'10111000'         ; Set Refill Mode
          btfsc PORTA,0             ; Check If Upper Sensor = 1
          movlw b'11000000'         ; Then Set Operation Mode 
          movwf PORTB               ; Move to PORTB
          btfss PORTA,0             ; Check If Upper Sensor = 1
          goto Prestart             ; If Not Return to Top of subroutine
          Return                    ; Return to Start

Run
          movlw b'11000000'         ; Set Operation Mode
          btfss PORTA,0             ; Check if Upper Sensor = 1
          movlw b'11100000'         ; Set Warning Mode
          movwf PORTB               ; Move to PortB
          btfss PORTA,1             ; Check If Lower Sensor = 1
          Call Refill               ; Go to Refill Subroutine
          Goto Run                  ; Return to Top
          
          
Refill
          movlw b'10111000'         ; Set Refill Mode
          btfsc PORTA,0             ; Check If Upper Sensor = 1
          movlw b'11000000'         ; Then Set Operation Mode 
          movwf PORTB               ; Move to PORTB
          btfss PORTA,0             ; Check If Upper Sensor = 1
          goto Refill               ; If Not Return to Top of subroutine
          Return                    ; Return to Start
          
          END
 

Re: Program Stack Overflow

Optimization 101: Yes, your MCU currently has space for many instructions, but that doesn't mean you should waste them. If Prestart and Refill do the same thing, replace them by one procedure, called "Fill" for example, and only call it twice in the code (once instead of "CALL Prestart" and once instead of "CALL Refill"). That will save you some 7 bytes of program memory, which - in your case - is more than 10% :p
 

Re: Program Stack Overflow

I've added many more lines of codes to do an indicator test that runs before it starts the prefill section. And I did remove the prefill section and just pointed the call to the refill subroutine instead of prefill. Here's my new code.

Code:
       list      p=16f628            ; list directive to define processor
       #include <p16f628.inc>        ; processor specific variable definitions
       errorlevel   -302             ;hide banking message
    ;*****   
     __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _LVP_OFF
    ;*****
    ;internal osc settings
    ;*****
    ; '__CONFIG' directive is used to embed configuration data within .asm file.
    ; The lables following the directive are located in the respective .inc file.
    ; See respective data sheet for additional information on configuration word.

    ;***** VARIABLE DEFINITIONS
w_temp        EQU     0x70          ; variable used for context saving
status_temp   EQU     0x71          ; variable used for context saving
Count1        EQU     0X20          ; First Counter for Delay 
    ;**********************************************************************
          ORG     0x000             ; processor reset vector
          goto    Start             ; go to beginning of program
          ORG     0x004             ; interrupt vector location
          movwf   w_temp            ; save off current W register contents
          movf   STATUS,w           ; move status register into W register
          movwf   status_temp       ; save off contents of STATUS register
          movf    status_temp,w     ; retrieve copy of STATUS register
          movwf   STATUS            ; restore pre-isr STATUS register contents
          swapf   w_temp,f
          swapf   w_temp,w          ; restore pre-isr W register contents
          retfie                    ; return from interrupt         

Start
          clrf     PORTA
          clrf     PORTB
          MOVLW    B'00000111'
          MOVWF    CMCON            ; Turn off comparator
          bsf      STATUS,RP0       ; bank one
          movlw    0xFF
          movwf    TRISA            ; porta all Input
          movlw    0x00 
          movwf    TRISB            ; portb all Output
          movlw   b'00000000'       ;See datasheet for prefered
          movwf   OPTION_REG        ;settings of OPTION_REG
          bcf      STATUS,RP0       ; return to bank 0
          call    Systest
          btfss   PORTA,0           ; Check if Upper Sensor = 1
          Call    Refill            ; If not go to Refill Subroutine
          Goto    Run               ; Then go to Operation Mode

Systest
          movlw b'10000000'         ; Set PortB,7 High the others Low
          movwf PORTB               
          movlw 0x05                ; Set Count1 to 05H
          movwf Count1             
          call Delay                ; Call Delay Subroutine
          movlw b'01000000'         ; Set PortB,6 High the others Low
          movwf PORTB
          movlw 0x05                ;Reset Counter1 to 05H
          movwf Count1
          call Delay                ;Call Delay Subroutine
          movlw b'00100000'         ; Set PortB,5 High the others Low
          movwf PORTB
          movlw 0x05                ;Reset Counter1 to 05H
          movwf Count1
          call Delay                ; Call Delay Subroutine
          movlw b'00010000'         ; Set PortB,4 High the others Low
          movwf PORTB
          movlw 0x05                ; Reset Counter to 05H
          movwf Count1                
          Call Delay                ; Call Delay Subroutine
          movlw b'11110000'         ; Set All Indicators High
          movwf PORTB
          movlw 0x05                ; Last Counter Reset to 05H
          movwf Count1
          call Delay                ; Call Delay Subroutine
          movlw b'10000000'         ; Turn on Power LED
          movwf PORTB
          RETURN                    ;Return to main program

Run
          movlw b'11000000'         ; Set Operation Mode
          btfss PORTA,0             ; Check if Upper Sensor = 1
          movlw b'11100000'         ; Set Warning Mode
          movwf PORTB               ; Move to PortB
          btfss PORTA,1             ; Check If Lower Sensor = 1
          Call Refill               ; Go to Refill Subroutine
          Goto Run                  ; Return to Top

Refill
          movlw b'10111000'         ; Set Refill Mode
          btfsc PORTA,0             ; Check If Upper Sensor = 1
          movlw b'11000000'         ; Then Set Operation Mode 
          movwf PORTB               ; Move to PORTB
          btfss PORTA,0             ; Check If Upper Sensor = 1
          goto Refill               ; If Not Return to Top of subroutine
          Return                    ; Return to Start
Delay
          decfsz Count1,1           ;Decrement Count1 1
          goto Delay                ;If Count1 > 0 Return to top
          Return                    ;Return to Previous place

          END
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top