PDA

View Full Version : I2CRead & I2CWrite not working as expected



Melanie
- 23rd July 2004, 17:04
I can't seem to Write properly to an I2C device
I can't seem to Read properly back from an I2C device
My I2C Serial EEPROM doesn't always save my data
I can't Write to the Registers on my I2C Real Time Clock, ADC etc


Check your I2CRead and IC2Write statements...

Do you have any CONSTANTS in the device address?

If so, your code is flawed... remove the constants and put in VARIABLES in their place...


Example: Write to location 8 on a 24LC32... these are NOT CORRECT...

I2CWrite SDA,SCL,$A0,$08,[DataA]
I2CWrite SDA,SCL,$A0,8,[DataA]
I2CWrite SDA,SCL,$A0,$0008,[DataA]
I2CWrite SDA,SCL,$A0,%00001000,[DataA]
I2CWrite SDA,SCL,$A0,%0000000000001000,[DataA]


Example: Write to location 8 on a 24LC32... this is CORRECT...

I2CAddress=8
I2CWrite SDA,SCL,I2CDevice,I2CAddress,[DataA]

where previously I2CAddress has been defined as a WORD, and I2CDevice has been defined as a BYTE and preloaded with $A0.

Remember that the type of VARIABLE I2CAddress must match the requirement for the device you are addressing... eg it's a WORD for devices like a 24LC32 or 24LC64, but it's a BYTE for other devices like a 24LC16 or DS1307 RTC. Check your device Datasheet.

F1CHF
- 13th April 2007, 23:53
Always and again Thanks Melanie for the support.
Just one question about the "label" at the end of a I2CWRITE command
I see in the help menu this sentence "If the optional Label is included, this label will be jumped to if an acknowledge is not received from the I2C device. "
My question :
Could we say this is a GOTO or a GOSUB command ?

I was "swimming" when I was building a prototype WITHOUT the I2C module
(TV RECEIVER MODULE) connected ....
Program was working ... let say 6 times ... and seems to go in a strange loop
... I would say a "dead loop" .... I use a Blinking led to follow the process !

I have removed this label, now it is working

Label is a sub routine with a return ...
I am sure I am wrong somewhere !
thanks in advance
Francois

skimask
- 14th April 2007, 00:00
My question :
Could we say this is a GOTO or a GOSUB command ?


It would be a GOTO command. I suppose it's a question of how you read the manual.
If the manual said 'If the optional Label is included, this label will be ----CALLED---- if an acknowledge is not received from the I2C device', then I would reasonably assume that it would be a goto...
But, the manual says 'this label will be ----JUMPED TO---- if an acknowledge....'. That tells me it's a GOTO.

If all else fails, check your .lst file and see what the compiler puts in there for you. Make a few 'special' labels so you can follow yourself thru the .lst file and search them in the file. You should be able to find what you need.

F1CHF
- 14th April 2007, 18:29
OK good, let assume this is a GOTO, that will explain my application
was going on a dead loop with a return ..
I must try to find a PBP Help File in FRENCH or read carrefully !
thanks for this help
Francois


It would be a GOTO command. I suppose it's a question of how you read the manual.
If the manual said 'If the optional Label is included, this label will be ----CALLED---- if an acknowledge is not received from the I2C device', then I would reasonably assume that it would be a goto...
But, the manual says 'this label will be ----JUMPED TO---- if an acknowledge....'. That tells me it's a GOTO.

If all else fails, check your .lst file and see what the compiler puts in there for you. Make a few 'special' labels so you can follow yourself thru the .lst file and search them in the file. You should be able to find what you need.

mister_e
- 14th April 2007, 18:37
good luck to find it in french... unless you want to try GooGLE or else on-line translator :eek: that will'nt be better ;)

CuriousOne
- 6th October 2021, 20:34
SDA var PORTA.1
SCL var PORTA.2
T1 var byte
T1=15
I2CAddress var word 'I2C address
I2CDevice var byte 'I2C device add
i2CDevice=$A0
I2CAddress=8
I2CWrite SDA,SCL,I2CDevice,I2CAddress,127
pause 100
i2cread SDA,SCL,I2CDevice,I2CAddress,T1
LCDOUT $FE,$c0, "value ", dEC T1
pause 1000
stop



