Shifting pins?
I've been away from the Propeller for a while and have been reading through the old projects to try to get up to speed on SPIN again.
Came across this in the TFT display code:
'pin definitions from tft.h. The pin manipulation
'macros have been converted to PRI functions.
CS_BIT = $04 << 8
RS_BIT = $08 << 8
WR_BIT = $10 << 8
RD_BIT = $20 << 8
Ok, so the pin assignments are shifted left 8 bits?
CS_BIT = $12
RS_BIT = $16
WR_BIT = $18
RD_BIT = $28
My question - what the advantage of specifying pin assignments with the shift operators?
Came across this in the TFT display code:
'pin definitions from tft.h. The pin manipulation
'macros have been converted to PRI functions.
CS_BIT = $04 << 8
RS_BIT = $08 << 8
WR_BIT = $10 << 8
RD_BIT = $20 << 8
Ok, so the pin assignments are shifted left 8 bits?
CS_BIT = $12
RS_BIT = $16
WR_BIT = $18
RD_BIT = $28
My question - what the advantage of specifying pin assignments with the shift operators?

Comments
pub pushData(data)
all_pin_low
outa |= (data << 2) ' bitwise OR (data shifted left two bits) ???
Bitwise OR what with what?
In the second post of yours, the data is shifted left two bits, then OR'd with OUTA because the I/O pins involved start with pin # 2 and go up from there (3, 4, ...). When the bits of OUTA are changed, the I/O pins change as well ... at least those that are configured as outputs.
Pre-computing the read / write versions of that value makes the code a little faster, but just storing them as raw values makes the correlation with the datasheet value harder, so they're often written with the shifts included. It's easy to see that ($3C<<1) is related to the address $3C from the datasheet, but $78 and $79 don't look anything like it.
Related to video, the Propeller output registers are arranged in groups of 8 pins. If the author of the TFT device code is using the video hardware to shift out data, he might have specified the pins as indices within the 8, then shifted them up to the correct pin group.
I can't guarantee that's what is happening in this case, but it's often the reason things are done this way.
It's from Local Roger's work on the TFT display.
I'm trying to figure out two things right now:
How the program communicated with (and controls) the display.
How the mailbox system works.
Here is the whole thing: except the whole thing doesnt fit in a message.
Currently runs on Martin Hodge' ASC board with the Radio Shack TFT display installed.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 'RTR Colors RED = $f800 GREEN = $07e0 BLUE = $001f BLACK = $0000 YELLOW = $ffe0 WHITE = $ffff CYAN = $07ff BRIGHTRED = $f810 ' looks PINK to me GRAY1 = $8410 GRAY2 = $4208 'TFT resolution 240*320 TFT_Min_X = 0 TFT_Min_Y = 0 TFT_Max_X = 240 TFT_Max_Y = 320 'TDT Direction Portrait = 0 Landscape = 1 'pin definitions from tft.h. The pin manipulation 'macros have been converted to PRI functions. CS_BIT = $04 << 8 RS_BIT = $08 << 8 WR_BIT = $10 << 8 RD_BIT = $20 << 8 'Macro definitions for char display direction LEFT2RIGHT = 0 DOWN2UP = 1 RIGHT2LEFT = 2 UP2DOWN = 3 'PASM mailbox commands #0 pmb_idle pmb_sendCMD pmb_sendDATA pmb_repeat 'set data "extra" iterations (1 is free) ' SendRegister isn't used in the demo. obj num : "Simple_Numbers" var LONG MS001 long PASM_mailbox byte DisplayDirect, atX, atY, a, b, atSize, ch, lin, col, TextColor pub main init MS001 := CLKFREQ / 1_000 ' define 1 millisec ' PatternExercises repeat TFT_DirplayDirect(Landscape) TFT_CLS TFT_Color(BLACK) Pattern1A Delay(6000) TFT_CLS TFT_Color(BLACK) Pattern1B Delay(6000) TFT_CLS TFT_Color(BLACK) Pattern2A Delay(4000) pri Pattern1A 'Small ' draw some ASCII letters according to DisplayDirect ' March 15, 2015 - uses the entire display via TFT_Char pointers ' TFT_Char( ch, atX+col*8*atSize, atY+lin*9*atSize, atsize, YELLOW) atSize := 1 repeat col FROM 0 to 9 repeat lin from 34 to 0 ch := col + "0" TFT_Char( ch, col*8*atSize, lin*9*atSize, atsize, YELLOW) repeat col FROM 0 to 9 repeat lin from 34 to 0 ch := col + "A" TFT_Char( ch, 80 + col*8*atSize, lin*9*atSize, atsize, BRIGHTRED) repeat col FROM 0 to 9 repeat lin from 34 to 0 ch := col + "K" TFT_Char( ch, 160 + col*8*atSize, lin*9*atSize, atsize, GREEN) TFT_Char( "X", 200 + 16*8*atSize, 160*9*atSize, atsize, BLUE) PRI Pattern1B repeat col FROM 9 to 0 ' columns 30 characters repeat lin from 34 to 0 ' lines ch := col +"A" TFT_Char( ch, col*8*atSize, lin*9*atSize, atsize, YELLOW) TFT_Char( ch, 80 + col*8*atSize, lin*9*atSize, atsize, RED) TFT_Char( ch, 160 +col*8*atSize, lin*9*atSize, atsize, GRAY1) delay ( 3000) repeat col FROM 0 to 09 ' columns 30 characters repeat lin from 34 to 0 ' lines TFT_Char( ch++, 80 + col*8*atSize, lin*9*atSize, atsize, Yellow) ch := 0 delay ( 3000) repeat col FROM 0 to 09 ' columns 30 characters repeat lin from 34 to 0 ' lines TFT_Char( ch++, 160 + col*8*atSize, lin*9*atSize, atsize, Yellow) ' --------------------------------------------------- pri Pattern2A 'Medium ' draw some ASCII letters according to DisplayDirect ' uses the entire display! atX := 0 atY := 0 atSize := 2 repeat lin from 17 to 0 ' lines 18 lines repeat col FROM 7 to 0 ' columns 8 columns ch := col + "0" 'create an ASCII character TFT_Char( ch, atX+col*8*atSize, lin*9*atSize, atsize, RED) TFT_Char( ch, 128+col*8*atSize, lin*9*atSize, atsize, RED) repeat lin from 17 to 0 ' lines 18 lines repeat col FROM 7 to 0 ' columns 8 columns ch := col + "A" 'create an ASCII character TFT_Char( ch, atX+col*8*atSize, lin*9*atSize, atsize, Yellow) TFT_Char( ch, 128+col*8*atSize, lin*9*atSize, atsize, Yellow) ' --------------------------------------------------- pri Pattern2B 'Medium ' draw some ASCII letters according to DisplayDirect ' uses the entire display! atX := 0 atY := 0 atSize := 2 repeat lin from 0 to 17 repeat col FROM 7 to 0 ch := col + "0" TFT_Char( ch, col*8*atSize, lin*9*atSize, atsize, BLUE) TFT_Char( ch, 128+col*8*atSize, lin*9*atSize, atsize, RED) Pri Land1 ' Landscape1 display ' Y axis runs backwards now and is the psuedo X axis for Landscape1 ' X asix runs forward and is used as the landscape Y axiz ' fails atY := 256, and wraps around above that? TFT_Color(black) TFT_DirplayDirect(1) atX := 0 atY := 255 ' fails at 256 or above atSize := 3 repeat lin from 0 to 9 ' lines repeat col FROM 0 to 9 ' columns ch := col + "0" 'create an ASCII character TFT_Char( ch, atX+lin*8*atSize, atY-col*8*atSize, atsize, CYAN) ' --------------------------------------------------- ' --------------------------------------------------- pub TFT_String(ptr, poX, poY, size, fgcolor) | c repeat c := byte[ptr++] if c == 0 ' zero terminated String return TFT_Char(c, poX, poY, size, fgcolor) ' char at X, Y, Size, Color if (DisplayDirect == LEFT2RIGHT) 'Portrait0 if(poX < TFT_Max_X) poX += 8*size 'Move cursor right = 0 = OK elseif (DisplayDirect == DOWN2UP) 'Landscape1 ' if(poY >0) ' poY -= 8*size if(poY < TFT_Max_Y -16*Size) poY -= 16*size 'Move cursor up = 1 elseif (DisplayDirect == RIGHT2LEFT) 'Portrait2 (upside down) if(poX > 0) poX -= 8*size 'Move cursor leftright = 2 elseif (DisplayDirect == UP2DOWN) ' Landscape3 (upside down&backwards) if(poY < TFT_Max_Y) poY += 8*size 'Move cursor down = 1 ' --------------------------------------------------- pub TFT_Char(ascii, poX, poY, size, fgcolor) | i, f, temp ' TFT_Char( ch, ATX+col*8*ATSize, ATY+lin*9*ATSize, ATsize, ATColor) ' setXY(poX,poY) if ((ascii < $20) or (ascii > $7e)) 'Unsupported char. ascii := "?" repeat i from 0 to 7 temp := byte[@Font+(ascii-$20)*8 +i] repeat f from 0 to 7 if ((temp>>f) & $01) if (DisplayDirect == LEFT2RIGHT) fillRectangle(poX+i*size, poY+f*size, size, size, fgcolor) elseif (DisplayDirect == DOWN2UP) fillRectangle(poX+f*size, poY-i*size, size, size, fgcolor) elseif (DisplayDirect == RIGHT2LEFT) fillRectangle(poX-i*size, poY-f*size, size, size, fgcolor) elseif (DisplayDirect == UP2DOWN) fillRectangle(poX-f*size, poY+i*size, size, size, fgcolor) 'from arduino library in arduino verion ' --------------------------------------------------- pub TFT_Color(cc) | i, f sendmultidata(cc, 38400 * 2) delay (50) return ' --------------------------------------------------- pub TFT_CLS | i, f sendmultidata(black, 38400 * 2) return ' --------------------------------------------------- pub TFT_LineOrientation(HV) ' Horizontal or Vertical sendCommand($03) if HV==1 'vertical senddata($5038) else 'horizontal senddata($5030) sendcommand($0022) 'start writeing to display RAM ' --------------------------------------------------- pub TFT_DirplayDirect(Direction) DisplayDirect := Direction ' --------------------------------------------------- pub setXY(poX, poY) sendCommand($0020) 'X sendData(poX) sendCommand($0021) 'Y sendData(poY) sendCommand($0022) 'Start to write to display RAM ' --------------------------------------------------- pub setPixel(poX, poY, color) setXY(poX,poY) sendData(color) ' --------------------------------------------------- pri delay(msec) waitcnt(cnt + clkfreq / 1000 * msec) pub init cognew(@tft_pasm_image, @pasm_mailbox) delay(100) sendcmdseq(@initseq1) delay(100) sendcmdseq(@initseq2) delay(100) sendcmdseq(@initseq3) delay(100) sendcommand($0007) senddata($0133) delay(50) exitstandby sendcommand($0022) ' TFT_CLS pub exitStandBy sendCommand($0010) sendData($14E0) delay(100) sendCommand($0007) sendData($0133) '-------------------------------------------------------- pri all_pin_input dira &= !all_pin_mask pri all_pin_output dira |= all_pin_mask pri all_pin_low ' outa &= !all_pin_mask ' These were defined as macros in the Arduino version pri CS_OUTPUT DIRA |= CS_BIT pri CS_HIGH OUTA |= CS_BIT pri CS_LOW OUTA &= !CS_BIT pri RS_OUTPUT DIRA |= RS_BIT pri RS_HIGH OUTA |= RS_BIT pri RS_LOW OUTA &= !RS_BIT pri WR_OUTPUT DIRA |= WR_BIT pri WR_HIGH OUTA |= WR_BIT pri WR_LOW OUTA &= !WR_BIT pri RD_OUTPUT DIRA |= RD_BIT pri RD_HIGH OUTA |= RD_BIT pri RD_LOW OUTA &= !RD_BIT pub pushData(data) ' all_pin_low outa |= (data << 2) pub getData ' delay(1) return (INA & $fc) >> 2 pub sendCommand(index) pasm_mailbox := index << 8 + pmb_sendcmd 'repeat while pasm_mailbox <> 0 pub sendData(data) pasm_mailbox := data << 8 + pmb_senddata 'repeat while pasm_mailbox <> 0 pub sendMultiData(data, qty) if qty > 1 pasm_mailbox := (qty - 1) << 8 + pmb_repeat sendData(data) repeat while pasm_mailbox <> 0 pri SendCmdSeq(ptr) | c, d ' repeat c := word[ptr] if c == $FFFF return ptr += 2 d := word[ptr] ptr += 2 sendcommand(c) senddata(d) '-------------------------------------------------------------- dat ' PAR passes the address of the Long mailbox. ' ' Mailbox = 0 = idle ' Low byte mailbox determines function org TFT_PASM_IMAGE ' 'InitStart ' mov outa,#0 mov dira,all_ctl_mask tpi_clear mov tmp, par wrlong zero, tmp ' tpi_loop mov tmp,par rdlong pmb_data, tmp test pmb_data, pmb_data wz if_z jmp #tpi_loop mov tmp,pmb_data and tmp,#$FF cmp tmp,#pmb_repeat wz if_z shr pmb_data,#8 if_z mov rcount, pmb_data if_z jmp #tpi_clear cmp tmp,#pmb_sendCMD wz if_nz jmp #tpi_notCMD ' dloop andn outa,cs_bit_mask andn outa,rs_bit_mask or outa,rd_bit_mask or outa,wr_bit_mask andn outa,wr_bit_mask andn outa,all_pin_mask 'or with zero is free or outa,wr_bit_mask andn outa,wr_bit_mask mov tmp,pmb_data shr tmp,#6 and tmp,all_pin_mask andn outa,all_pin_mask or outa,tmp or outa,wr_bit_mask or outa,cs_bit_mask jmp #tpi_clear tpi_notCMD cmp tmp,#pmb_sendDATA wz if_nz jmp #tpi_clear :loop andn outa,cs_bit_mask or outa,rs_bit_mask or outa,rd_bit_mask andn outa,wr_bit_mask ' andn outa,all_pin_mask mov tmp,pmb_data shr tmp,#14 and tmp,all_pin_mask or outa,tmp or outa,wr_bit_mask andn outa,wr_bit_mask andn outa,all_pin_mask mov tmp,pmb_data shr tmp,#6 and tmp,all_pin_mask or outa,tmp or outa,wr_bit_mask or outa,cs_bit_mask test rcount, rcount wz if_z jmp #tpi_clear sub rcount, #1 jmp #:loop CS_BIT_MASK long %0000_0100_0000_0000 '$0400 RS_BIT_MASK long %0000_1000_0000_0000 '$0800 WR_BIT_MASK long %0001_0000_0000_0000 '$1000 RD_BIT_MASK long %0010_0000_0000_0000 '$2000 all_pin_mask long %0000_0011_1111_1100 all_ctl_mask long %0011_1111_1111_1100 zero long 0 rcount long 0 pmb_data res 1 tmp res 1 ' ------------------------------------------- ' ' These routines PASM conversion candidates { pub InitStart CS_OUTPUT RD_OUTPUT WR_OUTPUT RS_OUTPUT all_pin_output all_pin_low pub sendCommand(index) ' CS_LOW RS_LOW RD_HIGH WR_HIGH WR_LOW pushData(0) WR_HIGH WR_LOW pushData(index & $ff) WR_HIGH CS_HIGH pub sendData(data) ' CS_LOW RS_HIGH RD_HIGH WR_LOW pushData((data & $ff00) >> 8) WR_HIGH WR_LOW pushData(data & $ff) WR_HIGH CS_HIGH pub sendRegister(index) CS_LOW RS_LOW RD_HIGH all_pin_output WR_LOW pushData(0) WR_HIGH WR_LOW pushData(index) WR_HIGH all_pin_input RS_HIGH RD_LOW RD_HIGH result |= getData << 8 RD_LOW RD_HIGH result |= getData CS_HIGH all_pin_output } ' ------------------------------------------ datbut I'm nowhere near able to code PASM yet.
How would that be written?
Which brings me back to the beginning question about how the pins are defined?
You already have all parts figured out, but just do not see it because it is so simple.
So first the thing with the pins.
Each 1 is the pin used in these masks. 0-31, the position of the 1 in the mask correspond to the pin used for CS,RS,WR,RD
Same with the all_ masks, each 1 represents the affected pins.
To use different pins you need to move the 1 around in the masks.
Then you have this in the code:
not sure why written like that, but this is basically the same as CS/RS/WR/RD_BIT_MASK, a long value with one bit set, the bit corresponding to the pin used.
So both definitions define each exactly the same value with different name and different way of notation. But both define a pin by setting the corresponding bit of the long.
so
CS_BIT_MASK long %0000_0100_0000_0000 is exactly the same as CS_BIT = $04 << 8, it is the value $0400.
here you are wrong. The pins are not written at the same time, they are changed bit by bit on each instruction.
the first three lines set some pins and the last two lines basically toggle pin defined by wr_bit_mask.
the spin instructions do basically the same.
a |= b will do an OR and then write the result to the left hand variable, so a = a OR b. Bitwise. and not affect the other bits of outa.
a &= b will do an AND and then write the result to the left hand variable, so a = a AND b. Bitwise. Since we want CS low we need to do a
a &= ! b, so a = a and (not b). Bitwise. To just clear the bit defined in cs_bit or cs_bit_mask, (since they are the same) and not affect the other bits of outa.
Have fun!
Mike
ANDN is one PASM instruction I really like. @chip has made a nice instruction set. Sometimes you wonder about some of them. I still want to try out that multi long add/subtract thing. Have no time for it but it is interesting. 512 bit integer? longlong's? Anyone?
Need to sleep.
Mike
My questions are probably confusing because I'm confused.
Seems to work that way a lot.
I guess I'm confused because I thought that these bit masks were defined as longs.
And thought that the entire bit mask long was being set here...
andn outa,cs_bit_mask
and the selected bit in the mask was the one that's being wigggled?
Or is that the only bit being manipulated?
(edit)
No, I get it.
That's the only bit being set or cleared.
Thanks
would translate to -
or outa,cs_bit_mask ' to set CS_BIT high
and
would be -
andn outa,cs_bit_mask ' to set CS_Bit low
Anywhere near close?
CS_BIT_MASK long %0000_0101_0000_0000
This will affect I/O pins 8 and 10 simultaneously (using CS_HIGH or CS_LOW or the equivalent PASM)
Good to hear from you!
Just trying to speed up the display writes.
Those CD_whatever routines get used a lot and look like potential.
Thank you for confirming the PASM instructions.
I'm on really shaky ground here, so maybe just one change at a time?
Is it shifting the control signals into the high byte of the lower word of that long?
Still not sure what pins are being used for data.
Might be that lower byte?
It is a wonderful Assembler language, like SPIN with some quirks attached, but easy to use.
And a lot of SPIN actually translate easy to PASM as seen in your examples. Just dive in. You might really like it.
Enjoy!
Mike
Most likely the lower byte is for the data. They are what I have seen used for a parallel data bus and used myself.
Sorry to intrude...
that's why I'm here asking confusing questions...
http://forums.parallax.com/discussion/132966/propeller-assembly-for-beginners#latest
I don't know if more copies are available, try contacting the author Harpit Singh Sandhu. I have a copy of the book and it does have a number of good tips/examples.
I've attached a PDF copy of the book's front/back covers.