Shop OBEX P1 Docs P2 Docs Learn Events
Please check what I have got done. — Parallax Forums

Please check what I have got done.

TCTC Posts: 1,019
edited 2013-04-29 12:53 in Propeller 1
Hello all, I am wondering if someone would be willing to take a look at my code, and tell me if there is something obvious that will not work? I am not done with it yet, nor have I tested it. I am trying to learn, but I also don’t want to get too far and find out there is an obvious bug that I cannot see since I do not have that much experience.

Any feedback would be appreciated.

I have included the datasheet of what I am working on.

Thank You

{ Controling the MAX6957 requires sending a 16-bit word.
  The first byte, D15 through D8, is the command address, and the second byte, D7 through D0, is the data byte.}

{   " |=|<(bit) " sets bit
    " &=!|<(bit) " Clears bit
    }

CON
        _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
        _xinfreq = 5_000_000

ON      =       1
OFF     =       0
GLOBAL  =       0
INDIVIDUAL =    1

read    =       1
write   =       0
{ === PINS === }
SCLK    =       2
DIN     =       1
CS      =       0
DOUT    =       4

{ === Port Configuration ===}
LED_    =       $00             {"OUTPUT" LED Segment Driver}
OUTPUT_ =       $01             {"OUTPUT" GPIO Output}
IN_WO   =       $10             {"INPUT" GPIO Input Without Pullup}
IN_W    =       $11             {"INPUT" GPIO Input With Pullup}

VAR
  byte  Config_data             {Configuration Register data.| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
                                                               &#61600;    &#61600;    &#61600;    &#61600;    &#61600;    &#61600;    &#61600;    &#61600;
           Transition Detection Control 0=Disabled, 1=Enabled &#9472;&#9496;    &#9474;    &#9474;    &#9474;    &#9474;    &#9474;    &#9474;    &#9474;
       Global Current Control 0=Global, 1=Individual Segmants &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9474;    &#9474;    &#9474;    &#9474;    &#9474;    &#9474;
                                               Don't care bit &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9474;    &#9474;    &#9474;    &#9474;    &#9474;
                                               Don't care bit &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9474;    &#9474;    &#9474;    &#9474;
                                               Don't care bit &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9474;    &#9474;    &#9474;
                                               Don't care bit &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9474;    &#9474;
                                               Don't care bit &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#9474;
             Shutdown Control 0=Shutdown, 1= Normal Operation &#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
}                                                               
  byte  IO_counter              {Input/Output counter. used to keep track of what IO port is being configured}
  
 
OBJ
  SPI      : "SPI_Asm"


PUB _TRANSITION (ON_OFF)
  if ON_OFF := ON
    Config_data|=|<7
  else
    Config_data&=!|<7
  _CONFIG  


PUB _CURRENT (GLOBAL_INDIVIDUAL)
  if GLOBAL_INDIVIDUAL := INDIVIDUAL
    Config_data|=|<6
  else
    Config_data&=!|<6
  _CONFIG


PUB _SHUTDOWN (ON_OFF)
  if ON_OFF := ON
    Config_data|=|<0
  else
    Config_data&=!|<0
  _CONFIG


PRI _CONFIG
  GPIO_write ($04, Config_data)


PUB one_PORT (port, read_write, data) : Data_byte
  if read_write == read
    Data_byte := GPIO_read (port + $20)

  if read_write == write
    GPIO_write (port + 20, data)


PUB four_PORT (read_write, data) : Data_byte
  if read_write == read
    Data_byte := GPIO_read ($40)

  if read_write == write
    GPIO_write ($40, data)


PUB five_PORT (read_write, data) : Data_byte
  if read_write == read
    Data_byte := GPIO_read ($41)

  if read_write == write
    GPIO_write ($41, data)


PUB six_PORT (read_write, data) : Data_byte
  if read_write == read
    Data_byte := GPIO_read ($42)

  if read_write == write
    GPIO_write ($42, data)


PUB seven_PORT (read_write, data) : Data_byte
  if read_write == read
    Data_byte := GPIO_read ($43)

  if read_write == write
    GPIO_write ($43, data)


PUB eight_PORT (port, read_write, data) : Data_byte
  if read_write == read
    Data_byte := GPIO_read (port + $40)

  if read_write == write
    GPIO_write (port + $40, data)      