Ports are set to digital, analog and comparators turned off. 4.7K resistors in place, 24C32 chip is brand new and authentic.
Only VDD/VSS and SDA/SCL pins are used, others are left floating, according to datasheet.
The interesting thing is, that i2cread returns nothing - I mean, I added T1=15 just for test, so that 15 is displayed, instead of 127
whole i2croutine doing nothing?

F1CHF
- 7th October 2021, 09:30
hello
start a TEST first to see if your I2C unit is OK
let go here
https://playground.arduino.cc/Main/I2cScanner/

francois

richard
- 7th October 2021, 11:17
Only VDD/VSS and SDA/SCL pins are used, others are left floating, according to datasheet.


start a TEST first to see if your I2C unit is OK
let go here


or read the data sheet again and work out the consequences of floating address pins on the device address

CuriousOne
- 8th October 2021, 06:09
From the datasheet:


DEVICE/PAGE ADDRESSES (A2, A1, A0): The A2, A1 and A0 pins are device address
inputs that are hard wired or left not connected for hardware compatibility with
AT24C16. When the pins are hardwired, as many as eight 32K/64K devices may be
addressed on a single bus system (device addressing is discussed in detail under the
Device Addressing section). When the pins are not hardwired, the default A2, A1, and A0
are zero.
WRITE PROTECT (WP): The write protect input, when tied to GND, allows normal write
operations. When WP is tied high to VCC, all write operations to the upper quandrant
(8/16K bits) of memory are inhibited. If left unconnected, WP is internally pulled down to
GND.

The A2, A1, and A0 pins use an internal proprietary circuit that biases them
to a logic low condition if the pins are allowed to float.

richard
- 8th October 2021, 08:02
to my surprise i found the 24c32 on my ds3231 module did not behave as expected when the resistor block [circled] was removed
to conserve energy for a battery device
9084

the address was still 0xAE, contrary to the datasheet , so i looked at a data sheet from another manufacturer, where for a 24c32n
they did not describe this address pin biased low behavior for their version

to ensure 0xA0 the pins needed to be grounded

so how sure are you that the datasheet matches the chip?
its an easy test

CuriousOne
- 8th October 2021, 08:06
I will try grounding. I will also hook up scope to see what happens.
I do have pull up resistors in place for SDA/SCL pins.
Regarding how I know about datasheet?
I bought this IC from digikey, and downloaded datasheet from the SKU page :)
This is genuine atmega part.

Ioannis
- 8th October 2021, 20:37
It could be that a static discharge killed the pull down circuitry, so the floating pins may not be a $A0 anymore.

I had in the past various issues with static and decided to be almost paranoid with this thing. Have anti-static mate on the floor, also on the bench and I earth my self too. Of course the soldering iron is earthed too by a tens of kΩ range resistor.

Chips from various vendors also have differences and datasheet may not cover that. Richard is right.

Ioannis

CuriousOne
- 8th October 2021, 20:42
Here I connected the scope.
This is how this code looks:
My scope (Hantek DSO2D10) Has I2C decode function, but I can't get it running properly.


mainloop:


For B0 = 0 To 15 step 2
I2CREAD DPIN,CPIN,$A0,B0,X
lcdout $fe, $1, dec b0, " ", dec X
pause 1000
Next B0


Goto mainloop


9085

CuriousOne
- 8th October 2021, 22:02
Oh by the way, I swapped chip with 24C04N - no difference.

CuriousOne
- 9th October 2021, 08:35
I set up I2C capture and it looks suspicious.
The 1st entry at "data" is actually and address of the chip
and 3rd entry - the address I'm sending to it for reading
but I'm getting no response?

9086

richard
- 9th October 2021, 10:04
yet still another pointless snippet , with nothing defined



I2CREAD DPIN,CPIN,$A0,B0,X


you persist in using incorrect syntax , it should be

I2CREAD DPIN,CPIN,$A0,B0,[X ]



