PDA

View Full Version : Help with GOSUB



HEXhacker
- 28th July 2015, 17:24
Hi. First time post here. I'm using PIC Basic Pro, MPLAB ASSEM and a PIC16F870.
Need some help with the GOSUB in my code.

I'm telling a Compact Flash card that I want to read 256 sectors and then pulse
RD low 65535 times to get the 16Bit data out. I do this 4 times because the whole
file is 4 x 256 sectors.

If I put the little REPEAT...UNTIL code after each call up of 256 sectors, the program
works fine. I can push the start button as many time as I need for the whole file
to be read from the compact flash card.

If I use a GOSUB dat to go to the little dat: REPEAT...UNTIL RETURN pulse RD low routine,
the program
will only work about 4-5 times and then vapour locks. The RD pin keeps running
(pulsing low) and doesn't stop after 65535 pluses. The code doesn't recover.

Any ideas?

Thanks

HenrikOlsson
- 28th July 2015, 18:00
Hi,
My initial thought, since you're saying that it does work if you paste the content of the dat subroutine inplace of each GOSUB to TO the dat subroutine, was/is that it's a timing issue. I don't know anything about the timing requirements of a CF card but using that GOSUB does introduce a couple of extra instruction cycles for the jump to and from the routine.

Then, when looking closer at the actual code for the dat subroutine:

dat:
i = 0 'pulse RD low 65535 times
REPEAT
rd[i] = 1 '<----What is the purpose of this line?
i = i + 1
pulsout rd, 4 '44.1KHz Playback
UNTIL i = 65535
RETURN
I'm wondering what you're trying to achieve with the rd[i]=1, specifically the [i] part, when you have rd is aliased to PortA.4?

Out of curiosity, I don't see you're actually reading the data that the card outputs. Are you "playing" it directly to a DAC or something like that?

/Henrik.

HEXhacker
- 28th July 2015, 18:59
Henrik, thanks for your reply.
Yes, I am getting all of the 16bit data out of the CF card. With the REPEAT....UNTIL after each block data call (4x256)
and with the GOSUB dat....RETURN used only once as a GOSUB. It isn't a timing issue with the CF card, it's that
the pulse counting "until i = 65535" seems to not work after running the program 5 times when using the GOSUB...RETURN.
Yes, I'm playing to a DAC.

The REPEAT...UNTIL is from the PBP manual and I adjusted it to work with my output pin. I'm new at this, so getting
it to work in the first place is a big deal.

The way I understand the sample from the manual:
i = 0 zeros out the word variable count
REPEAT
RD[i] = 1 aliasies the RD pin (PORTC.1 pin) to i and sets this pin HIGH to start.
i = i + 1 adds the count to word variable i
PULSOUT RD, 4 pulses the RD pin low
UNTIL i = 65535 keeps pulsing low until i variable reaches a count of 65535

This works except for the fifth time when used with the GOSUB....RETURN.
It's like the UNTIL i = 65535 hasn't counted up and stopped the pulsing.

Thanks.

HenrikOlsson
- 28th July 2015, 19:29
Hi,
You're missing my point - I think.
You have the variable rd aliases to PortA.3 (not PortC.1 as far as I can see) but what is supposed to happen inside the loop when you acces the rd "variable" as if it was an array - which is what you're doing with the rd[i] thing.

i will increment once per iteration. Each iteration thru the loop you do RD[i] = 1 where, as we said, i increments by one each time. What happens when i is, for example 1234, and the effect of the line is PortA.3[1234] = 1?

I don't think the problem has anything to do with the use of GOSUB or REPEAT UNTIL, I think it's just a coincidence and the fact that it works with the code pasted in multiple places just masks the real issue - which I think is the RD[i] = 1 line.

If what you want is to ensure that the RD-line is high before starting the pulsing I'd try

dat:
i = 0 'pulse RD low 65535 times
RD = 1 '<---No indexing stuff, just set the pin high.
REPEAT
i = i + 1
pulsout rd, 4 '44.1KHz Playback
UNTIL i = 65535
RETURN

/Henrik.

HEXhacker
- 28th July 2015, 19:46
Henrick,

