What are masks and how do they work?
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:
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:
..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/
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
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.
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 '  <-- channel 1 '  <-- 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/
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
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
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
- 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).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/build
http://forums.parallax.com/showthread.php?p=601870
(its under "Assembly Code Examples for the beginner - Many contributors" in the getting started sticky)
James
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
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
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.