PDA

View Full Version : SHIFTIN SHIFTOUT timing problem



BrianT
- 9th April 2010, 08:45
Does anyone know how to lengthen (slow down) the LOW period of the SHIFT clock?
The statement


DEFINE SHIFT_PAUSEUS 2

extends the HIGH period of the shift clock to about 10 uS but the LOW period remains fixed at about 2 uS. I need to retain something close to a 50:50 duty cycle but at a lower speed with about 10 uS HIGH and 10 uS LOW.

Cheers
Brian

Steve_88
- 9th April 2010, 19:22
I've dealt with this two ways, manually modify the shiftin/out library adding nop's in assembler to create a delay, or a better option is to bit bang the routines manually. This way you have complete control of the timing. Examples here

http://www.melabs.com/resources/samples/pbc/shift.bas

BrianT
- 10th April 2010, 00:28
Thanks for that Steve.

I had considered the bit bang approach and had found the BS2 routines on the Melabs site. I am using the Intersema pressure transducer which needs the SHIFTOUT value\bits option to clock out some 2 and 3 bit values as well as regular 8 bit bytes. I guess I'll just have to bite the bullet and dive into the assembler. The lazy option is not going to cut it.

Cheers
Brian

Steve_88
- 13th April 2010, 18:06
Hey Brian,

No need to use assembler depending upon yout timing requirements. You can insert pauses in the routines to meet your requirements. This also can makes it easy to read and write different numbers of bits.

BrianT
- 14th April 2010, 01:45
I could not make the PBP ShiftIn or ShiftOut routines work reliably with the latest Intersema MS5541C although the same code had worked a treat for several years. Intersema must have made some internal changes, one at least to reduce power consumption when MClk stops, or maybe meLabs has tweaked some code.

Intersema show DIn must be stable before SClk goes high. ShiftOut in PBP shows this as Mode 0. In the direction from Intersema to PIC, ShiftIn mode 2 should get the sense and timing right according to the PBP and Intersema waveform sketches. The problem seems to be that neither Intersema nor PBP specifies the setup time between data change and clock strobe. On an oscilloscope the clock follows data by a few hundred of nanoseconds which ought to be enough but I get many bad reads with the potted ShiftIn and ShiftOut routines.

I hand coded the 7 commands from PIC to Intersema and the single reply code from Intersema to PIC. The code is none too elegant but it now works 100% every time. Previously I was getting about 75% mis-reads of pressure data and some DA5541C chips would not work at all.



OutShift:
for fa = 1 to clockbits 'OutShift adds an extra bit at the end
din = (1 & iword) 'select lowest bit &
pauseus 1 'will actually be 4 uS or so
sclk = 1 : pauseus 1 : sclk = 0
iword = iword >> 1 'get next LSB, clock out zeros after 16 bits
next fa
sclk = 1 : pauseus 1 : sclk = 0 'extra clock per DA5541B_00513 page 13
return

ResetIntersema: ' resets ALL pressure sensors
' shiftout din, sclk, 0, [85, 85, 0\5] ' Sense of Din is IN to 5541
output din : output sclk
clockbits = 20 : iword = %0101010101010101 '16 bit data word
gosub outshift
return

ConvertDelay: ' specific to each sensor
if tank = 0 then
While dout0 = 1
wend
endif
if tank = 1 then
While dout1 = 1
wend
endif
if tank = 2 then
While dout2 = 1
wend
endif
return

FetchWord: ' read specific channel reply
input dout0 : input dout1 : input dout2 : output sclk : iword = 0
if tank = 0 then
for fa = 15 to 0 step -1 'need 17 clock bits so add one at end
sclk = 1 : pauseus 1 'wait for Intersema to present next bit
iword.0[fa] = dout0 'read the bit on selected channel
sclk = 0 'drop clock
next fa 'do it 16 times
endif
if tank = 1 then
for fa = 15 to 0 step -1 'need 17 clock bits so add one at end
sclk = 1 : pauseus 1 'wait for Intersema to present next bit
iword.0[fa] = dout1 'read the bit
sclk = 0 'drop clock
next fa 'do it 16 times
endif
if tank = 2 then
for fa = 15 to 0 step -1 'need 17 clock bits so add one at end
sclk = 1 : pauseus 1 'wait for Intersema to present next bit
iword.0[fa] = dout2 'read the bit
sclk = 0 'drop clock
next fa 'do it 16 times
endif
sclk = 1 : pauseus 1 : sclk = 0 ' 17th clock bit
ii = iword.byte0 : ij = iword.byte1
return

