Stack underflow using G0SUB, ok with a GOTO.

The bear

Senior Member
Hello Everyone,
Having just seen a post on todays forum , with a gosub/stack problem.

Would appreciate any comments/help on my program, one Hemi345 suggested for me.
I have modified it to suit my purposes, namely moving the slats on a venetian blind, triggered
by dawn & dusk light levels. Its still on the drawing board. using PE6, latest vers. bar one.
Stepper is a 28BYJ-48-ULN2003 driver.

Code:
#picaxe 14m2		;Stepper motor,Hemi345 14M2 20.01.15 vers 1.0
#no_data				;125 Bytes			PRINTED
setfreq m8
symbol mPause   = b0	; 5mS (speed of movement)
symbol mCycle   = b1	 ;0,1,2,3
symbol mDir 	= b3	; 0 & 2 (For. & Rev)
symbol mStep	= w2	;counting up

let dirsC=%00010111 'set C.0 thru C.4 to outputs
let dirsB= %00111100 ;set B.2 thru B.5 to o/p's
let pinsC=%00000000 'put C.0 thru C.4 low
mPause = 5 ;good starting torque @ 5ms pause
main:
label_01:
	gosub clockwise
	pause 500
	gosub anticlockwise
	pause 500
clockwise:
label_02:
	readadc B.1,b12 
if b12 < 70  then label_03 
	pause 100
	goto label_02
label_03:
	mDir=mDir + 2 MAX 3 % 3 'motor direction 0 CW, 2 CCW
	for mStep = 1 to 512  ; = about 1/4 turn. Amount of turn.& No.of cycles
		mCycle=mCycle + mDir - 1 % 4
		lookup mCycle,(%00000011,%00000110,%00010100,%00010001),pinsC
		pause mPause 'default 5 slow but good torque, 1 fast but very little torque
	next mStep
	let pinsC=%0000000	'put C.0 thru C.4 low
	pause 5000 ;pause between oscilliations
	return	;goto main
anticlockwise:
label_04:
	readadc B.1,b12  ;if pinc.3 = 0 then label_05
	pause 100
	if b12 > 80 then label_05
	goto label_04
label_05:
	mDir=mDir + 2 MAX 3 % 3 'motor direction 0 CW, 2 CCW
	for mStep = 1 to 512  ; = about 1/4 turn. Amount of turn.& No.of cycles
		mCycle=mCycle + mDir - 1 % 4
		lookup mCycle,(%00000011,%00000110,%00010100,%00010001),pinsC
		pause mPause	'default 5 slow but good torque, 1 fast but very little torque
	next mStep
	let pinsC=%0000000	'put C.0 thru C.4 low
	pause 5000 ;pause between oscilliations
	return	;Notes: Stack underflow if 'return' is used . GOTO = OK? ;
 

bpowell

Senior Member
Looking at your code, it looks like the main code flows right to "Label_01:" which has a couple of gosub's...that's okay.

Then, label_01 just flows right into clockwise:...this is bad, because the end of clockwise: has a "return" but no "Gosub" was used to get there (this time)...so the picaxe is looking for an address to "return" to...and it can't find it...this will cause a buffer underflow.

You will need to have some kind of a loop in your "Main:" program to keep the code isolated there unless it needs to gosub-out to another subroutine.
 

Technical

Technical Support
Staff member
The rule is quite simple, don't use gosub/return unless they are in matched pairs.
Anything else is bad programming technique (apart from 'reset', which resets the entire chip anyway).

There is never any reason to use goto out of a gosub, it will cause all sorts of strange issues.
 

The bear

Senior Member
Thank you for your help & comments.
As a beginner, I don't find it easy.
As far as I could see, there were two gosubs & two returns. This gave a stack underflow, hence my request for help.
Technical, are you saying they were not matched? Would you like to expand on that statement?
I may have fixed the program by adding the line "goto main" after the second gosub.
Regards, Bear..

Code:
#picaxe 14m2		;Stepper motor,Hemi345 14M2 22.01.15 vers 1.1
#no_data				;125 Bytes			PRINTED
setfreq m8
symbol mPause   = b0	; 5mS (speed of movement)
symbol mCycle   = b1	 ;0,1,2,3
symbol mDir 	= b3	; 0 & 2 (For. & Rev)
symbol mStep	= w2	;counting up

