Shop OBEX P1 Docs P2 Docs Learn Events
Polling 8 RC-receiver channels with still easy to understand PASM-code — Parallax Forums

Polling 8 RC-receiver channels with still easy to understand PASM-code

StefanL38StefanL38 Posts: 2,292
edited 2010-12-22 08:54 in Propeller 1
Hi PASM-experts,

I'm pretty good in coding in SPIN and Delphi. I have coded some small PASM-routines yet.
But I'm not an expert about PASM.

I want to read in 8 RC-signals (1-2 milliseconds every 20 millisecnds).
I want to do that explicit in a polling mode using just ONE cog.
I don't want to spend 4 cogs each with two counters for doing that
Even if this means that the pulselength deviates about 5 microseconds
depending on the time passing by between a transition and the detecting of that transition.

So my first aproach to this was to divide the PASM-code into quite a lot subroutines
that are called by conditional calls if_z if_c etc. This way the code stays easy to understand for me.

For a second channel I was just duplicating all the subroutines.
This is not very effective and means a lot of work for maintining the code.

I have commented the code intensivly to get into PASM-coding and to make it easy to understand for others what the commands are for.

I guess it can be done much more effective using self-modifying code.
In this first approach I avoided to to that to get the principle working at all.
With selfmodifying code things become more difficult to understand.

Now could somebody show me how polling 8 channels could be done with selfmodifying code?
It would be great not to post just plain code but to post intensivly commented code.
At my own comments you can see how intensive the comments should be.
I guess this way of commenting the code would be appreciated by all PASM-newbees.

Of course I know that all work here is done for free and that I can't expect anyone to
comment with such an intensity. But I would apprecieate it very much and me personally I
enjoy commenting.

Thank you very much in advance

best regards

Stefan

Comments

  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-12-21 18:25
    If you can tolerate the 10us resolution I think you'll find the attached code a bit more elegant.
  • StefanL38StefanL38 Posts: 2,292
    edited 2010-12-22 01:01
    Hi Jon

    thank you very much for your code-example. If I understand right the basic concept is to have a loop with a constant executiontime
    (through the waitcnt) so that incrementing longs directly tells the amount of 10microsecond-units the pulse was high. All 8 channels where sampeld within a 10 µsecond-time-frame.

    It mostly does not use selfmodifying code in a sense of modifying command-adresses but modifys operands like the bitmask and servochannel.
    There are only two place where adresses are changed. This is inside read-channel and write-channel

    I have extended the comments on these parts of the code
    Did I desrcibe it correct in the comments?
    ' chan = index of element to read
    ' value = value that is read
    
    rdchan                  mov     tmp1, #pwidth0                  'load COG-RAM-ADRESS of long labeled "pwidth0" into tmp1 
                            add     tmp1, chan                      'add channel number to tmp1
                                                                    'in COG-RAM after incrementing the source or destination-field by 1 the adress points to the next LONG
                                                                    'this is different in HUB-RAM. HUB-RAM-adresses are byte-based. So pointing to the next long means
                                                                    'incrementing the adress by 4
                                                                      
                            movs    rdval, tmp1                     'write new SOURCE-adress into sourcefield of the command labeled "rdval"
                                                                    'meaning read in value from long pwidthX where X is equal to chan
                                                                    'concrete example: chan contains value 5
                                                                    'movs rdval,tmp1 changes source-field of command mov  value,0-0 to  mov value, (adress of pwidth5)
                                                                    ' 
                            nop                                     'a nop HAS TO BE inserted that the change of the source-field-adress has time to be changed before
                                                                    'the command mov value... is executed
    rdval                   mov     value, 0-0                      'value := pwidth[chan]  
    rdchan_ret              ret
    
    
    ' chan = index of element to write
    ' value = value to write
    
    wrchan                  mov     tmp1, #pwidth0                  'load COG-RAM-ADRESS of long labeled "pwidth0" into tmp1
                            add     tmp1, chan                      'add channel number to tmp1
                            
                            movd    wrval, tmp1                     'write new DESTINATION-adress into destinationfield of the command labeled "wrval"
                                                                    'meaning write in value from long pwidthX where X is equal to chan
                                                                    'concrete example: chan contains value 5
                                                                    'movd wrval,tmp1 changes destination-field of command mov  0-0,value to  mov (adress of pwidth5),value 
                            
                            nop                                     'a nop HAS TO BE inserted that the change of the source-field-adress has time to be changed before
                                                                    'the command mov 0-0,value
                                                                    
    wrval                   mov     0-0, value                      ' pwidth[chan] := value
    wrchan_ret              ret   
    
    
    Instead of many calls ofsubroutines it is coded with pairs of jmp-commands for correct program-flow.

    Does one loop for all 8 channels need more than 5 microseconds? Meaning that the timebase of 10 microseconds is a minimum?

    best regards

    Stefan
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-12-22 08:05
    I am always concerned about the quality of one's code when comments are used to state the obvious; comments are intended to clarify what may not be obvious. It could be a difference between those that code for a living and those that do it as a hobby. The former group focuses on quality of code and comments over quantity.

    As you can see it is coded in a loop that uses bit masking to check channel status and changes, and uses two subroutines for reading and writing local arrays. The code is quite straightforward, which I think is always best. I haven't done any timing tests but I think it probably would work with 5us loop. I used 10us as this is an easy value to deal with an recognize as a servo position, e.g., 150 = 1.5ms.

    As I still have the PPDF hooked up I'll add timing tests to check the duration of loop.
  • StefanL38StefanL38 Posts: 2,292
    edited 2010-12-22 08:24
    Hi Jon,

    I'm a long term hobbyist programmer and had a job for about 4,5 years which included coding in delphi for industrial controls.

    Yes indeed it depends on who is reading the code. To an experienced expert a lot of things are obvoius.
    Which is not for a newbee. In case of PASM I'm somewhere between newbee and medium advanced.
    If I comment my code I have newbees in the back of my mind for which a lot of things are NOT obvoius.

    Would you say that commenting too much could lower the quality of the code?
    Or is it just not nescessary and for coding on a living would reduce rentablity?
    As commenting needs extra time.

    best regards

    Stefan
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-12-22 08:44
    I added a little bit of timing code to the measure object and it turns out that my first instincts were correct (i.e., using 10us). The max clock ticks through the loop is 463 which works out to 5.79us at 80MHz.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-12-22 08:54
    StefanL38 wrote: »
    Would you say that commenting too much could lower the quality of the code?
    Or is it just not nescessary and for coding on a living would reduce rentablity?
    As commenting needs extra time.

    These are, of course, opinions and those of us in Hollywood are full of them! <wink> Reliability and efficiency are my goals. Do you know why most people don't read user manuals? Because most of them tend to use a lot of words that say nothing (kind of like politicians). As I write a lot of code for public consumption I try to keep it as clean and organized as possible, without being overbearing.

    For example: I wrote an object for the 74x595 shift register that included a method called write() -- in my opinion, an obvious choice. A student suggested to me that I should have named that method:

    write_one_byte_to_74x595_shift_register()

    I'm not kidding! Can you imagine if you had to type all that every time you wanted to use the method? I suggested that his parents should demand their money back from the institution that implanted this nonsense. Of course, there's a balance, and I'm not suggesting that we go back to cryptic, single-letter variable names and line numbers. I strive to make my code readable and as self-documenting as possible (not as easy in Assembly as in high-level code). Comments in my programs are there for clarification/edification.

    My style works for me, especially when I have to go back to code that I wrote a year ago. I want to be able to pick it up without wading through reams of comments that, as you indicate, would have done nothing but consumed time typing.
Sign In or Register to comment.