ReadFactoryCal:
' This unpacks the factory calibration coefficients from the just
' read W1 ~ W4.
' These bitmaps are unpacked into the 6 working coefficients
' C1 to C6 which are then stored in EEROM for later use.
'W1
gosub resetintersema
' shiftout din, sclk, 0, [87, 1\5] ' Send W1 pattern to all sensors
clockbits = 12 : iword = %000101010111 'request W1 pattern
gosub outshift
gosub fetchword ' recall selected Tank reply
W1.byte0 = ii
W1.byte1 = ij
if (w1 = 0) or (w1 = 65535) then
debug "W1 error", 13, 10
goto readfactorycal
endif

'W2
gosub resetintersema
' shiftout din, sclk, 0, [215, 0\5] ' Send W2 pattern
clockbits = 12 : iword = %000011010111
gosub outshift
gosub fetchword
W2.byte0 = ii
W2.byte1 = ij
if (w2 = 0) or (w2 = 65535) then
debug "W2 error", 13, 10
goto readfactorycal
endif

'W3
gosub resetintersema
' shiftout din, sclk, 0, [55, 1\5] ' Send W3 pattern
clockbits = 12 : iword = %000100110111
gosub outshift
gosub fetchword
W3.byte0 = ii
W3.byte1 = ij
if (w3 = 0) or (w3 = 65535) then
debug "W3 error", 13, 10
goto readfactorycal
endif

'W4
gosub resetintersema
' shiftout din, sclk, 0, [183, 0\5] ' Send W4 pattern
clockbits = 12 : iword = %000010110111
gosub outshift
gosub fetchword
W4.byte0 = ii
W4.byte1 = ij
if (w4 = 0) or (w4 = 65535) then
debug "W4 error", 13, 10
goto readfactorycal
endif

CalcCoefficients: ' this serves all three sensors.
'C1
C1 = W1 >> 3 'unpack coefficient
read (108 + tank*20), z.byte0 'store
read (109 + tank*20), z.byte1
if z<>c1 then
write (108 + tank*20), c1.byte0 'store
write (109 + tank*20), c1.byte1
endif
'C2
C2 = ((W1 & %0000000000000111) << 10) + (W2 >> 6)
read (110 + tank*20), z.byte0
read (111 + tank*20), z.byte1
if z<>c2 then
write (110 + tank*20), c2.byte0
write (111 + tank*20), c2.byte1
endif
'C3
C3 = W3 >> 6
read (112 + tank*20), z.byte0
read (113 + tank*20), z.byte1
if z<>c3 then
write (112 + tank*20), c3.byte0
write (113 + tank*20), c3.byte1
endif
'C4
C4 = W4 >> 7
read (114 + tank*20), z.byte0
read (115 + tank*20), z.byte1
if z<>c4 then
write (114 + tank*20), c4.byte0
write (115 + tank*20), c4.byte1
endif
'C5
C5 = ((W2 & %0000000000111111) << 6) + (W3 & %0000000000111111)
read (116 + tank*20), z.byte0
read (116 + tank*20), z.byte0
if z<>c5 then
write (117 + tank*20), c5.byte1
write (117 + tank*20), c5.byte1
endif
'C6
C6 = W4 & %0000000001111111
read (118 + tank*20), z
if z<>c6 then
write (118 + tank*20), c6
endif

