Shop OBEX P1 Docs P2 Docs Learn Events
SPIN/ASM Driver lock up on code size greater than 480 longs? — Parallax Forums

SPIN/ASM Driver lock up on code size greater than 480 longs?

Timothy D. SwieterTimothy D. Swieter Posts: 1,613
edited 2009-03-18 03:13 in Propeller 1
Alright - same commercial project I am working through (i.e. can only post small portions of code). I have an object setup with several SPIN routines, then a data table in a DAT block, then an ASM routine in another DAT block. The SPIN code is for starting, stopping and sending commands to the ASM driver. The core of the driver is working and proven. However I started adding some additional SPIN code and commands. I am at a point where the driver appears to be locking up or isn't running properly, here is what I am seeing.

In the SPIN section is where the code was added. After review, commenting, uncommenting, etc I think what I am seeing is that the driver is locking up with the code size over a certain amount - 480 total longs. Now, again, remember the code I am adding is in the SPIN section, not the ASM section. When the driver is locking up and I get the Object Info - just the object (F8) I see the program is 471 longs, variables are 20 longs. When I comment out code (doesn't matter which SPIN code - any SPIN code - new code or old code - code that is being called or code that isn't implemented in the calling routines yet) and the program size drops to 460 longs or lower with 20 variable longs then the program/driver works fine. Futhermore, if I leave all the code in the SPIN section uncommented and take out portions of the data table to drop the size to 460 longs, 20 variables, the driver will still lockup, so it is as if the problem is in the SPIN section.

Again, it hasn't mattered which code I comment out or leave in. It appears to be the size. Am I barking up the wrong tree? What is happening here? Is this a symptom of a different problem?

FYI: In the ASM DAT section the status bar at the bottom of the Propeller Tool is telling me it is 491 bytes. So, I don't think it is a code size limit on a cog.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
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

