Shop OBEX P1 Docs P2 Docs Learn Events
Propeller IDE and (objects?) — Parallax Forums

Propeller IDE and (objects?)

I am getting back into using the propeller after about an 8 year break. For the most part, things have come back to me pretty easily but I am hitting a roadblock this morning. I am working with one of those graphical OLED modules. I wrote some code to draw to the screen using an all-spin I2C driver but found that screen refreshes were too slow for my preference so this morning I am converting it over to use an assembly version that can sustain a much higher bit rate. I am working with "I2C PASM driver v1.8od.spin" that I found in the github repository. If I call the start function from within my main program then I am finding that I cannot write to the display. In fact, I see nothing coming out of the I2C lines. If I put the call to start inside of the file that I have for driving the display then everything works. My code for driving the display is purely in spin at the moment and is not launched into another core as best as I can tell. Presumably this would mean that it is running on the same core as my main program. I would like to use I2C for other sensors and devices and would rather not hog two I2C lines for each device. What am I missing? :


The relevant parts of the main program:
CON
  _CLKMODE = XTAL1 + PLL16X
  _XINFREQ = 5_000_000
  
OBJ
    SERIAL      : "quadSerialPorts.spin"
    i2cfast     : "I2C PASM driver v1.8od.spin"
    OLED        : "SSD1306_fast.spin"
    
    
VAR
long    whichPin
long    LEDvalues[4]   
long    potentiometer
long    temp
long    time

long    numberOfEncoders
long    encoderBasePin
long    encoderPosition
long    encoderPosition2
long    encoderPosition3
byte    characterBuffer[16]
long    myStringPtr
long    A

byte    buff[16]

    
PUB launchStuff
''-------- This Block is what runs at startup ----------

    start_uarts
    SERIAL.tx(0,13)                ' the basic i/o methods are part of fullDuplexSerial4port

    'i2cfast.start(20,21,100000)    ' I can't put this here and still have the OLED work

    serial.str(0,string("Starting up the SSD1306 ...",13))
    
    oled.start($3C) ' The I2C start command is tucked into here

    oled.displayOn
    serial.str(0,string("Display is now on",13))

    oled.setPageMode
    oled.setTextRowCol(0,0)
    oled.putString(string("This is the"))
    oled.setTextRowCol(1,0)
    oled.putString(string("first display"))
    oled.setTextRowCol(2,0)
    oled.putString(string("################"))
    oled.setTextRowCol(3,0)
    oled.putString(string("################"))
    serial.str(0,string("Done putting string",13))
    
    waitcnt(cnt + clkfreq * 5)
    
    oled.clearDisplay 
    serial.str(0,string("Done clearing the screen",13))





  
        

PUB start_uarts
  SERIAL.init                    
  'AddPort      (port,rxpin,txpin,ctspin,rtspin,rtsthreshold,mode,baudrate)
  SERIAL.AddPort(0,   10,   11,   -1,    -1,    0,           0,   115200)
  SERIAL.AddPort(1,   12,   13,   -1,    -1,    0,           0,   115200)
  SERIAL.AddPort(2,   14,   15,   -1,    -1,    0,           0,   115200)
  SERIAL.Start
  ' Give it some time to start up
  time := cnt
  waitcnt(time += clkfreq/10)


Enough of the OLED display code to see what is going on.
VAR
    long    oledAddress  
    byte    buff[16]
   
        
              
OBJ
    i2cfast     : "I2C PASM driver v1.8od.spin"
    font        : "font.5x8.spin"  
        
    
PUB start(address) 
    ' This must be called before anything else
    oledAddress := address
    
    i2cfast.start(20,21,900000) '  ######################################## I have to put this here
    
    ' The Adafruit Arduino driver does this at startup:
    buff[0] := $AE
    buff[1] := $D5
    buff[2] := $80
    buff[3] := $A8
    i2cfast.writeBytes(address, $00, @buff, 4)
    
    
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $1F)
    
    waitcnt(cnt + 10000)
    buff[0] := $D3
    buff[1] := $00
    buff[2] := $40
    buff[3] := $8D
    i2cfast.writeBytes(address, $00, @buff, 4)
    
    
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $14)
    
    
    waitcnt(cnt + 10000)  
    buff[0] := $20
    buff[1] := $00
    buff[2] := $A1
    buff[3] := $C8
    i2cfast.writeBytes(address, $00, @buff, 4)  
      
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $DA)
    
    waitcnt(cnt + 10000) 
    i2cfast.writeByte(address, $00, $02)
    
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $81)
    
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $8F) 
    
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $D9)  
    
    waitcnt(cnt + 10000)
    i2cfast.writeByte(address, $00, $F1)  
    

Comments

  • The I2C driver you're using keeps information in VAR variables. This allows for multiple instances of the driver. However, this means that all calls to the driver's methods must come from that same object. So the object that calls the start method must also be used to call the other I2C methods.

    You can remove this restriction by modifying the I2C driver so that it uses DAT variables instead of VAR variables. Then you can call any of the methods from any object. The drawback is that you can then only have one instance of the driver.
  • Wuerfel_21Wuerfel_21 Posts: 5,107
    edited 2021-01-09 18:38
    Each instance of an object is seperate. That is, if you reference "I2C PASM driver v1.8od.spin" in two different files, those are two destinct entities. They will share code and DAT memory, but have seperate VAR memory. This is just a shortcoming of the way Spin works. Yes, it's quite annoying.

    There are multiple way of solving such issues. The easiest would be to edit the I²C object such that all instances act as one, by converting all VAR symbols into DAT symbols.
    For example,
    VAR
    long avar
    word foo,bar
    byte arr[8]
    
    would become
    DAT
    avar long 0
    foo  long 0
    bar  long 0
    arr  byte 0[8]
    
  • Thanks guys!
Sign In or Register to comment.