PDA

View Full Version : Help with assembly code problem



mynet43
03-17-2009, 10:09 AM
I'm modifying some code I wrote a while back, to make part of it assembly code, for speed.

I have a bug in the assembly code that I can't figure out. It looks right, but it doesn't work...

I've isolated it to a 'djnz' command in the code, that never finishes looping.

If I eliminate the line with the 'djnz', then it works fine, and outputs the correct debug data.

If the 'djnz' is in there, it gets stuck in the loop and never returns.

I'm sure I'm doing something dumb, so please help me find it.

Here's the important code:




'' ************************************************** ****************************
'' * "HC595.spin" 74HC595 SPIN Object *
'' * Version 1.2 *
'' ************************************************** ****************************
''
'' Calling sequence
'' OBJ
'' SReg : "HC595"
''
'' code segment
'' SReg.InitSer595 ' to initialize driver
'' more code
'' DataByte := toSend ' set up data to send to chip
'' SReg.WriteSer595(DataByte) ' send data to chip
'' more code
''

CON
_PinHigh = 1
_PinLow = 0

CLK = 0 ' pin number of CLK pin on chip (AKA SCK)
SER = 1 ' pin number of SER pin on chip
CLR = 2 ' pin number of SCLR pin on chip
RCK = 3 ' pin number of RCK pin on chip for LED arrays
GPN = 4 ' pin number of G pin on chip

RCK1 = 5 ' pin number for Vel digits
RCK2 = 6 ' pin number for Pwr digits
RCK3 = 7 ' pin number for Rep digits
RCK4 = 8 ' pin number for Wgt digits

clkmsk = 1 '1<<CLK ' set bit for CLK pin
sermsk = 2 '1<<SER ' set bit for SER pin
rckmsk = 4 '1<<RCK ' set bit for RCK pin

VAR
long cog, cmd, bitout, datalong

PUB InitSer595 ' initialize 74HC595 for startup
' set the control lines as outputs
dira[CLK] ~~
dira[SER] ~~
dira[CLR] ~~
dira[RCK] ~~
dira[GPN] ~~

dira[RCK1] ~~
dira[RCK2] ~~
dira[RCK3] ~~
dira[RCK4] ~~

outa[CLK] := _PinLow ' init main clock line to low
outa[RCK] := _PinLow ' init latch line to low

outa[RCK1] := _PinLow ' init latch line to low
outa[RCK2] := _PinLow ' init latch line to low
outa[RCK3] := _PinLow ' init latch line to low
outa[RCK4] := _PinLow ' init latch line to low

outa[GPN] := _PinHigh ' set outputs to 3-state
outa[CLR] := _PinLow ' set to clear register on chip
outa[GPN] := _PinLow ' turn on the chip and clear pins
outa[CLR] := _PinHigh ' return CLR pin to high after clear

if cog
cogstop(cog~ - 1)

cmd := 0 ' init for cognew
cog := cognew(@HC595_write, @cmd) +1
waitcnt(clkfreq/4 + cnt) 'wait 1/4 sec for cog to start


PUB WriteSer595(Data) | ix ' Data is long with 24 bits of data in bits 23 - 0
' Write 24 bits of data. ' Data is output MSB first.
datalong := Data
cmd := @datalong ' start the assy routine

repeat while cmd ' wait for assy routine to finish

return datalong ' debug output

DAT
''
''************************************
''* Assembly language 74HC595 driver *
''************************************

org
'************************************
HC595_write rdlong bit_addr,par wz ' wait for command
if_z jmp #HC595_write

rdlong bit_data,bit_addr ' get the data bits to shift out

mov bit_count,#24 ' shift out 24 bits
:bloop test bit_data,bit23 wz ' see if bit set
if_z andn outa,sermsk ' if bit zero, set pin to zero
if_nz or outa,sermsk ' if bit one, set pin to one
shl bit_data,#1 ' shift for next bit
or outa,clkmsk ' set clk high to toggle
andn outa,clkmsk ' set clk low to finish toggle
djnz bit_count,#:bloop ' loop for 24 bits

or outa,rckmsk ' now toggle RCK to latch the data
andn outa,rckmsk ' complete the bit toggle

mov t1,par 'reset sample pointer
add t1, #8 'add offset, t1 now points to datalong
mov t2,bit_count
wrlong t2,t1 'write sample to datalong


wrlong zero, par ' tell the calling routine we're done
jmp #HC595_write ' back to look for next data

'************************************
' Initialized data
'
bit23 long %1000_0000_0000_0000_0000_0000 'constants
zero long 0
fofo long $F0F0F0F0

'************************************
' Uninitialized data
'
bit_addr res 1 ' address of datalong passed in
bit_count res 1 '
bit_data res 1 ' LED array bit data to shift out
bit_out res 1 ' bit to send out to port

t1 res 1
t2 res 1




Thanks for the help.

Jim

Erik Friesen
03-17-2009, 10:37 AM
bit_count exits loop with 0

t2 then is loaded with bit_count

0 is written to the long location? why?

mynet43
03-17-2009, 10:44 AM
Sorry, I should have explained that.

The code:



mov t1,par 'reset sample pointer
add t1, #8 'add offset, t1 now points to datalong
mov t2,bit_count
wrlong t2,t1 'write sample to datalong




is used ONLY to pass back debug data so I can display it on the terminal.

Sometimes I have bit_count there, sometimes other debug data.