Comments

  • JetfireJetfire Posts: 34
    edited 2009-03-17 03:53
    Does your assembly code have ORG at the beginning? That's the first thing I thought of.
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 04:04
    Thanks for the question Jetfire. Yes, the DAT for the data table has nothing. Then follows a DAT for the assembly code with the first line being an ORG and no parameters (starts from default address loading in the COG).

    Other ideas?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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 05:25
    Timothy D. Swieter said...
    Other ideas?
    Is the SPIN code making any assumptions about how much hub memory is free (i.e. by using a hard-coded address for a buffer)?
  • kevin101kevin101 Posts: 55
    edited 2009-03-17 05:37
    I was thinking that maybe the assembly program was writing data to the hub after the 480th long, and would overwrite any spin located there. This depends on timothy's asm code, so I may be wrong. Check the pointer on the cognew instruction if it is used at all.

    just a thought
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 06:27
    Good ideas.

    The SPIN code isn't making any assumptions on memory or space for variables that I can see. There are a couple buffers declared as variables and those variables are strictly used with clear definitions (usually with variable[noparse][[/noparse]x] := value). There are various SPIN routines, and it hasn't mattered which ones are commented out or which lines are commented out - as long as the 460 longs program space isn't violated.

    Kevin101 - good thought. The ASM driver reads configurations as the beginning of the driver initialization. Then, when a command is passed to the driver it reads the command plus four parameters. This is the same template idea that I have seen used in other drivers like graphics and float, and also in the LM9033A LCD driver I created. This new code works, I have tested and used it extensively, and it worked until I added SPIN code. There is one variable that is written to the HUB RAM an it is a value of zero written to the PAR address (clears the command after execution).


    Here are more details after a little more investigation based on the above probing which triggers my thinking. Commenting or uncommenting the lines of SPIN are causing the ASM driver to function or not function properly. What I mean is, the ASM driver (with some lines commented out of SPIN) behaves as it should (it transmits and massages data - I am getting the data at the device that uses the data). I get great results and the driver is working. With those SPIN lines uncomments, it is like the ASM COG is locked up - not the calling COG or other cogs because I can still navigate on a menu structure (the calling COG), but the data sending isn't happening. So, the SPIN code isn't locking up, but the inclusion or exclusion of SPIN code is causing the ASM driver to function or not function.

    So, why would commenting/uncommenting and size have to do with if the ASM code works properly or not? I will try and desensitize portions of the ASM code and publish that, but my thinking isn't that the problem is there.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 06:34
    Here is the start of the assembly routine. I changed a couple names to protect the innocent.

    '***************************************
    DAT
    '***************************************
    ''  Assembly language driver
    
            org
    '-----------------------------------------------------------------------------------------------------
    'Start of assembly routine
    '-----------------------------------------------------------------------------------------------------
    Entry         mov       t0,     par             'Load address of command into t0 (par contains the address of the command)
    
                  'Bring over the data for the pin and create the mask'
                  add       t0,     #4              'Increment the address pointer by 4 bytes (skip over the command + parameter address)
                  rdlong    txPin,  t0              'Read value of RF_tx
                  mov       txMask, #1              'Load the mask with a 1
                  shl       txMask, txPin           'Create the mask for the proper I/O pin by shifting the 1
    
                  add       t0,     #4              'Increment the address pointer by 4 bytes
                  rdlong    ledPin, t0              'Read value of RF_led
                  mov       ledMask, #1             'Load the mask with a 1
                  shl       ledMask, ledPin         'Create the mask for the proper I/O pin by shifting the 1
    
                  'Next set up the I/O with the masks and the direction register
                  'all I/O pins are set to output here.
                  mov       dira,   txMask          'Set to an output and clears cog dira register
                  or        dira,   ledMask         'Set to an output
    
                  'Set the initial state of the I/O, unless listed here, the output is initialized as off
                  'all outputs are initialized as off
    
    '----------------------------------------------------------------------------------------------------- 
    'Main loop
    'wait for a command to come in, then process it.
    '-----------------------------------------------------------------------------------------------------
    CmdWait
    
                  rdlong    t0,     par        wz   'Check for a command being present
            if_z  jmp       #CmdWait                'If there is no command, jump to check again
    
                  mov       t1,     t0              'Move the address of the command
                  rdlong    paramA, t1              'Get parameter A value
                  add       t1,     #4              'Increment the address pointer by four bytes
                  rdlong    paramB, t1              'Get parameter B value
                  add       t1,     #4              'Increment the address pointer by four bytes
                  rdlong    paramC, t1              'Get parameter C value
                  add       t1,     #4              'Increment the address pointer by four bytes
                  rdlong    paramD, t1              'Get parameter D value
    
                  shr       t0,     #16        wz   'Get the command
                  cmp       t0,     #(_forceTX>>16)+1 wc    'Check for valid command
      if_z_or_nc  jmp       #:CmdExit               'Command is invalid so exit loop
                  shl       t0,     #1              'Shift left, multiply by two
                  add       t0,     #:CmdTable-2    'add in the "call" address"
                  jmp       t0                      'Jump to the command
    
                  'The table of commands that can be called                
    :CmdTable     call      #periodicTX             'Set or remove a flag for periodic transmitting of RF packet
                  jmp       #:CmdExit
                  call      #sendPCKTs              'Send x number of RF packets
                  jmp       #:CmdExit
                  call      #chngPCKcnt             'Change the numbe of packets sent in RF transmission
                  jmp       #:CmdExit
                  call      #forceTX                'Force the TX line to the transmitter IC to be on/off
                  jmp       #:CmdExit
    :CmdTableEnd  
    
                  'End of processing a command
    :CmdExit      wrlong    _zero,  par             'Clear the command status
                  jmp       #CmdWait                'Go back to waiting for a new command
    
    



    After the above code is sub-routines for the various commands and sending data out. The behavour that I see when the driver behaves improperly is that no data is being sent and the LED I/O is stuck on.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-17 06:40
    You mentioned a DAT section for tables. Do you access this data from COG via HUB access? When you uncomment SPIN code this shifts as well. You could try to move that DAT section in front of the SPIN code that you uncomment and see if something changes.
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 06:44
    MagIO2 - the data table is used only in SPIN code, not in the ASM routine. In fact it is only one accessed from one of the many SPIN routines that I have. At the moment the structure of the document is as follows. I can certainly move things around if you think it would help.

    CON
    VAR
    OBJ - not used
    PUBs/PRIs
    DAT - table of values - Propeller Tool status bar says this section is 765 bytes
    DAT - ASM routine (part of which is shown in the post above)

    Are you suggesting moving the DAT(table) section above the PUBs/PRIs? I can certainly try it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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 06:49
    Entry         mov       t0,     par             'Load address of command into t0 (par contains the address of the command)
    ...
    CmdWait
                  rdlong    t0,     par        wz   'Check for a command being present
            if_z  jmp       #CmdWait                'If there is no command, jump to check again
    
                  mov       t1,     t0              'Move the address of the command
    


    That looks odd. par holds the address of the command (Entry line). Then in CmdWait you actually load the command into t0 and then treat t0 as an address again (last quoted line)? Shouldn't that last line read mov t1,par?

    This may be intentional if the command holds a pointer to its parameters but I just thought I point it out anyway.

    Post Edited (kuroneko) : 3/17/2009 6:57:22 AM GMT
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 07:01
    In the Entry section t0's value is used as the address of space in the HUB RAM. That value is incremented which is actually incrementing an address (pointer) into HUB RAM to read data out of.

    Then, the CMDWait section reads the CONTENTs of par into t0. So t0 is now the value of what par is pointing to in HUB RAM. If the value is zero, then the code checks again. If the value is non-zero then it moves on. t0 is copied to t1 for processing, because later I use t0 again - this avoids reading par and syncing with the HUB RAM again. The comments are confusing, I suppose you would have to see the spin code. The contents of PAR is a variable called Command. Command is then made up of a pointer and value in the upper 16 bits.

    See Graphics.spin or Float32 (I think) or LM9033A LCD driver for more examples (complete with SPIN code) to see how the passing of a command and parameters are done in this method. It is sort of tricky until you write it out (or rewrite it and debug it) but boy is it a nice technique for creating drivers.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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 07:14
    OK, back to square one [noparse]:)[/noparse] Do you have a way of verifying the commands including parameters (i.e. assuming the SPIN code sends the right commands, they should appear down there unchanged)?
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-17 07:20
    Can it be that the rdlong adresses have to be aligned to longs? Do you use word or byte types for the command buffer? So, maybe depending on the length of the SPIN code alignment is correct or not and your code works or not?
  • kuronekokuroneko Posts: 3,623
    edited 2009-03-17 07:27
    MagIO2 said...
    Can it be that the rdlong adresses have to be aligned to longs?
    They don't have to, however only bits 15:2 are considered for a rdlong. So yes, that might be an issue if SPIN gets it wrong somehow.
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 07:28
    Kuroneko - I don't have a mechanism to echo back the commands/parameters. The driver sends data out and I confirm that the commands are controlling the driver as expected and sending the data, the correct data, because the end device is receiving the correct data and processing it. The data is all being received by the end device. I am about to o-scope the data lines coming from this driver to ensure the timers are correct for transmitting, and the correct number of packets are being sent but since I am receiving data I only expect tweaking and nothing wrong in this area.

    Another thing I know is that the commands are being executed. Most of the SPIN code is structured to wait for the commands to be done before returning to the calling cog. Something like this, where 'a' is the start of four variables with parameters. You can see in the ASM code I posted that the par is written with zero after the command is processed, so the code waits for the command. The parameters are read near the start of the ASM.

      command := _pokeintheeye + @a
    
      'wait for the command to complete
      repeat while command
    
    



    I know this is working because it is not causing the calling cog to hang. Hmmm....maybe I can do more testing in this area because I would think that it should be hanging if the ASM cog is really walking off a cliff. Hmmm...

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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

    Post Edited (Timothy D. Swieter) : 3/17/2009 7:33:19 AM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2009-03-17 07:32
    Timothy D. Swieter said...
    The driver sends data out and I confirm that the commands are controlling the driver as expected and sending the data, the correct data, because the end device is receiving the correct data and processing it.
    But you also mentioned The behavour that I see when the driver behaves improperly is that no data is being sent and the LED I/O is stuck on. So maybe the command itself is OK but the parameters aren't (see alignment issue raised by MagIO2)?
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 07:35
    Looking..........

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-03-17 08:00
    In general I like the idea of a 'heartbeat' in such kind of loops. Simply toggle a output pin behind "if_z jmp #CmdWait 'If there is no command, jump to check again".
    But in your case in the command buffer you can have what ever you want without a problem. Because in your exit you always set the command back to zero and every waiting SPIN code will continue. Thats some kind of robust programming, but it's a program with Alzheimer as it simply forgets that there was an error.
    In this case I'd place a errorbeat ;o) which is only executed in case of an erroneous command.

    Isn't it a nice challenge to find those kind of bugs. I really miss my java debugger in these times. Step through the code, do code changes on the fly .... ;o)
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-17 08:07
    MagIO2 - (got distracted, haven't looked back at the RF driver yet for long alignment - coming up soon) I see what you are saying about heartbeats and reporting errors. In the case of this driver, most of the data and processing occurs in spin before passing details to the ASM loop. Therefore data processing error should occur before the driver, where the driver is merely toggling outputs. So, the very basic way of set/clear works. However I see some other code that I am thinking through where returning a zero for good and maybe some other values for various errors would work well. This is certainly helpful for when the command list is long and more responsibility is dedicated to the driver than what I have now. I really like this idea.

    Oh - I guess I also have an LED that gives some feedback under certain commands. I only have four commands right now, one sets/clears a flag, another changes a parameter for the other commands. yet another only forces I/O for testing purposes and finally there is the one command that does all the heavy lifting and sending of data. In the future this may be expanded to be multiple commands. First, get the SPIn processing and cog dysfunction working properly.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-03-17 08:43
    Tim,
    Do you have a spare cog and 2 IO pins to communicate with the pc?
    If so, you could use my debugger to trace the code, particularly if it occurs quickly. See my signature for link to the thread.
    If you dont follow my debugger PM me and I'll give you my msn address.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBladeProp, SixBladeProp, website (Multiple propeller pcbs)
    · Prop Tools under Development or Completed (Index)
    · Emulators (Micros eg Altair, and Terminals eg VT100) - index
    · Search the Propeller forums (via Google)

    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-03-17 11:29
    Tim,

    You may already be doing this but do you ever check that the assembly cog actually starts either by checking the return value from the cognew or a led set in the asm cog?

    "Command is then made up of a pointer and value in the upper 16 bits. "
    Don't forget not all of the PAR variable actually gets passed into the cog.
  • stevenmess2004stevenmess2004 Posts: 1,102
    edited 2009-03-17 11:34
    You may also want to remember how objects are laid out (only one object, if there is more than one object than all the VAR sections are grouped together after all the objects). Just reading it again quickly I would guess that the address you are passing into the PAR register is getting too big and ending up further down in memory and part of the address is getting chopped off when then causes your asm code to read commands from the wrong place. Not sure that's right after all.

    Object table
    Method Table
    DAT section
    PUB methods
    PRI methods
    VAR section

    In this section
    shr       t0,     #16        wz   'Get the command
                  cmp       t0,     #(_forceTX>>16)+1 wc    'Check for valid command
      if_z_or_nc  jmp       #:CmdExit               'Command is invalid so exit loop
                  shl       t0,     #1              'Shift left, multiply by two
                  add       t0,     #:CmdTable-2    'add in the "call" address"
                  jmp       t0                      'Jump to the command
    


    should t0 be t1? t0 just holds the contents of the PAR register.

    Post Edited (stevenmess2004) : 3/17/2009 11:43:48 AM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2009-03-17 12:09
    stevenmess2004 said...
    should t0 be t1? t0 just holds the contents of the PAR register.
    Nope, it's rdlong t0, par (CmdWait) so that's fine.
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-18 02:57
    Thank you guys for the help and support and probing of ideas - especially since I am holding you in the dark on the code side. I like having a forum here where I can bounce ideas off the walls and get other people to ask questions which causes me to probe deeper.

    Good news is.......I think I found the problem. Bad news is......I don't understand why.

    First, last night I was really getting bogged down thinking through this problem. I get like that after trying and trying and getting no where. Therefore I stopped working on the problem, that is why my posting stopped. I have gotten bogged down before and the lesson I learn is that I just need to walk away and stop thinking about it. I need to clear my head. After some time I return with a fresh mind - like I did this morning. I have a fresh mind and I start to reread everything I posted. I start to test assumptions. I review what I know and what I don't know. I retest to prove the problem or not. (of course I complicated matters yesterday by troubleshooting multiple bugs in multiple locations - which didn't help my focus).

    So - this morning I think I found the problem. There is a piece of code I haven't posted yet. It is ASM code that has a flag and if the flag is set (non-zero) it branches to one direction and if the flag is not set (zero) it takes another path. The default, I was assuming, is not set and taking the "main path". The flag is reserved space at the end of the ASM routine. The flag was not initialized by the ASM code (I assumed this should be default to zero - no?). With all my SPIN code included (more than 460 longs), it appears that the flag was non-zero as it was getting stuck in that other path (a future feature half written). But, with some of my SPIN code commented out (doesn't matter which code, just as long as I am below 460) then the flag would be zero. Mind you, none of the commands/parameters at this time are manipulating the flag, it is only a reserved variable in ASM.

    So, I am guessing that when I write something like:

    periodicTXfg  res 1     'Flag to indicate if to periodic transmit or not
    
    



    That it isn't always initiated to zero - or at least doesn't appear to me to be that way based on my testing. Of course maybe there is some other bug that is clobbering the flag and I am looking for that now too. I also have my ASM routine initialized the flag to zero just after the I/O is initialized.

    So - all of this to find a flag that is sometimes initialized as non-zero and other times is zero and the only way I can change between the two was how much SPIN code was present. Surely there is some thing else I haven't found yet.

    So - all this talk here has helped me narrow down on the problem. Now if only I do why - I can spend sometime figuring it out, but I also need to move to the next coding task.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • mctriviamctrivia Posts: 3,772
    edited 2009-03-18 03:05
    you are correct res 1 will reserve 1 long with an indeterminent state. use

    periodicTXfg long 0

    to define it at start up.


    res reserves space for assembly code but that space is still available for spin or assembly code from other locations.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Need to make your prop design easier or secure? Get a PropMod has crystal, eeprom, and programing header in a 40 pin dip 0.7" pitch module with uSD reader, and RTC options.
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2009-03-18 03:09
    I like learning - no matter how long I have using the prop, I keep learning.

    I just checked the Propeller Manual regarding RES and it didn't mention that it is initialized to an indeterminante state. If this is true (and makes sense because there is also the other way of intializing a vriable) then it should get mentioned.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    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
  • mctriviamctrivia Posts: 3,772
    edited 2009-03-18 03:13
    you can actually predict the state the res will start up at by reading the generated eeprom file. The space is kept available for spin code and to my playing seems to be usually constants or assembly code following. So the value is usually the same every time for a particular build.

    The advantage of using res is the space gets reused over. very useful if your code is nearng the 32k limit. i almost always use the long, byte, or word opcode so I know for sure the start value.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Need to make your prop design easier or secure? Get a PropMod has crystal, eeprom, and programing header in a 40 pin dip 0.7" pitch module with uSD reader, and RTC options.
Sign In or Register to comment.