Shop OBEX P1 Docs P2 Docs Learn Events
Shifting pins? — Parallax Forums

Shifting pins?

cavelambcavelamb Posts: 720
edited 2016-02-18 19:32 in Propeller 1
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?



Comments

  • Also having some trouble wrapping my head around this one:


    pub pushData(data)
    all_pin_low
    outa |= (data << 2) ' bitwise OR (data shifted left two bits) ???

    Bitwise OR what with what?
  • I can't speak about the specific case you've cited, but the I/O pins are represented in the DIRA, OUTA, and INA registers as bits, one per I/O pin (bits 0-31 are I/O pins 0-31). There are some special cases like the counters where the actual I/O pin number is given in the control value for the counter. Sometimes it's easier to define the I/O pin name as a bit value and sometimes it's easier to use the pin number.

    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.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2016-02-18 20:48
    In some cases, communicating with other devices requires either following or preceding the data being sent with additional status bits. For example, in I2C communication, you generally send a 7-bit device address, followed by a single bit to tell the device if you want to read from it or write to it. In this case, the datasheet will specify the address as a 7 bit value (like $3C), but in actual use, when sending 8 bits, you'd send either (($3C<<1) + 0) for a read, or (($3C<<1) + 1) for a write.

    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.
  • kwinnkwinn Posts: 8,697
    No idea why it was done like that but it does have the effect of putting the data into the next byte of the long. Could just as easily have added two zeros on the end of the hex digits instead of the shifting.

  • 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
    }
    ' ------------------------------------------
    dat
    
  • and these are the places that I suspect could really speed the thing up...
    but I'm nowhere near able to code PASM yet.
    ' 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
    
  • cavelambcavelamb Posts: 720
    edited 2016-02-19 05:00
    dumb
  • cavelambcavelamb Posts: 720
    edited 2016-02-19 01:42
    So converting these routines to PASM???
    How would that be written?
    Which brings me back to the beginning question about how the pins are defined?
    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
    
  • Your questions are quite confusing, but I try to get you thru it.

    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.
      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
    

    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:
      CS_BIT      = $04 << 8
      RS_BIT      = $08 << 8
      WR_BIT      = $10 << 8
      RD_BIT      = $20 << 8
    

    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.

    What I think is happening is all the output pins are written at the same time -
    eight bits of data AND the control signals (first step of control signals)
    is gang-banged in a single output instruction.
    Then the control signals are wiggled to complete the transfer.

    here you are wrong. The pins are not written at the same time, they are changed bit by bit on each instruction.
    andn outa,cs_bit_mask  ' here outa will change one bit - defined in cs_bit_mask - and set it to zero - so CS LOW
     andn outa,rs_bit_mask ' here outa will change one bit - defined in rs_bit_mask - and set it to zero - so RS LOW
     or  outa,rd_bit_mask    ' here outa will change one bit - defined in rd_bit_mask - and set it to one - so RD HIGH
     or  outa,wr_bit_mask   ' here outa will change one bit - defined in wr_bit_mask - and set it to one - so WR HIGH
     andn outa,wr_bit_mask ' here outa will change one bit - defined in wr_bit_mask - and set it to zero - so WR LOW
    ...
    

    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.
    pri CS_HIGH
      OUTA |= CS_BIT   ' here outa will change one bit - defined in cs_bit - and set it to one- so CS HIGH
      
    pri CS_LOW
      OUTA &= !CS_BIT  ' here outa will change one bit - defined in cs_bit - and set it to zero - so CS LOW
    ...
    

    Have fun!

    Mike



  • I do have to add that

    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
  • cavelambcavelamb Posts: 720
    edited 2016-02-19 03:36
    Thanks, Mike.

    My questions are probably confusing because I'm confused.
    Seems to work that way a lot.
    msrobots wrote: »
    Your questions are quite confusing, but I try to get you thru it.

    CS_BIT_MASK long %0000_0100_0000_0000 is exactly the same as CS_BIT = $04 << 8, it is the value $0400.

    What I think is happening is all the output pins are written at the same time -
    eight bits of data AND the control signals (first step of control signals)
    is gang-banged in a single output instruction.
    Then the control signals are wiggled to complete the transfer.

    here you are wrong. The pins are not written at the same time, they are changed bit by bit on each instruction.
    andn outa,cs_bit_mask  ' here outa will change one bit - defined in cs_bit_mask - and set it to zero - so CS LOW
     andn outa,rs_bit_mask ' here outa will change one bit - defined in rs_bit_mask - and set it to zero - so RS LOW
     or  outa,rd_bit_mask    ' here outa will change one bit - defined in rd_bit_mask - and set it to one - so RD HIGH
     or  outa,wr_bit_mask   ' here outa will change one bit - defined in wr_bit_mask - and set it to one - so WR HIGH
     andn outa,wr_bit_mask ' here outa will change one bit - defined in wr_bit_mask - and set it to zero - so WR LOW
    ...
    


    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
  • cavelambcavelamb Posts: 720
    edited 2016-02-19 03:49
    So to replace these SPIN routines with PASM?
    
    pri CS_HIGH
      OUTA |= CS_BIT   ' OR the CS bit
    

    would translate to -

    or outa,cs_bit_mask ' to set CS_BIT high

    and
    pri CS_LOW
      OUTA &= !CS_BIT
    

    would be -

    andn outa,cs_bit_mask ' to set CS_Bit low


    Anywhere near close?
  • Mike GreenMike Green Posts: 23,101
    edited 2016-02-19 04:18
    Your CS_HIGH and CS_LOW routines are correct and the corresponding PASM instructions are correct too. If you want to change more than one bit at a time, you can just make CS_BIT contain several 1 bits like:

    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)
  • Hi Mike,
    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?

  • msrobots wrote: »
    Your questions are quite confusing, but I try to get you thru it.

    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.
      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
    

    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:
      CS_BIT      = $04 << 8
      RS_BIT      = $08 << 8
      WR_BIT      = $10 << 8
      RD_BIT      = $20 << 8
    

    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.

    Have fun!

    Mike


    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?
  • no reason to fear PASM.

    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
  • kwinnkwinn Posts: 8,697
    cavelamb wrote: »
    msrobots wrote: »
    Your questions are quite confusing, but I try to get you thru it.

    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.
      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
    

    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:
      CS_BIT      = $04 << 8
      RS_BIT      = $08 << 8
      WR_BIT      = $10 << 8
      RD_BIT      = $20 << 8
    

    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.

    Have fun!

    Mike


    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?

    Most likely the lower byte is for the data. They are what I have seen used for a parallel data bus and used myself.
  • Dont want to hijack this so I appologize for butting in. Is there a good source for learning pasm other the in prop manual?

    Sorry to intrude...
  • not that I know of.

    that's why I'm here asking confusing questions...
  • I thought there was one but I lost it before I went through it..
  • In response to the brief hijacking of this thread, check out the following previous forum discussion for information about the PASM book => "Propeller 102: A beginner's guide to learning PASM"

    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.
  • That was it Thankyou!
Sign In or Register to comment.