Yes, sorry, RD is variable of pin PORTA.3
The "RD[i] = 1" is from the PBP manual where I subbed RD for a PORTx.x pin in the original.
I'll try your suggested change.
Thanks,
Jim

HenrikOlsson
- 28th July 2015, 20:04
Hi,
RD is just a name that you created which points to same memory adress (PortA) and bit at that adress (.3) as PortA.3 does.

So RD[i] is then the same thing as PortA.3[i] but why are you doing it? What's the intended purpose of the [i] part of it?

What will happen is that the first time thru the loop (when i=0) you will set PortA.3 high - which I think is all you want to do, but please correct me if that's not the case. Next time (when i=1) you'll set PortA.4 high. Next time (when i=2) you'll set PortA.5 high and so on. When i is 23456 you will set a bit, which 23456 bits "away" from PortA.3 in the memory map....

Look at sextion 7.6.5 in the PBP3 manual for more details on array indexing, which is what you're doing effectively.

I think you'll see the potential issue with this and the fact that it worked before is just pure luck as far as I can see.

/Henrik.

HEXhacker
- 28th July 2015, 21:10
Henrick,

I tried your suggestion and it still vapour locks after the fifth "play" start button push.

This is from the PBPro manual:

i = 0 They don't tell you "i" needs to be a variable, I figured it out after awhile though.
REPEAT
PORTB.0[i] = 0 I changed the PORTB.0 to my RD variable name for my PORTA.3 pin and made the pin = 1 to start high
i = i + 1 I added the PULSOUT RD, 4 so that the pin would pulse LOW
UNTIL i > 7 I changed the ">" to "=" so that when i = 65535 it was done

It was the only example I could find where I could pulse a pin for a certain number of times.

All I'm doing is pulsing the RD pin low 65535 times. Each time the pin is pulsed low the i variable counts up
and when the count reaches 65535, it stops pulsing and continues on with what was next in the code.

I'm trying to use the GOSUB...RETURN so that I'm not using up space having 4 separate REPEAT....UNTIL's in the code.

I'm not trying to do any "array indexing".

Thanks, Jim

HenrikOlsson
- 28th July 2015, 21:31
Hi Jim,

It was the only example I could find where I could pulse a pin for a certain number of times.
That's not what that particullar code example does. It IS "indexing" port pins starting at PortB.0 and ending at PortB.7 setting them low, one by one.


I'm not trying to do any "array indexing".
I figured you're not trying to but that IS effectively what you're doing ;-)

PortA.3 = 1 will set PortA.3 high - this is what you want.
PortA.3[3]=1 will set PortA.6 high because you're adding an offset of 3 - not what you want in this case.
PortA.3[i] will set "something" high - what that "something" is depends on the value of i which is incrementing each time thru the loop - definitely not what you want in this case.


All I'm doing is pulsing the RD pin low 65535 times. Each time the pin is pulsed low the i variable counts up and when the count reaches 65535, it stops pulsing and continues on with what was next in the code.
Yes and no. You're actually pulsing the pin 65536 times, since you're starting at 0 and stopping at 65535 but I Think 65536 is what you want. And since the i variable is couting up you're setting 65536 consecuitive bits, starting at PortA.3 high.

As a test, try

dat:
RD = 1
For i = 0 to 65535
RD = 0 ' Pull pin low
PAUSEUS 10 ' Wait 10us
RD = 1 ' Pull pin high
PAUSEUS 10 ' Wait 10us
NEXT
RETURN

/Henrik.

HenrikOlsson
- 28th July 2015, 21:39
Oh, one more thing....which I should have caught from the start:
Before the dat subroutine you need to put a GOTO Mainloop, otherwise the execution will "fall into" the dat subroutine after the last GOSUB dat you have in there. When it then hits the RETURN there's no matching GOSUB and you'll have a stack underflow and it goes off to la-la-land. I suspect THAT is what you're seeing but the issues with unintentional "array indexing" is still very much relevant!

/Henrik.

HEXhacker
- 28th July 2015, 22:28
Henrick,

I see what you mean, I took the wrong example for what I wanted, messed with it and by pure luck
it worked if I used it where/when I needed it and not used in a GOSUB!

I tried your code example and it worked for five "start" button presses and then the same problem
where the RD pin doesn't stop pulsing at 65535 and just keeps running on.

