PDA

View Full Version : I2C problem writing to slave



Lazuli
- 21st June 2011, 21:13
Hi everyone,
Once more I am struggling with I2C. I had two PIC16F877A communicating nicely. I built my code based on the example of master and slave from the website. But now, I have added more code to my slave code and that makes the writing command from master to slave fail. I have a time error on the master and the slave also does not receive the single byte I am trying to write to it.
Problem is that I need this piece of code in the slave.
I tried to add some test to make it loop only on the receive command until I2C has finished transmission but I could not make it work.
Is interrupt the way to go for that?
Any other idea or code example to avoid this type of issue?

Thanks for any help.
regards

mackrackit
- 22nd June 2011, 09:13
You will need to post the modified code before anyone will be able to help trouble shoot the problem.

Lazuli
- 22nd June 2011, 17:50
Hi,

sorry for that, here is the code.
As you will see, the slave i2c part is unchanged, I just add some call to subroutine in the main loop.
The funny thing is that it does not affect the read command from the other pic but only the write command which result in a time error.
It seems to be linked to the time it takes during the main loop as I can make the write command fail by either uncomment the hserout or the call to subroutine.
But why is there no effect on the read command? This one with all the code active always send me the right values.
NOTE: the code is not finished and some change in subroutine (ADC and average computation) is not reflected yet in some other part of the code, so don't be surprised. I was planning to finish to trouble shoot once I could have the 2 pic communicating.

Thanks for your help


' Name : I2CSLAVE.pbp
' Compiler : PICBASIC PRO Compiler 2.6
' Assembler : PM or MPASM
' Target PIC : 40-pin 16F877A
' Hardware : Lab-X1
' Oscillator : 4MHz internal or external
' Keywords : I2CREAD, I2CWRITE, LCDOUT
' Description : PICBASIC PRO program for I2C slave program - PIC16F877/PIC-X1.
'

DEFINE LOADER_USED 1 ' Using boot-Loader
Define HSER_CLROERR 1 'to automatically clear any buffer overflow of serial input
Define HSER_BAUD 4800 'Set to NMEA baud rate standard

' Define ADCIN parameters
Define ADC_BITS 10 ' Set number of bits in result
Define ADC_CLOCK 3 ' Set clock source (3=rc)
Define ADC_SAMPLEUS 50 ' Set sampling time in uS

' Alias I2C pins
scl VAR PORTC.3 ' I2C clock input
sda VAR PORTC.4 ' I2C data input

' Define used register flags
SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag
BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full
R_W VAR SSPSTAT.2 ' SSP (I2C) Read/Write
D_A VAR SSPSTAT.5 ' SSP (I2C) Data/Address
CKP VAR SSPCON.4 ' SSP (I2C) SCK Release Control
SSPEN VAR SSPCON.5 ' SSP (I2C) Enable
SSPOV VAR SSPCON.6 ' SSP (I2C) Receive Overflow Indicator
WCOL VAR SSPCON.7 ' SSP (I2C) Write Collision Detect

' Define constants
I2Caddress CON $a0 ' Make our address 2

' Allocate alias
qUp var PORTA.2
qDown var PORTA.5

' Allocate variables
qpot var word 'raw potentiometer reading
qpotflt var word 'raw pot filtered
xqpot var word 'used to compute average
qpotnb var byte 'filtering number
qpotold var word
qpotCal var byte 'calibrated pot reading (20 - 220)
qpos var byte '0 down, 1 up
CalFlag var byte
x var word
y var word
QDmax var word
QUmax var word
Qmin var word
PotDA var word 'amplitude pot for Down position
PotDOf var word
PotUA var word 'amplitude pot for up position
PotUOf var word
QposPerc var byte
Qdraft var byte
ind var byte
bogus var word 'dummy for div32
Qstatus var byte 'to send status info to Master, 0 acq, 1 cal, 2 mov up, 3 mov down
datain var byte 'received data from Master
DataOut var byte[4]
readcnt var byte
result VAR BYTE ' ADC result


' Initialize ports and directions
ADCON1 = %10010101
TRISA = %11111111 ' Set PORTA to all input

' Initialize I2C slave mode
SSPADD = I2Caddress ' Set our address
SSPCON2 = 0 ' General call address disabled
SSPCON = $36 ' Set to I2C slave with 7-bit address

readcnt = 0 ' Zero counter

GoTo mainloop ' Skip over subroutines

'*****************************QMove*************** ***************************
QMove:
if qpotold > qpot then
if qpotold-qpot > 4 then
if qUp=1 then qPos=0
if qDown=1 then qpos=1
endif
else
if qpot-qpotold > 4 then
if qUp=1 then qPos=1
if qDown=1 then qpos=0
endif
endif
return
'*****************************CalProc************* ***************************
CalPROC:
if qUp=1 and qpos=1 then
QUmax = QUmax max qpot
endif
if qDown=1 and qpos=0 then
QDmax = QDmax max qpot
endif
Qmin = Qmin min qpot

