Shop OBEX P1 Docs P2 Docs Learn Events
Another i2c assembly driver — Parallax Forums

Another i2c assembly driver

RaymanRayman Posts: 14,652
edited 2015-05-23 09:34 in Propeller 1
Still working on code for a new board (Manta) and needed an assembly i2c driver...
Found some in OBEX, but I couldn't figure out how to adapt them for what I needed.
So, wrote a new one.

This one is pretty generic, but also has code for these specific chips:
LSM9DS0 - a nine degree of freedom mems with gyro, accelerometer and compass
TSC2003 - touchscreen chip used in my 4.3" and 3.5" LCD boards
PCA9554 - I/O expander
DS1339 - RTC clock

But, I think it can be fairly easily adapted to interface to other chips as well.

This demo of the driver is for an improved version of the PTP2 board for 3.5" touchscreen.
The old one was slow to start because used Spin to initialize the LCD over I2C.
Switching to assembly makes startup much faster.

Another nice feature is that the touchscreen math is now done in assembly.
This makes the touchscreen response much faster.


PTP2_Paint_Rev2 - Archive [Date 2015.05.15 Time 09.09].zip

Comments

  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-15 08:57
    I recently wrote one, too. It just does the basics, but seems to work perfectly -- that said, I'm obviously biased about my own code. Would love it you could give it a try in your app.
  • RaymanRayman Posts: 14,652
    edited 2015-05-15 09:57
    Might be a problem with pullups... Code says pull-ups are required on both SDA and SCL.
    My boards are like the Parallax ones, with just one pull up.

    That's one of the problems I had trying other codes in OBEX.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-05-15 11:04
    Rayman wrote: »
    My boards are like the Parallax ones, with just one pull up.

    The only Parallax boards I'm aware of without pull-ups on both lines are the Demo Board and the Propeller Professional Development Board. All the rest have pull-ups on both.
  • RaymanRayman Posts: 14,652
    edited 2015-05-15 13:16
    I guess you're right, they must have started adding the second pullup at some point...
  • RaymanRayman Posts: 14,652
    edited 2015-05-15 16:21
    Actually, I just checked and my Manta board also has both pullups...

    So, I guess I could do it Jon's way.

    Still, if somebody is desperate for pins, they might think about using SCL after boot up.
    Plus, this way is compatible with older boards with just the one pullup.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-15 19:25
    Plus, this way is compatible with older boards with just the one pullup.

    You're right, but -- technically -- I'm pretty sure that driving SCL violates the I2C spec. I'm very fastidious with my designs; every one of them has proper bypass caps and pull-ups on the I2C lines, even if some example circuits do not.
  • photomankcphotomankc Posts: 943
    edited 2015-05-15 20:08
    JonnyMac wrote: »
    You're right, but -- technically -- I'm pretty sure that driving SCL violates the I2C spec. I'm very fastidious with my designs; every one of them has proper bypass caps and pull-ups on the I2C lines, even if some example circuits do not.

    People appreciate that! I had to write my own a long time back because I could not use the ones that drove SCL and ignored the possibility of clock stretch. Many other uC based devices do it and it took me a long time to figure out a weird intermittent problem because of that.
  • RaymanRayman Posts: 14,652
    edited 2015-05-16 06:54
    The Propeller itself must violate the I2C spec, since it boots with the single pull up.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-16 07:49
    Indeed, it does. Back in those days I don't think anyone thought about using those pins as a general-purpose I2C port. Since the pull-up doesn't interfere with a driven clock line (boot-up), Parallax includes the SCL pull-up now (they have for a few years).
  • dbpagedbpage Posts: 217
    edited 2015-05-16 08:56
    Jon,
    Can multiple cogs use your driver by properly using locks?
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-16 09:09
    The current version doesn't return from a call until the requested I2C process is finished (I may change this later), so there's no reason multiple Spin cogs couldn't use the driver. Still, I would setup some kind of cooperative mechanism between then as a cog may need several individual I2C access requests to complete a larger task. Using a global "Hey, the I2C buss is busy now" flag would be useful in these cases.
  • RaymanRayman Posts: 14,652
    edited 2015-05-16 14:17
    One other thing this driver has is a stub for enabling automatic polling of the 9DOF mems. This allows you do use other things on the I2C bus, while not losing any 9DOF data.
    This 9DOF chip puts out sample data at pretty high rates, you have to take care, if you don't want to miss any data, like in IMU usage
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2015-05-23 09:34
    JonnyMac wrote: »
    I recently wrote one, too. It just does the basics, but seems to work perfectly -- that said, I'm obviously biased about my own code. Would love it you could give it a try in your app.

    Here is an elementary shell for the MCP3428. It seems to work just fine, Saleae protocol decoder likes it.
    {MCP3428 Demo}
    
    CON                                 'Belonging to main
            _clkmode = xtal1 + pll16x   'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
             Slv3428=%11010000        'slave address
    
             #0, ACK, NAK
                           
    VAR
      byte     D3428[34]        'data returned from 3428
      Long     cog             'data returned from starting i2c cog
      byte     WriteSlvA[2]    'two bytes for writing:  Slave address and Configuration Byte' 
      byte     ReadSlvA        'one byte for reading: slave address ORred with read bit
      
    
    OBJ
      pst      : "parallax serial terminal"
      i2c      : "jm_i2c_fast"
    
      
    PUB main                                     
      pst.Start (115_200)                        'start up ser terminal
      pst.str(String("hello, world   "))         'runs in cog 1
      pst.NewLine
      waitcnt(clkfreq/10+cnt)
    
      cog := i2c.setup(400_000)
      pst.str(String("Value from i2c.setup:   "))
      pst.hex(cog,8)
      pst.NewLine
      waitcnt(clkfreq/10+cnt)
    
      cog := i2c.present(Slv3428)
      pst.str(String("Value from i2c.present   "))
      pst.hex(cog,8)        
      pst.NewLine
      waitcnt(clkfreq/10+cnt)
    
      WriteSlvA[0] := Slv3428           'slave address
      WriteSlvA[1] := %0_00_1_00_00     'configuration byte template
      ReadSlvA := Slv3428 | 1           'set read bit 
    
    
      repeat
         Read3428(1)                    'read from channel 1
         pst.str(string("Channel 1:  "))
         pst.bin(D3428[0],8)
         pst.char(" ")
         pst.bin(D3428[1],8)
         pst.char(" ")
         pst.bin(D3428[2],8)
         
         Read3428(3)                    'and now channel 3
         pst.str(string("   Channel 3:  "))
         pst.bin(D3428[0],8)
         pst.char(" ")
         pst.bin(D3428[1],8)
         pst.char(" ")
         pst.bin(D3428[2],8)
         
         pst.newline
         waitcnt(clkfreq+cnt)
    
         
    PUB Read3428(Channel)                                'read specified channel (1..4)
        WriteSlvA[1] := %00010000 | ((Channel-1) << 5)   'insert channelnumber 
        i2c.start
        i2c.pwrite(@WriteSlvA,2)                         'set configuration register
        repeat 
          i2c.start                                        'restart
          i2c.pwrite(@ReadSlvA,1)    '                     'issue read command
          i2c.pread(@d3428, 3, NAK)                        'dataHi, dataLo, Config
          i2c.stop
        until (D3428[2] & $80) == 0                        're-read until conversion is complete        
        return 
    
Sign In or Register to comment.