Shop OBEX P1 Docs P2 Docs Learn Events
Help with assembly code problem — Parallax Forums

Help with assembly code problem

mynet43mynet43 Posts: 644
edited 2009-03-19 14:45 in Propeller 1
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[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

  • Erik FriesenErik Friesen Posts: 1,071
    edited 2009-03-17 02:37
    bit_count exits loop with 0

    t2 then is loaded with bit_count

    0 is written to the long location? why?
  • mynet43mynet43 Posts: 644
    edited 2009-03-17 02:44
    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[noparse]:([/noparse]
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-03-17 03:03
    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. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 03:35
    Phil - could you explain further what you mean by point number 3?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • kuronekokuroneko Posts: 3,623
    edited 2009-03-17 03:49
    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. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 04:02
    Thank you - I learned a new way of doing pin setting today! Makes perfect sense.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • mynet43mynet43 Posts: 644
    edited 2009-03-17 18:10
    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)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-03-17 19:01
    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. smile.gif )

    -Phil
  • mynet43mynet43 Posts: 644
    edited 2009-03-17 23:08
    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)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-03-17 23:20
    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! smile.gif

    -Phil
  • mparkmpark Posts: 1,305
    edited 2009-03-19 00:30
    One vote for actually solving the mystery here.
  • mynet43mynet43 Posts: 644
    edited 2009-03-19 14:45
    @ mpark,

    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
Sign In or Register to comment.