First, I’m new to I2C and USART programming so I apologize if the question is an obvious one.
I have GCBASIC v0.98.00, PICKIT3 programmer and MPLAB IPE.
I use an PIC16F886 (Say PIC n.1) receiving data as an I2C Slave and a second PIC (say PIC n.2) transmitting data as an I2C Master.
PIC n.2, on a button press, send two bytes data on I2C to the address of PIC n.1.
PIC n.1 receives the data and send them to a terminal (CoolTerm) on a laptop trough a USART RS232 connection.
I assumed that the data received by PIC n.2 are made by a Start condition, the bits related to the two data byte and a Stop bit.
I.e., I assume that the stop bit occurs only at the end of the flux of data (two bytes in my test).
Accordingly, I hold a loop until the stop bit is received, i.e., SSPSTAT.P = 1.
Within the loop I wait for the condition SSPSTAT.BF = 1 AND SSPIF = 1, i.e., the SSPBUF is full and the interrupt due to the receive condition is set.
when this condition is satisfied I first clear the interrupt bit SSPIF, then load SSPBUF on an array element (the current one) then I increase the index of the current array element and I set SSPCON.CKP on with the aim of release the clock.
As a matter of fact I assume that the clock has been previously stretched by I2C hardware.
For timing purpose I add 3us delay then I return to the wait. This is repeated until the stop bit is received.
I attach the main part defining the I2C and USART parameters:
#chip 16F886, 16
#option explicit
#config OSC= HS 'HS=Higest gain setting of internal inverter-amplifier
'___________
' I2C
' Define I2C settings
#define HI2C_BAUD_RATE 100
#define HI2C_DATA PORTC.4
#define HI2C_CLOCK PORTC.3
'Set pin I2C directions
Dir HI2C_DATA in
Dir HI2C_CLOCK in
'Now set up the I2C slave
HI2CMode Slave
HI2CSetAddress 0xA0 '=esadecimale 'in binario= b'10100000'
'______________
' USART
#define USART_BAUD_RATE 9600
#define USART_DELAY 5 ms
#define USART_BLOCKING
'Set pin USART directions
Dir portC.7 IN
Dir portC.6 OUT
#define SerInPort PORTc.7
#define SerOutPort PORTc.6
and here is the subroutine reading the I2c received data
Dim flag as Byte
Dim flag1 as Byte
n_elm=0
SET SSPSTAT.R_NOT_W ON 'Enable receive
PIE1.SSPIE=1 'enable MSSP interrupt
'Clear Collisions
SET SSPCON1.WCOL OFF
SET SSPCON1.SSPOV Off
'Wait for receive
do until SSPSTAT.P = 1 'do until StopBit=1
Wait Until SSPSTAT.BF = 1 AND SSPIF = 1 'wait until full buffer and interrpt is on
set PIR1.SSPIF off
Var_Array(n_elm) = SSPBUF
n_elm=n_elm+1
set SSPCON.CKP on
wait 3 us
Loop
n_elm=n_elm-1
The problem:
Usually the data are correctly received. However, frequently they are not immediatly received when I press the button on PIC n.2 and at a new button press I receive the previous data, the address slave as a data and the new data.
It seems like the clock stretching does not work as I assumed.
Can someone help?
Thank you
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Anobium,
thank you for your quick answer.
I know that there are libraries on the subject. I also downloaded them and read a little. I also read the AN734 Microchip note wherein the step by step process usefull to accomplish I2C communication is reported and I have seen the flowchart for slave unit of my interest.
However, my main aim is to deeply understand how the communication work, not only to communicate.
And then, the satisfaction to implement a routine following my understanding is the core of my aim.
I'm sorry, this is an hobby not a work.
In the case of my interest, I suspect that my doubts are essentially related to the clock stetching procedure. Also reading the AN734 note I did not gained a clear picture of the problem.
As an example, when the step by step procedure is described, at point 7 (page 4) is reported that if SEN=1 slave software sets the CKP bit to release the SCL line.
Accordingly, it seems that it is possible to control the clock stretching delay.
On the other side on the PIC16F886 datasheet, the bit SEN of the SSPCON2 register is described in "I2C Master mode only".
And so, in slave mode I do not understand how SEN can be set.
Anyway I will study better the available libraries as well as the Master_Demo_16F886 which refers to master mode.
Many thanks for your attention
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Study the demos - it would take some time to deeply understand the APPNOTE. The Master and Slave IS based on the APPNOTE but with the context of making 16f and 18f work.
I cannot remember the specific of clock stretching but look at State 06 in the ISR Handler - there is a lot of discussion on this. But, these libraries are tested and I know that folks have created working solutions - the simple code in State 06 in the ISR should give you the insight.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I went thru a similar journey as this with the AN976. So from a long time back, here are the subs I used for the reading the PIC slave. This assumed a single Master, single Slave relationship, and therefore would probably not be as robust as the GCB library.
If anything useful can be gleaned, then you are welcome. I think I used a 16f877a as Master, and 16f88 as Slave for my tests at the time. Also the CKE bit is set during initialization.
'###############PIC SLAVE###############sub StartSlaveSET SEN ON 'setstartconditionwaitSlaveSEN:IfSENONThengotowaitSlaveSENendsubsubTxI2CSlave(SendByte)SSPBUF=SendBytebusidleslaveACK:IfACKSTATONThengotoSlaveACK'Check if slave acknowleged'Print("tx")endsubsubRxI2CSlaveSetRCENONslaveRCEN:IfRCENONThengotoslaveRCENReadByte=SSPBUFendsubsubbusidlenotidle:IfSSPCON2ANDb'00000000'NOT1Thengotonotidlewaitbusidle:IfR_WOnThengotowaitbusidleendsubsubMasterRcvNACKSetACKDTOn'Select master not acknowledge Set ACKEN On waitMRcvNAck: If ACKEN ON Then goto waitMRcvNAck 'CheckifoperationcompleteendsubsubStopSlaveSETPENON'Set Stop condition waitSlaveStop: IF PEN ON Then goto waitSlaveStop 'CheckifoperationcompleteendsubsubWritePicSlave(writeID,I2CData)#NR StartTxI2C(writeID)'Device ID write byte TxI2CSerial(I2CData) 'SendoutdatabytetoslaveMasterNACKStopendsubFunctionReadPicSlave(readID)StartSlaveTxI2CSlave(readID)'Device ID read byte RxI2CSlave MasterRcvNACK StopSlave ReadPicSlave = ReadByteend function
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I used SSPCON2.SEN and SSPCON.CKP to attempt controlling the clock stretching. It is shown in the following as Bold Characters
Sub MyHI2CReceive ( n_elm )
Dim flag as Byte
Dim flag1 as Byte
n_elm=0
SET SSPSTAT.R_NOT_W ON 'Enable receive
PIE1.SSPIE=1 'enable MSSP interrupt
'Clear Collisions
SET SSPCON1.WCOL OFF
SET SSPCON1.SSPOV Off
'Wait for receive
do until SSPSTAT.P = 1 'do until StopBit=1
Wait Until SSPSTAT.BF = 1 AND SSPIF = 1 'wait until full buffer and interrpt is on
**set SSPCON2.SEN=0
set SSPCON.CKP=0**
set PIR1.SSPIF off
Var_Array(n_elm) = SSPBUF
n_elm=n_elm+1
** set SSPCON2.SEN=1
set SSPCON.CKP on**
wait 3 us
Loop
n_elm=n_elm-1
End Sub
As I said in my first post, PIC n.2, the trasmitting one, trasmit upon pressing a button.
Now data are read regularly when the button is regularly pressed.
On the contrary, when the button is continuosly pressed the reception fails and PIC n.1, the receiving one, freeze.
There are collisions, I suppose.
My attempts to manage collisions by using SSPCON1.WCOL and SSPCON1.SSPOV have been unsuccessfull till now.
On the other side this also means that still I'm not able to fully control the clock stretching on the receiver.
Thank you all
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
First, I’m new to I2C and USART programming so I apologize if the question is an obvious one.
I have GCBASIC v0.98.00, PICKIT3 programmer and MPLAB IPE.
I use an PIC16F886 (Say PIC n.1) receiving data as an I2C Slave and a second PIC (say PIC n.2) transmitting data as an I2C Master.
PIC n.2, on a button press, send two bytes data on I2C to the address of PIC n.1.
PIC n.1 receives the data and send them to a terminal (CoolTerm) on a laptop trough a USART RS232 connection.
I assumed that the data received by PIC n.2 are made by a Start condition, the bits related to the two data byte and a Stop bit.
I.e., I assume that the stop bit occurs only at the end of the flux of data (two bytes in my test).
Accordingly, I hold a loop until the stop bit is received, i.e., SSPSTAT.P = 1.
Within the loop I wait for the condition SSPSTAT.BF = 1 AND SSPIF = 1, i.e., the SSPBUF is full and the interrupt due to the receive condition is set.
when this condition is satisfied I first clear the interrupt bit SSPIF, then load SSPBUF on an array element (the current one) then I increase the index of the current array element and I set SSPCON.CKP on with the aim of release the clock.
As a matter of fact I assume that the clock has been previously stretched by I2C hardware.
For timing purpose I add 3us delay then I return to the wait. This is repeated until the stop bit is received.
I attach the main part defining the I2C and USART parameters:
and here is the subroutine reading the I2c received data
The problem:
Usually the data are correctly received. However, frequently they are not immediatly received when I press the button on PIC n.2 and at a new button press I receive the previous data, the address slave as a data and the new data.
It seems like the clock stretching does not work as I assumed.
Can someone help?
Thank you
We have libraries for this.
Your code should be robust using the software library. Have your looked and the library implementation and rejected?
https://github.com/Anobium/Great-Cow-BASIC-Demonstration-Sources/blob/master/I2C%20Solutions/I2C%20Slave%20Solutions/Control%20LEDs%20-%20Master%20and%20Slave/SWI2C_Master__LED_Demo_16F886.gcb
Hi Anobium,
thank you for your quick answer.
I know that there are libraries on the subject. I also downloaded them and read a little. I also read the AN734 Microchip note wherein the step by step process usefull to accomplish I2C communication is reported and I have seen the flowchart for slave unit of my interest.
However, my main aim is to deeply understand how the communication work, not only to communicate.
And then, the satisfaction to implement a routine following my understanding is the core of my aim.
I'm sorry, this is an hobby not a work.
In the case of my interest, I suspect that my doubts are essentially related to the clock stetching procedure. Also reading the AN734 note I did not gained a clear picture of the problem.
As an example, when the step by step procedure is described, at point 7 (page 4) is reported that if SEN=1 slave software sets the CKP bit to release the SCL line.
Accordingly, it seems that it is possible to control the clock stretching delay.
On the other side on the PIC16F886 datasheet, the bit SEN of the SSPCON2 register is described in "I2C Master mode only".
And so, in slave mode I do not understand how SEN can be set.
Anyway I will study better the available libraries as well as the Master_Demo_16F886 which refers to master mode.
Many thanks for your attention
Study the demos - it would take some time to deeply understand the APPNOTE. The Master and Slave IS based on the APPNOTE but with the context of making 16f and 18f work.
I cannot remember the specific of clock stretching but look at State 06 in the ISR Handler - there is a lot of discussion on this. But, these libraries are tested and I know that folks have created working solutions - the simple code in State 06 in the ISR should give you the insight.
I went thru a similar journey as this with the AN976. So from a long time back, here are the subs I used for the reading the PIC slave. This assumed a single Master, single Slave relationship, and therefore would probably not be as robust as the GCB library.
If anything useful can be gleaned, then you are welcome. I think I used a 16f877a as Master, and 16f88 as Slave for my tests at the time. Also the CKE bit is set during initialization.
I used SSPCON2.SEN and SSPCON.CKP to attempt controlling the clock stretching. It is shown in the following as Bold Characters
As I said in my first post, PIC n.2, the trasmitting one, trasmit upon pressing a button.
Now data are read regularly when the button is regularly pressed.
On the contrary, when the button is continuosly pressed the reception fails and PIC n.1, the receiving one, freeze.
There are collisions, I suppose.
My attempts to manage collisions by using SSPCON1.WCOL and SSPCON1.SSPOV have been unsuccessfull till now.
On the other side this also means that still I'm not able to fully control the clock stretching on the receiver.
Thank you all