Show5541Coefficients: 'only used during diagnostics
' high txd : pause 1
' debug 13, 10, "Tank #", #tank, ", W1 = ", #w1, ", W2 = ",_
' #w2, ", W3 = ", #w3, ", W4 = ", #w4, 13, 10
' debug "Derived coeffs C1 = ", #C1, ", C2 = ", #C2, ", C3 = ",_
' #C3, ", C4 = ", #c4, ", C5 = ", #C5, ", C6 = ", #C6, 13, 10

return

ReadTank: ' D1 is Pressure - D2 is Temperature. Same code for all 3.
'MUST know Tank# before calling this routine.
'D1
gosub resetintersema
' shiftout din, sclk, 0, [47, 0\5] ' Select D1 pattern
clockbits = 11 : iword = %00000101111
gosub outshift
gosub convertdelay
gosub fetchword
d1.byte0 = ii
d1.byte1 = ij
if (d1 = 0) or (d1 = 65535) then
debug "D1 error", 13, 10
goto readtank
endif


'D2
gosub resetintersema
'shiftout din, sclk, 0, [79, 0\5] ' Select D2 pattern
clockbits = 11 : iword = %00001001111
gosub outshift
gosub convertdelay
gosub fetchword
D2.byte0 = ii
D2.byte1 = ij
if (d2 = 0) or (d2 = 65535) then
debug "Tank ", #tank, ", D2 error", 13, 10
goto readtank
endif

CalcTempPress:
read (108 + tank*20), c1.byte0
read (109 + tank*20), c1.byte1
read (110 + tank*20), c2.byte0
read (111 + tank*20), c2.byte1
read (112 + tank*20), c3.byte0
read (113 + tank*20), c3.byte1
read (114 + tank*20), c4.byte0
read (115 + tank*20), c4.byte1
read (116 + tank*20), c5.byte0
read (117 + tank*20), c5.byte1
read (118 + tank*20), c6

ut1 = 8*c5 + 10000
dt = d2 - ut1
if dt < 0 then
dt2 = dt - (dt*dt)/(128*64)
else
dt2 = dt - (dt*dt)/(128*16)
endif
' tanktemp = 200 + (dt*(c6+100))/2048 'simpler form, less accurate??
tanktemp = 200 + dt2*(c6 + 100)/2048
offset = c2 + ((c4 - 250)*dt)/4096 + 10000
senstvty = c1/2 + ((c3 + 200)*dt)/8192 + 3000
tankpress = (senstvty*(d1 - offset))/4096 + 1000

BoundsCheck:
if (tankpress > 8000) or (tankpress < 700) then
debug 13, 10, "Bounds error. Tank = ",#tank, ", TankPress = ", _
#tankpress," mB", 13, 10
goto readtank 'retry until value is within bounds
endif

if tank = 0 then
t0pressure = tankpress
t0celsius = tanktemp
' debug "T0 D1, D2 = ", dec d1,", ", dec d2, ", T0 Pressure = ", dec t0pressure, ", Temp ", dec t0celsius, 13, 10
endif

if tank = 1 then
t1pressure = tankpress
t1celsius = tanktemp
' debug "T1 D1, D2 = ", dec d1,", ", dec d2, ", T1 Pressure = ", dec t1pressure, ", Temp ", dec t1celsius, 13, 10
endif

if tank = 2 then
t2pressure = tankpress
t2celsius = tanktemp
' debug "T2 D1, D2 = ", dec d1,", ", dec d2, ", T2 Pressure = ", dec t2pressure, ", Temp ", dec t2celsius, 13, 10
endif
return



The minimum pauseus is 4 uS so there is now plenty of time for the data to stabilise before the clock strobe.

The Intersema pressure sensors are spectacular little temperature and pressure sensors and up until some recent changes have served me very well. With this new code, the conversion takes about 1 mS longer and the code is slightly bigger but I am now in control of the read & write process.

I hope someone finds this useful.

Cheers
BrianT

Steve_88
- 15th April 2010, 02:17
Hi Brian,

Glad you have it working. Can you tell a little more about what your doing with the pressure/temperature sensors? I do a lot of data acquisition work involving those types of measurements.

