I was tinkering with an I2C routine on the 509 and it was annoying me that I had
to maintain a temporary port "shadow" variable to control the port data
direction register side of things. (I can supply the source for this)
For I2C, I prefer not to drive the outputs directly, but to use a 1K or 10K pull
up and switch the port "data direction register" to input/output so that I dont
end up with any nasty "sinking feelings" - driving the pic output into a held
low pin, for example (yes, it happened on a previous product - sucked the hold
up caps of their juice causing incomplete power downs)
Anyone have a clever way of getting around this....or am I stuck with a bloated
driver? Or, heaven forbid, do I have to go to 'direct drive' of the
outputs......
>Hi,
>
>I was tinkering with an I2C routine on the 509 and it was annoying me that I had
>to maintain a temporary port "shadow" variable to control the port data
>direction register side of things. (I can supply the source for this)
>
>For I2C, I prefer not to drive the outputs directly, but to use a 1K or 10K pull
>up and switch the port "data direction register" to input/output so that I dont
>end up with any nasty "sinking feelings" - driving the pic output into a held
>low pin, for example (yes, it happened on a previous product - sucked the hold
>up caps of their juice causing incomplete power downs)
>
>Anyone have a clever way of getting around this....or am I stuck with a bloated
>driver? Or, heaven forbid, do I have to go to 'direct drive' of the
>outputs......
>
>TIA
>
>Dan
I've never seen this as a problem - it's rare to be messing with TRIS
bits on anything other than I2C pins, so normally you know the fixed
bits of the TRIS value to write during the I2C code, and if you do
need to TRIS-twiddle outside the I2C code, the code that does this
will know what state to leave the I2C pins (i.e. idle) in as I2C bus
will probably be inactive outside of the I2C code.
The only time this won't work is if interrupt code is twiddling the
port.
For the vast majority of I2C devices in a single-master system, you
only need a pullup on SDA - SCL can be driven directly. According to
the I2C spec a slave can drive SCL to hold the bus but I've never seen
a device that does this.
I usually define 2 constants, sdalo and sdahi, for the TRIS bitmask to
set SDA low and high respectively, and write these constants to
TRIS<port> to set the required
If anyone's interested I have some highly optimised 16C5x code to
read/write one or more bytes from I2C eeproms (68 words code, 4 ram,
no stack)
imho, if you arrange all your I2C code to use only bsf and bcf type
instructions, and apply masking to all intructions operating on the
remaining bits of the port, then you do not really need a shadow. This works
for me. I only use a shadow when the port is used in multi-bit configuration
with arithmetic operations of some kind. The bit-banged operations I
implement always use bsf and bcf to access the port. The code size is rather
good like this (for me). If you mean the shadow of the tris register, then
no, there is no way around that, unless you have all other pins with fixed
directions, in which case you can do:
for example to turn a I2C data pin input:
movlw TRIS_PRESET ; a constant, I2C data bit is output (1) in it
tris GPIO
and output:
bsf GPIO,I2CBIT ; set output bit in buried output register high
movlw TRIS_PRESET
andlw TRIS_I2COUT ; bit mask, all 1's except I2C data bit
tris GPIO
I don't think that 6 instructions are too much for this.
>
>Hi,
>
>I was tinkering with an I2C routine on the 509 and it was annoying me that
>I had
>to maintain a temporary port "shadow" variable to control the port data
>direction register side of things. (I can supply the source for this)
>
>For I2C, I prefer not to drive the outputs directly, but to use a 1K or
>10K pull
>up and switch the port "data direction register" to input/output so that I
>dont
>end up with any nasty "sinking feelings" - driving the pic output into a held
>low pin, for example (yes, it happened on a previous product - sucked the hold
>up caps of their juice causing incomplete power downs)
>
>Anyone have a clever way of getting around this....or am I stuck with a
>bloated
>driver? Or, heaven forbid, do I have to go to 'direct drive' of the
>outputs......
>
>TIA
>
>Dan
Dan:
Haven't had a chance to look at Mike's code, but I would hard-code
TRIS values as well. Assuming that the port (GPIO reg) is set for a '0'
output on the desired pin, I would
MOVLW B'xxbb0bbb' ; select bits as req'd, i2c pin is 0-output
BTFSS STATUS,Carry ; assumes you are rolling the bits out
MOVLW B'xxbb1bbb' ; carry was 0 - make the pin an input
TRIS GPIO
This assumes you are shifting the bits out (through carry) and want
a low output for a 1, but you can see that this approach can be esily
modified for many situations. Hope it helps.
>Hi,
>
>imho, if you arrange all your I2C code to use only bsf and bcf type
>instructions, and apply masking to all intructions operating on the
>remaining bits of the port, then you do not really need a shadow. This works
>for me. I only use a shadow when the port is used in multi-bit configuration
>with arithmetic operations of some kind. The bit-banged operations I
>implement always use bsf and bcf to access the port. The code size is rather
>good like this (for me). If you mean the shadow of the tris register, then
>no, there is no way around that, unless you have all other pins with fixed
>directions, in which case you can do:
>
>for example to turn a I2C data pin input:
>
> movlw TRIS_PRESET ; a constant, I2C data bit is output (1) in it
> tris GPIO
>
>and output:
>
> bsf GPIO,I2CBIT ; set output bit in buried output register high
This should be BCF - you want a low output if the TRIS bit is enabled
> movlw TRIS_PRESET
> andlw TRIS_I2COUT ; bit mask, all 1's except I2C data bit
> tris GPIO
>
>I don't think that 6 instructions are too much for this.
"Peter L. Peres" wrote:
>
> ... The bit-banged operations I
>implement always use bsf and bcf to access the port. The code size is rather
>good like this (for me)...
I'd be careful with this approach. BSF and BCF are read before
write operations, so use the actual voltages on the pins to determine what
to write back to the GPIO port. If there's a 'difficult' load on the pin
(user puts very small R, large cap, etc. there) then the pin will be
written as this incorrect value, not what you originally wrote to it.
> I've never seen this as a problem - it's rare to be messing with TRIS
> bits on anything other than I2C pins, so normally you know the fixed
> bits of the TRIS value to write during the I2C code, and if you do
> need to TRIS-twiddle outside the I2C code, the code that does this
> will know what state to leave the I2C pins (i.e. idle) in as I2C bus
> will probably be inactive outside of the I2C code.
Also, one can let FSR point to TRISA/B and then bit-access both PORT
and TRIS bits without switching banks all the time!
>> I've never seen this as a problem - it's rare to be messing with TRIS
>> bits on anything other than I2C pins, so normally you know the fixed
>> bits of the TRIS value to write during the I2C code, and if you do
>> need to TRIS-twiddle outside the I2C code, the code that does this
>> will know what state to leave the I2C pins (i.e. idle) in as I2C bus
>> will probably be inactive outside of the I2C code.
>
>Also, one can let FSR point to TRISA/B and then bit-access both PORT
>and TRIS bits without switching banks all the time!
..except when using eeproms you often need the FSR to point to where
you're reading/writing the data!
since there exists no BCF on W one has to make do with what one can, such as
an AND with the inverted bit mask of the interesting bit. Maybe I did not
make myself clear. Here goes again:
If you have the code snippet:
bsf GPIO,I2CBIT
movlw TRIS_PRESET
andlw TRIS_I2COUT
tris GPIO
then TRIS_PRESET would be something like B'10101' and TRIS_I2COUT would be
B'11110' to turn GPIO,0 to output as I2C data line (SDA). If you mean the
bsf GPIO,I2CBIT, you are right, it should be bcf, to output low first.
Anyway a 220R series resistor with the SDA line never hurt anyone and helps
stop RF from travelling around on the SDA line. ;-)
> If you have the code snippet:
>
> bsf GPIO,I2CBIT
> movlw TRIS_PRESET
> andlw TRIS_I2COUT
> tris GPIO
>
> then TRIS_PRESET would be something like B'10101' and TRIS_I2COUT
> would be B'11110' to turn GPIO,0 to output as I2C data line (SDA).
Peter:
I meant to say something about this when you originally posted it...
There seems little need to waste a cycle performing an "and" on two
constants; with TRIS_I2COUT defined as 10100 and TRIS_I2CIN defined
as 10101, you could replace your movlw/andlw/tris with:
part 1 1966 bytes content-type:text/plain; charset=us-ascii
Hi Peter,
I was doing a direction change with another pin which made it necessary to use
the shadow. Oh well, at least I wasnt doing something over-complicated through
stupidity (like normal)
imho, if you arrange all your I2C code to use only bsf and bcf type
instructions, and apply masking to all intructions operating on the
remaining bits of the port, then you do not really need a shadow. This works
for me. I only use a shadow when the port is used in multi-bit configuration
with arithmetic operations of some kind. The bit-banged operations I
implement always use bsf and bcf to access the port. The code size is rather
good like this (for me). If you mean the shadow of the tris register, then
no, there is no way around that, unless you have all other pins with fixed
directions, in which case you can do:
for example to turn a I2C data pin input:
movlw TRIS_PRESET ; a constant, I2C data bit is output (1) in it
tris GPIO
and output:
bsf GPIO,I2CBIT ; set output bit in buried output register high
movlw TRIS_PRESET
andlw TRIS_I2COUT ; bit mask, all 1's except I2C data bit
tris GPIO
I don't think that 6 instructions are too much for this.
Peter
part 2 165 bytes content-type:application/octet-stream; (decode)
>>Mike: should be bcf
>
>Hi Mike,
>
>since there exists no BCF on W one has to make do with what one can, such as
>an AND with the inverted bit mask of the interesting bit. Maybe I did not
>make myself clear. Here goes again:
>
>If you have the code snippet:
>
> bsf GPIO,I2CBIT
^^^^^^^ this is the line I was pointing out as wrong. the GPIO bit must be set low, not high to get the required pulldown
when the corresponding TRIS bit is set low.
> movlw TRIS_PRESET
> andlw TRIS_I2COUT
> tris GPIO