I can read a byte from the slave i2c bus.
but when I try to read two bytes are the bus stops.
here's the master code that reads a byte:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'CHIP
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#CHIP 16F876A,4
#CONFIG OSC=XT,WDT_OFF,PWRTE_ON,CP_OFF,DEBUG_OFF,WRT_OFF,CPD_OFF,LVP_OFF,BODEN_ON,BOREN_OFF
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'VARIABLES & DEFINE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
DIM Contador AS INTEGER
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'SUB & FUNCTION
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB Setup_I2C()
SSPSTAT=b'1100000'
SSPADD=b'00001001'
SSPCON2=0
SSPCON=b'00111000'
SET PIR1.SSPIF OFF
SET PIR2.BCLIF OFF
END SUB
SUB W_MSSP()
DO
LOOP UNTIL PIR1.SSPIF=1
PIR1.SSPIF=0
END SUB
SUB START
SET SSPCON2.SEN ON
W_MSSP()
END SUB
SUB RESTART
SET SSPCON2.RSEN ON
W_MSSP()
END SUB
SUB STOP
SET SSPCON2.PEN ON
W_MSSP()
END SUB
SUB I2C_ACK()
SET SSP1CON2.ACKDT OFF
SET SSP1CON2.ACKEN ON
W_MSSP()
END SUB
SUB I2C_Not_ACK()
SET SSP1CON2.ACKDT ON
SET SSP1CON2.ACKEN ON
W_MSSP()
END SUB
SUB Tx_I2C(SendByte AS BYTE)
SSPBUF=SendByte
W_MSSP()
DO
LOOP UNTIL SSPCON2.ACKSTAT=0
END SUB
FUNCTION I2C_Rx() AS BYTE
SSPCON2.RCEN=1
W_MSSP()
I2C_Rx=SSPBUF
END FUNCTION
SUB WRITE_Memory(ID_Address AS BYTE,Address AS WORD,Dato AS WORD)#NR
START()
Tx_I2C(ID_Address)
Tx_I2C(Address_H)
Tx_I2C(Address)
Tx_I2C(Dato)
STOP()
END SUB
SUB WRITE_Slave(IDAddress AS WORD,Dato AS WORD)#NR
START()
Tx_I2C(IDAddress)
Tx_I2C(Dato)
STOP()
END SUB
FUNCTION READ_Memoria(ID_Address AS WORD,Address AS WORD)
START()
Tx_I2C(ID_Address)
Tx_I2C(Address_H)
Tx_I2C(Address)
RESTART()
Tx_I2C(ID_Address+1)
READ_Memoria=I2C_Rx()
I2C_Not_ACK()
STOP()
END FUNCTION
FUNCTION READ_Slave(ID_Address AS WORD,Comando AS BYTE)
START()
Tx_I2C(ID_Address)
Tx_I2C(Comando)
RESTART()
Tx_I2C(ID_Address+1)
EPWrite 0x00,I2C_Rx()
I2C_Not_ACK()
STOP()
END FUNCTION
Inicio:
TRISA=b'000000'
TRISB=b'00000000'
TRISC=b'00011000'
PORTA=b'000000'
PORTB=b'00000000'
PORTC=b'00000000'
INTCON=b'00000000'
CVRCON=b'00000000'
CCP1CON=b'00000000'
CCP2CON=b'00000000'
ADCON0=b'00000000'
ADCON1=b'10000110'
Setup_I2C()
WAIT 1 s
READ_Slave(0xA6,0xF1)
PulseOut PORTC.5,1 s
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'CHIP
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#CHIP 16F88,4
#CONFIG OSC=XT,MCLR_ON,CP_OFF,CCP1_RB3,DEBUG_OFF,WRT_PROTECT_OFF
#CONFIG CPD_OFF,LVP_OFF,BODEN_ON,PWRTE_ON,WDT_OFF,IESO_OFF,FCMEN_OFF
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INTERRUPT
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Interrupt SSP1Ready call I2C_Interrupt
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'VARIABLES
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
DIM InByte,Clear_Address,Contador,Valor(2) AS BYTE
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'SUB AND FUNCTION
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB I2C_Interrupt()#NR
IF PIR1.SSPIF=1 THEN
IF SSPSTAT.D_A=1 THEN
InByte=SSPBUF
EPWrite SSPBUF,SSPBUF
END IF
IF SSPSTAT.R_W=1&InByte=0xF1 THEN
SSPBUF=Valor(Contador)
Contador+=1
IF Contador>1 THEN Contador=0:InByte=0x00
END IF
Clear_Address=SSPBUF
SSPCON.CKP=1
PIR1.SSPIF=0
END IF
END SUB
INICIO:
TRISA=b'000000'
TRISB=b'00010010'
PORTA=b'000000'
PORTB=b'00000000' '
INTCON=b'11000000'
SSPADD=0xA6
SSPSTAT=b'00000000'
SSPCON=b'00110110'
PIE1.SSPIE=1
CVRCON=b'00000000'
CMCON=b'00000111'
CCP1CON=b'00000000'
ANSEL=b'00000000'
ADCON0=b'00000000'
ADCON1=b'10000000'
Contador=0
Valor(0)=0xAA
Valor(1)=0xAB
InByte=0x00
DO
''''''''''''''''''''''
LOOP
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
but trying to read a second byte blocks.
this is changing:
.
FUNCTION READ_Slave(ID_Address AS WORD,Comando AS BYTE)
START()
Tx_I2C(ID_Address)
Tx_I2C(Comando)
RESTART()
Tx_I2C(ID_Address+1)
EPWrite 0x00,I2C_Rx()
I2C_ACK()
EPWrite 0x01,I2C_Rx()
I2C_Not_ACK()
STOP()
END FUNCTION
.
thanks in advance, and sorry for my english
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Alejandro,
Here is some code from my Master I2C read16bit procedure. Don't have any time to help verify your code, but maybe the comments will help you along : ) The word variable could be assembled from the ReadHighByte and ReadLowByte, good luck.
Sub Read16bit(WrtCtrl8bit,Addr8bit,RdCtrl8bit)
Start
TxI2C(WrtCtrl8bit) 'Device ID write byte
TxI2C(Addr8bit) 'Send byte address
Restart
TxI2C(RdCtrl8bit) 'Device ID read byte
RxI2CWord 'Receive data byte
Set ACKDT Off 'Select master acknowledge
MasterAck 'Master Ack or NoAck depending on ACKDT
ReadHighByte = ReadByte
RxI2CWord
MasterNAck
ReadLowByte = ReadByte
Stop
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am suspicious of trying to do the EPWrite and I2C at the same time, i.e. EPWrite 0x00,I2C_Rx(). Why not try saving to HighByte = I2C_RX() and LowByte = I2C_RX() first; Then write to eeprom later?, i.e. EPWrite 0x00, HighByte……..
Here is so more code from 4-5 years ago. The ACK settings are different for RXI2C() and RXI2CWord().
sub RxI2C
#IFDEF PIC
SET SSPIF OFF
SET RCEN ON 'Initiate reception
waitRx:
IF SSPIF OFF THEN goto waitRx 'Check if operation complete
ReadByte = SSPBUF 'Read byte in buffer
'Wait for Not acknowledge
SET SSPIF OFF
SET ACKEN ON
waitNoAck:
IF SSPIF OFF THEN goto waitNoAck 'Check if operation complete
#ENDIF
#IFDEF AVR
ReadByte = TWDR
Set TWINT On 'No "Set TWEN On" for NACK
waitRx1:
If TWINT On Then goto waitRx1
waitNoAck1:
If TWSR AND 0xF8 <> 0x50 Then goto waitNoack1
ReadByte = TWDR ;???
#ENDIF
end sub
sub RxI2CWord '(ReadByte)
#IFDEF PIC
SET SSPIF OFF 'Set PIR1.SSPIF Off
SET RCEN ON 'Initiate reception
waitRxWord:
IF SSPIF OFF THEN goto waitRxWord 'Check if operation complete
ReadByte = SSPBUF 'Read byte in buffer
#ENDIF
#IFDEF AVR
'use TWEA for NACK
#ENDIF
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
here is the change I made to the I2C routines Rx ().
Addition enabling dell'ACKDT after the reading of the data:
FUNCTION I2C_Rx() AS BYTE
SSPCON2.RCEN=1
W_MSSP()
I2C_Rx=SSPBUF
SET SSPCON2.ACKEN ON
W_MSSP()
END FUNCTION
works well, but retrieves a byte at a time:
FUNCTION READ_Slave_8BIT(ID_Address AS WORD,Comando AS BYTE,Address AS BYTE)#NR
START()
Tx_I2C(ID_Address)
Tx_I2C(Comando)
RESTART()
Tx_I2C(ID_Address+1)
SET SSPCON2.ACKDT ON
EPWrite Address,I2C_Rx()
STOP()
END FUNCTION
I created this routine:
FUNCTION READ_Slave_16BIT(ID_Address AS WORD,Comando AS BYTE,Address AS BYTE)#NR
START()
Tx_I2C(ID_Address)
Tx_I2C(Comando)
RESTART()
Tx_I2C(ID_Address+1)
SET SSPCON2.ACKDT OFF
EPWrite Address,I2C_Rx()
SET SSPCON2.ACKDT ON
EPWrite Address+1,I2C_Rx()
STOP()
END FUNCTION
I read the first and the MSB in writing to the EEPROM address 0x00.
the second does not stores it, but does not block the program.
At this point I doubt if it's a management problem or a problem in the eeprom handling routines in the slave.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for your suggestions.
the problem was in the slave code of 16F88.
so it works perfectly:
FUNCTION I2C_Rx() AS BYTE
SSPCON2.RCEN=1
W_MSSP()
I2C_Rx=SSPBUF
SET SSPCON2.ACKEN ON
W_MSSP()
END FUNCTION
FUNCTION READ_Slave_16BIT(ID_Address AS WORD,Comando AS BYTE) AS WORD
DIM H_Byte,L_Byte AS BYTE
START()
Tx_I2C(ID_Address)
Tx_I2C(Comando)
RESTART()
Tx_I2C(ID_Address+1)
SET SSPCON2.ACKDT OFF
H_Byte=I2C_Rx()
SET SSPCON2.ACKDT ON
L_Byte=I2C_Rx()
STOP()
READ_Slave_16BIT=L_Byte
READ_Slave_16BIT_H=H_Byte
END FUNCTION
This is the interrupt slave that works (rustic, but it works):
SUB I2C_Interrupt()#NR
IF PIR1.SSPIF=1 THEN
PIR1.SSPIF=0
IF SSPSTAT.D_A=1 THEN
IF SSPBUF>0xEF&SSPBUF<0xF5 THEN InByte=SSPBUF
EPWrite SSPBUF,SSPBUF
WAIT 20 ms
END IF
IF SSPSTAT.R_W=1 THEN
DO
LOOP UNTIL SSPSTAT.BF=0
SSPCON.WCOL=0
SELECT CASE InByte
CASE 0xF0
SSPBUF=Valor(Contador)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF1
SSPBUF=Valor(Contador+1)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF2
SSPBUF=Valor(Contador+2)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF3
SSPBUF=Valor(Contador+3)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF4
SSPBUF=Valor(Contador+4)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE ELSE
SSPBUF=0x00
END SELECT
END IF
Clear_Address=SSPBUF
SSPCON.CKP=1
END IF
END SUB
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Glad you got it going. MSSP can be a tricky, it took me forever to find out that the slave clock stretching, SSPCON.CKP = 0 helps out a lot. Instead of the 'wait 20 ms' in the interrupt routine, try nop:nop:nop:nop, I remember there is some sort of setup time required.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This will help to see if the master could write on a particular register of the slave.
now no longer needed.
This is the complete code of the slave
it is best to use the nop.
we say that the interrupts are somewhat sensitive to delay(WAIT)
This is the complete code of the slave who will manage the sensors (temperature, Lighting, humidity, battery level and battery level system motors and sonar) of the robot
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'CHIP
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#CHIP 16F88,4
#CONFIG OSC=XT,MCLR_ON,CP_OFF,CCP1_RB3,DEBUG_OFF,WRT_PROTECT_OFF
#CONFIG CPD_OFF,LVP_OFF,BODEN_ON,PWRTE_ON,WDT_OFF,IESO_OFF,FCMEN_OFF
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'INTERRUPT
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Interrupt SSP1Ready call I2C_Interrupt
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'VARIABLES
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
DIM InByte,Clear_Address,Contador AS BYTE
DIM ADC_SyS(2),ADC_Aux(2),ADC_TEMP,ADC_Lm(2),ADC_Hm(2) AS WORD
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'SUB AND FUNCTION
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB I2C_Interrupt()#NR
IF PIR1.SSPIF=1 THEN
PIR1.SSPIF=0
IF SSPSTAT.D_A=1 THEN
IF SSPBUF>0xEF&SSPBUF<0xF4 THEN InByte=SSPBUF
END IF
IF SSPSTAT.R_W=1 THEN
DO
LOOP UNTIL SSPSTAT.BF=0
SSPCON.WCOL=0
SELECT CASE InByte
CASE 0xF0
SSPBUF=ADC_SyS(Contador)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF1
SSPBUF=ADC_Aux(Contador)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF2
SSPBUF=ADC_TEMP
CASE 0xF3
SSPBUF=ADC_Lm(Contador)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE 0xF4
SSPBUF=ADC_Hm(Contador)
Contador+=1
IF Contador>=0x02 THEN Contador=0x00
CASE ELSE
SSPBUF=0x00
END SELECT
END IF
Clear_Address=SSPBUF
SSPCON.CKP=1
END IF
END SUB
SUB SENSORES()#NR
ADC_SyS(0)=ReadAD10(AN0)/256
ADC_SyS(1)=ReadAD10(AN0)%256
ADC_Aux(0)=ReadAD10(AN1)/256
ADC_Aux(1)=ReadAD10(AN1)%256
ADC_TEMP=((ReadAD10(AN2))/1024)*500
ADC_Lm(0)=ReadAD10(AN3)/256
ADC_Lm(1)=ReadAD10(AN3)%256
ADC_Hm(0)=ReadAD10(AN4)/256
ADC_Hm(1)=ReadAD10(AN4)%256
END SUB
INICIO:
TRISA=b'011111'
TRISB=b'00010010'
PORTA=b'000000'
PORTB=b'00000000'
INTCON=b'11000000'
SSPADD=0xA6
SSPSTAT=b'00000000'
SSPCON=b'00110110'
PIE1.SSPIE=1
CVRCON=b'00000000'
CMCON=b'00000111'
CCP1CON=b'00000000'
ANSEL=b'00011111'
ADCON0=b'00000001'
ADCON1=b'10000000'
Contador=0
InByte=0x00
DO
SENSORES()
WAIT 200 ms
LOOP
missing only handle digital compass that I am building.
Thanks to all.
and sorry for my English.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I can read a byte from the slave i2c bus.
but when I try to read two bytes are the bus stops.
here's the master code that reads a byte:
This is the code of the slave 16F88:
but trying to read a second byte blocks.
this is changing:
thanks in advance, and sorry for my english
Hi Alejandro,
Here is some code from my Master I2C read16bit procedure. Don't have any time to help verify your code, but maybe the comments will help you along : ) The word variable could be assembled from the ReadHighByte and ReadLowByte, good luck.
..Master I2C read16bit procedure..
this code does not know him.
could you kindly send it??
I am suspicious of trying to do the EPWrite and I2C at the same time, i.e. EPWrite 0x00,I2C_Rx(). Why not try saving to HighByte = I2C_RX() and LowByte = I2C_RX() first; Then write to eeprom later?, i.e. EPWrite 0x00, HighByte……..
Here is so more code from 4-5 years ago. The ACK settings are different for RXI2C() and RXI2CWord().
here is the change I made to the I2C routines Rx ().
Addition enabling dell'ACKDT after the reading of the data:
works well, but retrieves a byte at a time:
I created this routine:
I read the first and the MSB in writing to the EEPROM address 0x00.
the second does not stores it, but does not block the program.
At this point I doubt if it's a management problem or a problem in the eeprom handling routines in the slave.
Thanks for your suggestions.
the problem was in the slave code of 16F88.
so it works perfectly:
This is the interrupt slave that works (rustic, but it works):
Now I have to see how to manage the information to be sent without being too in interrupt the I2C slave
thanks again.
+ are always in love with GCBASIC :-)
Glad you got it going. MSSP can be a tricky, it took me forever to find out that the slave clock stretching, SSPCON.CKP = 0 helps out a lot. Instead of the 'wait 20 ms' in the interrupt routine, try nop:nop:nop:nop, I remember there is some sort of setup time required.
This will help to see if the master could write on a particular register of the slave.
now no longer needed.
This is the complete code of the slave
it is best to use the nop.
we say that the interrupts are somewhat sensitive to delay(WAIT)
This is the complete code of the slave who will manage the sensors (temperature, Lighting, humidity, battery level and battery level system motors and sonar) of the robot
missing only handle digital compass that I am building.
Thanks to all.
and sorry for my English.
Good Job!!! Very neat and clearly written. Thanks for sharing.