Thanks

BrianT
- 15th April 2010, 03:06
Hi Steve,
I use the MS5540 1 bar sansor for reading atmospheric pressure in a sample chamber where I must know the oxygen partial pressure very accurately. I also use this sensor for altitude in bird migration studies.

I use several MS5541 14 bar sensors in a gas mixer where I can mix O2, CO2 and N2 to 0.1 mB precision. I also use these in archival dataloggers which are surgically implanted in salmon, tuna, kingfish and penguins for physiological studies of aquaculture species.

Cheers
Brian

Ramius
- 18th March 2011, 11:03
Hi All!
I am very new to all of this and trying to learn and study what and how those of you who know this very well are doing. Is there any chance I could see the whole program/code for the MS5541 for a single unit? It would be very much appreciated.

Thanks, Ed

BrianT
- 18th March 2011, 12:45
Hi Ed,

Here is a code snip for driving the Intersema MS5541.



'************************* Defines *****************************

DEFINE OSC 4 'Define crystal frequency
DEFINE DEBUG_REG PORTB 'Debug output pin port
DEFINE DEBUG_BIT 6 'Debug output pin bit
DEFINE DEBUG_BAUD 19200 'Debug baud rate
DEFINE DEBUG_MODE 0 'Debug mode: 0 = True, 1 = Inverted


'************** Intersema Variables *********************************
C1 var word ' 5540 Pressure sensitivity
C2 var word ' 5540 Pressure Offset
C3 var word ' 5540 Temp Coef of pressure sensitivity
C4 var word ' 5540 Temp Coef of Pressure Offset
C5 var word ' 5540 Reference temperature
C6 var word ' 5540 temp coef of Temp reading
' C1 to C6 are in EEROM as VAL.byte0, VAL.byte1 from 108 to 159
D1 var word ' raw pressure word from Intersema sensor
D2 var word ' raw temperature word
D1Flag var bit
W1 var word ' coefficient from 5540
W2 var word ' coefficient from 5540
W3 var word ' coefficient from 5540
W4 var word ' coefficient from 5540
' W1 to W4 are NOT stored in EEROM - they are not needed again.
dT var long ' intermediate calc value
dT1 var long ' intermediate calc value
dT2 var long
UT1 var word ' Calibration temperature
II var byte 'used ONLY within Intersema routines
IJ var byte
IK var byte
IL var byte
ILoop var word
CalFlag var bit 'EEROM 99. Used to reduce wear on EEROM

'General purpose Intersema and DS1629 RTC/Temperature variables
ClkChk var word '= 8192 if IntRC clock is exactly on frequency
TimeFlag var bit
TempRead var word
CntRem var word
CntPerC var word

IW var long
IX var long
IY var long
IZ var long

T2 var long 'Second order Temperature correction
P2 var long 'Second order Pressure correction
Offset var long
Senstvty var long
Pressure var long '
Celsius var long 'a LONG allows negative temperatures

goto endofsubroutines ' jump subroutines at startup
'*************************** Subroutines *****************************

ResetIntersema:
' need 32768 @ 50% for Intersema on CCP2.
TRISB = %10000001 : TRISD.7 = 0 'DIn, DOut & SClk
high presspwr : pause 100 : hpwm 2, 127, 32767 : pause 50
shiftout din, sclk, 0, [85, 85, 0\5] ' Sense of Din is IN to 5541
pauseus 100
return

FetchWord:
shiftin dout, sclk, 2, [ij, ii, ik\1]
'IJ is hi byte, II is lo byte, IK is a dummy and discarded
return

CalSensor:
read 99, calflag : if calflag = 1 then calsensordone
debug 13, 10, "Fetch Intersema data", 13, 10
' This fetches and unpacks the factory calibration coefficients
' from W1 ~ W4. W values need not be stored.
' These bitmaps are unpacked into the 6 working coefficients
' C1 to C6 which must be stored in EEROM for later use.
'W1
gosub resetintersema
shiftout din, sclk, 0, [87, 1\5] ' Send W1 pattern to all sensors
gosub fetchword ' get reply
W1.byte0 = ii
W1.byte1 = ij