proper code, not snippet with undefined rubbish, its not hard



#CONFIG __config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG
;pic16f1825

DEFINE OSC 32
OSCCON=$70
ANSELA=0
ANSELC=0
trisa.0=0
DEFINE I2C_SLOW 1
ANSELA = 0
a Var Byte
addr Var word
ar Var Byte


SCL var Porta.2
SDA var Porta.1
lata.0=1
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ; if not used for pwr
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug 13,10,"Start",13 ,10


a=20
addr=$200
I2cwrite Sda,SCL,$a0 ,addr,[a]
pause 10


addr=$200
I2CREAD Sda,SCL,$a0 ,addr,[ar ]
debug 13,10,sdec ar
end

what a write looks like

9087

what a read looks like

9088

CuriousOne
- 10th October 2021, 08:00
Well, if there's syntax error, compiler should warn about it, right?

CuriousOne
- 10th October 2021, 08:23
I tried to add brackets and now it starts working, but in the weird way.

I2CWRITE DPIN,CPIN,$A0,B0,[127]
Writes 127 into eeprom
but if I substitute variable there, no matter, byte or word
after reading, I'm getting zeroes.

richard
- 10th October 2021, 08:57
Well, if there's syntax error, compiler should warn about it, right?

no the compiler produces code to I2CREAD DPIN,CPIN from device $A0 @eeprom address B0,X then read nothing as asked for
there is no error



I tried to add brackets and now it starts working, but in the weird way.


I2CWRITE DPIN,CPIN,$A0,B0,[127]
Writes 127 into eeprom
but if I substitute variable there, no matter, byte or word
after reading, I'm getting zeroes.


produce a compliable example that demonstrates the problem

CuriousOne
- 10th October 2021, 09:03
DPIN Var PORTA.2 ' I2C data pin
CPIN Var PORTA.1 ' I2C clock pin
B0 Var word
B1 Var byte
B2 Var byte
X var byte
x=0


For B0 = 0 To 15
b1=b2
I2CWRITE DPIN,CPIN,$A0,B0,[99]
Pause 10 '
pause 100
Next B0


mainloop:


For B0 = 0 To 15
I2CREAD DPIN,CPIN,$A0,B0,[X]
lcdout $fe, $1, dec b0, " ", dec X
pause 1000
Next B0

Goto mainloop

End

richard
- 10th October 2021, 09:20
DPIN Var PORTA.2 ' I2C data pin
CPIN Var PORTA.1 ' I2C clock pinB0 Var wordB1 Var byteB2 Var byteX var bytex=0 For B0 = 0 To 15 b1=b2 I2CWRITE DPIN,CPIN,$A0,B0,[99] Pause 10 'pause 100 Next B0mainloop: For B0 = 0 To 15 I2CREAD DPIN,CPIN,$A0,B0,[X] lcdout $fe, $1, dec b0, " ", dec X pause 1000 Next B0 Goto mainloop </pre> End

so we guess whats wrong then

DPIN,CPIN are analog
the chip[undefined] has no porta
the vcc is too low
the clock is too fast
the lcd is not setup properly
the config settings are incorrect
the interrupt in the unseen part of the code is ruining the timing
what's the point

richard
- 10th October 2021, 09:27
this


'* pic16f1825 : eprom addr =$a0
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG


DEFINE OSC 32
OSCCON=$70
ANSELA=0
ANSELC=0
trisa.0=0
DEFINE I2C_SLOW 1
ANSELA = 0
B0 Var word
X var byte
SCL var Porta.2
SDA var Porta.1
lata.0=1
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ; if not used for pwr
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug 13,10,"Start",13 ,10
clear
For B0 = 0 To 15
I2CWRITE sda,scl,$A0,B0,[99]
Pause 10 '
Next B0
pause 100
mainloop:
For B0 = 0 To 15
I2CREAD sda,scl,$A0,B0,[X]
debug 13,10, dec b0, " ", dec X
Next B0
pause 1000
Goto mainloop
end




produces as expected this

Start