Thanks for your time and help,

Jim

HenrikOlsson
- 28th July 2015, 22:32
Hi Jim,

Did you add a GOTO Mainloop at the end of the actual Mainloop, before the subroutine?
If so, can you post the code again, exactly as it is now? We'll get it sorted and ironed out.
I have to sign off for today though.

/Henrik.

HEXhacker
- 28th July 2015, 22:36
Henrick,

Just saw your last post about the GOTO MAINLOOP
You're saying to put it above the dat: subroutine and not below it like I
have it now. I'll try it out.
Thanks,
Jim

HenrikOlsson
- 28th July 2015, 22:55
Hi Jim,

Yes, before the dat subroutine.

If there is no Goto Mainloop there the program will "fall into" the subroutine as it comes out of the main loop. Since it wasn't intentionally jumped to with a GOSUB at that time it doesn't know where to go once it gets to the RETURN at the end of the subroutine and it all falls to pieces.

Look at this:


Mainloop:
Do this
Gosub Sub_1
Do something else
Gosub Sub_2
Goto MainLoop

Sub_1:
Whatever
RETURN

Sub_2:
Whatever
RETURN

If the Goto MainLoop isn't there the program will just continue into Sub_1 as if it was actually called with a GOSUB (which it wasn't). So at the end of Sub_1 there's a RETURN but to where should it return? There's no return adress on the stack. Things go bad.

Hope that makes sense. Midnight here, got to go now.

/Henrik.

HEXhacker
- 28th July 2015, 23:18
Henrik,

That was it! I had my GOTO Mainloop after the dat: subroutine. I moved it up like you
mentioned and it works.

GOSUB dat 'last gosub dat

GOTO MAINLOOP
dat:
RD = 1
For i = 0 to 65535
RD = 0 ' Pull pin low
PAUSEUS 10 ' Wait 10us
RD = 1 ' Pull pin high
PAUSEUS 10 ' Wait 10us
NEXT
RETURN

END

Thanks a ton! If you were here, I'd buy you a beer.
Instead, I'm taking a vacation day tomorrow and goin' fishing.

Jim

Archangel
- 29th July 2015, 02:07
Henrik,



Thanks a ton! If you were here, I'd buy you a beer.
Instead, I'm taking a vacation day tomorrow and goin' fishing.

Jim

Wow, beer and fishing all in the same post :D

stanon1
- 6th August 2015, 11:06
One thing i have learnt about pbp;

NEVER use GOSUB without a matching RETURN;
NEVER use RETURN without a matching GOSUB

but when using ASM, i seem to get away with using goto with return and sometimes i can call a sub that terminates with a goto... don't know why it worked but then maybe pbp GOSUB is very much different from asm CALL

stanon1

HenrikOlsson
- 6th August 2015, 21:24
Whenever you GOSUB somewhere the adress after from where you GOUSBed is pushed onto the stack (stored in memory). If another GOSUB is executed the adress after THAT gosub is pushed onto the stack and the first adress stored is "pushed down". When a RETURN is executed the adress at the top of the stack is popped (retreived) and the execution jumps to that adress. This is how it works in any language, not just PBP.

If you GOSUB somewhere you must go back with a RETURN.
You can not RETURN from somwhere to where you did not GOSUB.

This too is NOT unique to PBP.

Now, it's perfectly fine to use GOTO from a subroutine to which you jumped with a GOSUB as long as you eventually end up at a "matching" RETURN. Example:

Main:
Toggle PortB.0
Pause 100
GOSUB CheckSwitch
Goto Main

CheckSwitch:
If PortA.0 = 1 THEN
GOTO DoThis
ELSE
GOTO DoThat
ENDIF
RETURN

DoThis:
' Whatever
RETURN

DoThat:
' Whatever
RETURN


In the above example the RETURN instryction at the end of DoThis and DoThat "matches" the GOSUB in the Main loop, Everything is fine. However, if you in somewhere in the main loop (or whatever) did a GOTO DoThat things would go bad because there's a "non matching" RETURN at the end. When the execution hits that RETURN it will pop "something" of off the stack and go there - not what you want.

Again, this is NOT unique to PBP in any way.

/Henrik.