MCP342x ADC module

Coding and general discussion relating to user created compiler modules

Moderators: David Barker, Jerry Messina

Post Reply
matherp
Registered User
Registered User
Posts: 31
Joined: Tue May 31, 2011 2:59 pm
Location: Cambridge

MCP342x ADC module

Post by matherp » Sun Jun 19, 2011 10:11 am

Hi all

I've attached a module and test program to control the microchip MCP342x range of ADCs. I've found these are very useful providing very stable readings and as they have an internal programmable gain they can direct read thermocouples.

Hope the code is of some use. Please feel free to let me have any constructive comments as to how the code could be improved

Best Regards

Peter

Module

Code: Select all

Module MCP342x 
{
*****************************************************************************
*  Name    : MCP342x.BAS                                                   *
*  Author  : Peter Mather                                                   *
*  Notice  : Copyright (c) Peter Mather                      *
*          : All Rights Reserved                                            *
*  Date    : 12/06/2011                                                     *
*  Version : 1.0                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
}
{
Routines to control a Microchip MCP3421, MCP3422, MCP3424 i2c ADC
All use is in single shot mode and the start conversion routine is non-blocking
reading the value waits on completion by the ADC and is blocking until the conversion is complete
The MCP342x have an internal voltage reference and the results are not related to Vdd
Therefore it is possible to also return absolute signed voltage measurements
The MCP342x work perfectly for direct thermocouple measurement with gain set to 8 and 16 or 18 bit resolution
}
Include "I2C.bas"
Include "usart.bas"
Include "convert.bas"
Const MCP_Address(8) As Byte = (%11010000,%11010010,%11010100,%11010110,%11011000,%11011010,%11011100,%11011110) //valid addresses for MCP342x
Const ADC_mask As Byte = %10011111
Const Gain_mask As Byte = %11111100
Const Resolution_mask As Byte = %11110011
Public Const Bits18 As Byte = %00001100
Public Const Bits16 As Byte = %00001000
Public Const Bits14 As Byte = %00000100
Public Const Bits12 As Byte = %00000000
Const StartBit As Byte = %10000000
Dim ConfigByte(8) As Byte 
{
Select the ADC in the stored config for chip, valid values are 0-3 NB for 3421 bits are ignored, for 3422 only lsb is used
}
Public Sub SelectADC(ByVal chip As Byte, ByVal ADC As Byte)
    ADC = (ADC And $03) << 5 
    ConfigByte(chip) = (ConfigByte(chip) And ADC_mask) Or ADC
End Sub
{
Select the gain in the stored config for chip, valid values are 1, 2, 4, 8
}

Public Sub SetGain(ByVal chip As Byte, ByVal Gain As Byte)
    Dim gainbits As Byte
    gain=gain And $0F
    gainbits=255
    While gain <> 0
        gainbits=gainbits+1
        gain=gain >> 1
    Wend
    ConfigByte(chip) = (ConfigByte(chip) And Gain_mask) Or gainbits
End Sub

{
Select the resolution in the stored config for chip, valid values are Bits12, Bits14, Bits16, Bits18
}
Public Sub SetResolution(ByVal chip As Byte, ByVal Resolution As Byte)
    Resolution = Resolution And (Not Resolution_mask) //check it isn't an invalid number
    ConfigByte(chip) = (ConfigByte(chip) And Resolution_mask) Or Resolution
End Sub
{
Start a one shot conversion on chip specified using stored config parameters
}
Public Sub StartConversion(ByVal Chip As Byte) 
       ConfigByte(chip)=ConfigByte(chip) Or StartBit
       I2C.Start                          
       I2C.WriteByte(MCP_Address(chip))              
       I2C.WriteByte(ConfigByte(chip))       
       I2C.Acknowledge(I2C_NOT_ACKNOWLEDGE)
       I2C.Stop
End Sub

{
Start a one shot conversion on chip specified 
Select the ADC in the stored config for chip, valid values are 0-3 NB for 3421 bits are ignored, for 3422 only lsb is used
Select the resolution in the stored config for chip, valid values are Bits12, Bits14, Bits16, Bits18
Select the gain in the stored config for chip, valid values are 1, 2, 4, 8
}
Public Sub StartConversion(ByVal Chip As Byte, ByVal ADC As Byte, ByVal resolution As Byte, ByVal gain As Byte) 
       SelectADC(chip,ADC)
       SetGain(chip,gain)
       SetResolution(chip,resolution)
       ConfigByte(chip)=ConfigByte(chip) Or StartBit
       I2C.Start                          
       I2C.WriteByte(MCP_Address(chip))              
       I2C.WriteByte(ConfigByte(chip))       
       I2C.Acknowledge(I2C_NOT_ACKNOWLEDGE)
       I2C.Stop
