Shop OBEX P1 Docs P2 Docs Learn Events
Need code for MCP3428 Please — Parallax Forums

Need code for MCP3428 Please

CelticLordCelticLord Posts: 50
edited 2015-05-12 07:40 in Propeller 1
If anyone has/is/will writing code for the MCP3428 Please let me know.
Appreciate any help.

Comments

  • ElkinElkin Posts: 58
    edited 2015-05-05 04:23
    How about Johnny Mac's code for the 320x on the OBEX? the 320x series is a 12 bit A/D but that could be changed to 16 in the code. Rest of the code is probably similar and you might be able to figure out the rest from it.

    http://obex.parallax.com/object/315
  • ksltdksltd Posts: 163
    edited 2015-05-05 08:17
    The parts couldn't be more different. The 320x family is SPI interfaced, the 3428 is I2C. The 320x's engine converts as you read the data. The 3428 requires that you wait until a sample's conversion is ready.
  • idbruceidbruce Posts: 6,197
    edited 2015-05-05 08:27
    It would be helpful, if you specified what type of programming language support you need, e.g. Spin, PropBasic, FORTH, C
  • CelticLordCelticLord Posts: 50
    edited 2015-05-05 10:07
    Right you are idbruce, SPIN is what I need.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-05-05 12:45
    The Propeller Board of Education uses an I2C ADC chip (AD7993 (I think)). An object written for the AD7993 could be used as a starting point for an object to interface with the MCP3428.

    From looking at the datasheets of the two chips, it looks like they share a basic communication protocol (I suppose most I2C chips do). I don't think it would be trivial to convert an object written for the AD7993 to work with the MCP3428 but it might be easier than starting from scratch.
  • CelticLordCelticLord Posts: 50
    edited 2015-05-10 16:41
    I have been trying to figure this out to no avail. I have this bee hive monitor put together but the resolution of the MCP3208 is inadequate for the scale. I need this to work so I don't have to tear open the hive all the time, I can just read the weight and know its collection time. It also lets me track the overall health of the hive ect. I see others are interested in code for this as well, Could someone please write this code.
    Thanks
  • pmrobertpmrobert Posts: 673
    edited 2015-05-10 17:38
    What scale are you using,
    what weight range are you measuring,
    what is meaningful and relevant resolution in grams or Kg or whatever unit,
    at what time span and intervals do you need to acquire this, etc?
    Pictures of your hive and existing setup may help as well.
    Enquiring minds want to know...

    -Mike

    "Knowledge Is Good." - Emil Faber
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-10 18:12
    I'm sincerely curious: What makes you think you could put such an object to work if you cannot write it?

    I'll have a crack after "Game of Thrones" -- but I don't have one, so I cannot test it.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-05-10 19:00
    CelticLord wrote: »
    I have been trying to figure this out to no avail. I have this bee hive monitor put together but the resolution of the MCP3208 is inadequate for the scale. I need this to work so I don't have to tear open the hive all the time, I can just read the weight and know its collection time. It also lets me track the overall health of the hive ect. I see others are interested in code for this as well, Could someone please write this code.
    Thanks

    You say you've been trying to figure this out but if that were so then you would have some code that you could post so others could "help" you in the proper sense. There is nothing magical about the MCP3428 or any other I2C chip, they are just have a bunch of registers and use the standard I2C bus to access those registers. Seeing the OBEX is overflowing with I2C drivers I wonder why you haven't used one of those as a starting point, modified the device address, then had a go at reading the registers at least? The configurations register is there to write to, just waiting to be written to, just as the ADC conversion data is waiting to be read. just do it.

    I2C START
    WRITE DEVICE ADDRESS with R/W low (writing)
    WRITE CONFIGURATION
    I2CSTOP

    I2CSTART
    WRITE DEVICE ADDRESS with R/W high (reading)
    READ 2 BYTES OF DATA + OPT CONFIGURATION
    I2CSTOP

    Isn't that simple???
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-10 23:34
    As Peter correctly points out, with an I2C object (I used my own) and a bit of code it's pretty easy to interface with this device. I found a Schmarschmino library for the MCP342x and decided -- for those that might make the switch -- to pattern my object after that.

    Again, I don't have a device to test with so this code is, as the MIT license states, provided "as is" with no guarantees. Should you decide to modify, "improve," or "enhance" this object, you must remove all traces of my name before re-posting.


    11 MAY 2015 : Code updated per note from Dave Hein (post #14) -- directly accounts for both address pins floating (was indirect before).
    11 MAY 2015 : Added sample size constants and ready() method
    12 MAY 2015 : Changed adc method names to prevent confusion with generic I2C methods; changed interface to set_channel(); added read_mv() method
  • CelticLordCelticLord Posts: 50
    edited 2015-05-11 06:43
    Thank you JonnyMac and all.
    I'm suspecting the chip is bad as it displays 255 no mater what.
    Hence my frustration with this. I will try remounting a chip.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-05-11 07:54
    CelticLord wrote: »
    Thank you JonnyMac and all.
    I'm suspecting the chip is bad as it displays 255 no mater what.
    Hence my frustration with this. I will try remounting a chip.

    You want help but at what point do you decide "no matter what"? Is it simply by pushing the button again and again? Load my Explorer (see sig) into your Prop and connect to it via a terminal at 115200k baud.On startup it will list details about the hardware and also the whatever it finds on the I2C bus which should then display device $D1 (reading %1101000), with 12-bits of ADC data by default as the high byte, low byte, configurations byte etc. This is called "troubleshooting" and through the process of elimination you can work what it must be by what it isn't.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-05-11 10:53
    CelticLord, if you are receiving 255 from the chip you may not be addressing it correctly. How do you have the Adr0 and Adr1 pins wired? If they are floating, and you are passing (2, 2) to Jon's start routine it will not work. The startx routine is missing the case for (2, 2). Use the parameters (0, 0) instead since this maps to the same address.
  • Atal1101Atal1101 Posts: 11
    edited 2015-05-11 11:20
    Another possible route could be to start with the code for the MCP3202 (available on the ObEx in Spin) and try to alter from there. I'm not familiar with the specific differences between the two chips, but they're in the same family at least so the conversion shouldn't be too awful.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2015-05-11 11:39
    Atal1101 wrote: »
    Another possible route could be to start with the code for the MCP3202 (available on the ObEx in Spin) and try to alter from there. I'm not familiar with the specific differences between the two chips, but they're in the same family at least so the conversion shouldn't be too awful.

    Take a look at post #3. The 320x is SPI, the sensor in question is I2C.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-11 12:47
    Dave Hein wrote: »
    CelticLord, if you are receiving 255 from the chip you may not be addressing it correctly. How do you have the Adr0 and Adr1 pins wired? If they are floating, and you are passing (2, 2) to Jon's start routine it will not work. The startx routine is missing the case for (2, 2). Use the parameters (0, 0) instead since this maps to the same address.

    The original code defaulted to %000 with both inputs floating. In order to prevent confusion, I've added both pins floating to the case statement. New code is posted above.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-05-11 13:14
    Yes, you are correct, the original code did handle the floating case by initializing devid to WR_342x. So now I'm curious why it didn't work for CelticLoad. CelticLord, can you post your code?
  • CelticLordCelticLord Posts: 50
    edited 2015-05-11 16:23
    OK
    It was the chip but not that it was bad but the jump wires were to messy (long) probably inducing resistance, cross-talk, ect....
    I rewired it and am getting readings, but all three reads are the same value. The photo transistor changes the value as I illuminate it.
    **I am using a photo transistor for testing only**
    I am grounding the A0 & A1 for an address of 1101000
    Here is the code im using with JonnyMac's Driver from this post.
    CON
      _clkmode = xtal1 + pll16x                                  'clock mode 
      _xinfreq = 5_000_000                                       '* crystal frequency
    
    
      CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
    
      'MCP3428 ADC Values                           
      SCL = 1                                     ' Clock        MCP3428 Pin 8
      SDA = 0                                     ' Data In/Out  MCP3428 Pin 7
                                 
    OBJ
      SN  : "Simple_Numbers"
      pst : "Parallax Serial Terminal Plus"
      adc : "mcp3428"
            
    VAR
      Byte DataH, DataL, DataC 
      
    PUB Main
      pst.Start(57600)
    
        
      'MCP3428 Initialized
        adc.startx(SCL, SDA, 0, 0)
        adc.set_channel(0, 0)
      repeat 
        DataH := adc.read
        DataL := adc.read
        DataC := adc.read 
    
     
       
        pst.Position(1, 10)
        pst.Dec(DataH)
        pst.Position(1, 16)
        pst.Dec(DataL)
        pst.Position(1, 22)
        pst.Dec(DataC)
        pst.Str(String("   "))
    

    What am I doing wrong in the code for all 3 reads to be the same?
  • D.PD.P Posts: 790
    edited 2015-05-11 16:32
    CelticLord wrote: »
    OK
    It was the chip but not that it was bad but the jump wires were to messy (long) ect..
    I rewired it and am getting readings, but all three reads are the same value. The photo transistor changes the value as I illuminate it.
    **I am using a photo transistor for testing only**
    Here is the code im using with JonnyMac's Driver from this post.
    CON
      _clkmode = xtal1 + pll16x                                  'clock mode 
      _xinfreq = 5_000_000                                       '* crystal frequency
    
    
      CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
    
      'MCP3428 ADC Values                           
      SCL = 1                                     ' Clock        MCP3428 Pin 8
      SDA = 0                                     ' Data In/Out  MCP3428 Pin 7
                                 
    OBJ
      SN  : "Simple_Numbers"
      pst : "Parallax Serial Terminal Plus"
      adc : "mcp3428"
            
    VAR
      Byte DataH, DataL, DataC 
      
    PUB Main
      pst.Start(57600)
    
        
      'MCP3208 Initialized
      repeat 
        adc.startx(SCL, SDA, 0, 0)
        adc.set_channel(0, 3)
    
        DataH := adc.read
        DataL := adc.read
        DataC := adc.read 
    
     
       
        pst.Position(1, 10)
        pst.Dec(DataH)
        pst.Position(1, 16)
        pst.Dec(DataL)
        pst.Position(1, 22)
        pst.Dec(DataC)
        pst.Str(String("   "))
    

    What am I doing wrong in the code for all 3 reads to be the same?
  • D.PD.P Posts: 790
    edited 2015-05-11 16:53
    Johnny's code:
    pub read | raw, cfg
    
    '' Read result from previous conversion
    '' -- setup by set_channel or write() to configuration register
    '' -- application must correct sign of long value
    ''    * sign position based on bits used in reading
    
      raw := 0
    
      i2c.start
      i2c.write(devid | 1)                                           ' read mode
      raw.byte[1] := i2c.read(i2c#ACK)                               ' high byte of volts
      raw.byte[0] := i2c.read(i2c#ACK)                               ' low byte of volts
      cfg := i2c.read(i2c#NAK)                                       ' configuration bits
      i2c.stop             
    
      return raw    
    

    Is returning "raw" which is both the high and low byte

    Then look at the procedure raw2mv in the code to convert this reading to millivolts depending on bits and gains settings.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-11 16:59
    You might want to wait a half a second before reading the device after setting the configuration register.

    I updated the code to add a method called ready() -- this will return true when the ready bit is clear.

    FTR: My name is Jon.
  • CelticLordCelticLord Posts: 50
    edited 2015-05-12 04:42
    Ok The problem was me thinking I was reading back 3 bytes High byte Low byte and a status byte why, don't ask I feel like an idot lol.
    I changed the variable recieving the read to a WORD and it works perfect.
    I understand this a little better. Thank you all for the help, I really needed it and can now get this on a pcb and into my hive.
    Jon, Peter Jakacki , and Duane Thank you very much for the driver and advice.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-12 06:53
    Ok The problem was me thinking I was reading back 3 bytes High byte Low byte and a status byte why, don't ask I feel like an idot lol.


    Nobody is asking you to feel like an idiot, but for myself (and perhaps others that provide code "on demand" for forum members) I will ask that you do me the courtesy to read the code I've written for you. The comments for that method state that it returns the result of the last conversion, and the method is less than 10 lines of code -- one can easily see three calls to i2c.read().
    pub read | raw, cfg
    
    '' Read result from previous conversion
    '' -- setup by set_channel or write() to configuration register
    '' -- application must correct sign of long value
    ''    * sign position based on bits used in reading
    
      raw := 0
    
      i2c.start
      i2c.write(devid | 1)                                           ' read mode
      [COLOR="#FF0000"]raw.byte[1] := i2c.read(i2c#ACK)                               ' high byte of volts
      raw.byte[0] := i2c.read(i2c#ACK)                               ' low byte of volts
      cfgbits := i2c.read(i2c#NAK)                                   ' configuration bits[/color]
      i2c.stop        
         
      return raw                                                     ' return raw reading
    


    I changed the variable recieving the read to a WORD and it works perfect.


    You really should use a LONG. It is the native type for the Propeller (hence fastest, and uses the least amount of code), and allows for sign bit correction and straightforward use of signed value. There is a method in the object called raw2mv() that converts the raw reading to millivolts. That method needs to know what the bit size and gain factor settings are. It returns and signed LONG.


    I'm glad you got things working. Good luck with your hive project. I have a friend in the movie business (she's a costumer) who keeps bees and supplies me and other friends with raw honey.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-05-12 07:40
    I don't tend to post "fresh" code unless requested by another forum member -- my preference is to wring-out and object with a few applications before sharing. As that was not the case here I have made changes based on responses to the object.

    That latest is attached to post #11 (where the original code was); it has several changes.

    -- interface to set_channel() no longer assumes 16-bit sample size; sample size is now a parameter (use constants SAMP_12, SAMP_14, and SAMP_16)
    -- the write() method has been renamed write_cfg() to prevent confusion with generic I2C method
    -- the read() method has been renamed read_raw() to prevent confusion with generic I2C method
    -- added read_mv() method to simplify use
    -- updated comments and added code examples where helpful
Sign In or Register to comment.