Need help with my Max31856 thermocouple program
Capt. Quirk
Posts: 872
I believe my problem is with how I am sending a byte address and a byte of data to
PUB Config_Data. The max 31856 is intended to work with 8 bit micro-processors.
I think my problem is I am sending byte of hex data, and when it gets to the Config_Data
routine it is converted to a long and Config_Data only reads the first the first 8 bits.
Bill M.
PUB Config_Data. The max 31856 is intended to work with 8 bit micro-processors.
I think my problem is I am sending byte of hex data, and when it gets to the Config_Data
routine it is converted to a long and Config_Data only reads the first the first 8 bits.
Bill M.
CON '' Max31856.spin
{{ Copied portions of:
* Propeller SPI Engine ... Spin Version v1.0 *
* Author: Beau Schwabe *
* Copyright (c) 2009 Parallax *
* PlayingWithFusion_MAX31856.c
-----------------------------------------------------------
Notes:
Use Mode 3, Msbpost for Writes and Reads
CS0 must idle high !!
}}
CON
_clkmode = xtal1 + pll8x
_xinfreq = 10_000_000
' Write Registers
Write_REG_CR0 = $80 ' Config Reg 0 - See Datasheet, pg 19
Write_REG_CR1 = $81 ' Config Reg 1 - averaging and TC type
Write_REG_MASK = $82 ' Fault mask register (for fault pin)
Write_REG_CJHF = $83 ' Cold Jcn high fault threshold, 1 degC/bit
Write_REG_CJLF = $84 ' Cold Jcn low fault threshold, 1 degC/bit
Write_REG_LTHFTH = $85 ' TC temp high fault threshold, MSB, 0.0625 degC/bit
Write_REG_LTHFTL = $86 ' TC temp high fault threshold, LSB
Write_REG_LTLFTH = $87 ' TC temp low fault threshold, MSB, 0.0625 degC/bit
Write_REG_LTLFTL = $88 ' TC temp low fault threshold, LSB
Write_REG_CJTO = $89 ' Cold Jcn Temp Offset Reg, 0.0625 degC/bit
Write_REG_CJTH = $8A ' Cold Jcn Temp Reg, MSB, 0.015625 deg C/bit (2^-6)
Write_REG_CJTL = $8B ' Cold Jcn Temp Reg, LSB
' Read Registers
Read_REG_CR0_Read = $00 ' Config Reg 0 - See Datasheet, pg 19
Read_REG_CR1_Read = $01 ' Config Reg 1 - averaging and TC type
Read_REG_MASK_Read = $02 ' Fault mask register (for fault pin)
Read_REG_CJHF_Read = $03 ' Cold Jcn high fault threshold, 1 degC/bit
Read_REG_CJLF_Read = $04 ' Cold Jcn low fault threshold, 1 degC/bit
Read_REG_LTHFTH_Read = $05 ' TC temp high fault threshold, MSB, 0.0625 degC/bit
Read_REG_LTHFTL_Read = $06 ' TC temp high fault threshold, LSB
Read_REG_LTLFTH_Read = $07 ' TC temp low fault threshold, MSB, 0.0625 degC/bit
Read_REG_LTLFTL_Read = $08 ' TC temp low fault threshold, LSB
Read_REG_CJTO_Read = $09 ' Cold Jcn Temp Offset Reg, 0.0625 degC/bit
Read_REG_CJTH_Read = $0A ' Cold Jcn Temp Reg, MSB, 0.015625 deg C/bit (2^-6)
Read_REG_CJTL_Read = $0B ' Cold Jcn Temp Reg, LSB
Read_REG_LTCBH_Read = $0C ' Linearized TC Temp, Byte 2, 0.0078125 decC/bit
Read_REG_LTCBM_Read = $0D ' Linearized TC Temp, Byte 1
Read_REG_LTCBL_Read = $0E ' Linearized TC Temp, Byte 0
Read_REG_SR_Read = $0F ' Status Register
' CR0 Configs
CMODE_OFF = $00
CMODE_AUTO = $80
ONESHOT_OFF = $00
ONESHOT_ON = $40
OCFAULT_OFF = $00
OCFAULT_10MS = $10
OCFAULT_32MS = $20
OCFAULT_100MS = $30
CJ_ENABLED = $00
CJ_DISABLED = $08
FAULT_AUTO = $00
FAULT_MANUAL = $04
FAULT_CLR_DEF = $00
FAULT_CLR_ALT = $02
CUTOFF_60HZ = $00
CUTOFF_50HZ = $01
' CR1 Configs
AVG_SEL_1SAMP = $00
AVG_SEL_2SAMP = $20
AVG_SEL_4SAMP = $40
AVG_SEL_8SAMP = $60
AVG_SEL_16SAMP = $80
B_TYPE = $00
E_TYPE = $01
J_TYPE = $02
K_TYPE = $03
N_TYPE = $04
R_TYPE = $05
S_TYPE = $06
T_TYPE = $07
{{ MASK Configs
CJ_HIGH_MASK = $20
CJ_LOW_MASK = $10
TC_HIGH_MASK = $08
TC_LOW_MASK = $04
OV_UV_MASK = $02
OPEN_FAULT_MASK = $01
' ----------------------------- Config Details -------------------------------
' Write_REG_CR0 = $80 ' Config Reg 0 - See Datasheet, pg 19
' CR0 Configs
CMODE_OFF = $00
ONESHOT_ON = $40
OCFAULT_OFF = $00
CJ_ENABLED = $00
FAULT_AUTO = $00
FAULT_CLR_DEF = $00
CUTOFF_60HZ = $00
'----------------------------
' Address: $80 'REG_CR0
' Write Data $40 'CR0_Data
' Write_REG_CR1 = $81 ' Config Reg 1 - averaging and TC type
' CR1 Configs
AVG_SEL_1SAMP = $00
K_TYPE = $03
'%x000_0011 = $03
'----------------------------
' Address: $81 'REG_CR1
' Write Data $03 'CR1_Data
Read_REG_LTCBH = $0C ' Linearized TC Temp, Byte 2, 0.0078125 decC/bit
Read_REG_LTCBM = $0D ' Linearized TC Temp, Byte 1
Read_REG_LTCBL = $0E ' Linearized TC Temp, Byte 0
CS0 must idle high !!
Msbpost for Writes and Reads
'' Used for SHIFTIN routines
'' MSBPOST = 2
'' MSBPOST - Most Significant Bit first ; data is valid after the clock
'' Used for SHIFTOUT routines
'' MSBFIRST = 5
'' MSBFIRST - Most Significant Bit first ; data is valid after the clock
'------------------- End Config Details -----------------------------------------------------
}}
CS0 = 0
'CS1 = 1
'CS2 = 2
'CS3 = 3
CLK = 1
MISO = 2 ' MISO
MOSI = 3 ' MOSI
ClockDelay = 500 ' spi pulse width
C_Konstant = 0.0078125 ' float used to convert data to celsius
F_Konstant = 1.8 ' float used to convert celsius to farenhiet
'-------------------------------------------------------------------------------------------
OBJ
pst : "Parallax Serial Terminal"
'----------------------------------------------------------------------------------------------
PUB Main | temp, tempC, tempF
pst.Start(115_200) ' Start the pst console.
waitcnt(clkfreq + cnt) ' min 200us delay
outa[CS0] := 1 ' CS0 idles high
' outa[CS0,CS1,CS2,CS3] := 1
' CS0 has 4 possible inputs on this board made by Playing with Fusion.
' http://www.playingwithfusion.com/productview.php?pdid=70
outa[clk]:= 0 ' clock idles low
'' I believe I am sending a long filled with a byte of data, and when "Config_Data"
'' runs, it is shifting in the msb of the long and not the msb of the byte I intended
'' it too.
Config_Data(CS0, $80, $40) ' Configure Address $80; $40 Config Data
Config_Data(CS0, $81, $03) ' Configure Address $81; $03 Config Data
waitcnt(clkfreq/4 + cnt) ' must have a ~200ms delay before the first conversion
' could change it to: waitcnt(16000000 + cnt) = .2ms
Repeat
' Config_Data(CS0, Address, Config) ' Update the current TC, for new data format, like
' 4 read average.
pst.clear
temp:= Lin_TC_Temp(CS0, $C) ' Pass the IC# and the address ($0C) to be read.
' return the binary 19 bit result
if temp == 0 ' A test to see if "Config_Data" was sucessful?
pst.str(string("No Data")) '
temp >>= 5 ' Convert 24 bit# into a 19 bit#
'' Convert binary output to celsius
tempC := C_Konstant * temp ' C_Konstant = .0078125
pst.dec(tempC) '
tempF := (tempC * F_Konstant) + 32 ' F_Konstant = 1.8
pst.dec(tempF)
' must have a ~200ms delay before the next single conversion
pst.str(string(pst#NL,"Test Complete"))
pst.Chars(pst#NL, 3)
waitcnt(clkfreq + cnt) ' Use a 1 second delay while testing.
' --------------------------------------------------------------------------------
PUB Config_Data(_CS, Address, Config) '' Should be OK ''
outa[_CS]:= 0 ' Clock idles HIGH
repeat 8 ' bits
Address <<= 8 ' shift a byte into the ic
outa[clk]:=1
outa[MOSI] := (Address <-= 1) & 1 ' config data is loaded to master data out
outa[clk]:= 0 ' data is latched inside max31856
pst.hex(Address, 2)
repeat 8 ' bits
Config <<= 8 ' shift a byte into the ic
outa[clk]:=1
outa[MOSI] := (Config <-= 1) & 1 ' config data is loaded to master data out
outa[clk]:= 0 ' data is latched inside max31856
pst.hex(Config,2)
outa[_CS]:= 1 ' CS0 idles HIGH
' --------------------------------------------------------------------------------
PUB Lin_TC_Temp(_CS, address) | Data ' address is $C
' Clock idles LOW
' CS0 idles HIGH
outa[_CS]:= 0 ' CS0 low
'' Address is OK ''
repeat 8 ' bits
Address <<= 8 ' shift a byte into the ic
outa[clk]:=1
outa[MOSI] := (Address <-= 1) & 1 ' config data is loaded to master data out
outa[clk]:= 0 ' data is latched inside max31856
'waitcnt(clkfreq/10 + cnt) ' delay between each byte write
repeat 24
PreClock(clk)
data := (data << 1) | ina[MISO]
outa[_CS]:= 1
Return Data
' ---------------------------------------------------------------------------------------------------
PUB PostClock(_Cpin)
waitcnt(ClockDelay + cnt)
!outa[_Cpin]
waitcnt(ClockDelay + cnt)
!outa[_Cpin]
' --------------------------------------------------------------------------------------------------------
PUB PreClock(_Cpin)
!outa[_Cpin]
waitcnt(ClockDelay + cnt)
!outa[_Cpin]
waitcnt(ClockDelay + cnt)

Comments
PUB Config_Data(_CS, Address, Config) '' Should be OK '' outa[_CS]:= 0 ' Clock idles HIGH Address <<= (32 - 8) ' Shift value to upper byte repeat 8 ' bits ' Address <<= 8 ' shift left an entire byte every iteration? ' shift a byte into the ic outa[clk]:=1 outa[MOSI] := (Address <-= 1) & 1 ' config data is loaded to master data out outa[clk]:= 0 ' data is latched inside max31856 pst.hex(Address, 2) Config <<= (32 - 8) repeat 8 ' bits ' Config <<= 8 ' shift a byte into the ic outa[clk]:=1 outa[MOSI] := (Config <-= 1) & 1 ' config data is loaded to master data out outa[clk]:= 0 ' data is latched inside max31856 pst.hex(Config,2) outa[_CS]:= 1 ' CS0 idles HIGH ' --------------------------------------------------------------------------------I've only messed with the MAX31855, which seems to be a completely different beast.
You've also got a problem with mixing floats and integers in your conversions. You either have to convert the integer reading from the MAX31856 into a float, multiply using your floating point constants, and use a float-to-string object to display it; or preferably instead of multiplying the reading by 0.0078125, you'd instead divide it by 128. To convert to Fahrenheit, you cannot use the floating 1.8 constant, but have to multiply by 9 and divide by 5, add 32. In order to not lose any lower bits, you could multiply by 900, divide by 5, and add 3200, yielding degrees F x 100.
I might need help on the accuracy in the future, but right now the temps are close.
Bill M.
I am interested in any suggestions to improve it. I am curious about the CJ temperature function,
and why it may or may not be necessary with this chip? The data sheet says the CJ temp is taken
in account before the TC temp is outputted.
I need to begin testing with tc temp averaging. The chip offers averaging of 2, 4, 8, and 16 samples.
There is no need for the software to be fast, but I do want to fine tune the accuracy, make the code as
reliable as possible, and I need to set-up a data acquisition, with a display asap.
Thanks for taking some time!
Bill M.
Any advice on writing code?
CON '' Test v0.1.6 {{ Copied portions of: * Propeller SPI Engine ... Spin Version v1.0 * * Author: Beau Schwabe * * Copyright (c) 2009 Parallax * * See end of file for terms of use. * PlayingWithFusion_MAX31856.c ----------------------------------------------------------- Notes: Use Mode 3, Msbpost for Writes and Reads CS0 must idle high !! 1. Add more diagnotic pst code, adjusted iputs, outputs pin declerations Commented the main loop so only the Configurion Registers section will run. Ran a ground wire from the board ti the spin stamp. 2. Add more diagnotic pst code, Uncommented the upper half of repeat loop 3. Added a longer pause inbetween config and TC data because on the first itteration ther was no data from the TC. But on each successive itteration the TC data was consistant. 4.The longer delay between config and TC data worked and no I get consistant TC data. 5. Added floating point routines to handle temp conversions 6. ** floating point routines to handle temp conversions Failled Program stalled at FP routines. 7. The floating point routines caused problems, and so I took some advice from Chris Gadd and simplified the math. 8. Ver.0.1.6 now works. 9. New version 0.1.7 and I am removing the clutter caused by the pst statements and update the comments. 10. New baseline program test v1.1.0 max31856 }} CON '*** Spin Stamp *** _clkmode = xtal1 + pll8x _xinfreq = 10_000_000 ' Write Registers Write_REG_CR0 = $80 ' Config Reg 0 - See Datasheet, pg 19 Write_REG_CR1 = $81 ' Config Reg 1 - averaging and TC type Write_REG_MASK = $82 ' Fault mask register (for fault pin) Write_REG_CJHF = $83 ' Cold Jcn high fault threshold, 1 degC/bit Write_REG_CJLF = $84 ' Cold Jcn low fault threshold, 1 degC/bit Write_REG_LTHFTH = $85 ' TC temp high fault threshold, MSB, 0.0625 degC/bit Write_REG_LTHFTL = $86 ' TC temp high fault threshold, LSB Write_REG_LTLFTH = $87 ' TC temp low fault threshold, MSB, 0.0625 degC/bit Write_REG_LTLFTL = $88 ' TC temp low fault threshold, LSB Write_REG_CJTO = $89 ' Cold Jcn Temp Offset Reg, 0.0625 degC/bit Write_REG_CJTH = $8A ' Cold Jcn Temp Reg, MSB, 0.015625 deg C/bit (2^-6) Write_REG_CJTL = $8B ' Cold Jcn Temp Reg, LSB ' Read Registers Read_REG_CR0_Read = $00 ' Config Reg 0 - See Datasheet, pg 19 Read_REG_CR1_Read = $01 ' Config Reg 1 - averaging and TC type Read_REG_MASK_Read = $02 ' Fault mask register (for fault pin) Read_REG_CJHF_Read = $03 ' Cold Jcn high fault threshold, 1 degC/bit Read_REG_CJLF_Read = $04 ' Cold Jcn low fault threshold, 1 degC/bit Read_REG_LTHFTH_Read = $05 ' TC temp high fault threshold, MSB, 0.0625 degC/bit Read_REG_LTHFTL_Read = $06 ' TC temp high fault threshold, LSB Read_REG_LTLFTH_Read = $07 ' TC temp low fault threshold, MSB, 0.0625 degC/bit Read_REG_LTLFTL_Read = $08 ' TC temp low fault threshold, LSB Read_REG_CJTO_Read = $09 ' Cold Jcn Temp Offset Reg, 0.0625 degC/bit Read_REG_CJTH_Read = $0A ' Cold Jcn Temp Reg, MSB, 0.015625 deg C/bit (2^-6) Read_REG_CJTL_Read = $0B ' Cold Jcn Temp Reg, LSB Read_REG_LTCBH_Read = $0C ' Linearized TC Temp, Byte 2, 0.0078125 decC/bit Read_REG_LTCBM_Read = $0D ' Linearized TC Temp, Byte 1 Read_REG_LTCBL_Read = $0E ' Linearized TC Temp, Byte 0 Read_REG_SR_Read = $0F ' Status Register ' CR0 Configs CMODE_OFF = $00 CMODE_AUTO = $80 ONESHOT_OFF = $00 ONESHOT_ON = $40 OCFAULT_OFF = $00 OCFAULT_10MS = $10 OCFAULT_32MS = $20 OCFAULT_100MS = $30 CJ_ENABLED = $00 CJ_DISABLED = $08 FAULT_AUTO = $00 FAULT_MANUAL = $04 FAULT_CLR_DEF = $00 FAULT_CLR_ALT = $02 CUTOFF_60HZ = $00 CUTOFF_50HZ = $01 ' CR1 Configs AVG_SEL_1SAMP = $00 AVG_SEL_2SAMP = $20 AVG_SEL_4SAMP = $40 AVG_SEL_8SAMP = $60 AVG_SEL_16SAMP = $80 B_TYPE = $00 E_TYPE = $01 J_TYPE = $02 K_TYPE = $03 N_TYPE = $04 R_TYPE = $05 S_TYPE = $06 T_TYPE = $07 {{ ****MASK Configs************** CJ_HIGH_MASK = $20 CJ_LOW_MASK = $10 TC_HIGH_MASK = $08 TC_LOW_MASK = $04 OV_UV_MASK = $02 OPEN_FAULT_MASK = $01 Write_REG_CR0 = $80 ' Config Reg 0 - See Datasheet, pg 19 CR0 Configs CMODE_OFF = $00 ONESHOT_ON = $40 OCFAULT_OFF = $00 CJ_ENABLED = $00 FAULT_AUTO = $00 FAULT_CLR_DEF = $00 CUTOFF_60HZ = $00 ---------------------------- Address: $80 'CR0_REG Write Data $40 'CR0_Data Write_REG_CR1 = $81 ' Config Reg 1 - averaging and TC type CR1 Configs AVG_SEL_1SAMP = $00 K_TYPE = $03 ---------------------------- Address: $81 'REG_CR1 Write Data $03 'CR1_Data Read_REG_LTCBH = $0C ' Linearized TC Temp, Byte 2, 0.0078125 decC/bit Read_REG_LTCBM = $0D ' Linearized TC Temp, Byte 1 Read_REG_LTCBL = $0E ' Linearized TC Temp, Byte 0 ------------------------------------------------------------------------ }} CS0 = 0 ' CS idles high (output) 'CS1 = 1 'CS2 = 2 'CS3 = 3 CLK = 1 ' clk idles low (output) MISO = 2 ' Din (input) MOSI = 3 ' Dout (output) CR0_REG = $80 ' configuration register CR0_Data = $40 ' configuration register data CR1_REG = $81 ' configuration register CR1_Data = $03 ' configuration register data TC_Temp = $0C ' first register location for a 3 byte read OBJ pst : "Parallax Serial Terminal" PUB Main | temp, tempC, tempF waitcnt(clkfreq/4 + cnt) ' min 200us delay ??? pst.Start(115_200) ' Start the pst console. ' clock and cs_x are always out puts and remain the same throughout ' the program. ' ------------------------------ Set up pin directions --------------------------------------------------- ' CS0 has 4 possible inputs on this board made by Playing with Fusion. ' http://www.playingwithfusion.com/productview.php?pdid=70 dira[CS0]~~ ' make cs_0 an output outa[CS0]~~ ' CS0 idles high ' outa[CS0,CS1,CS2,CS3]~~ dira[clk]~~ ' make the clock pin an output outa[clk]~ ' clock idles low dira[mosi]~~ ' make the mosi an output ' shiftout determines MOSI current state hi/lo, not Set-up dira[miso]~ ' make the miso an input ' shiftin determines MISO current state hi/lo, not Set-up ' --------------------------------- Set Configurion Registers ---------------------------------------------- Config_Data(CS0, 8, CR0_REG, CR0_Data) ' Configure Address $80; Config Data $40 waitcnt(1200 + cnt) ' 15us delay for diagnostic purposes Only Config_Data(CS0, 8, CR1_REG, CR1_Data) ' Configure Address $81; $03 Config Data waitcnt(clkfreq + cnt) ' must have a long delay before the first conversion Repeat ' Main Loop temp:= Lin_TC_Temp(CS0, TC_temp) ' Pass the IC# and the address ($0C) to be read. ' return the binary 24 bit result temp >>= 5 ' Convert 24 bit# into a 19 bit# tempC := temp / 128 pst.dec(tempC) pst.Chars(pst#NL, 1) ' tempF := ((tempC * 9/5) + 32) pst.dec(tempF) ' display 19 bit # for testing info pst.Chars(pst#NL, 1) waitcnt(clkfreq/4 + cnt) ' Use a 1/4 second delay before looping back PUB Config_Data(CSpin, Bits, Register, Data) ' CS0, 8, CR0_REG, CR0_Data shiftout '' Config_Data is receiving data from each function call and '' pre-aligning the data proerly before it shifts the register '' and data out to the max31856. outa[CSpin]~ ' pull CS low to begin conversion '' Shiftout MSBFIRST Register <<= (32 - Bits) ' pre-align msb repeat Bits outa[MOSI] := (Register <-= 1) & 1 ' shiftout data one bit at a time PostClock ' spi clock routine '' Shiftout MSBFIRST Data <<= (32 - Bits) ' pre-align msb repeat Bits outa[MOSI] := (Data <-= 1) & 1 ' shiftout data one bit at a time PostClock ' spi clock routine outa[CSpin]~~ ' pull CS high back to idle position PUB Lin_TC_Temp(CSpin, TC_reg) | Data '' TC_Temp = $0C, The byte register address for raw 3 byte temperature data outa[CSpin]:= 0 ' pull CS low Data ~ ' clear data from last itteration ''MSBFIRST ' Shiftout Address TC_reg <<= (24) ' pre-align msb repeat 8 outa[MOSI] := (TC_reg <-= 1) & 1 ' shiftout data one bit at a time PostClock ' spi clock routine ''MSBPOST ' Shiftin TC Data to the propeller repeat 24 PreClock ' spi clock routine Data := (Data << 1) | ina[miso] ' shiftin data one bit at a time outa[CSpin]:= 1 ' reset CS high return Data ' back to the main loop PUB PostClock ' 1200 = 15us delay waitcnt(1200 + cnt) !outa[clk] waitcnt(1200 + cnt) !outa[clk] PUB PreClock ' 1200 = 15us delay !outa[clk] waitcnt(1200 + cnt) !outa[clk] waitcnt(1200 + cnt)If you're making decisions based on the temperature, it'd be a good idea to read the fault status register before accepting the data.
Not sure why you'd need a waitcnt at the beginning of the object.
A number of methods could be slightly simplified if you only have a single SPI device by hardcoding outa[CS0]~ rather than using a CSpin parameter.
Instead of having code for shifting data out in multiple places, I'd use a single method and call it as needed such as
PRI Transfer(Data,Bits) '' Send / receive Data <<= (32 - bits) ' Move data to MSB repeat bits outa[MOSI] := (Data <-= 1) & 1 ' Send from MSB outa[clk]~~ outa[clk]~ Data |= ina[MISO] ' Receive into LSB return Data & (|< Bits - 1) ' Mask received data and returnSpin is slow enough that you probably don't need to specify a clock delay.Nothing too glaring; those are all just personal preferences, the most important thing is if it works.
Good job with the version control; that's something that I struggle with--make a change, save as a new file, and later on forget what the difference is between my dozen or so files.