When the 'djnz' is in there, it never gets to this code:(

Phil Pilgrim (PhiPi)
03-17-2009, 11:03 AM
I can't see why your loop doesn't terminate, but I do have some other observations:

1. Your assembly code won't be able to output anything on outa without initializing dira in the assembly cog itself.

2. You also need cog-resident (i.e. long) definitions for your pin masks. As it is, you're using the data at the cog address defined by the nine LSBs of the various masks you've defined as CONstants.

3. Your andn and or to outa could be replaced by a single muxnz.

-Phil

Timothy D. Swieter
03-17-2009, 11:35 AM
Phil - could you explain further what you mean by point number 3?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Timothy D. Swieter, E.I.
www.brilldea.com (http://www.brilldea.com) - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
www.tdswieter.com (http://www.tdswieter.com)

kuroneko
03-17-2009, 11:49 AM
Timothy D. Swieter said...
... explain further what you mean by point number 3?



if_z andn outa,sermsk ' if bit zero, set pin to zero
if_nz or outa,sermsk ' if bit one, set pin to one


is equivalent to



muxnz outa,sermsk

Timothy D. Swieter
03-17-2009, 12:02 PM
Thank you - I learned a new way of doing pin setting today! Makes perfect sense.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Timothy D. Swieter, E.I.
www.brilldea.com (http://www.brilldea.com) - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
www.tdswieter.com (http://www.tdswieter.com)

mynet43
03-18-2009, 02:10 AM
I solved it, finally!

Phil had the answer to the djnz loop problem, but it wasn't obvious.

The problem was several things:
1. The 'dira' commands needed to be in the assembly code, because it's operating in another cog.
2. The masks also needed to be defined in the assembly DAT section.

Apparently the djnz didn't work because the bad pin masks caused problems with the processor.

It's working great now. Here's the final code:



DAT
''
''************************************
''* Assembly language 74HC595 driver *
''************************************

org
'************************************
HC595_write rdlong bit_addr,par wz ' wait for command
if_z jmp #HC595_write

cmp init,#0 wz ' init only once
if_nz jmp #:doit

mov init,#1 ' set to true
or dira,clkmsk ' set control lines to output
or dira,sermsk ' set control lines to output
or dira,rckmsk ' set control lines to output

andn outa,clkmsk ' set clock to low
andn outa,rckmsk ' set rck to low, no latch yet
:doit
rdlong bit_data,bit_addr ' get the data bits to shift out

mov bit_count,#24 ' shift out 24 bits
:bloop test bit_data,bit23 wz ' see if bit set
if_z andn outa,sermsk ' if bit zero, set pin to zero
if_nz or outa,sermsk ' if bit one, set pin to one
shl bit_data,#1 ' shift for next bit
or outa,clkmsk ' set clk high to toggle
andn outa,clkmsk ' set clk low to finish toggle
djnz bit_count,#:bloop ' loop for 24 bits

or outa,rckmsk ' now toggle RCK to latch the data
andn outa,rckmsk ' complete the bit toggle

wrlong zero, par ' tell the calling routine we're done
jmp #HC595_write ' back to look for next data

'************************************
' Initialized data
'
bit23 long %1000_0000_0000_0000_0000_0000
zero long 0

clkmsk long 1 '1<<CLK ' set bit for CLK pin
sermsk long 2 '1<<SER ' set bit for SER pin
rckmsk long 8 '1<<RCK ' set bit for RCK pin

init long 0 ' initialization flag to avoid setup entry

'************************************
' Uninitialized data
'
bit_addr res 1 ' address of datalong passed in
bit_count res 1 '
bit_data res 1 ' LED array bit data to shift out




Thanks for the help!

It runs in 48 usec, instead of over 1000 in spin. Big difference where I'm using it.

Jim

Phil Pilgrim (PhiPi)
03-18-2009, 03:01 AM
mynet43 said...
Apparently the djnz didn't work because the bad pin masks caused problems with the processor.

I'm glad you got it working, but this couldn't have been the problem with the djnz. Without having set dira, anything done to outa would have a nil effect. And even with dira set, if some pins did change, it wouldn't screw up the processor unless an external connection caused excessive current draw. Are you sure you were using djnz bit_count,#:bloop, as you posted, or was it djnz bit_count,:bloop? (It's okay: we all do it from time to time. http://forums.parallax.com/images/smilies/smile.gif )

-Phil

mynet43
03-18-2009, 07:08 AM
Hi Phil,

Yes, this is one thing I'm sure about. I learned that one a long time ago anout the local # sign.

Besides, this is one line that never got retyped. I would put a ' in front of it to make it a comment, and then delete the ' when I wanted to try it again.

Obviously I was guessing about the cause of the djnz not working. The bad masks were the only thing that seemed to make sense.

If you're really curious, I can go back and try to make it happen again and see if I can isolate it to one instruction.

Anyway, thanks again. You pointed out some things that really helped solve the problem.

Jim

Phil Pilgrim (PhiPi)
03-18-2009, 07:20 AM
Jim,

Despite an abiding mystery, there's no need to futz with it anymore, unless you really want to. I'm just glad it's working! http://forums.parallax.com/images/smilies/smile.gif

-Phil

mpark
03-19-2009, 08:30 AM
One vote for actually solving the mystery here.

mynet43
03-19-2009, 10:45 PM
@ mpark,

I've decided not to reconstruct the crime.:)

There were so many problems with the original code that it would be a pain. If I wasn't so busy, I'd do it.

BTW, you can see that the djnz was constructed correctly by looking at the original posting compared to the final code.

FYI, I did output the original values of sermsk, clkmsk and rckmsk. They were: 08BC2E15, 5C680000 and 623C2E12. Which gives you an indication of how bad things were.:(

Jim