PUB DISPLAY_TEST | TEST_VALUE
{ Display test mode turns on all ports configured as LED drivers by overriding, but not altering, all controls and port registers, except the port configuration register}
{ Every time "DISPLAY_TEST" is called, the display register will be inverted. }

{ Read the value on "test register" ($07)}
  TEST_VALUE := GPIO_read($07)

{ Invert the value from "test register", and load it back}
  GPIO_write($07, !TEST_VALUE)
 
 
PUB GLOBAL_CURRENT (Adj)
{ Global current register, sets the current for all ports configured as LED segment drivers}
{ there are only 16-steps (4-bits) of current control}

  GPIO_write($02, Adj) 


PUB PORT_CONFIG (IO_D, IO_C, IO_B, IO_A)
{ The port configuration registers set the 28 ports, P4 to P31, individually as either LED drivers or GPIO.
  A pair of bits in registers 0x09 through 0x0F sets each port's configuration.}

{ To set a port's configuration, call "PORT_CONFIG" with corisponding port's configuration value.
  4 port's must be configurated at A time.
  port's are ordered from highest to lowest, P7-P4, P11-P8, P15-P12, P19-P16, P23-P20, P27-P24, P31-P28.
  Ports P3-P0 are internal and cannot be used, or configured.
  The 36-pin version of the MAX6957 has 28 usable ports
  The 28-pin version of the MAX6957 has 20 usable ports
  Any ports NOT being used should be set to outputs, if this is not done the unused ports remain as floating inputs.}

  IF IO_counter < $09           { Is this the first time method is called?}
    IO_counter := $09           { set counter to first port configuration batch}

{ send port cofiguration address, and data}
  GPIO_write(IO_counter, IO_D<<6 | IO_C<<4 | IO_B<<2 | IO_A)
  
{ increment port configuration address}
  IO_counter += 1 


PUB GPIO_write (Command_byte, Data_byte)
{  The MAX6957 contains a 16-bit shift register into which DIN data are clocked on the rising edge of SCLK, when CS is low.
   When CS is high, transitions on SCLK have no effect.
   When CS goes high, the 16 bits in the Shift register are parallel loaded into a 16-bit latch.
   The 16 bits in the latch are then decoded and executed.

  The MAX6957 is written to using the following sequence:}

{    1) Take SCLK low }
  LOW(SCLK)
    
{    2) Take CS low. This enables the internal 16-bit shift register. }
  LOW(CS)
  
{    3) Clock 16 bits of data into DIN-D15 first, D0 last-observing the setup and hold times(bit D15 is low, indicating a write command). }
  SPI.start(1,0)
  SPI.SHIFTOUT (DIN, SCLK, SPI#MSBFIRST, 8, Command_Byte&=!|<7) { "&=!|<" sets bit 7 to 0 }
  SPI.SHIFTOUT (DIN, SCLK, SPI#MSBFIRST, 8, Data_byte)
  
{    4) Take CS high (either while SCLK is still high after clocking in the last data bit, or after taking SCLK low). }
  HIGH(CS)
  SPI.stop
  
{    5) Take SCLK low (if not alredy low).}
  LOW(SCLK)


PUB GPIO_read (Command_byte): Data_byte
{ Any register data within the MAX6957 may be read by sending a logic high to bit D15.
  The sequence is:}

{    1) Take SCLK low.}
  LOW(SCLK)
  
{    2) Take CS low (this enables the internal 16-bit shift register).}
  LOW(CS)
  
{    3) clock 16 bits of data into DIN-D15 first to D0 last. D15 is high, indicating a read command and bits D14 through D8 containing the address of the register to be read. Bits D&-D0 contain dummy data, which is discarded.}
  SPI.start(1,0)
  SPI.SHIFTOUT (DIN, SCLK, SPI#MSBFIRST, 8, Command_Byte|=|<7) { "|=|<" sets bit 7 to 1}
  SPI.SHIFTOUT (DIN, SCLK, SPI#MSBFIRST, 8, $00)    

{    4) Take CS high (either while SCLK is still high after clocking in the last data bit, or after taking SCLK low), positions D7 though D0 in the Shift register are now loaded with the register data addressed by bits D1 through D8.}
  HIGH(CS)
  
{    5) Take SCLK low (if not already low).}
  LOW(SCLK)
  