0 99
1 99
2 99
3 99
4 99
5 99
6 99
7 99
8 99
9 99
10 99
11 99
12 99
13 99
14 99
15 99

CuriousOne
- 10th October 2021, 09:32
Pins are configured properly, LCD also working fine.



TRISA=%00000000 'SET A TO OUTPUT
TRISC=%00001101
TRISB=%00011000
ANSELH=%00000000 ' ADC OFF B
ANSEL=%000000000 ' turn off ADC
ADCON1=%10000000 'adc justify
OSCCON=%01110101 'SET FREQUENCY TO 8MHZ
WPUB=%00000000 'turn off Pullups
CM1CON0=0 'DISABLE COMPARATORS
CM2CON0=0


This code works, if there is a number [99] or whatever in the write loop
If I modify that part to look like
I2CWRITE DPIN,CPIN,$A0,B0,[B1]
or any other variable instead of B1
all zeros get written into there, instead of actual variable value.

richard
- 10th October 2021, 09:58
This code works, if there is a number [99] or whatever in the write loop
If I modify that part to look like
I2CWRITE DPIN,CPIN,$A0,B0,[B1]
or any other variable instead of B1
all zeros get written into there, instead of actual variable value.


what code ?
minimal, complete and verifiable example MCVE , its not hard

this code

'* pic16f1825 : eprom addr =$a0 #CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG


DEFINE OSC 32
OSCCON=$70
ANSELA=0
ANSELC=0
trisa.0=0
DEFINE I2C_SLOW 1
ANSELA = 0
B0 Var word
b2 var byte
X var byte
SCL var Porta.2
SDA var Porta.1
lata.0=1
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ; if not used for pwr
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug 13,10,"Start",13 ,10
clear
For B0 = 0 To 15
b2=99+b0
I2CWRITE sda,scl,$A0,B0,[b2]
Pause 10 '
Next B0
pause 100
mainloop:
For B0 = 0 To 15

I2CREAD sda,scl,$A0,B0,[X]
debug 13,10, dec b0, " ", dec X
Next B0
pause 1000
Goto mainloop
end





produces as expected





Start

0 99
1 100
2 101
3 102
4 103
5 104
6 105
7 106
8 107
9 108
10 109
11 110
12 111
13 112
14 113
15 114

CuriousOne
- 10th October 2021, 10:50
The code which I've posted, which writes 99 into eeprom.
I replace 99 with any other value - it works.
I put variable name into brackets - it writes zeroes into eeprom.
no matter what type of variable or what value do it has.

CuriousOne
- 10th October 2021, 11:24
Here is full complete code.



;----[16F886 Hardware Configuration]--------------------------------------------
#CONFIG
cfg1 = _INTRC_OSC_NOCLKOUT ; INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
cfg1&= _WDT_ON ; WDT enabled
cfg1&= _PWRTE_OFF ; PWRT disabled
cfg1&= _MCLRE_OFF ; RE3/MCLR pin function is digital input, MCLR internally tied to VDD
cfg1&= _CP_OFF ; Program memory code protection is disabled
cfg1&= _CPD_OFF ; Data memory code protection is disabled
cfg1&= _BOR_OFF ; BOR disabled
cfg1&= _IESO_ON ; Internal/External Switchover mode is enabled
cfg1&= _FCMEN_ON ; Fail-Safe Clock Monitor is enabled
cfg1&= _LVP_OFF ; RB3 pin has digital I/O, HV on MCLR must be used for programming
cfg1&= _DEBUG_OFF ; In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
__CONFIG _CONFIG1, cfg1


cfg2 = _BOR40V ; Brown-out Reset set to 4.0V
cfg2&= _WRT_OFF ; Write protection off
__CONFIG _CONFIG2, cfg2


#ENDCONFIG


'chip configs
TRISA=%00000000 'SET A TO OUTPUT 1=input
TRISC=%00001101 'set half C for in/out
TRISB=%00011000 'set PortB to output
ANSELH=%00000000 ' ADC OFF B
ANSEL=%000000000 'configure PortA as digital except first 2
ADCON1=%10000000 'adc justify
OSCCON=%01110101 'SET FREQUENCY TO 8MHZ
WPUB=%00000000 'turn off Pullups
CM1CON0=0 'DISABLE COMPARATORS
CM2CON0=0 'SAME HERE
'CCP1CON=%01000000 ' configure pwm
'PSTRCON=%00010110 'disable C pwm