let dirsC=%00010111 'set C.0 thru C.4 to outputs
let dirsB= %00111100 ;set B.2 thru B.5 to o/p's
let pinsC=%00000000 'put C.0 thru C.4 low
mPause = 5 ;good starting torque @ 5ms pause
main:
label_01:
	gosub anticlockwise
	pause 500
	gosub clockwise
	goto main;	;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
clockwise:
label_02:
	readadc B.1,b12 
if b12 < 70  then label_03		;GOSUB CLOCKWISE
	pause 100
	goto label_02
label_03:
	mDir=mDir + 2 MAX 3 % 3 'motor direction 0 CW, 2 CCW
	for mStep = 1 to 5;12  ; = about 1/4 turn. Amount of turn.& No.of cycles
		mCycle=mCycle + mDir - 1 % 4
		lookup mCycle,(%00000011,%00000110,%00010100,%00010001),pinsC
		pause mPause 'default 5 slow but good torque, 1 fast but very little torque
	next mStep
	let pinsC=%0000000	'put C.0 thru C.4 low
	pause 5000 ;pause between oscilliations
	return	;goto main
anticlockwise:
label_04:
	readadc B.1,b12  
	pause 100
	if b12 > 80 then label_05
	goto label_04
label_05:					;ANTICLOCKWISE:
	mDir=mDir + 2 MAX 3 % 3 'motor direction 0 CW, 2 CCW
	for mStep = 1 to 5;12  ; = about 1/4 turn. Amount of turn.& No.of cycles
		mCycle=mCycle + mDir - 1 % 4
		lookup mCycle,(%00000011,%00000110,%00010100,%00010001),pinsC
		pause mPause	'default 5 slow but good torque, 1 fast but very little torque
	next mStep
	let pinsC=%0000000	'put C.0 thru C.4 low
	pause 5000 ;pause between oscilliations
	return	;Notes: Stack underflow if 'return' is used. ;
 
Last edited by a moderator:

Technical

Technical Support
Staff member
Yes, you have fixed it yourself (but have accidentally lost a required pause before the goto). The trick is to follow everything line by line and make sure there is no way to accidentally 'fall' into a sub procedure without the proper gosub. Or use the simulator, which will warn you if this happens!
 

bpowell

Senior Member
I'm not sure if this code will work right...

for instance, this line:
Code:
if b12 > 80 then label_05
How will the PICAXE interpret this? Will it read that as a "Goto label_05" or as "Gosub label_05"?

You have a "Return" at the end of Label_05...so if the PICAXE jumped in there from a GOTO...you'll get a stack underflow...

You should remove ambiguity and clearly tell the compiler what you want done, "Gosub or Goto".

Also, at a quick glance, if that's a "Gosub label_05" then you'll be stuck in the "Anticlockwise" sub forever...as the "Return" will bring you right back to the "goto label_04" line...so there is some program flow work that needs to be addressed.

All a part of the learning process...you're on the right track for sure!
 

geoff07

Senior Member
The stack is where the chip stores temporary information. When you call a subroutine, the stack holds the address of where to return to after the subroutine has completed. Stack overflow occurs when there is too much on the stack. Underflow, when there is too little i.e. in this case no return address when a return statement is to be executed. You need to keep your subroutines separate from the main code, and only access the subroutine code through a call, exiting via a return. Subroutines are a very good idea, and can make code much clearer by allowing you to move detail out of the main loop. There is a very small time penalty if you use a lot but if time was critical you wouldn't be using a Picaxe anyway.

Gotos are dangerous because when reading the code you don't know where control has come from, especially if there are lots of gotos aiming at the same label. They are akin to jumper wires on a pcb. Far better to avoid them altogether, from the point of view of program clarity. There are very few situations in Picaxe Basic where they are needed (a serin timout is one example). It is better to use explicit flow of control using if/then/else, select/case, do/loop, for/next etc. You can implement virtually anything with these constructs and they will make reading your code in future much easier.

Descriptive names for variables and labels are also highly desirable, also for clarity.
 

The bear

Senior Member
Thank you for your comments and help.
I will endeavour to heed your advice.
The simulator is in use all the time, its my quality control.
Its hard going, but its enjoyable and very useful, (Thanks to my friend JPB33 who introduced me to Picaxe).
Regards, Bear..
 

srnet

Senior Member
Gotos are dangerous because when reading the code you don't know where control has come from, especially if there are lots of gotos aiming at the same label
I would agree that its a good idea to avoid Gotos, but saying they are 'dangerous' is just plain silly.

Any PICAXE command is 'dangerous' when not used correctly.
 
Top