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

Propeller Assembly for beginners

1235729

Comments

  • jazzedjazzed Posts: 11,803
    edited 2011-07-29 10:46
    mindrobots wrote: »
    This thread is becoming an interesting study in so many things that may or may not be helpful to Harprit and his efforts. This posting certainly follows those lines! :smile:

    ...
    This is one of the most wonderful posts I've read in a while. Thank you for taking the time to write it.

    --Steve
  • HarpritHarprit Posts: 539
    edited 2011-07-29 12:04
    Back to basic guys!
    I know this is not quite right but...
    Why does this not open up a third cog and toggle line 12
    It compiles but I get a dead line 12
    In other word, how do you start two PASM cogs
    PUB null | P_Val, Delay_Val
      cognew(@generate, @P_Val)            ' start second cog at "generate" 
      cognew(@Toggle, @Delay_Val)          'start third cog  at toggle
      repeat
       'do something unrelated to other cogs
    DAT
    Org  0
    generate  mov     outa,               set_dira
                      jmp     #generate
    
    org  30
    toggle    mov     dira,               set_dira
                mov     outa,               pin_hi
                mov     outa,               pin_lo
                jmp     #toggle
    
                      'Constants. This section is similar to the CON block in SPIN           
    Set_dira      long      %00000001_00000000_00010000_00000000   'Set dira register
    Pin_Hi        long      %00000000_00000000_00010000_00000000                          
    Pin_Lo        long      %00000000_00000000_00010000_00000000
                    
    
  • HarpritHarprit Posts: 539
    edited 2011-07-29 12:23
    My goal is to provide enough information to allow someone who knows nothing about

    binary math
    PASM
    assembly language
    jargon infested writings

    to want to mess around with PASM and his propeller chip
    Maybe inspire him or her to learn more from you guys.
    I will keep in very simple and disappoint some of you who think there is no way I can get this done

    Here is letter from some one who know very little but is very excited. I got it this morning.
    All he is really turned on about is controlling a few LEDs.
    Hopefully some day he will make a great Tech or even an Engineer. Made my day.

    Dear Sir:

    I am enjoying your book immensely! I especially enjoyed seeing your section on page 23/24, A Fundamental Reality We Have to Consider, as I need to have LEDs on all my I/O pins (not multiplexed, and more than 10 ma. per pin -- very bright). I plan on using a LYP47F reverse mount LED from OSRAM (sold by Mouser). (The reverse mount and small size are why I chose that style.)

    I was a bit surprised to see the 7404 driving LEDs, so I set up six on a chip with 470 ohms as you suggested. Ran all afternoon until I had to shut down and go home! I measured the total chip current (ICCL = 49.2 ma). This exceeded the data sheet spec (33 ma max) a bit but did not blow any outputs. As a personal hobby application or learning situation I can see the 7404 working fine.

    However, I have been looking for a long time for a chip for product development where reliability and safety margins can be considered in the design. I am wondering if you might know of anything more robust (and as simple as the 7404) that you could suggest where I would have more driving current per LED. You are the only author that has addressed the situation I face. (Another issue was how to interface a 5 volt family to the Propeller. So I thank you for moving me forward on my project!)

    I am looking forward to the remainder of your book. Very well done.
    (I like that fact that you do not repeat all the material in other reference sources, but direct the reader to the sources. That makes your book a faster/easier read and more pages for what it is you want to guide us through.)

    Thanking you in advance,
  • mindrobotsmindrobots Posts: 6,506
    edited 2011-07-29 12:28
    Lots of things going on here - not sure most of them are what you intend.

    First, the startup state on a reset or freshly started COG for the direction register (DIRA) is 0, that is, all pins set as INPUT

    Your first COGNEW starts a COG at address 0 (generate) and begins program execution there
    1) move the contents of Set_dira to the outa register (this sets bits 12 and 24 to 1, BUT the DIRA register is still INPUT
    2) jump back to 1

    You've never set DIRA to output, you'll never see bits 12 and 24 anywhere.

    Your second COGNEW starts execution in a new cog at address toggle
    1) you set DIRA bits 12 and 24 to output
    2) you set OUTA bit 12 HIGH
    3) you set OUTA bit 12 HIGH (even though the label says Pin_Lo, you still have a 1 bit at bit 12)
    4) you jump back to #1 and do the same things

    Even if you did set bit 12 LO in #3, it woudl be toggling so fast, you would need an oscilscope or logic probe to see it.

    Here's code from Potatohead's tutorial that does what you want - two cogs blinking two leds. I was running this on a Quickstart, so it blinks pin 16 and 17
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    PUB Main
      ' a freshly started COG has OUTA = 0 and DIRA = 0 - this is where understanding the HW is important
      cognew(@Toggle, 0)    ' start a COG at address Toggle
      cognew(@Toggle1, 0)   ' start a COG at address Toggle1
    DAT
    {Toggle Pin 16}
            ORG   0          ' Begin at COG RAM address 0
    Toggle
            mov   dira, Pin16       ' move CONTENTS of COG Memory Pin16 to DIRA register
                                    ' This sets PIN 16 to OUTPUT
            mov   Time, cnt         ' move CONTENTS of CNT register to COG Memory address Time
            add   Time, #$f         ' bump the counter a bit (trust me on this one for now)
    :loop
            waitcnt         Time, Delay  ' Tell this COG to wait until the CNT register equals the contents of Time
                                         ' when CNT = Time, start the COG and add contents of Delay to Time for the next loop           
            xor   outa, Pin16            ' toggle bit 16 of OUTA (this is where understanding BINARY operations 
                                                ' comes into play)
            jmp   #:loop                 ' jump to :loop - need the # in this case since you want the IMMEDIATE address
                                         ' 
    Pin16   long  |< 16                  ' %00000000_00000001_0000000_00000000 if you prefer
    Delay   long  5_000_000              ' delay for 5_000_000 clock ticks
    Time    res   1                      ' a place to save the WAITCNT value
    {Toggle Pin 17}                      ' similar code for the second PIN (PIN#17)
            ORG   0
    Toggle1  mov   dira, Pin17
            mov   Time1, cnt
            add   Time1, #$F
    :loop  waitcnt         Time1, Delay1
            xor   outa, Pin17
            jmp   #:loop
    Pin17    long  |< 17
    Delay1   long  80_000_000
    Time1    res   1
    

    When I was learning assembler way back when, I was always told to "play computer" it might sound dumb but it really helps to go through each instruction and do everything the computer has to do. If you understand how the computer works for each instruction, you can "play computer" through ANY program.

    P.S. This is not how I usually comment code but for instructional purposes, step by step comments are often helpful. I normally despise code such as:
    $daysInWeek = 7;              # set daysInWeek to 7
    

    oh, wait, I don't normally comment code.........:innocent:
  • HarpritHarprit Posts: 539
    edited 2011-07-29 12:47
    @mindrobot/Rick

    I'll take a closer look at the code you sent

    For now, just FYI
    If I eliminate the initial "jmp generate" instruction,
    the I/O works fine and I can see it on the scope just fine so that part seems OK
    Pin 24 should not make any difference to the cog running.
    It was a mistake but its not critical.
    I removed it, nothing changed

    Finally, Thanks I think I can make it work now.

    Regards
    HSS
  • mindrobotsmindrobots Posts: 6,506
    edited 2011-07-29 12:52
    True, if you remove the "jmp generate" instruction, something will work but do you know both COGs are REALLY doing??? (and why) :smile:

    :smile: I didn't know I was going to need a scope to see the examples in your book work, I need to find a new book since I don't have a scope. :smile:
  • HarpritHarprit Posts: 539
    edited 2011-07-29 13:18
    @Rick:

    That's a tough call
    I will add LEDs to this code for now but eventually we will need a scope.
    Its really a very basic piece of equipment every serious beginner need to learn how to use.
    Just too much stuff that goes too fast to not own one. Its our eyes in electronics.

    HSS
  • mindrobotsmindrobots Posts: 6,506
    edited 2011-07-29 13:43
    :smile: Note to self: After building things since 1975, I need to buy a scope to be a serious beginner.

    @Harpirt: I removed the jmp #generate and I got no output on either pin when I watched it through the logic probe on Gear. If you watch COG1 and COG2 run, you see them looping through all of COG memory and they just happen to execute your instructions as they loop.

    If I remove the jmp #generate AND the 'ORG 30' I get a steady HIGH on PIN 12 and a pulsed pin 24. COG1 and COG2 are at least inthe tight loop inside your code.

    Both COGs are running through the same code path pulsing the same pin at the same rate. I can't imagine this is what you intended by your example. I'm not sure what concept this shows your reader.

    The example I attached from Potatohead's tutorial shows two COGs pulsing two LEDs at two different rates - this at least shows independent COG funtions.

    I'm not trying to be difficult, just providing feedback from 'a PASM beginner'.
  • jazzedjazzed Posts: 11,803
    edited 2011-07-29 14:55
    Harprit wrote: »
    Back to basic guys!
    I know this is not quite right but...
    Why does this not open up a third cog and toggle line 12
    It compiles but I get a dead line 12
    In other word, how do you start two PASM cogs
    PUB null | P_Val, Delay_Val
      cognew(@generate, @P_Val)            ' start second cog at "generate" 
      cognew(@Toggle, @Delay_Val)          'start third cog  at toggle
      repeat
       'do something unrelated to other cogs
    DAT
    Org  0
    generate  mov     outa,               set_dira
                      jmp     #generate
    
    org  30
    toggle    mov     dira,               set_dira
                mov     outa,               pin_hi
                mov     outa,               pin_lo
                jmp     #toggle
    
                      'Constants. This section is similar to the CON block in SPIN           
    Set_dira      long      %00000001_00000000_00010000_00000000   'Set dira register
    Pin_Hi        long      %00000000_00000000_00010000_00000000                          
    Pin_Lo        long      %00000000_00000000_00010000_00000000
                    
    

    Some observations:
    As mentioned in #127: Pin_Hi and Pin_Lo both have bit 12 set and thus no toggling.
    Referring to post #128: removing "jmp #generate" just makes both cogs run the same loop.
    "toggle" is at "generate" cog's address 2 (or address 1 if you get rid of "jmp #generate").
    Remember that saying org 30 does not change the cog start address.

    "MOV OUTA, PEACE" - @mindrobots

    --Steve
  • mindrobotsmindrobots Posts: 6,506
    edited 2011-07-29 15:09
    What was strange (and unexpected to PASM newbie, me) The code generated sequentially, 0 thru 4 or 5 but the ORG 30 caused the label 'toggle' to be at $1E. This caused the jmp to go to $1E and then execute code from there to the end of COG memory. This is a least how GEAR simulated it.

    I was expecting the ORG 30 to cause a hole in the COG memory.....I expected incorrectly. I have much to learn!

    @Steve, it's an honor to be quoted! :smile:

    I guess MOV OUTA, PEACE only shows if you're sure of your direction! :lol:
  • jazzedjazzed Posts: 11,803
    edited 2011-07-29 15:41
    mindrobots wrote: »
    @Steve, it's an honor to be quoted! :smile:

    I guess MOV OUTA, PEACE only shows if you're sure of your direction! :lol:

    Indeed. I quoted you precisely since PEACE is variable but normally understood.
    #PEACE would mean "immediately" within a smaller range :)

    Yes, "jmp #toggle" is adjusted by org 30. The rules of org have been mentioned in this thread.
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-29 16:36
    mindrobots wrote: »
    2) I don't know Kuroneko but respect his knowledge and talent and genius. I assume he didn't just walk in one day from being a frustrated musician and decide to download the Propeller datasheet and start writing complex PASM code.
    Apologies when this came accross as you only need the datasheet. At the time I already had lots of experience with different chips so the datasheet was sufficient. Also, I started simple, working my way up ... and I can't even play an instrument ...
  • HarpritHarprit Posts: 539
    edited 2011-07-29 17:24
    Well, I finally got two Cogs working at the same time in PASM. Took all day.
    My problem was that I did not appreciate that each cog has to be defined completely with
    all its subroutines, variables and constants before you enter ORG 0 and start
    defining the second Cog and all its goodies.
    And you cannot duplicate variable names even across cogs (Which I thought was rather strange)

    And you still have to watch for I/O conflicts..

    I will post my program soon.

    Thanks for all the help guys.
    Harprit
  • mindrobotsmindrobots Posts: 6,506
    edited 2011-07-29 17:33
    YAY!! It's always good to end the day with a victory!!
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-29 18:04
    Harprit wrote: »
    And you cannot duplicate variable names even across cogs (Which I thought was rather strange).
    Global (variable) labels that is. After all, it's still the same DAT block. You could work around that issue by using local labels (which are sufficently separated by the main label), e.g.
    DAT             org     0
    
    one             mov     :b, :a
    '               ...
                    
    :a              long    0
    :b              res     1
    
    DAT             org     0
    
    [COLOR="orange"]two[/COLOR]             neg     :b, :a
    '               ...
    
    :a              long    0
    :b              res     1
    
    And be careful with multi cog images in the same file. You can easily end up with one image referencing a symbol in another.
  • HarpritHarprit Posts: 539
    edited 2011-07-29 19:36
    I will post complete listing after I clean it up tomorrow. But essentially......
    The problem I am having is that I read a potentiometer into a global variable in one Cog
    I add the global variable to another variable in a second Cog and it acts like it is 0 all the time. (I know that for sure)
    (It actually varies 12 bits from 0 to 4095. And I know that for sure)
    What up?

    Harprit
  • potatoheadpotatohead Posts: 10,261
    edited 2011-07-29 20:03
    Are you using HUB instructions? Have you verified they are, in fact, pointing to the same address?

    (This is why PAR is a great idea, BTW)
  • HarpritHarprit Posts: 539
    edited 2011-07-29 20:19
    I though it might be something really silly on my part that you have seen 1000 times.
    No, not using HUB instruction
    Lets wait till I can post the code.
    Using PAR for transfer to the SPIN cog but both my other cogs are using PASM
    Par to SPIN works fine, thats how I know variable is being read right.
    One PASM cog determines variable (and xfers to SPIN via PAR) but the other one will not read it as same global name.

    Thanks
    HSS
  • potatoheadpotatohead Posts: 10,261
    edited 2011-07-29 21:55
    You need a hub operation.
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-07-30 01:09
    There is the shared HUB-RAM and to each cog exclusive COG-RAM

    If you want to transfer a value from one cog to another the only way is
    writing the value from COG1-RAM WRLONG ==> HUB-RAM
    then reading the HUB-RAM with COG2 RDLONG COG2-RAM <=== HUB_RAM

    I think it is the same with the HUB-RAM-adress itself too.This means declare a SPIN-variable and start the two cogs
    from SPIN. If you want to start the second cog from PASM do I remember right that DIRB and OUTB are existing as registers that are just not connected to any hardware?
    But can be used as some kind of global scratchpad-RAM that is easy adressable?

    keep the questions coming
    best regards

    Stefan
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-30 01:26
    StefanL38 wrote: »
    If you want to transfer a value from one cog to another the only way is writing the value from COG1-RAM WRLONG ==> HUB-RAM then reading the HUB-RAM with COG2 RDLONG COG2-RAM <=== HUB_RAM
    Have a look at [thread=129585]this thread[/thread] when you have a minute :)
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-07-30 01:56
    Hi kuroneko,

    I agree there is more than one way to communicate between cogs.
    Would you mind answering the question about DIRB/OUTB as scratchpad-RAM
    or do you insist on test it yourself :-)

    keep the improving comments coming
    best regards

    Stefan
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-30 02:04
    StefanL38 wrote: »
    Would you mind answering the question about DIRB/OUTB as scratchpad-RAM or do you insist on test it yourself :-)
    I wasn't quite sure about your use of global (unless you meant that in the context of a single cog). Both registers are just that, registers. No side effects, no outside connection(s). So feel free to use them. If you don't actively use counters then those registers are free as well. Which is true for nearly every SPR. Personally I stay away from dira for storage/code and vscl for code.

    I think Cluso's debugger uses the first four SPRs and somewhere there is a cog storage object which uses the whole SPR area.
  • HarpritHarprit Posts: 539
    edited 2011-07-30 09:09
    I am ready to post my program but the read/write routine is not working to my satisfaction (or at all)
    So the program is not runnable.
    The problem is that I can not read and write across two PASM cogs accurately.
    I am using WRLONG and RDLONG to main memory per the PASM manual (and Stephan in #143)

    I have a question (here is what I am doing)

    If I have a variable "data_read"
    in a PASM cog and then write

    WRLONG data_read, temp_var
    data_read res 1 'later on in the program to set up the variable

    and then read Temp_var into a second PASM cog with

    RDLONG time, temp_var

    should it work?..It should the way I read it.
    It does not for some reason, in my program. I get 0.

    Harprit
  • jazzedjazzed Posts: 11,803
    edited 2011-07-30 09:31
    It would be so much easier to help if you just post your code. No guessing.

    Is temp_var an address pointing to a hub memory location?

    RDLONG D, S ' D is the variable you want to read to and S is where you want to read from.
    WRLONG D, S ' D is the variable you want to write and S is where you want to write to.

    Harprit wrote: »
    I am ready to post my program but the read/write routine is not working to my satisfaction (or at all)
    So the program is not runnable.
    The problem is that I can not read and write across two PASM cogs accurately.
    I am using WRLONG and RDLONG to main memory per the PASM manual (and Stephan in #143)

    I have a question (here is what I am doing)

    If I have a variable "data_read"
    in a PASM cog and then write

    WRLONG data_read, temp_var
    data_read res 1 'later on in the program to set up the variable

    and then read Temp_var into a second PASM cog with

    RDLONG time, temp_var

    should it work?..It should the way I read it.
    It does not for some reason, in my program. I get 0.

    Harprit
  • HarpritHarprit Posts: 539
    edited 2011-07-30 09:39
    I am hesitant to do this because it is not cleaned up
    I will clean it up later. This is per JAZZED request
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    PUB null | P_Val
      cognew(@generate, @P_Val)            ' start new cog at "generate" and read variable at P_Val
      cognew(@Toggle, 0)                   ' start new cog at Toggle         
    '===========================================================================================================================
    '=======================================COG 1 works fine====================================================================
    '===========================================================================================================================
      dira[0 ..11]~~                       ' all lines are outputs except 26
      repeat                               ' endless loop to display data
        outa[0..11] := P_Val               ' displays 1.5 bytes of data                         
       
    DAT 
    
    '===========================================================================================================================
    '=======================================COG 2 works fine====================================================================
    '===========================================================================================================================
                  org 0               'sets the starting point in Cog
    generate      mov       dira,   set_dira        'sets direction of the prop pins
                  call      #chip_sel_lo            'selects chip by pulling line low
                  call      #Clk_lo                 'START. Clock needs to be low to load data
                  call      #Din_hi                 'must start with Din high to set up 3208
                  call      #Tog_clk                'clk hi to read data
               
                  call      #Din_Hi                 'SINGLE DIFF  Low to load
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                     
                  call      #Din_Lo                 'D2 Low to load input line selection sequence 000 for line 0
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                
                  call      #Din_Lo                 'D1 Low to load input line selection sequence 000 for line 0
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
               
                  call      #Din_Lo                 'D0 Low to load input line selection sequence 000 for line 0
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                     
                  call      #Din_Lo                 'blank bit needs a clock cycle, next
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
                     
                                                    'next toggle is for the null bit, nothing read
                  call      #Tog_Clk                'toggle clock line hi then low to read in the data
              
                  mov       dat_red,  #0            'Clear register we will read data into             
                  mov       count,    #12           'Counter for number of bits we will read
    read_bit      mov       temp,     ina           'read in what is in all the input lines
                  andn      temp,     inputmask wz  'mask off everything except Dout line. Set Z flag
            if_nz add       Dat_red,  #1            'if value is still positive add 1 to data register 
                  ror       Dat_red,  #1            'roll register right 1 bit to get ready for next bit
                  call      #Tog_Clk                'toggle clock to get next bit ready in Dout
                  sub       count,    #1 wz         'decrement the "bits read" counter. Set Z flag
            if_nz jmp       #read_bit               'go up and do it again if counter not 0
                  rol       dat_red,  #12           'roll back 12 bits to get data into 12 LSBits of register  
                  wrlong    dat_red, par            'put it in PAR to share it as P.Val
                  call      #Chip_Sel_Hi            'Put chip to sleep by delselecting it, for low power usage
                  rdlong    dat_red, temp2          'get data that as read    **********************************************************
                  jmp       #generate               'go back to do it all again 
     
    'Subroutines
    Clk_Hi        mov       temp,   outa            'Get the OUTA register
                  or        temp,   clk_bit         'OR it with the Clock Bit to male high
                  mov       outa,   temp            'put it back in OUTA register
    Clk_Hi_ret              ret
    
    Clk_Lo        mov       temp,   outa            'Get the OUTA register    
                  andn      temp,   clk_bit         'ANDN it with the Clock Bi to make lowt
                  mov       outa,   temp            'put it back in OUTA register
    Clk_Lo_ret              ret                     'return from this subroutine
    
    Tog_Clk       call      #Clk_hi                 'make clock bit high
                  call      #clk_lo                 'make clock bit low
    Tog_Clk_ret             ret                     'return from this subroutine
                                                
    Din_Hi        mov       temp,   outa            'Get the OUTA register
                  or        temp,   din_Bit         'Makes the Din high
                  mov       outa,   temp            'put it back in OUTA register
    Din_Hi_ret              ret                     'return from this subroutine
                                                  
    Din_Lo        mov       temp,   outa            'Get the OUTA register
                  andn      temp,   din_Bit         'makes Din low
                  mov       outa,   temp            'put it back in OUTA register
    Din_Lo_ret              ret                     'return from this subroutine
                                                    
    Chip_Sel_Hi   mov       temp,   outa            'Get the OUTA register
                  or        temp,   chs_Bit         'Makes Chip select high
                  mov       outa,   temp            'put it back in OUTA register
    Chip_Sel_Hi_ret         ret                     'return from this subroutine
                                                  
    Chip_Sel_Lo   mov       temp,   outa            'Get the OUTA register
                  andn      temp,   chs_Bit         'makes chip select low
                  mov       outa,   temp            'put it back in OUTA register
    Chip_Sel_Lo_ret         ret                     'return from this subroutine
                                                  
    Read_Dout     mov       temp,   ina             'Get the INA register
    Read_Dout_ret           ret                     'return from this subroutine
                                               
    Read_Next_Bit mov       temp,   ina             'Get the INA register
                  or        temp,   inputmask       'mask all but Din bit
    Read_Next_Bit_ret       ret                     'return from this subroutine
                  
    'Constants. This section is similar to the CON block in SPIN           
    Set_dira      long      %00001011_00000000_00000000_00000000   '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
    inputmask     long      %11111011_11111111_11111111_11111111   'Mask for reading the Dout bit only
     
    'Variables. This section is similar to the VAR block in SPIN 
    temp          res       1       'temporary storage variable 
    temp2         res       1       'temporary storage variable 
    count         res       1       'temporary storage variable
    Dat_Red       res       1       'temporary storage variable
    
    '===========================================================================================================================
    '=======================================COG 3 can't move temp2 into variable effectively====================================
    '===========================================================================================================================
                  
                  org       0              'begin a 0
    toggle        mov       dira, pin_12   'set pin 12 as output
    
    toggle1       mov       temp1,   outa  'read in outa                       
                  or        temp1, pin_12  'make pin 12 lo
                  mov       outa, temp1    'put it back in outa 
                  call      #clkdelay      'call the delay subroutine
                  
                  mov       temp1, outa    'read in outa
                  andn      temp1, pin_12  'make pin 12 high
                  mov       outa, temp1    'put it back in outa
                  call      #clkdelay      'call the delay subroutine
                  
                  jmp      #toggle1        'repeat
                 
    clkdelay      rdlong   time, temp2     'the delay subroutine,load TEMP2 into time ********ACTS LINE TEMP2=0************************
                  add      time, #$1f      'delay added to skip past underflow of CNT
    dloop         sub      time, #1 wz     'sub 1 from time and set flag if 0
            if_nz jmp      #dloop          'if flag not 0 go back to take4
    clkdelay_ret           ret             'return for delay subroutine
    
    'Constants. This section is similar to the CON block in SPIN
    Pin_12         long      %00000000_00000000_00010000_00000000
    del_time       long      400
    'Variables. This section is similar to the VAR block in SPIN
    deltime2       res      1      'temporary storage variable
    temp1          res      1      'temporary storage variable  
    time           res      1      'temporary storage variable
    
    


    Harprit
  • jazzedjazzed Posts: 11,803
    edited 2011-07-30 10:38
    You have to create variables for each cog that contains the hub address for rdlong/wrlong.

    Using temp2 will not work because it contains some other data (it can be forced to work with advanced understanding of SPIN/PASM).

    Here's a simple sharedmem.spin example (as simple as i know how to make it).
    ''
    '' SIMPLE share data demo
    ''
    
    con ' clock setup
    
            _clkmode = xtal1 + pll16x
            _clkfreq = 80_000_000
    
    var ' hub shared memory section. variables must be kept in this order
    
            long share              ' share is set to par
            long data               ' data is at share address + 4
    
    '===============================
    ' test harness
    
    obj
      sx : "FullDuplexSerial"
              
    pub main
    '' program main entry point
    
      sx.start(31,30,0,115200) ' start console at 115200 for debug output
      start ' start the producer and consumer cogs
    
      repeat ' print shared data every second
    
        sx.hex(share, 8)
        sx.tx(" ")
        sx.hex(data, 8)
        sx.tx($d)
        waitcnt(_clkfreq+cnt)
    
    '===============================
        
    pub start
    '' start producer and consumer cogs
    
      cognew(@producer, @share)
      cognew(@consumer, @share)
      waitcnt(_clkfreq+cnt)
              
    dat org
    '---------------------------------
    ' producer is used to write incrementing data to two shared hub variables
    '
    producer
                  ' par will have the hub address of share
                  ' padr will have the hub address of data
                  ' let's put the address of data in padr
                  
                  mov       padr, par               ' save par to padr
                  add       padr, #4                ' reference the second long in the shared memory
    
                  ' will increment pshare and pdata in the loop for writing
                  ' set pshare and pdata to known values
                  
                  mov       pshare, #0              ' could have used "pshare long 0" instead below   
                  mov       pdata, #0               ' could have used "pdata  long 0" instead below
    
    '---------------------------------
    ' main program loop
    '
    :loop
                  add       pshare, #1              ' increment variable
                  wrlong    pshare, par             ' write pshare to hub share variable
                  add       pdata, #1               ' increment variable
                  wrlong    pdata, padr             ' write pdata to hub data variable
                  jmp       #:loop
    
    '---------------------------------
    ' variables
    '
    pshare        res 1
    pdata         res 1
    padr          res 1
    
    dat org
    '---------------------------------
    ' consumer is used to read producer data from two shared hub variables
    '
    consumer
                  ' par will have the hub address of share
                  ' cadr will have the hub address of data
                  ' let's put the address of data in cadr
                  
                  mov       cadr, par               ' save par to padr
                  add       cadr, #4                ' reference the second long in the shared memory
    
    '---------------------------------
    ' main program loop simply reads from shared memory
    '
    :loop
                  rdlong    cshare, par             ' read pshare from hub share variable
                  rdlong    cdata, cadr             ' read pdata from hub data variable
                  jmp       #:loop
    
    '---------------------------------
    ' variables
    '
    cshare        res 1
    cdata         res 1
    cadr          res 1
    
  • HarpritHarprit Posts: 539
    edited 2011-07-30 10:52
    Jazzed:

    Let me get your ideas implemented and I will get back with the forum when I get it working

    Thanks
    Harprit
  • StefanL38StefanL38 Posts: 2,292
    edited 2011-07-30 11:40
    Hi Harprit,

    if I remember right all predefined longs (constants) like
    'Constants. This section is similar to the CON block in SPIN            Set_dira      long      %00001011_00000000_00000000_00000000   '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 inputmask     long      %11111011_11111111_11111111_11111111   'Mask for reading the Dout bit only
    

    and all reserved longs (not predefined) acting as variables
    'Variables. This section is similar to the VAR block in SPIN  temp          res       1       'temporary storage variable  temp2         res       1       'temporary storage variable  count         res       1       'temporary storage variable Dat_Red       res       1       'temporary storage variable 
    

    should be placed behind the last PASM-command.

    temp2 that should contain the HUB-RAM-adress is never initialised with a valid HUB-RAM-adress.

    You start a second cog for toggling the IO-pin 12
    The code uses temp2 as the HUB-RAM-adress. But here it is the same temp2 is not initialised with a valid HUB-RAM-adress

    As you start the second cog from SPIN too you simply use the second parameter there too.
    instead of
      cognew(@Toggle, 0)                   ' start new cog at Toggle         
    

    use
      cognew(@Toggle, @P_Val)                   ' start new cog at Toggle         
    

    With this cognew the second cog has the HUB-RAM-adress of variable P_Val in its PAR-register
    and can be accessed with
    clkdelay      rdlong   time, par     'the delay subroutine,load TEMP2 into time ********ACTS LINE TEMP2=0************************ 
    

    another comment on your variable names

    using temp1, temp2 is bad programming style. The names temp1, temp2 don't say anything about their purpose.
    If you think about the code your brain has to do some extra work translating temp1 contains bitpattern of outa
    temp2 contains HUB-RAM-adress of P_Val. This extra brain-work makes it harder to understand for beginners.

    Variable-names should be selfexplaining.
    P_Val says almost nothing. "MCP3802_ADC_Val1" is self-explaining

    As you write a book for PASM-beginners I even would define a variable for par.
    So the codeline looks like this
                 'the delay subroutine
                 'the value of the SPIN-variable P_Val accessed through its HUB-RAM-adress "HUB_RAM_Adr_of_ADC_Val1"
                 'is used as start-value for the variable named "time" which is counted down to zero
                 'in a loop to generate a delay 
    clkdelay      rdlong   time, HUB_RAM_Adr_of_ADC_Val1 
    

    I also added a comment of 4 lines to explain its purpose in detail.
    That's what I would call easy to understand

    "HUB_RAM_Adr_of_ADC_Val1" is a quite long name I guess for 50-90% of all programmers too long but it is self-explaining
    maybe something like "HR_Ptr_ADC1" is still saying enough if you use the leading characters "HR_Ptr" as a short name for H)ub-R)am-Pointer all the the time
    whenever you use RDLONG or WRLONG.

    If somebody says: "too many characters to type". I'm using Ctrl-Cursor Ctrl-Shift-curcor Ctrl-C, Ctrl-v all the time and this even avoids typos.
    When writing the variable names with ctrl-c/v it doesn't matter how long they are. always the same amount of keypresses.

    I guess if you use self-explaining variable-names it will be easier for yourself to find bugs.
    And you are giving a good model for beginners how to write code in a good style.

    keep the questions coming and continue to post your code

    best regards

    Stefan
  • jazzedjazzed Posts: 11,803
    edited 2011-07-30 12:44
    StefanL38 wrote: »
    Hi Harprit,

    if I remember right all predefined longs (constants) like
    'Constants. This section is similar to the CON block in SPIN
    Set_dira      long      %00001011_00000000_00000000_00000000   'Set dira register                                                                                     ...
    

    and all reserved longs (not predefined) acting as variables
    'Variables. This section is similar to the VAR block in SPIN  temp          res       1       'temporary storage variable  temp2         res       1       'temporary storage variable  count         res       1       'temporary storage variable Dat_Red       res       1       'temporary storage variable 
    

    should be placed behind the last PASM-command.
    Longs can be put anywhere. Any long that does not have the upper 16 bits (more or less) set will be treated as a NOP instruction. Often when pressed for space, variables are put in an initialization section where the init code can be over-written. The "RES" variables absolutely must be put at the end of a DAT section for a COG because RES does not allocate space for the variables.

    Just my personal preference and you can ignore this if you like, but I like shorter variable names and comment decorations. Variable names should communicate their purpose without expanding into sentences like VariableNamesShouldCommunicateTheirPurpose. Huge comment decorations are wasteful and generally tell the reader things about the programmer that may not be interpreted as intended.

    Please consider trimming any code or comment line which has more than 70 characters.

    "MOV OUTA, PEACE"
Sign In or Register to comment.