'W2
gosub resetintersema
shiftout din, sclk, 0, [215, 0\5] ' Send W2 pattern
gosub fetchword
W2.byte0 = ii
W2.byte1 = ij

'W3
gosub resetintersema
shiftout din, sclk, 0, [55, 1\5] ' Send W3 pattern
gosub fetchword
W3.byte0 = ii
W3.byte1 = ij

'W4
gosub resetintersema
shiftout din, sclk, 0, [183, 0\5] ' Send W4 pattern
gosub fetchword
W4.byte0 = ii
W4.byte1 = ij

'Unpack W1 ~ W4 into C1 ~ C6 coefficients
'C1
C1 = W1 >> 3
write 108, c1.byte0
write 109, c1.byte1
'C2
C2 = ((W1 & %0000000000000111) << 10) + (W2 >> 6)
write 110, c2.byte0
write 111, c2.byte1
'C3
C3 = W3 >> 6
write 112, c3.byte0
write 113, c3.byte1
'C4
C4 = W4 >> 7
write 114, c4.byte0
write 115, c4.byte1
'C5
C5 = ((W2 & %0000000000111111) << 6) + (W3 & %0000000000111111)
write 116, c5.byte0
write 117, c5.byte1
'C6
C6 = W4 & %0000000001111111
write 118, c6.byte0
write 119, c6.byte1

' high pgc : pause 1
' debug "Intersema Factory data ", $0D, $0A, "W1 = ,"_
' , #w1, ", W2 = ,", #w2, ", W3 = ,", #w3, ", W4 = ,", #w4, $0D, $0A
' debug "Derived coefficients", $0D, $0A, "C1 = ,", #C1, ", C2 = ,", #C2,_
' ", C3 = ,", #C3, ", C4 = ,", #c4, ", C5 = ,", #C5, ", C6 = ,", #C6.byte0,_
' $0D, $0A

' read 99, calflag : if calflag = 0 then write 99, 1
CalSensorDone:
return

ReadIntersema: '
' D1 is Pressure - D2 is Temperature
' Uses LONG datatype to handle negative temperatures
' This routine reads the sensor and returns Pressure word
' and Celsius long
' A, II, IJ, W and X are all destroyed

gosub resetintersema
'D1
shiftout din, sclk, 0, [47, 0\5] ' Select D1 pattern
While dout = 1 : wend 'Convert5541Delay:
gosub fetchword
' This returns ii = lobyte, ij = hibyte from the sensor
D1.byte0 = ii
D1.byte1 = ij
'D2
shiftout din, sclk, 0, [79, 0\5] ' Select D2 pattern
While dout = 1 : wend
gosub fetchword
D2.byte0 = ii
D2.byte1 = ij

CalcTempPress: '32 bit signed arithmetic version. Handles negatives.
read 108, c1.byte0
read 109, c1.byte1
read 110, c2.byte0
read 111, c2.byte1
read 112, c3.byte0
read 113, c3.byte1
read 114, c4.byte0
read 115, c4.byte1
read 116, c5.byte0
read 117, c5.byte1
read 118, c6.byte0

'formulae for DS5541 are NOT the same as for DS5540
ut1 = 8*c5 + 10000
dt = d2 - ut1
Celsius = 200 + dt*(c6 + 100)/2048
offset = c2 + ((c4 - 250)*dt)/4096 +10000
senstvty = c1/2 + ((c3 + 200)*dt)/8192 + 3000
pressure = (senstvty * (d1 - offset))/4096 + 1000

'NOT applying second order temperature correction in this
'version.
'Note 2nd order correction formula ambiguity in datasheet.

if celsius < 0 then 'high bit of 32 bit number is set
temp2 = 1000 - celsius
else
temp2 = 1000 + celsius
d[17] = temp2.byte0
d[18] = temp2.byte1
endif
if calflag = 0 then
high pgc : pause 1
debug "MS5541 Celsius = ", sdec Celsius/10, ".", dec1 celsius//10, _
", Pressure = ", dec pressure, " mBar, recorded as ",_
dec temp2, 13, 10
endif
return