End Sub

{
Wait for the conversion to complete on the chip specified and return the value as a 32bit signed integer
}
Public Function ReadVal(ByVal Chip As Byte) As LongInt
Structure TWord 
   LSB As Byte 
   MSB As Byte
   HSB As Byte
   sign As Byte 
End Structure 
Dim value As Tword , donestatus As Byte, resolution As Byte
       Repeat 
            I2C.Start
            I2C.WriteByte(MCP_Address(chip) + 1)
            value.HSB= I2C.ReadByte
            I2C.Acknowledge(I2C_ACKNOWLEDGE)
            value.MSB = I2C.ReadByte
            I2C.Acknowledge(I2C_ACKNOWLEDGE)
            value.LSB = I2C.ReadByte
            I2C.Acknowledge(I2C_ACKNOWLEDGE)
            donestatus = I2C.ReadByte  And StartBit
            I2C.Acknowledge(I2C_NOT_ACKNOWLEDGE)
            I2C.Stop
       Until donestatus=0 
       resolution= (Not Resolution_mask) And ConfigByte(chip)
       If resolution = Bits18 Then
            If value.HSB<128 Then
                value.sign=0
            Else
                value.sign=255
            EndIf
       Else
            value.LSB=value.MSB
            value.MSB=value.HSB
            If value.MSB<128 Then
                value.sign=0
                value.HSB=0
            Else
                value.sign=255
                value.HSB=255
            EndIf
       EndIf
       ReadVal=value
End Function

{
Wait for the conversion to complete on the chip specified and return the voltage measured as a floating point value
}
Public Function ReadVolts(ByVal Chip As Byte) As Float
Dim vcalc As Float
Dim resolution,gain As Byte
vcalc = Float(ReadVal(chip))
resolution= (Not Resolution_mask) And ConfigByte(chip)
gain= ConfigByte(chip) And (Not Gain_mask)

Select resolution
Case Bits18
    vcalc=vcalc / 131072.0
Case Bits16
    vcalc=vcalc /32768.0
Case Bits14
    vcalc=vcalc /8192.0
Case Bits12
    vcalc=vcalc /2048.0
End Select

Select gain
Case 0
    vcalc=vcalc *2.048
Case 1
    vcalc=vcalc * 1.024
Case 2
    vcalc=vcalc * 0.512
Case 3
    vcalc=vcalc * 0.256
End Select
ReadVolts=vcalc

End Function
{
Initialisation of config bytes
}
ConfigByte(0)=0
ConfigByte(1)=0
ConfigByte(2)=0
ConfigByte(3)=0
ConfigByte(4)=0
ConfigByte(5)=0
ConfigByte(6)=0
ConfigByte(7)=0

End Module
Test program

Code: Select all

{
*****************************************************************************
*  Name    : MCPtest.BAS                                                   *
*  Author  : Peter Mather                                                   *
*  Notice  : Copyright (c) Peter Mather                       *
*          : All Rights Reserved                                            *
*  Date    : 12/06/2011                                                     *
*  Version : 1.1                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
}

// if device and clock are omitted, then the compiler defaults to 
// 18F452 @ 20MHz - they are just used here for clarity...
Device = 18F4520
Clock = 20
Include "usart.bas" 
Include "convert.bas" 
Include "mcp342x.bas"
Include "i2c.bas"
SetBaudrate(br19200)
DelayMS (100) 
I2C.Initialize  
DelayMS(100)  
// program start...
USART.SetBaudrate(br19200)
USART.Write("MCPTest V1.1",13,10)
// output the result
While true
    MCP342x.SetResolution(0,Bits16)
    MCP342x.SetGain(0,8)
    MCP342x.SelectADC(0,2)
    MCP342x.StartConversion(0)
    USART.Write("Value 16 bit = ", DecToStr(MCP342x.ReadVal(0)), 13, 10)
    MCP342x.StartConversion(0,2,Bits12,4)
    USART.Write("Value 12 bit = ", DecToStr(MCP342x.ReadVal(0)), 13, 10)
    MCP342x.StartConversion(0,2,Bits18,8)
    USART.Write("Volts = ", FloatToStr(MCP342x.ReadVolts(0),6), 13, 10)
