Shop OBEX P1 Docs P2 Docs Learn Events
What are masks and how do they work? — Parallax Forums

What are masks and how do they work?

SciNemoSciNemo Posts: 91
edited 2009-10-13 14:09 in Propeller 1
I am working on a project that involves a row of 8 led's. I've found this nifty chunk of pasm called "Mother of all LED Sequencers" that should do what I want. The only problem is this:

ledmask long $00FF0000       ' 8 LED's at I/O pins 16 to 23 for the demo board



I know that the hex is called a mask, and I thought I knew how they worked, but it seems I do not. I tried this:

ledmask long %00000000000000000000111111110000



..because I want it to use pins 4 through 11, but it does not work. Is my understanding of masks correct? Aren't they just like a row of switches that show which ports to turn on or off (in this case at least)?

So how do I change the hex to make it use pins 4 through 11, and why doesn't my modified code work?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Not the fish.
sites.google.com/site/bitwinproject/

Comments

  • localrogerlocalroger Posts: 3,452
    edited 2009-10-11 22:42
    The mask doesn't determine which bits get flipped; it keeps other bits from getting flipped as you're flipping the ones you're interested in. So you need to change the mask, but somewhere else in the code you must also change the bits that are getting flipped so that they are within the range of the changed mask. Presumably you don't want to turn all 8 LED's on and off at the same time, you want to set a pattern; that also needs to be moved to the new pins.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-10-11 22:42
    It's impossible to tell why your modified code doesn't work since you've not included all of the code. Changing "ledmask" as you've done is the right idea, but there may be other parts of the program that makes assumptions about which I/O pins are being used.

    The term "mask" has different uses. In this case, you have a 32-bit word where each of the bits has a particular meaning (an I/O pin number). You have a constant "ledmask" where there are bits set to 1 where an I/O pin is used by the program. Typically, this mask is copied to the data direction register or sometimes used for the data output register value.
  • SciNemoSciNemo Posts: 91
    edited 2009-10-11 22:46
    Here is the code I am using:

    CON
    
      _clkmode        = xtal1 + pll16x
      _xinfreq        = 5_000_000
    
    PUB Main
    
      cognew(@Step000,@Pat1)
    
      repeat
    
    DAT
            org     0
    {   Step000 initialize   }
    Step000 or      DIRA, ledmask           ' Set output lines in the direction register
            mov     Time, delay             ' Setup arbitrary initial $01312D00
            add     Time, cnt               
    
    { Step010 setup the first sequence }
    :Step010
            mov     P0,par                  ' Get data patterns starting address
            mov     P1,P0                   ' Setup working pointer
            rdlong  Reps,P1                 ' Get Repetition count
            add     P1,#4                   ' Advance pointer to sequence timing
            rdlong  Dly,P1                   'Get sequence timing
    
    { Step020 set working pointer to start of sequence }
    :Step020
            mov     P2,P1                    'P1 points to sequence timing
            add     P2,#4                    'P2 now points to element count
            
    { Step030 get element count }
    :Step030
            rdlong  Ectr,P2               ' Get element count
            
    { Step040 get next pattern element }
    :Step040
            add     P2,#4                 ' Advance pointer to next element
            rdlong  T1,P2                 ' Get the pattern
            
    { Step050 turn on leds }
    :Step050
            xor     T1,#0                  ' For the Demo Board 03ff0000 (ledmask) for the PropRPM
    '        xor     T1,ledmask             ' For the PropRPM
            mov     outa,T1                ' Set the pattern in T1
            
    { Step060 wait }
    :Step060                                ' wait, until wakeup time, then add Dly
            waitcnt Time, Dly               ' to time which becomes time of next wakeup
            
    { Step070 test for end of current sequence }
    :Step070
            djnz    ECtr,#:step040
                    
    { Step080 test for end of sequence repetitions }
    :Step080
            djnz    Reps,#:step020
    
    { Step090 get next sequence }
    :Step090
            add     P2,#4             ' Advance pointer to Reps of next sequence
            mov     P1,P2
            rdlong  Reps,P1           ' Get repetition count
            add     P1,#4             ' Advance working pointer to first element
            rdlong  Dly, P1           ' Get the sequence timing
                           
    { Step100 test for last sequence }
    :Step100
            tjz     Reps,#:Step010    ' if end of patterns start all over again
            jmp     #:Step020         ' else start the next pattern
    
            
    ' ===========================================================================================
    ' in the data below the sequence clock is calculated by dividing clkfreq by the desired period
    ' and converting to hex  for example: 1/4 second = clkfreq/4 = HEX(80_000_000/4) = $01312D00
    '----------------- < I have precalculated some common clock periods here > ----------------
    '   1/2 --> $02625A00      1/3 --> $0196E6AA        1/4 --> $01312D00       1/5 --> $00F42400
    '   1/6 --> $00C67355      1/7 --> $00AE62DB        1/8 --> $00989680       1/9 --> $0087A238
    '  1/10 --> $007A1200     1/16 --> $004C4640       1/20 --> $003D0900      1/25 --> $0030D400
    '  1/30 --> $002860AA     1/32 --> $002625A0       1/40 --> $001E8480      1/50 --> $00186A00
    '  1/64 --> $001312D0    1/100 --> $000C3500      1/128 --> $00098968     1/200 --> $00061A80
    ' 1/256 --> $0004C464    1/500 --> $00027100      1/512 --> $0002625A    1/1000 --> $00013880
    '1/1024 --> $0001312D   1/2000 --> $00009C40     1/2048 --> $00009896    1/2500 --> $00007D00
    
    '          ------------ << PATTERN DATA >> ---------------
    ' One light from each edge to center and back 5 times
    Pat1  long  25, $002625A0, 9                   '$0196E6AA = 1/32 second
          long  $00810000, $00420000, $00240000, $00180000, $00000000, $00180000, $00240000, $00420000
          long  $00810000
    ' Two lights from each edge to center and back 5 times
    Pat2  long  5, $00989680, 11                   '$01312D00 = 1/8 second
          long  $00810000, $00C30000, $00660000, $003C0000, $00180000, $00000000, $00180000, $003C0000
          long  $00660000, $00C30000, $00810000
    ' Shift from all off to all on 5 times
    Pat3  long  5, $002625A0, 32                   '$002625A0 = 1/32 second
          long  $00010000, $00030000, $00070000, $000F0000, $001F0000, $003F0000, $007F0000, $00FF0000
          long  $00FE0000, $00FC0000, $00F80000, $00F00000, $00E00000, $00C00000, $00800000, $00000000
          long  $00800000, $00C00000, $00E00000, $00F00000, $00F80000, $00FC0000, $00FE0000, $00FF0000
          long  $007F0000, $003F0000, $001F0000, $000F0000, $00070000, $00030000, $00010000, $00000000
    ' Alternate between left 4 and right four 5 times
    Pat4  long  25, $01312D00,  2              '$01312D00 = 1/4 second
          long  $000F0000, $00F00000
    ' Four lights shifting left and right 5 times
    Pat5  long  5, $01312D00,  9
          long  $000F0000, $001E0000, $003C0000, $00780000, $00F00000, $00780000, $003C0000, $001E0000
          long  $000F0000
    ' Light one at a time from left to right and back 5 times
    Pat6  long  5, $01312D00, 16
          long  $00010000, $00020000, $00040000, $00080000, $00100000, $00200000, $00400000, $00800000
          long  $00800000, $00400000, $00200000, $00100000, $00080000, $00040000, $00020000, $00010000
    'One light sliding left and right leaving a light on at each direction change till all on and then reverse
    Pat7  long  15, $001312D0, 57                  '001312D0 =  1/64 second
          long  $00800000, $00C00000, $00A00000, $00900000, $00880000, $00840000, $00820000, $00810000
          long  $00830000, $00850000, $00890000, $00910000, $00A10000, $00C10000, $00E10000, $00D10000
          long  $00C90000, $00C50000, $00C30000, $00C70000, $00CB0000, $00D30000, $00E30000, $00F30000
          long  $00EB0000, $00E70000, $00EF0000, $00F70000, $00FF0000, $00F70000, $00EF0000, $00E70000
          long  $00EB0000, $00F30000, $00E30000, $00D30000, $00CB0000, $00C70000, $00C30000, $00C50000
          long  $00C90000, $00D10000, $00E10000, $00C10000, $00A10000, $00910000, $00890000, $00850000
          long  $00830000, $00810000, $00820000, $00840000, $00880000, $00900000, $00A00000, $00C00000
          long  $00800000
    ' Every other light alternating 5 times
    Pat8  long  25, $01312D00,  2
          long  $00AA0000, $00550000
    ' right four (low nibble) count up 0-15 & left four (high nibble) count down 15-0
    Pat9  long  20, $001312D0, 16               ' 1/64 second
          long  $00810000, $00420000, $00c30000, $00240000, $00a50000, $00660000, $00e70000, $00180000
          long  $00990000, $005a0000, $00db0000, $003c0000, $00bd0000, $007e0000, $00ff0000, $00000000
    ' fill from center left and right to the edge and back
    PatA  long  10, $01312D00,  8
          long  $00180000, $003c0000, $007f0000, $00ff0000, $007f0000, $003c0000, $00180000, $00000000
    'left right left right moving towards center each time
    PatB  long  50, $00186A00,  8
          long  $00800000, $00010000, $00400000, $00020000, $00200000, $00040000, $00100000, $00080000
    'For PropPM Board using 10 lights all off, one on moving from one end to the other and repeat
    PatC  long  5, $01312D00, 10
          long  $00010000, $00020000, $00040000, $00080000, $00100000, $00200000, $00400000, $00800000
          long  $01000000, $02000000      
    'For PropPM Board using 10 lights all on,  one off moving from one end to the other and repeat
    PatD  long  3, $02625A00, 10                '$02625A00 = 1/2 second
          long  $03FE0000, $03FD0000, $03FB0000, $03F70000, $03EF0000, $03DF0000, $03BF0000, $037F0000
          long  $02FF0000, $01FF0000
    PatEnd  long  0
    
    ' Generate this waveform by passing Wave as the starting pattern. The timing word is 72_727 clocks 
    '  calculated as follows: 72_727 = clkfreq * period (seconds)/element count = 80_000_000*0.010/11
    ' &#61569;&#61570;&#61573;&#61569;&#61570;&#61573;&#61569;&#61570;&#61574;&#61574;&#61573;&#61569;&#61570;&#61573;&#61569;&#61570;&#61573;&#61569;&#61570;&#61574;&#61574;&#61573;&#61569;&#61570;&#61573;&#61569;&#61570;&#61573;&#61569;&#61570;&#61574;&#61574;&#61573;      <-- channel 1
    ' &#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61570;&#61573;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61570;&#61573;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61569;&#61570;&#61573;&#61569;      <-- channel 2  10 ms rising edge to rising edge
    Wave    long  $ffffffff, $00011C17, 11
            long  $00010000, $00000000, $00000000, $00010000, $00000000, $00000000, $00010000
            long  $00030000, $00010000, $00000000, $00000000
            long  0
    
    
    '   INITIALIZED VARIABLES        
    delay   long  $01312D00      'Totally arbitrary startup delay
    
    '=======<< choose one of these to match the board you are using >========
    ledmask long $0000ff00  ' 8 LED's at I/O pins 16 to 23 for the demo board
    
    '   UNINITIALIZED VARIABLES
    P0      res   1         'Data starting address pointer
    P1      res   1         'Current pattern starting address pointer
    P2      res   1         'Current element address pointer
    ECtr    res   1         'Element counter
    Reps    res   1         'Element repetition count
    Dly     res   1         'Sequence Timing clock period
    Time    res   1         'Holds the next wakeup time 
    T1      res   1         'Temp variable
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Not the fish.
    sites.google.com/site/bitwinproject/
  • kuronekokuroneko Posts: 3,623
    edited 2009-10-12 00:39
    From a quick glance, you changed the mask (I assume your LEDs are actually connected to pins 8-15) but the patterns are still set for pin 16-23. So in :Step050 you want something like shr T1, #8.
  • SciNemoSciNemo Posts: 91
    edited 2009-10-12 22:51
    My leds are actually connected to pins 4-11, as I said in my initial post. I have changed that line of code like you suggested, and now 4 of the LEDs light up. Changing it to #4 or #12 does not make the other leds light up.

    Update: Fixed it, although i am not really sure how. This part is changed:

    { Step050 turn on leds }
    :Step050
            shr     T1,#12
            mov     outa,T1                ' Set the pattern in T1
    



    And:

    ledmask long %0000000000000000111111110000
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Not the fish.
    sites.google.com/site/bitwinproject/

    Post Edited (SciNemo) : 10/12/2009 11:31:29 PM GMT
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-10-12 23:41
    This is a most timely post as I'm about to start writing some code to do something similar. I think I understand the question, but I don't understand the solution (yet!).

    I know how to turn pins on and off. But not how to prevent other pins changing - eg you don't want the vga display going haywire when another pin changes.

    Could some kind soul explain (and it may only be a couple of lines of pasm code) how to:

    1) set a mask so only pin 1 ever changes when outputting a 32 bit long.
    2) turn pin 1 high
    3) turn pin 1 low

    and then, just to make it explicitly clear, set a new mask that
    4) only allows pin 2 to change
    5) turns pin 2 high
    6) turns pin 2 low

    I think I am close to understanding this. Presumably there is something like a logical 'and' with xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0 to set pin 1 low and a logical 'or' with xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1 to set that pin high. What I'm not 100% clear about is whether 'x' matters if you have already set a mask earlier?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/build
  • localrogerlocalroger Posts: 3,452
    edited 2009-10-12 23:51
    Dr_Acula -- You need to remember that each COG has its own OUTA register. If any cog has DIRA set for a pin, that pin becomes an output; of course more than one can try, and all of the cogs that choose to OUTA a bit get ORed together. So to keep your code from interfering with other COGs, all you have to do is keep DIRA and OUTA to 0 on the pins you're not using. That's what the mask is for.

    So for what you ask, you'd do something like...

    and bitpatt, #1
    mov outa,bitpatt    'turns low/high
    xor bitpatt, negone 'inverts entire pattern by xoring with $FFFF_FFFF
    and bitpatt,#1      'again isolate the bit
    mov outa,bitpatt    'turns high/low
     
    ..
    negone long $FFFF_FFFF   'you need this to do NOT via XOR
    



    Then, to manipulate bit 2 instead, you'd just change the #1's to #2's (or move them to a mask long that can be changed).

    Post Edited (localroger) : 10/12/2009 11:57:07 PM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2009-10-13 01:50
    SciNemo said...
    Update: Fixed it, although i am not really sure how. This part is changed:

    { Step050 turn on leds }
    :Step050
            shr     T1,#12
            mov     outa,T1                ' Set the pattern in T1
    


    And:

    ledmask long %0000000000000000111111110000
    

    OK, the program you're using is supposed to run on the demo board (ignoring the PropPM comments for now). Which means:
    • 8 contiguous LEDs
    • LED block is located at pin 16..23
    Point one gives us the mask which is 0xFF (i.e. 8 (contiguous) bits set), point two the bit offset in a long and therefore the final mask value 0xFF << 16 = 0x00FF0000. The data you sent to outa is only loosely related to the mask set in dira. But if you want to see something on your output pins then it should uses the same bit locations [noparse]:)[/noparse] So the 8bit LED data has to be shifted by 16 too (there is no point sending the LED pattern to bits 0..7 in outa, they are set as inputs so it wouldn't have any effect) . If you look at the data table this becomes obvious (0x00--0000).

    Back to your requirements. You have your LEDs connected to pins 4..11. Therefore the mask for those 8 output pins is 0xFF << 4 = 0x00000FF0. The existing data is pre-shifted by 16. As you need them only shifted by 4 you have to undo the shl #16 and then apply a shl #4. The undo is a shr #16. Combined with your required shl #4 that becomes shr #12.

    The shr #8 I mentioned before was to match your mask (0x0000FF00). So for LEDs connected to 4..11 that would (obviously) only light up 4 of them (0x0000FF00 defines pins 8..15 as outputs which only covers pin 8..11 of your requirement).
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-10-13 04:52
    Thanks localroger, I'm going to be putting that to use right away!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/build
  • JavalinJavalin Posts: 892
    edited 2009-10-13 09:36
    A very good PASM tuturial was written by Beau after I asked similar questions ages ago

    http://forums.parallax.com/showthread.php?p=601870

    (its under "Assembly Code Examples for the beginner - Many contributors" in the getting started sticky)

    James
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-10-13 11:46
    Ok, I'm on the steep part of the learning curve (SciNemo is a bit ahead of me!).

    Since last post, some boards I designed have arrived and I'm happily testing things. Got text on a vga screen from a keyboard. But I still don't understand it all. I keep thinking in 8 bit and with instructions like 'rotate' that rotate just one place per instruction. I'm still not used to rotating a variable number of places in one instruction.

    But I worked out how instructions work that mask a certain pin. Nothing new for veterans, but I think it is cunning. You set a variable equal to the pin number, eg 14 (decimal). In a binary long that is 00000000000000000000000000001110. You then convert that to a mask with just two machine code instructions:
    mov mymask,#1
    shl mymask,pinnumber
    
    


    Ok, 4 instructions really as I think mymask needs some space reserved and pinnumber needs to be set to 14. Still getting my head around setting variables at the end of a program rather than the beginning.

    But it is cunning nevertheless as it replaces multiple instructions in a loop in 8 bit assembly with a rotate left by n.

    I *think* I understand the next bit. My understanding from the documentation is that you can set the status of a bit and mask it all with one instruction. I thought I understood that. But now I don't.

    Ok, I'm looking at the code in the standard keyboard.spin object. There is this line:
    transmit
    _c1                     or      dira,cmask              'pull clock low
    
    


    But how does that pull a line low?

    Ok, earlier I think it set cmask as something like 0000001000000 ie one bit set high. (not 100% sure though) But if you OR that, isn't that setting the bit high, not low. The xor bit under this makes sense as that flips the bit, but I don't understand how an OR pulls a pin low. There is something I don't understand here as I would have thought that definitely setting a pin high would be an OR with 1 (and definitely setting it low is an AND with 0).

    Even though I am very confused, I think I am working out enough to write some raw pasm now rather than just do the script kiddie thing.

    Help with the above would be most appreciated.

    Addit: Hmm - is this right? or dira,mymask sets the mask of that pin only (that is the OR) bit. But it also defaults to setting the pin low to start with? Is that right? Then you xor it to make it high?

    This is theoretical as I can't seem to be able to put assembly instructions in the PUB main. I take it you can't do that.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/build

    Post Edited (Dr_Acula) : 10/13/2009 12:07:32 PM GMT
  • localrogerlocalroger Posts: 3,452
    edited 2009-10-13 12:26
    Dr_Acula:· re: or·dira,cmask, that is a bit sneaky.· Remember that if a bit in DIRA is 0 it's an input.· If OUTA contains 0 on that bit and you write 1 to DIRA, it will pull the pin low.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-10-13 13:09
    Ah, yes that is sneaky!

    I'm working with spin at the moment sending pins high and low. All working very nicely. Lots of pauses to test things and the logic probe is getting a workout. Down the track I'll translate to pasm. One cool thing I have found is that HCT logic works fine at 3V. I knew HC did, but I wasn't sure about HCT.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/build
  • JonnyMacJonnyMac Posts: 9,202
    edited 2009-10-13 14:09
    Setting (defined output) pins high and low with a mask in PASM is very easy... use or to set (high) masked (1) pins, andn to clear (low) them. For example, you could toggle P0 really fast like this:

    asm                     mov     dira, #%1                       ' P0 is an output
    :loop                   or      outa, #%1                       ' make high
                            nop
                            andn    outa, #%1                       ' make low
                            jmp     #:loop
    



    The andn instruction (which has been around in Parallax languages since the BASIC Stamp 1) is really useful -- it allows us to use one mask for setting (with or) and clearing (andn) desired bits.
Sign In or Register to comment.