Shop OBEX P1 Docs P2 Docs Learn Events
Propeller Assembly for beginners - Page 18 — Parallax Forums

Propeller Assembly for beginners

1151618202129

Comments

  • HarpritHarprit Posts: 539
    edited 2012-01-12 18:11
    There is a lot of code.
    There Are three programs. Each will run on its own also. They are called within each other
    The mother program is the first one. Also run the Propeller Serial Terminal to see what is going on.
    For best results copy them and run them in your prop tool as three files
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      bits=12
      pots=4
      
    VAR
      long  P_Val[7]
      long  pot_sub
      long  clear
      
    OBJ                                                            
      'fds : "FullDuplexSerial"
      ms  : "MsecDelay"     'pulses line 1
      
    PUB Main                            'P_VAL is a local variable here   
    dira[0..4]~~
    'fds.start(31,30,0,115200)          'start console at 115200 for debug output
    cognew(@Chirper, @P_Val)               'start new cog at "tone", read var to P_Val
    ms.main
    waitcnt(clkfreq/40 +cnt)  
      repeat                            'endless loop
      
           
    DAT           org       0                         'sets the starting point in Cog
    Chirper       mov       dira,      set_dira       'set direction of ports
                  mov       mem,       par  
                  rdlong    delta,     mem 
                  mov       mem1,      mem           
                  add       mem1,       #4
                  rdlong    delta2,  mem1      
                  
    loop1         mov       temp,      ina            'read inputs 
                  and       temp,      read_bit  wz   'isolate pin 1
            if_z jmp        #loop1                    'stay here if bit is 0
                  call      #chirp                    'call chirp
                  
    loop2         mov       temp,      ina            'read inputs      
                  and       temp,      read_bit  wz   'isolate pin 1   
            if_nz jmp       #loop2                    'stay here if 1          
                  call      #chirp                    'call chirp
                  jmp       #loop1                    'stay here if bit is not 0
    'subroutines
    Chirp         mov       count,     #4            'counter for chirps 
                  mov       delay,     cnt            'load counter with clock counter
                  add       delay,     #12            'increment delay to get over overflow
                  
    loop          waitcnt   delay,     delta          'delay
                  or        outa,      out_bit        'make bit high
                  waitcnt   delay,     delta          'delay
                  andn      outa,      out_bit        'make bit low             
                  sub       count,     #1   wz        'subtract 1 from counter
           if_nz  jmp       #loop                     'loop back if not done w/counts        
    Chirp_ret     ret                                 'return from chirp sub
    
    set_dira      long      %00001011_00000000_00000000_00000111   'Set dira register
    out_bit       long      %00000000_00000000_00000000_00000100   'out bit for speaker      
    Read_bit      long      %00000000_00000000_00000000_00000001   'read bit           
    'delta         long      4000                      'interval between changes in chirp
    'code_val  long  3000
    delta res 1            
    delta2 res 1 
    temp          res       1     'temporary storage location
    count         res       1     'memory location for PAR variable 
    delay         res       1     'delay constant for CNT             
    mem res 1
    mem1 res 1
    

    {{
    022 PASM Read4Pots.spin
    Program to read 4 pots
    Repeats the program GOOD 006 PASM ReadPot 4 times
    Installs in separate cog.
    Reads resistances to 12 bits appears in POT_RES global variable
    15 Dec 2011
    By Harprit Sandhu
    }}
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      bits=12
      pots=4
      
    VAR
      long P_Val[7]
      long  pot_sub
      long  clear
      
    OBJ                                                            
      fds : "FullDuplexSerial"
      
    PUB Main                            'P_VAL is a local variable here
    fds.start(31,30,0,115200)            'start console at 115200 for debug output       
    cognew(@Read_Pots, @P_Val)           'start new cog at "generate", read var to P_Val 
    waitcnt(clkfreq/40 +cnt)
    dira[0..3]~~
      repeat                            'endless loop
        pot_sub:=0                      'reset id of pot to be printed
        fds.tx($1)                      'home to 0,0
        repeat pots                     'loop to display data
          fds.bin(P_val[pot_sub], bits) 'print to the PST in binary                                 
          repeat 2                      'two spaces                                                          
            fds.tx(" ")                 'space to erase old data overflow        
          fds.dec(P_val[pot_sub])       'print value as decimal value     
          repeat 2                      'two spaces
            fds.tx(" ")                 'space to erase old data overflow        
          fds.dec(pot_sub)              'print value as decimal value     
          repeat 3                      'three spaces
            fds.tx(" ")                 'space to erase old data overflow
          fds.tx($d)                    'new line
          pot_sub:=(pot_sub)+1          'increment display counter
        waitcnt(clkfreq/60+cnt)         'flicker free wait
        clear:=clear+1                  'increment counter. This routine clears up screen
        if clear>10                     'decision point     by erasing extra lines of bot
          fds.tx(16)                    'clear screen       of PST display every 10 loops
          clear:=0                      'reset counter
    '----------------------------------end of first Cog------------------------------------------
    DAT           org 0                              'sets the starting point in Cog
    Read_Pots     'first set up all the counters and addresses needed
                  mov       pots_read, #4           'number of pots to read [also change data]
                  mov       bits_read, #12          'bit resolution of 3208 IC, can be less
                  mov       mem,       par          'get address of mem for PAR
                  mov       dira,      set_dira     'sets direction of the prop pins
                  mov       pot_id,    #0           'first pot read is pot 0
                   
    Next_pot      or        outa ,   chs_Bit        'makes Chip select high
                  andn      outa,    chs_Bit        'makes chip select low 
                  andn      outa ,   clk_bit        'ANDN it with the Clock Bit to make low
                  or        outa ,   din_Bit        'makes the Din high
                  call      #Tog_clk                'toggle clock line hi-low to read data
                  or        outa ,   din_Bit        'makes the Din high 
                  call      #Tog_Clk                'toggle clock line hi-low to read data
                  
                  mov       temp2,     pot_id       'we will read three bits from this pot
                  call      #get_third_bit          'get bit
           if_nz  jmp       #its_one                'jump to set it as needed
                  jmp       #its_zero               'jump to set it as needed
    its_one       call      #Set_next_bit1          'setting bit subroutine call
                  jmp       #continue1              'go to next bit
    its_zero      call      #Set_next_bit0          'setting bit subroutine call
    continue1     call      #get_second_bit         'get bit
           if_nz  jmp       #its_one1               'jump to set it as needed
                  jmp       #its_zero1              'jump to set it as needed
    its_one1      call      #Set_next_bit1          'setting bit subroutine call
                  jmp       #continue2              'go to next bit
    its_zero1     call      #Set_next_bit0          'setting bit subroutine call
    continue2     call      #get_first_bit          'get bit
           if_nz  jmp       #its_one2               'jump to set it as needed
                  jmp       #its_zero2              'jump to set it as needed
    its_one2      call      #Set_next_bit1          'setting bit subroutine call
                  jmp       #continue3              'go to next bit
    its_zero2     call      #Set_next_bit0          'setting bit subroutine call
    
    continue3     andn      outa ,   din_Bit        'makes Din low              
                  call      #Tog_Clk                'toggle clock line hi-low to read data
                  call      #Tog_Clk                'toggle clock line hi-low to read data                        
                  mov       Data_read,  #0          'clear register we will read data into             
                  mov       bit_count, bits_read    'counter for number of bits we will read
    read_bit      mov       temp,     ina           'read in what is in all the input lines
                  andn      temp,     mask26 wz     'mask off except Dout line. Set Z flag    
                  shl       Data_read,  #1          'shift register left 1 bit for next bit
            if_nz add       Data_read,  #1          'if value + add 1 to data register    
                  call      #Tog_Clk                'toggle clock get next bit ready in Dout
                  sub       bit_count, #1 wz        'decr the "bits read" counter. Set Z flag
            if_nz jmp       #read_bit               'go up do it again if counter not yet 0 
                  wrlong    Data_read,  mem         'write it in PAR to share it as P.Val
                  add       mem,  #4                'add 4 to hub address for next long
                  add       pot_id, #1              'so we can look at next pot
                  mov       temp2, pot_id           'recall what pot we are reading
                  sub       temp2, pots_Read   wz   'check if it is how many we want to read
          if_nz   jmp       #Next_pot               'if it is not 0 go up and read next pot
                  jmp       #Read_pots              'go back beginning and do all pots again
                 
    'subroutines used
    Set_next_bit0  andn     outa ,    din_Bit       'makes Din low in 000 for line
                  call      #Tog_Clk                'toggle clock line hi-low to read data              
    Set_next_bit0_ret       ret                     'return from this subroutine
    
    Set_next_bit1 or        outa ,    din_Bit       'makes Din high in 000 for line
                  call      #Tog_Clk                'toggle clock line hi-low to read data              
    Set_next_bit1_ret       ret                     'return from this subroutine
    
    Tog_Clk       nop                               'nop to settle signals
                  or        outa,      clk_bit      'make clock bit high
                  nop                               'nop to settle signals
                  andn      outa,      clk_bit      'make clock bit low
                  nop                               'nop to settle signals
    Tog_Clk_ret   ret                               'return from this subroutine         
    
    Get_first_bit  mov      temp2,     pot_id       'get current pot number
                   andn     temp2,     mask0 wz     'get last bit
    Get_first_bit_ret       ret                     'return
    
    Get_second_bit mov      temp2,     pot_id       'get current pot number
                   shr      temp2,     #1           'shift right 1 bit to get second bit
                   andn     temp2,     mask0 wz     'return   
    Get_second_bit_ret      ret                
    
    Get_third_bit  mov      temp2,     pot_id       'get current pot number
                   shr      temp2,     #2           'shift right 2 bits to get third bit
                   andn     temp2,     mask0 wz     'return 
    Get_third_bit_ret        ret                               
     
    Set_dira      long      %00001011_00000000_00000000_00001111   'Set dira register                                 
    Chs_Bit       long      %00000001_00000000_00000000_00000000   'Chip select bit     24
    Din_Bit       long      %00000010_00000000_00000000_00000000   'Data in bit         25
    Dout_Bit      long      %00000100_00000000_00000000_00000000   'Data out bit        26
    Clk_Bit       long      %00001000_00000000_00000000_00000000   'Clock bit           27
    mask26        long      %11111011_11111111_11111111_11111111   'Mask to read Dout bit
    mask0         long      %11111111_11111111_11111111_11111110   'Mask to read 0 bit                                                                                         
    
    mem            res      1       'Par location
    temp           res      1       'temporary storage variable, misc
    temp2          res      1       'temporary storage variable, misc
    bit_count      res      1       'temporary storage variable, read bit counter
    Data_Read      res      1       'temporary storage variable, data being read 
    pot_id         res      1       'current pot id number
    pots_read      res      1       'total number of pots to be read.
    bits_Read      res      1       'resolution of data read, 12 bits max
    
    {
    
                                                                      
    Read pot and displa on PST through 022 PASM Rea4PotsX
    set up basic count oscillator
    
    }
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      
    VAR
      long  P_Val2[7]
    
    obj
      msd2 : "msecdelay2"    'reqads 4 pots
      
    PUB Main                           
    dira[0..4]~~
    cognew(@MilSecDelay, @P_val2)              
      msd2.main
    waitcnt(clkfreq/20 +cnt)        
      repeat                        'endless loop
    
    DAT           org       0
    MilSecDelay   mov       dira,      set_dira       'sets direction of the prop pins 
                  mov       beats,     #0             'clear the beats register  
    loop2         mov       Clock_spd, Clk_speed      'set counter to clock speed 
                  mov       mem,       par            'get par address
                  add       mem,       #4
                  rdlong   pot_zero,   mem
      
    Add_To_Count  sub       Clock_spd,  pot_zero    wc      'subtract beats from counter and set carry bit
                  add       beats,     #1             'add 1 to the answer
           if_nc  jmp       #Add_To_Count             'if the carry is not set, do it again
                  sub       beats,     #1             'subtract one to answer to make correction
                  mov       delay,     cnt            'read in CNT
                  add       delay,     #100           'add to skip over counter fill
    
    loop          andn      outa,      test_bit       'bits low
                  waitcnt   delay,     beats          'pause
                  or        outa,      test_bit       'bits high
                  waitcnt   delay,     beats          'pause
                  
                  'wrlong   beats,     mem  
                  jmp       #loop                     'loop back
    
    Set_dira      long      %00001011_00000000_00000000_00000111   'Set dira register  
    test_bit      long      %00000000_00000000_00000000_00000001
    Clk_Speed     long      80_000_000
    
    pot_zero long 400
    'pot_zero     res       1
    bps           res       1                        
    mem           res       1      'memory location for PAR variable 
    delay         res       1       'delay constant for CNT
    beats         res       1       'the divider for the clock 
     mem1 res 1                                                      
    Clock_spd     res       1       'counter for clock
    

    HArprit
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-12 18:38
    Assuming you have a top level object (which references other objects) please archive said object (File->Archive) and attach it here. No-one is going to guess what the relationship of those three fragments is. For example, how should I name these objects (if important)? What are those msecdelay objects?
  • HarpritHarprit Posts: 539
    edited 2012-01-12 19:06
    This is the software for a metronome.

    The second "022....." cog reads 4 potentiometers and stores the values in hub memory. It calls nothing. Only the first pot read will be used.

    The third file "mSecDelay2" takes what is in the first pot and divides the clock values by it to get a frequency. It then generates this freq on line 1. This is the frequency of the metronome.

    File one "MSecdelay" looks at line 1 and provides a chirp on line 3 every time the signal changes. The output goes to a speaker.

    The problem is that I cannot read the pot all the way to the first file.

    H
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-12 19:48
    Not sure I got the right idea here but it should do. The main program generates 4 pseudo random values and stores them in an array. Two helper objects monitor entry 0 of said array and indicate change or generate a frequency based on the stored value. Important bit here is that all objects need to have an idea where the shared data (block) is.

    Change is indicated on pin 16 (inverts LED every time a change is detected), the other object generates a square wave on pin 17 using the data value for NCO setup.

    The role(s) of each object can be changed, i.e. data can be generated in a child object.
  • StephenMooreStephenMoore Posts: 188
    edited 2012-01-13 21:31
    Harprit,

    I just wanted to tell you that I found this thread about a week ago and I have read every entry. I am learning PASM and your learning experience has proven to be a real treasure trove for my own. There have been a great number of things I have learned to do including getting up and going with the PASD debugger which, although simple, is a great way to watch variables... especially pointers to variables.

    You are a real trooper to joust with the pros and I think your effort is a noble one.

    As for the pros, these guys are awesome and it is a real delight for me to see how the mystery of their code gets figured out by running on my own props.

    I look forward to seeing your book someday and I also hope some more advanced treatments may get published by the experts in this forum.

    Propeller assembler is loads of fun to work with and a great way for me to keep my mind active during the winter months.

    Thank you.

    SM
  • HarpritHarprit Posts: 539
    edited 2012-01-14 13:19
    Please run this program on your computer
    Use PST to see what is going on
    Tell me why I dont get a clean two line display on the PST.
    {{ Program 017 PASM minimum PAR.spin
      This program is a minimal implementation for two variables and PAR.
     
      There are two Cogs in this program, one in SPIN and one in PASM
      Cog 1 in SPIN displays the variables on the console
      Cog 2 in PASM sets the variables to 1111 and 2222
        Finds the location of PAR and moves it to mem1
        Then mem2 is set to mem1 +4. 
        The two variables are transferred to mem1 and mem2
        and become available to the SPIN environment
        Loop.
    }}
    VAR
    long sharedVar[2]
    word clear
    
    OBJ
      fds: "FullDuplexSerial"
      
    PUB Main                          'displays values on console
      fds.start(31,30,0,115200)           'start console at 115200 for debug output
      cognew(@SecondCog, @SharedVar) 'start the second Cog in PASM
      waitcnt(clkfreq/40+cnt)             'wait 1/4 for everything to stabilize.
      clear:=0
      repeat                              'loop
        fds.tx($1)                        'home to 0,0
        fds.dec(SharedVar)                'display first value
        fds.tx($d)                        'new line
        fds.dec(SharedVar[1])             'display second value 
        clear:=clear+1                    'increment counter. This routine clears up screen
        if clear>10                       'decision point     by erasing extra lines of bot
          fds.tx(16)                      'clear screen       of PST display every 10 loops
          clear:=0                        'reset counter            
        waitcnt(clkfreq/6+cnt)            'flicker free wait
        
    DAT
        org    0                          'start at 0 location in the cog
    SecondCog                             'start point identification
          mov      mem1,       PAR        'find location of PAR, put in MEM1
          mov      mem2,       mem1       'make MEM2=MEM1
          add      mem2,       #4         'add 4 to MEM2
    re_do wrlong   var_one,   mem1        'write variable to location MEM1
          wrlong   var_two,   mem2        'write variable to location MEM2
          jmp      #re_do                 'jump back, do it again
     
    var_one   long      1111        'variable declaration
    var_two   long      2222        'variable declaration
    
    mem1      res       1           'first address storage space
    mem2      res       1           'second address storage space
    
    

    HSS
  • Heater.Heater. Posts: 21,230
    edited 2012-01-14 13:59
    I don't have PST here so I can't see any screen clearing. Your variables seem to be written out just fine though.

    Where are your clock settings. I had to add them:
    CON
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
    

    I'm not so happy with the commenting style. Having a comment "loop" next to a "repeat" statement is pointless, clutters up the page and is annoying. As this a book on PASM not Spin one should not have to be explaining what the Spin keywords are all the time.

    Similarly the "add 4 to MEM2" conveys no information, presumably the operation of ADD is explained by now.
  • HarpritHarprit Posts: 539
    edited 2012-01-14 17:36
    That fixed it but I was under the impression that if you did not specify the clock, there was a slow speed default value that the system assumed. Am I wrong?

    PST is the parallax serial terminal and is provided with the propeller tool. Start it and the screen will appear.
    Parallax Serial Terminal.exe

    Will take your other comments into account. Thanks for the help

    HSS
    ====================================
    [FONT=Arial, sans-serif]SM

    Thanks for your comments. I'm enjoying it. Book should be done some time late spring.

    HSS [/FONT]
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-14 17:44
    Harprit wrote: »
    That fixed it but I was under the impression that if you did not specify the clock, there was a slow speed default value that the system assumed. Am I wrong?
    It's simply not accurate enough. The compiler fixes e.g. RCFAST at 12MHz. My chips usually run at 13.5MHz which sort of upsets the timing calculations for the serial driver.
  • Heater.Heater. Posts: 21,230
    edited 2012-01-14 18:02
    I don't have a Propeller Tool because I don't have Windows to run it on. Mac an Linux users have the serial terminal built into BST which does not support special codes for screen clearing etc. You might want to bear this in mind for the non-Windows users in your audience.
  • frank freedmanfrank freedman Posts: 1,982
    edited 2012-01-14 20:55
    Harprit wrote: »
    Please run this program on your computer
    Use PST to see what is going on
    Tell me why I dont get a clean two line display on the PST.
    {{ Program 017 PASM minimum PAR.spin
      This program is a minimal implementation for two variables and PAR.
     
      There are two Cogs in this program, one in SPIN and one in PASM
      Cog 1 in SPIN displays the variables on the console
      Cog 2 in PASM sets the variables to 1111 and 2222
        Finds the location of PAR and moves it to mem1
        Then mem2 is set to mem1 +4. 
        The two variables are transferred to mem1 and mem2
        and become available to the SPIN environment
        Loop.
    }}
    VAR
    long sharedVar[2]
    word clear
    
    OBJ
      fds: "FullDuplexSerial"
      
    PUB Main                          'displays values on console
      fds.start(31,30,0,115200)           'start console at 115200 for debug output
      cognew(@SecondCog, @SharedVar) 'start the second Cog in PASM
      waitcnt(clkfreq/40+cnt)             'wait 1/4 for everything to stabilize.
      clear:=0
      repeat                              'loop
        fds.tx($1)                        'home to 0,0
        fds.dec(SharedVar)                'display first value
        fds.tx($d)                        'new line
        fds.dec(SharedVar[1])             'display second value 
        clear:=clear+1                    'increment counter. This routine clears up screen
        if clear>10                       'decision point     by erasing extra lines of bot
          fds.tx(16)                      'clear screen       of PST display every 10 loops
          clear:=0                        'reset counter            
        waitcnt(clkfreq/6+cnt)            'flicker free wait
        
    DAT
        org    0                          'start at 0 location in the cog
    SecondCog                             'start point identification
          mov      mem1,       PAR        'find location of PAR, put in MEM1
          mov      mem2,       mem1       'make MEM2=MEM1
          add      mem2,       #4         'add 4 to MEM2
    re_do wrlong   var_one,   mem1        'write variable to location MEM1
          wrlong   var_two,   mem2        'write variable to location MEM2
          jmp      #re_do                 'jump back, do it again
     
    var_one   long      1111        'variable declaration
    var_two   long      2222        'variable declaration
    
    mem1      res       1           'first address storage space
    mem2      res       1           'second address storage space
    
    

    HSS


    What do you think is wrong with this code? What have you done to isolate the failures so that 1) we know that it is not just being thrown out there for the others to solve gaining you nothing in additional knowledge to pass on, and 2) so that the extra eyes on this code do not have to guess what you may have already tried and end up needlessly duplicating your efforts?
    FF
  • HarpritHarprit Posts: 539
    edited 2012-01-15 07:13
    Frank:

    I thought that was way stronger than it needed to be.

    I did not think there was anything wrong with the code but it would not work right. I don't ask for help unless I am really stuck and I do like to understand every line of code that I hope to include in my book. As it turned out it is more important to specify the clock frequency than I had imagined. And the clock has to be precisely defined. I was oblivious to that and it was explained to me in a very kind way. The code would have been OK if there was no communication to the PST. These are the finer points in the calculus. The kind of stuff beginners like me are likely to miss. And I did miss it. It was not a useless exercise. If there was already a book for beginners out there (written by someone like you) I would be reading it instead of puzzling all this out for myself and for others like me. On the other hand I do think that a book for beginners, written by you, would not be suitable for beginners like me. It would be way too advanced.

    Maybe you need to consider notching it down a tad. I'm not in this to irritate you. I'm trying to learn and then teach.

    H
  • HarpritHarprit Posts: 539
    edited 2012-01-15 07:19
    Heater

    As I was adding your comments on my commenting to my notes it occurred to me that it would be very helpful to my style if I had an example of a well commented file from you (and others). Could you re-comment my program (or another program of your choice) is a way that you felt was exemplar and re-post it.

    H
  • Heater.Heater. Posts: 21,230
    edited 2012-01-15 08:51
    Good idea Harprit. However it relies on the assumption that my actual commenting style is as good as I say your should be:)

    The arguments about commenting style are endless as it is quite subjective. Part of the problem is that the style of commenting should be targeted at the reader audience. Rather like the style of the book itself.

    When learning a new language or library API I find my self creating experimental code with excessively detailed comments. Basically because I have to remind myself of every little feature all the time. I've just been going through that recently with the OpenGL functions. But then when I am familiar with things the production code gets a lot more terse comments.Mainly because eventually it's tedious to see the same comments explaining the same little details all the time. It's partly because I know the future audience of my code will be more familiar with things, if they are not they will have to go through the same learning steps I did.

    I think a good general rule is not say things in the comments that the programming language can say for itself. Hence my advice not to put a comment like "loop" next to a "repeat" statement. Or a comment like "increment A" next to a statement like A := A + 1".

    Comments should tell what the intended function of objects and methods is. How the user can actually use them, what the parameters are etc.
    Comments should point out any non-obvious things going on in the code, or surprises, or the reason why things are done as they are done. Things that the language cannot tell you for itself.
  • potatoheadpotatohead Posts: 10,260
    edited 2012-01-15 09:00
    A = A + 1 'point to next pixel (functional comment, IMHO)
  • HarpritHarprit Posts: 539
    edited 2012-01-15 09:37
    Heater

    That was very illuminating. Lets keep in mind that I am writing to a beginner. Usually not the kind of guy that wants to find it all out for himself. My purpose in commenting every line is kind of strange and unusual. If you ignore to PASM code in my listings and read just the comments a line at a time if gives you a pseudo code of what needs to be done. Here is a listing. See if what I am trying to do is actually working. Since you are not supposed to read the PASM each line needs a comment.

    Do you think this is an unsatisfactory way to do it for beginners?
    This code reads a signal on a pin and chirps the speaker ever time the signal changes.
    DAT           org       0                         'sets the starting point in Cog
    Chirper       mov       dira,      set_dira       'set direction register
    loop1         mov       temp,      ina            'read inputs into temp
                  andn      temp,      mask0     wz   'isolate pin 1
            if_nz jmp       #loop1                    'stay here if pin is 1
                  call      #chirp                    'call chirp routine
                 
    loop2         mov       temp,      ina            'read inputs      
                  andn      temp,      mask0     wz   'isolate pin 1   
            if_z jmp        #loop2                    'stay here if pin is 0        
                  call      #chirp                    'call chirp routine           
                  jmp       #loop1                    'return to top              
    'subroutine
    Chirp         mov       count,     #6             'counter for number of chirps                     
                  mov       delay,     cnt            'load delay with clock counter
                  add       delay,     #9             'increment delay to get over overflow              
    :loop         waitcnt   delay,     beat_delay     'delay
                  or        outa,      out_bit        'make speaker bit high
                  waitcnt   delay,     beat_delay     'delay
                  andn      outa,      out_bit        'make speaker bit low             
                  sub       count,     #1   wz        'subtract 1 from counter
           if_nz  jmp       #:loop                    'loop back if not done w/counts        
    Chirp_ret     ret                                 'return from chirp sub   
    
    set_dira      long      %00001011_00000000_00000000_00000111   'Set dira register
    out_bit       long      %00000000_00000000_00000000_00000100   'out bit for speaker
    mask0         long      %11111111_11111111_11111111_11111110   'mask for bit 1
    beat_delay    long      70000
    
    temp          res       1     'temporary storage location
    count         res       1     'memory location for PAR variable 
    delay         res       1     'delay constant for CNT
    
    

    H
  • JonnyMacJonnyMac Posts: 9,030
    edited 2012-01-15 09:49
    This code is valid:
    sub       count,     #1   wz        'subtract 1 from counter
           if_nz  jmp       #:loop                    'loop back if not done w/counts
    


    ...but an experienced programmer would use:
    djnz      count, #:loop             ' decrement count, back to :loop if > 0
    


    The djnz instruction has been optimized because it is so common. Your teaching the first way is akin to showing a child how to do a wobbly walk (which he/she will naturally do, anyway) instead of showing the correct practice in the first place....
  • frank freedmanfrank freedman Posts: 1,982
    edited 2012-01-15 11:55
    Harprit wrote: »
    Frank:

    I thought that was way stronger than it needed to be.

    I did not think there was anything wrong with the code but it would not work right. I don't ask for help unless I am really stuck and I do like to understand every line of code that I hope to include in my book. As it turned out it is more important to specify the clock frequency than I had imagined. And the clock has to be precisely defined. I was oblivious to that and it was explained to me in a very kind way. The code would have been OK if there was no communication to the PST. These are the finer points in the calculus. The kind of stuff beginners like me are likely to miss. And I did miss it. It was not a useless exercise. If there was already a book for beginners out there (written by someone like you) I would be reading it instead of puzzling all this out for myself and for others like me. On the other hand I do think that a book for beginners, written by you, would not be suitable for beginners like me. It would be way too advanced.

    Maybe you need to consider notching it down a tad. I'm not in this to irritate you. I'm trying to learn and then teach.

    H

    Not taken as irritant, just needed to know what you had checked and tried. Otherwise you could be swamped with multiple replies from the forum all telling you to check things you had already done probably twice over. Now that would be an irritant........

    As to writing a book, I am way to incompetent on the prop. With over 16 years of writing and delivering technical training, the challenge to doing that would be time and desire to do it and the requisite time taken from family to do that since I gotta keep on working. Not happening, and that would be after I get to the level on the prop I would consider myself to be competent and experienced enough to consider such a project.

    My main point was show us what you have done, how have you tried to solve your issue before throwing it to us. Most people prefer to help on this forum, but having all the data needed makes a big difference in how that help is given and how fast the issue is solved. In this case, you could have found it if you had a set starting checklist or framework if you did not realize that the clock set up was missing. If you had posted that you were trying to do this with the internal clock, someone would have immediately said that you were headed for shallow water on this one because unless as I saw somewhere you don't compensate for the fact that no prop is the exact same as another for internal clock, your serial comms will not work. From there someone would..... and so on.

    Sorry if it sounded too harsh,

    FF
  • Heater.Heater. Posts: 21,230
    edited 2012-01-15 14:23
    Harprit,

    I totally understand that your commenting style is geared to the beginner. Nothing wrong with that. I guess I got hooked up on that "repeat" - "loop" pair where the comment has no value at all, at least after the very first example of using "repeat" it is not required anymore.

    In that last example I'd be careful with "jmp #loop1 'return to top". Problem here is that the "jmp" is not a "return" in the commonly accepted sense of calling a subroutine and returning from it. You see the room for confusion here.

    As an aesthetic point, I like all my comments to begin with upper case letters and end with full stops They are written in the English language after all. Oh yea and one space between the comment marker and the first char of the comment.

    Having Uppercase first chars and full stops means you can continue a comment over two or more lines, even at the side of code, and it reads nicely.

    As for your chirping code, it chirps every time the pin changes. I'm sure detecting the pin change with XOR and having only one call to chirp would save some code in the "chirper" loop. Saving code space is not the point but less code is less to read and simpler understand.

    Having done that there is only one call to chirp so it need not be a subroutine. There goes even more code....
  • HarpritHarprit Posts: 539
    edited 2012-01-15 19:52
    OK. Lots of good stuff here. Thanks to every one. I will try to keep your ideas in mind as I proceed.

    MY Next problem.
    I cannot figure what makes everything in the par variables go to zero when I call a new method.

    I start a new cog. I store four variables @someVariable
    Sometimes I start a new cog and every thing stays in place and I call recall the @somevariables
    Sometimes I start as new cog and everything goes to zeros

    Lets not ask me to post code. Its gets too complicated. But I will if you insist.

    Can we discuss what the rules are to keep from messing up. Simple rules suitable for beginners.

    H
  • frank freedmanfrank freedman Posts: 1,982
    edited 2012-01-15 20:16
    Harprit wrote: »
    Heater

    That was very illuminating. Lets keep in mind that I am writing to a beginner. Usually not the kind of guy that wants to find it all out for himself. My purpose in commenting every line is kind of strange and unusual. If you ignore to PASM code in my listings and read just the comments a line at a time if gives you a pseudo code of what needs to be done. Here is a listing. See if what I am trying to do is actually working. Since you are not supposed to read the PASM each line needs a comment.

    Do you think this is an unsatisfactory way to do it for beginners?
    This code reads a signal on a pin and chirps the speaker ever time the signal changes.
    DAT           org       0                         'sets the starting point in Cog
    Chirper       mov       dira,      set_dira       'set direction register
    loop1         mov       temp,      ina            'read inputs into temp
                  andn      temp,      mask0     wz   'isolate pin 1
            if_nz jmp       #loop1                    'stay here if pin is 1
                  call      #chirp                    'call chirp routine
                 
    loop2         mov       temp,      ina            'read inputs      
                  andn      temp,      mask0     wz   'isolate pin 1   
            if_z jmp        #loop2                    'stay here if pin is 0        
                  call      #chirp                    'call chirp routine           
                  jmp       #loop1                    'return to top              
    'subroutine
    Chirp         mov       count,     #6             'counter for number of chirps                     
                  mov       delay,     cnt            'load delay with clock counter
                  add       delay,     #9             'increment delay to get over overflow              
    :loop         waitcnt   delay,     beat_delay     'delay
                  or        outa,      out_bit        'make speaker bit high
                  waitcnt   delay,     beat_delay     'delay
                  andn      outa,      out_bit        'make speaker bit low             
                  sub       count,     #1   wz        'subtract 1 from counter
           if_nz  jmp       #:loop                    'loop back if not done w/counts        
    Chirp_ret     ret                                 'return from chirp sub   
    
    set_dira      long      001011_00000000_00000000_00000111   'Set dira register
    out_bit       long      000000_00000000_00000000_00000100   'out bit for speaker
    mask0         long      111111_11111111_11111111_11111110   'mask for bit 1
    beat_delay    long      70000
    
    temp          res       1     'temporary storage location
    count         res       1     'memory location for PAR variable 
    delay         res       1     'delay constant for CNT
    
    

    H

    Not sure what is meant by the statement "Since you are not supposed to read the PASM each line needs a comment."
    As one progresses through PASM, it will become with repetition knowing what each instruction does, and can/should be read and understood. Teach to not comment the obvious, confusing and obfuscating the big picture. Many of the comments in this code are appropriate as they expose intent. A good comment on the function of the routine and comments on variable definitions go a long way to understanding. As PASM gets more understandable, many of your comments should drop out anyway. The chirp routine really only needs a description of what it does after which even the newbie should be able to puzzle it out because there are no real hidden or less than evident things going on here. Sure, the newb may have to bounce between the prop book and the code a few times, but if the vars are properly described as to their use, reading the code becomes quite clear and is a good exercise for the newb anyway.

    I would comment the Chirp routine with a standalone comment that it is used to make a chirp sound when called. First comment ok, number of chirps. Cool. Second line obvious what code does, but what is the delay for? Third, why magic number 9? Newb won't know why unless the text or comment tells him it accounts for the time from when the count value was stored until the wait count was actually called and why it is needed (I had lots of fun with this one in my ADC objects.....). Maybe make the first comment get count and adjust n counts until waitcnt actually called. The text will hopefully explain thios concept prior to exploring the code.

    Course as Heater has hinted at, only politics, religion, and coding methods and languages have caused as many flame wars as commenting and even coding style in general. Well may be OS's also......

    Short answer, don't comment the obvious.

    Frank

    The more proficient one becomes reading and understanding, the faster they will be able to code in it as there won't be as much need to constantly go to references to figure out how to accomplish something.
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-15 20:48
    Harprit wrote: »
    I cannot figure what makes everything in the par variables go to zero when I call a new method.
    re: [post=1065430]post #512[/post], are you sure you look at the same set of variables? Over there you have 3 (local) sets. And don't just think they are the same, prove it. If they are then someone is obviously clearing them. Find out where.
  • HarpritHarprit Posts: 539
    edited 2012-01-16 08:19
    JM and Frank

    I will be showing compacted, more efficient code in the programs as I get further down the book.
    Not quite ready yet.
    Thanks again.

    K:

    I'm taking a closer look at the code as suggested.

    H
  • HarpritHarprit Posts: 539
    edited 2012-01-17 12:05
    I got it. Please ignore this and next post.


    I'm still not clear about this passing variables bit:

    Question
    This is regard variable stored with the PAR pointer.
    If I store 1 variable in the PAR area in one Cog, first location
    and another variable in PAR, second location using Cog two
    Should not I be able to read both variable from a third Cog if all cogs are started passing the same variable array
    I am having trouble doing this.

    Here is the code, use PST to view results
    WHY IS THE SECOND VARIABLE SCREWED UP?
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      bits =32
      pots=2
      
    
    VAR
      long P_Val[2]
      long  pot_sub
      
    OBJ                                                            
      fds : "FullDuplexSerial"
      
    PUB Go
    fds.start(31,30,0,115200)           'start console at 115200 for debug output 
    main       
    waitcnt(clkfreq/40 +cnt)
      repeat                            'endless loop 
        pot_sub:=0                      'reset id of pot to be printed
        fds.tx($1)                      'home to 0,0
        repeat pots                     'loop to display data
          fds.bin(P_val[pot_sub], bits) 'print to the PST in binary                                 
          repeat 2                      'two spaces                                                          
            fds.tx(" ")                 'space to erase old data overflow        
          fds.dec(P_val[pot_sub])       'print value as decimal value     
          repeat 2                      'two spaces
            fds.tx(" ")                 'space to erase old data overflow        
          fds.dec(pot_sub)              'print value as decimal value     
          repeat 3                      'three spaces
            fds.tx(" ")                 'space to erase old data overflow
          fds.tx($d)                    'new line
          pot_sub:=(pot_sub)+1          'increment display counter
        waitcnt(clkfreq/60+cnt)         'flicker free wait
       
    PUB Main                           
      dira[0..2]~~                         
      Cog1(@P_Val)
      Cog2(@P_Val)
    
    
    PUB Cog1(address)             
      cognew(@C_og1, address)
        
    PUB Cog2(address)             
      cognew(@C_og2, address)
    
      
    Dat           org 0 
    C_og1        
    loop1         mov mem, par
                  wrlong one, mem
                  jmp #loop1
    
    C_og2        
    loop2         mov mem, par
                  add mem, #4
                  wrlong two, mem
                  jmp #loop2
    
    one  long 1
    two  long 2
    
    mem res 1
    

    H
  • HarpritHarprit Posts: 539
    edited 2012-01-17 12:47
    I got it
    Cog 2 must be started in another object
    H
  • HarpritHarprit Posts: 539
    edited 2012-01-17 12:57
    Question:

    Is it true that you can only start one new PASM Cog from any one object
    (Though you can call many objects)
    and is it because you can only have one "org 0" in any one DAT declaration

    H
  • jazzedjazzed Posts: 11,803
    edited 2012-01-17 13:06
    This should work.
    Dat           org 0 
    C_og1        
    loop1         mov mem, par
                  wrlong one, mem
                  jmp #loop1
    
    one  long 1
    two  long 2
    
    mem res 1
    
    Dat           org 0 
    C_og2        
    loop2         mov _mem, par
                  add _mem, #4
                  wrlong _two, _mem
                  jmp #loop2
    
    _one  long 1
    _two  long 2
    
    _mem res 1
    
  • HarpritHarprit Posts: 539
    edited 2012-01-17 13:32
    I tried something like that, it scrambles the first variable.
    I thought it was because both cogs started at ORG 0 but I may be wrong
    H
  • jazzedjazzed Posts: 11,803
    edited 2012-01-17 14:19
    Harprit wrote: »
    I tried something like that, it scrambles the first variable.
    H

    I would expect that according to your example. You are passing the same address to Cog1 and Cog2. I.E.
     PUB Main                             
      dira[0..2]~~                           
      Cog1(@P_Val)  
      Cog2(@P_Val)
    
    PUB Cog1(address)
      cognew(@C_og1, address)
    
    PUB Cog2(address)
      cognew(@C_og2, address)
    
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-17 15:55
    Harprit wrote: »
    Is it true that you can only start one new PASM Cog from any one object
    No.
    Harprit wrote: »
    ... and is it because you can only have one "org 0" in any one DAT declaration
    There is no such limitation. Nothing is stopping you from having say 42 org directives in a single file (and any number of DAT blocks). Most commonly you'll have one each (single cog image) though.
Sign In or Register to comment.