DelayMS(1000)
Wend

User avatar
ohararp
Posts: 194
Joined: Tue Oct 03, 2006 11:29 pm
Location: Dayton, OH USA
Contact:

Post by ohararp » Sun Jun 19, 2011 6:02 pm

Peter, looks good. I am doing some thermocouple and I2C stuff now. I might have to look at pricing for these compared to the dedicated IC approach I am using now...looks like they are 1/3 the cost of the solution I am using now. mmmm, good stuff.

Just curious what you have been using all those 18-bits for?
Thanks Ryan
$25 SMT Stencils!!!
www.ohararp.com/Stencils.html

matherp
Registered User
Registered User
Posts: 31
Joined: Tue May 31, 2011 2:59 pm
Location: Cambridge

Post by matherp » Sun Jun 19, 2011 10:00 pm

I'm building avionics for a homebuilt aircraft . Current project is an EGT system to get best possible leaning

User avatar
ohararp
Posts: 194
Joined: Tue Oct 03, 2006 11:29 pm
Location: Dayton, OH USA
Contact:

Post by ohararp » Tue Jun 21, 2011 2:28 pm

Peter, I had forgotten I had played with these a while back and could never get 18-bit mode working. Thanks for the great module. Unfortunately, I was unable to run this in SF (seems like it has been really buggy lately) on the 18F26K22 chips I wanted to use. However, I got everything up and running in PDS and will be doind a quick writeup on my app (direct strain measurement of a load cell from the wheatstone bridge). These fit the bill perfect for this project! Thanks!
Thanks Ryan
$25 SMT Stencils!!!
www.ohararp.com/Stencils.html

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Post by David Barker » Tue Jun 21, 2011 3:02 pm

What's been really buggy? If you mean the compiler, more of a meaningful description of the problem would be helpful. I think most registered users of the latest build have been rather pleased with the compiler support of late and comments like this are not helpful.

User avatar
ohararp
Posts: 194
Joined: Tue Oct 03, 2006 11:29 pm
Location: Dayton, OH USA
Contact:

Post by ohararp » Tue Jun 21, 2011 4:44 pm

David, thanks for checking in on this. I really like to use SF vs PDS but have been trying ot use the last set of 18FKX622 series parts without much luck. I can use the 18F25K20 all day long but have yet to make some good attempts with these other parts. I was able to get it working in PDS so that will be a good baseline for asm etc. I'll get some source code up here ofr review/debate.

PS Sorry for saying the dreaded "bug" word. I think it would have been more approriate to say at first try I was not able to get this module and source up and running.
Thanks Ryan
$25 SMT Stencils!!!
www.ohararp.com/Stencils.html

matherp
Registered User
Registered User
Posts: 31
Joined: Tue May 31, 2011 2:59 pm
Location: Cambridge

Post by matherp » Tue Jun 21, 2011 4:50 pm

Ryan

I've got both 25K22 and 26K22 working well with SF after Jerry's help. See
http://www.sfcompiler.co.uk/forum/viewtopic.php?t=1481
for essential changes to setalldigital needed for these chips which must be called before using i2c etc.. The issue is that there are key registers not in the access page. I've also got DS30 bootloader versions working. I'm away from home at the moment - if you are interested let me know and I can post them when I return

Best regards

Peter

Jerry Messina
Swordfish Developer
Posts: 1469
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Tue Jun 21, 2011 5:01 pm

Another thing to watch out for with the K22 series is that the IO pins have slew-rate control, and they default to 'slow' mode.

This slows the pin transitions down by a factor of 10, so that can be an issue as well. See the SLRCON register.

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Post by David Barker » Tue Jun 21, 2011 5:15 pm

> I can use the 18F25K20 all day long but have yet to make some
> good attempts with these other parts. I was able to get it working
> in PDS so that will be a good baseline for asm etc. I'll get some
> source code up here ofr review/debate.

The Swordfish compiler generates the same ASM code, whether it's a 18F452 or 18F25K22. PDS works in a similar way. However, the register definitions and setup requirements are, in most case, completely different and will guide the compiler accordingly. Jerry has done great work with some of his recent modules and other users (like Peter) are building on this work.

If you are unable to put these pieces together, by all means ask for help on the forum and I and others will try and help. However, please don't say the compiler is 'really buggy lately' without some serious qualification. The Swordfish code generator is as good as many competing products - in addition, the open source nature of the modules makes the product even more versatile.

Post Reply