{    6) issue another read or write command (which can be a No-Op), and examine the bit stream at Dout; the second 8 bits are the contents of the register addressed by bits D1 through D8 in step 3.}
  LOW(CS)
  Data_byte := SPI.SHIFTIN (DOUT, SCLK, SPI#MSBPOST, 16)
  HIGH(CS)
  SPI.stop
  LOW(SCLK)
  
       
PUB HIGH(Pin)
    dira[Pin]~~
    outa[Pin]~~

         
PUB LOW(Pin)
    dira[Pin]~~
    outa[Pin]~

Comments

  • TCTC Posts: 1,019
    edited 2013-04-27 11:00
    Here is my code in spin
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-04-27 12:32
    The only think I notice glancing at the code is your repeated starting and stopping of the SPI object. Unless there's a good reason not to just leave the SPI cog running, I'd only start it once. Not having to continually relaunch the PASM driver should speed up the program.
  • TCTC Posts: 1,019
    edited 2013-04-27 13:13
    I did it to keep it simple. Could it make that much of a difference?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-04-27 15:55
    TC wrote: »
    I did it to keep it simple. Could it make that much of a difference?

    It could make a noticeable difference in speed but I wouldn't worry about it for now, if the way you're currently doing it, makes more sense to you than the way I suggested. Once you have your program running you can decide if you want to optimize it or not.
  • kuronekokuroneko Posts: 3,623
    edited 2013-04-27 16:50
    TC wrote: »
    Hello all, I am wondering if someone would be willing to take a look at my code, and tell me if there is something obvious that will not work?
    All the _PORT methods can be handled by a single one (using port, mode and data as parameters), e.g. eight_PORT(0, write, 42) is the same as four_PORT(write, 42). If you want to keep them then one_PORT needs to be fixed ($20 vs 20). Also, _TRANSITION, _CURRENT and _SHUTDOWN use something in the form of if a := b which in your case is the same as saying if b. It's probably just a typo (== vs :=). HTH

    An alternative way of writing the _PORT methods (read == 1, write == 0):
    PUB _PORT (port, read_write, data)
    
      if read_write[COLOR="#D3D3D3"]{== read}[/COLOR]
        return GPIO_read (port)
    
      GPIO_write (port, data)
    
  • TCTC Posts: 1,019
    edited 2013-04-28 10:22
    Duane Degn wrote: »
    It could make a noticeable difference in speed but I wouldn't worry about it for now, if the way you're currently doing it, makes more sense to you than the way I suggested. Once you have your program running you can decide if you want to optimize it or not.

    Thank You. I will change it at a later time, but for right now I am going to leave it.
  • TCTC Posts: 1,019
    edited 2013-04-28 10:30
    kuroneko wrote: »
    All the _PORT methods can be handled by a single one (using port, mode and data as parameters), e.g. eight_PORT(0, write, 42) is the same as four_PORT(write, 42). If you want to keep them then one_PORT needs to be fixed ($20 vs 20). Also, _TRANSITION, _CURRENT and _SHUTDOWN use something in the form of if a := b which in your case is the same as saying if b. It's probably just a typo (== vs :=). HTH

    An alternative way of writing the _PORT methods (read == 1, write == 0):
    PUB _PORT (port, read_write, data)
    
      if read_write[COLOR="#D3D3D3"]{== read}[/COLOR]
        return GPIO_read (port)
    
      GPIO_write (port, data)
    

    four_PORT, five_PORT, six_PORT, and seven_PORT are only for the 36-pin SSOP, and the 40-pin TQFN packages. They are there so more than 1 port, and less than 8 ports at a time can be controled. For the "20" in one_PORT, I seen that after I uploaded the file. Thank you for the code suggestion, it does make better sense.
  • kuronekokuroneko Posts: 3,623
    edited 2013-04-28 16:30
    TC wrote: »
    four_PORT, five_PORT, six_PORT, and seven_PORT are only for the 36-pin SSOP, and the 40-pin TQFN packages.
    How does the s/w know about this? IOW if you have to configure it anyway (assumption on my part) you might as well use one universal access method (with configured offsets and/or limits).
  • TCTC Posts: 1,019
    edited 2013-04-29 12:53
    kuroneko wrote: »
    How does the s/w know about this? IOW if you have to configure it anyway (assumption on my part) you might as well use one universal access method (with configured offsets and/or limits).

    I added comments with the methods. I do plan on making it more condensed; just right now I just wanted to get my mind back to using spin. The object works, I tried it out last night. Now to figure out what am I going to do with it. I don’t want to stop while I’m ahead.
Sign In or Register to comment.