Help with assembly code problem
mynet43
Posts: 644
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:
Thanks for the help.
Jim
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[noparse][[/noparse]CLK] ~~ dira[noparse][[/noparse]SER] ~~ dira[noparse][[/noparse]CLR] ~~ dira[noparse][[/noparse]RCK] ~~ dira[noparse][[/noparse]GPN] ~~ dira[noparse][[/noparse]RCK1] ~~ dira[noparse][[/noparse]RCK2] ~~ dira[noparse][[/noparse]RCK3] ~~ dira[noparse][[/noparse]RCK4] ~~ outa[noparse][[/noparse]CLK] := _PinLow ' init main clock line to low outa[noparse][[/noparse]RCK] := _PinLow ' init latch line to low outa[noparse][[/noparse]RCK1] := _PinLow ' init latch line to low outa[noparse][[/noparse]RCK2] := _PinLow ' init latch line to low outa[noparse][[/noparse]RCK3] := _PinLow ' init latch line to low outa[noparse][[/noparse]RCK4] := _PinLow ' init latch line to low outa[noparse][[/noparse]GPN] := _PinHigh ' set outputs to 3-state outa[noparse][[/noparse]CLR] := _PinLow ' set to clear register on chip outa[noparse][[/noparse]GPN] := _PinLow ' turn on the chip and clear pins outa[noparse][[/noparse]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
Comments
t2 then is loaded with bit_count
0 is written to the long location? why?
The code:
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[noparse]:([/noparse]
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, E.I.
www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
www.tdswieter.com
is equivalent to
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Timothy D. Swieter, E.I.
www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, 3.0" LCD Composite video display, eProto for SunSPOT
www.tdswieter.com
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:
Thanks for the help!
It runs in 48 usec, instead of over 1000 in spin. Big difference where I'm using it.
Jim
-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
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!
-Phil
I've decided not to reconstruct the crime.[noparse]:)[/noparse]
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.[noparse]:([/noparse]
Jim