EndOfSubRoutines:
'*********************** Initialise *****************************

FetchDepth:
gosub readintersema
'debug "T2 = ", dec temp2, 13, 10
debug dec (temp2 - 1000)/10, ".", dec1 (temp2 - 1000)//10, _
", ", #pressure, " mBar", 13, 10

'this returns Pressure & Celsius, both words.
hpwm 2, 0,0 'turn off Mclk

ShutDown:
gosub shutdownmemory
gosub lowestpower
end

ZZZZZ:

HTH
Brian

Ramius
- 29th March 2011, 00:43
My guess is that Brian is busy? I was wondering if anyone would know how to do the PIC pin assignments? Several things have me lost such as in the code there is only 1 reference to the sensor's MCLK pin? Mostly I am familiar with using:
' ** Declare Pins Used **
Sclk Var PortB.0
Din Var PortB.1
This code has me completely lost!

Thanks in advance, eventually it will all come back to me, Ed

BrianT
- 30th March 2011, 00:46
Hi Ed,
Yes you do need a set of hardware defines such as
MClk VAR PortC.1
SClk VAR PortC.4

MClk in my design is driven by CCP2 so it cannot be randomly assigned but any of the other Intersema pins can be attached to any PIC pins.

YOU, and only you, can write the hardware defines as they are dependent on how you have laid out your circuit board.

Or have I missed your question?

HTH
BrianT

Ramius
- 30th March 2011, 14:25
Thanks Brian! :)
Yes I noticed that depending upon the PIC there is only one pin marked as CCP2. My guess is that by using HPWM the PIC knows to use this pin and it still must have a hardware definition? MCLK is shown as a comment so it has been confusing to know what to do for the hardware defines. Another thing I did not understand is why use CCP2 and not CCP1?

For 3.3 v to 5.0 v conversion (bi-directional) a device that does this known as the ADG3304 if this is of value. The device can also be used for other voltage level changes.

Variations in atmospheric pressure causes the zero reference point (the surface of the water) to change so to maintain accuracy a simple water detector (two transistors) could be used to set the zero reference (surface) point.

Thanks for answering and hope I have made some small contribution to you and others.

Ed

Ramius
- 8th April 2011, 18:54
A little help please.

high presspwr ' there is no pin defined as presspwr

temp2 = 1000 - celsius ' there is no variable named temp2

d[17] = temp2.byte0
d[18] = temp2.byte1 ' There is no array named d.

high pgc ' there is no pin defined as pgc

gosub shutdownmemory ' there is no sub-routine with this name

gosub lowestpower ' there is no sub-routine with this name either end '

I do not wish it to stop or end just continue to get int information.

Thanks, Ed

Archangel
- 11th April 2011, 21:08
high presspwr ' there is no pin defined as presspwr If that is so, then pick one and make it so, some thing like


presspwr var PortA.0

temp2 = 1000 - celsius ' there is no variable named temp2
temp2 var word 'a byte only holds 0-255


d[17] = temp2.byte0
d[18] = temp2.byte1 ' There is no array named d.
assigns value to 2 bytes in array, set up array,


d var byte[18]



high pgc ' there is no pin defined as pgc
again make a pin do this by assigning it to that duty

pgc var PortA.1 ' or some other unused pin

gosub shutdownmemory ' there is no sub-routine with this nameMake a sub directory or remove the call to it and send the code elsewhere using
goto or gosub as appropriate.

gosub lowestpower ' there is no sub-routine with this name either end '


I do not wish it to stop or end just continue to get int information. same answer as above. this is the disadvantage to using code you did not write, you are forced into the position of clairvoyant as you try to imaging what the programmer envisioned.
Probably the best argument for chewing through someone else's code is to learn from it, the cost is the frustration of trying to understand it.
I hope you found something useful in my rant,
JS