if qdown=1 then calflag=2
if calflag=2 and qdown=0 then calflag=3
if calflag=3 and qUp=1 then calflag=4
if calflag=4 and qUp=0 then
PotDA=qdmax-qmin
x=qmin*220
y=div32 PotDa
PotDOf= 120-y 'offset +100 to avoid any negative number
PotUA=qdmax-qmin
x=qmin*220
y=div32 PotUa
PotUOf= 120-y 'offset +100 to avoid any negative number
write 0, word potda, word PotDOf, word PotUA, word PotUOf, qpos
calflag=0 'back to acquisition mode
endif
return


'*****************************Getx**************** ***************************
' Subroutine to get pot value
getx:
ADCIN 0, qpot ' Read channel 0 to qpot
xqpot=xqpot+qpot
qpotnb=qpotnb+1
if qpotnb= 8 then
qpotnb=0
qpotflt=xqpot/8
xqpot=0

dataout[0]=qpotflt
dataout[1]=qpotCal
dataout[2]=Qstatus
hserout ["$pot,", dec qpotflt]
hserout ["$qup,", dec qUp]
hserout ["$qdown,", dec qDown]
hserout ["$cf,", dec calflag]
hserout ["$qdm,", dec qdmax]
hserout ["$qum,", dec qumax]
hserout ["$qm,", dec qmin]
gosub QMove
if calflag=0 then
if qpos=0 then
bogus = 220 * qpot
qpotcal = div32 potda
qpotcal=qpotcal+PotDOf-100
else
bogus = 220 * qpot
qpotcal = div32 potUa
qpotcal=qpotcal+PotUOf-100
endif
gosub convert
else
gosub CalPROC
endif
endif
Return

'*******************************conversion******** ***************************
convert:
if qpos=0 then
' down position
lookdown2 qpotcal,<=[20,22,26,33,42,55,73,96,127,167,192,206,230],ind
lookup ind,[67,70,73,77,80,83,87,90,93,97,98,99,100], qposperc
lookup ind,[166,171,176,180,184,187,191,193,196,198,199,200,20 0],qdraft
else
' up position
lookdown2 qpotcal,<=[20,21,24,28,33,39,46,53,62,72,83,94,106,119,133,14 8,163,179,195,204,208,220],ind
lookup ind,[63,60,57,53,50,47,43,40,37,33,30,27,23,20,17,13,10 ,7,3,2,1,0],qposperc
lookup ind,[161,156,150,144,138,132,125,118,111,104,97,89,81,7 3,65,56,48,39,30,26,23,20],qdraft
endif
'dataout[0]= qposperc
'dataout[0]= qpot
''dataout[1]= qdraft
'dataout[1]= qpot
'dataout[2]= Qstatus
return

i2cslave: ' I2C slave subroutine
SSPIF = 0 ' Clear interrupt flag

IF R_W = 1 Then i2crd ' Read data from us
IF BF = 0 Then i2cexit ' Nothing in buffer so exit
IF D_A = 1 Then i2cwr ' Data for us (not address)
IF SSPBUF != I2Caddress Then i2cexit ' Clear the address from the buffer
readcnt = 0 ' Mark as first read
GoTo i2cexit

i2cwr: ' I2C write data to us
datain = SSPBUF ' Put data into array
if datain=127 then
calflag=1 ' goes into calibration mode
qpos=1 ' calibration is started from keel
endif
wflag=0
GoTo i2cexit

i2crd: ' I2C read data from us
IF D_A = 0 Then
readcnt = 0 ' Mark as first read
EndIF

SSPBUF = dataout[readcnt] ' Get data from array
CKP = 1 ' Release SCL line
readcnt = readcnt + 1 ' Move along read count
GoTo i2cexit ' That's it

i2cexit:
Return

mainloop: ' Main program loop
IF SSPIF ' Check for I2C interrupt flag
GoSub i2cslave
EndIF
if calflag>0 then
Qstatus=1
else
if qUp=1 then
Qstatus=2
elseif qDown=1 then
Qstatus=3
else
Qstatus=0
endif
endif
gosub getx
'dataout[0]=qpotflt '----------------With everything as comment, I2C works to write and read
'dataout[1]=qpotCal '---------------- if I uncomment all this, i2c still works with a read command
'dataout[2]=Qstatus '---------------- if I uncomment either the hserout or only the call to the subroutine
'hserout ["$pot,", dec qpotflt] '---------------- read comment is still OK but write command fails
'hserout ["$qup,", dec qUp]
'hserout ["$qdown,", dec qDown]
'hserout ["$cf,", dec calflag]
'hserout ["$qdm,", dec qdmax]
'hserout ["$qum,", dec qumax]
'hserout ["$qm,", dec qmin]
'gosub QMove
'if calflag=0 then
' if qpos=0 then
' bogus = 220 * qpot
' qpotcal = div32 potda
' qpotcal=qpotcal+PotDOf-100
' else
' bogus = 220 * qpot
' qpotcal = div32 potUa
' qpotcal=qpotcal+PotUOf-100
' endif
' gosub convert
'else
' gosub CalPROC
'endif

GoTo mainloop ' Do it all forever

End

Lazuli
- 23rd June 2011, 05:22
OOOPS, I posted the wrong code. I tried to modify the code once I had issues and moving around some procedure and did not posted the original one which did not have dupplicate.
I am going to clean that and will post the right one later.