DEFINE OSC 8
DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 3
DEFINE ADC_SAMPLEUS 50
'lcd config
pause 200
' Set LCD Data port
DEFINE LCD_DREG PORTC
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 1
DEFINE LCD_BITS 4
DEFINE LCD_LINES 2
DEFINE LCD_COMMANDUS 1500
DEFINE LCD_DATAUS 44
define i2c_slow 1




DPIN Var PORTA.2 ' I2C data pin
CPIN Var PORTA.1 ' I2C clock pin
B Var word
B1 Var byte
B2 Var byte


For B = 0 To 15
b1=99+b
I2CWRITE dpin,cpin,$A0,B,[b1]
Pause 10 '
Next
pause 100


mainloop:


For B = 0 To 15
I2CREAD DPIN,CPIN,$A0,B,[b2]
lcdout $fe, $1, dec b, " ", dec b2
pause 1000
Next

Goto mainloop

End


And funny thing happens - the returned value of B2, as shown on display, is 114! for all 16 locations.
looks like 1st loop executed before writing to EEPROM ?

CuriousOne
- 10th October 2021, 12:14
Maybe read routine is faulty?

CuriousOne
- 10th October 2021, 12:19
yes it is read routine - it reads eeprom only once.

richard
- 10th October 2021, 12:27
works perfectly on simulator

had to increase some delays for slow old lcd
pause 1000
' Set LCD Data port
DEFINE LCD_DREG PORTC
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 1
DEFINE LCD_BITS 4
DEFINE LCD_LINES 2
DEFINE LCD_COMMANDUS 2000
DEFINE LCD_DATAUS 44
lcdout $fe, $1, "ready " ;added to prove lcd working
pause 1000


9089

CuriousOne
- 10th October 2021, 13:57
I will use everything different - LCD, PIC, EEPROM and will check again...

ChuckR
- 27th October 2021, 19:36
I have experienced an I2CREAD problem that might be related to this one. Coincidentally, I was using the DS3231 RTC device also, and it works fine with the PBP I2CREAD and I2CWRITE commands. My design also includes the Everset ES100 time code receiver (Canaduino), which responded correctly to I2CWRITE commands, but not to the I2CREAD command. I was able to enable the ES100 by writing to it, but when I tried to read its interrupt status, the ES100 clamped the I2C clock line after the I2CREAD's 3rd (read) byte.

Referring to the lower scope screen in post #16 in this thread, it can be seen the PBP's I2CREAD command does not execute a full stop and start sequence between bytes 3 and 4 of the I2CREAD command. The ES100 requires (at the end of its 2nd byte) that the clock line be released high followed by the data line being released high (this is the stop sequence). Then, the 3rd byte starts with the data line being pulled low followed by the clock line being pulled low (the start sequence).

In the traces below, it can be seen that start sequence at the beginning of the 4th byte is correct with the data going low followed by the clock going low, but it was not preceded by stop sequence. The data is released high followed by the clock released high rather than the reverse order.

To solve the incompatibility of the PBP I2CREAD command with the ES100, I wrote a bit-banger routine that manipulates the clock and data lines in the proper sequences for start, stop, ack and nak, and combined these with the SHIFTOUT and SHIFTIN commands to send and receive data bytes.

My interpretation of the I2C standard is that either a full start/stop or a restart sequence is permitted, with the restart having a slight speed advantage in time critical applications.

The 24Cxx data sheet I checked seems to spec that only a restart sequence (that is, not a complete stop/start sequence) is required which the scope trace fulfills, but if you're really stumped on this, you might try implementing a full start/stop to see if this makes it act correctly.

An alternate I2CREAD command addition to PBP that provides this full start/stop sequence would be nice to have.

http://www.picbasic.co.uk/forum/attachment.php?attachmentid=9088&d=1633766449