Am in the midst of a project, and am having a stumbling-block in regards to I2C-2 that I hope someone can help me with?
Master and Slave, MCU: PIC18F87K22
Master and Slave, crystal: 16MHz
Master and Slave, Edit Project window; PLLx4: Enable
Master and Slave, Edit Project window; Clock Frequency: 64MHz
Master and Slave, Edit Project window; MSSP address masking: 7 Bit address masking mode
Master-MCU Libraries: Button and I2C
Slave-MCU Libraries: I2C only
Background of wider project:
I am using both I2C-1 and I2C-2.
I2C-1 communicates with IC's on a bus, PC9956A (LED driver for 8x8 RGB LED matrix modules), using I2C High-speed mode >400KHz, with great success.
As stated, the I2C-1 bus works really well.
At present I have the Master and Slave MCU's connected to the I2C-2 bus, with 4.7K pull-up resistors connected to +5V power-line.
I intend to use I2C-2 to communicate between the Master-MCU, the Slave-MCU, an RTC (DS1307), and an EEPROM.
So far I have not connected the RTC, nor the EEPROM to this I2C-2 bus, as I wanted to get the Master and Slave MCU's to talk first before connecting and testing them out on the bus as well.
The ideal working code, in both test-code and final project working code, sees the Master-MCU read one byte from the Slave.
At least for now, getting one byte read will do.
Later, when the I2C-2 bus works, I might try reading multiple bytes from the Slave-MCU.
Issues with I2C-2 (Master-MCU):
(For the test code; I have cut back most of the other code and cut out the I2C-1 code to better test out my issue.)
I set up the Master-MCU I2C-2 via Mikro Libraries with this code:
Code: Select all
'------------------------------------------------------------------------------' Port D
'
Dim I2C2_SDA2 as sbit at LATD5_bit
Dim I2C2_SDA2_Dir as sbit at TRISD5_bit
'
Dim I2C2_SCL2 as sbit at LATD6_bit
Dim I2C2_SCL2_Dir as sbit at TRISD6_bit
'
Code: Select all
Sub procedure Init_I2C() ' Set up I2C
'--------------------------------------------------------------------------'
I2C2_SDA2_Dir = 1 ' RD5
I2C2_SCL2_Dir = 1 ' RD6
'--------------------------------------------------------------------------'
I2C2_SDA2 = 0
I2C2_SCL2 = 0
'--------------------------------------------------------------------------'
I2C2_Init(100000) ' 100kHz
Delay_ms(10) ' Wait till I2C settles
End sub
But my code in the Master Project Code uses the "I2C2_Rd(0)" after calling the Salve-MCU, like this;
Code: Select all
'==============================================================================' I2C routines
Sub procedure ReadSlave(Dim WriteAddress4Slave as byte) ' I2C2 Read
I2C2_Start()
I2C2_Wr(WriteAddress4Slave + 1)
I2CVAR9 = I2C2_Rd(0)
I2C2_Stop()
Display_FLG = 0xFF
End sub
'------------------------------------------------------------------------------'
Code: Select all
'----------------------------------------------------------------------------'
If Button(PORTF, 1, 1, 1) then
OS_BTN_PRST1 = 255
End if
If OS_BTN_PRST1 and Button(PORTF, 1, 1, 0) then
ReadSlave(0xB0) ' 0xB0 + 1 = 0xB1 (read) ***Main I2C Address***
OS_BTN_PRST1 = 0
End if
'----------------------------------------------------------------------------'
When I look at what's happening on an oscilloscope, I get this;
As shown, the Master-MCU sends the correct Slave-Address, a Read-bit, and a 'high-ACK' then the Stop-bit.
It's as if the I2C2_Rd(0) isn't taken into account.
As such, the Slave-MCU does not respond, and the Master-MCU hangs.
Issues with I2C-2 (Slave-MCU):
(For the test code; I have cut back most of the other code to better test out my issue.)
I have poured through the datasheet for PIC18F87K22, specifically, "21.4 I2C Mode" and "21.4.3 Slave Mode".
Some of it is a little confusing, but I think I have everything okay... I hope
Here is the I2C-2 code to enable the I2C module in the MCU:
Code: Select all
'------------------------------------------------------------------------------' Port D
'
Dim I2C_SDA2 as sbit at PortD.5
Dim I2C_SDA2_Dir as sbit at TRISD5_bit
'
Dim I2C_SCL2 as sbit at PortD.6
Dim I2C_SCL2_Dir as sbit at TRISD6_bit
'
Code: Select all
Sub procedure Init_I2C() ' Sets up Slave I2C registers and Address
'------------------------------------------------------------------------------' I2C-2 Set-Up Slave Mode
I2C_SDA2_Dir = 1 ' RD5
I2C_SCL2_Dir = 1 ' RD6
SSP2STAT = 0x80 ' %1000 0000 - SMP = 1 (Slew Rate control disabled for standard speed mode)
SSP2CON1 = 0x29 ' Load SSP2ADD to load SSP2MSK
SSP2ADD = 0xF1 ' Address masking
SSP2CON1 = 0x26 ' 7-bit address Slave Mode
SSP2CON2 = 0x01 ' No Interrupt with a general call, Clock-stretching enabled (SEN)
SSP2ADD = 0xB0 ' Slave Address
SSP2MD_bit = 1 ' I2C-2 (MSSP2) is enabled
'------------------------------------------------------------------------------' Interrupts
SSP2IE_bit = 1 ' I2C-2 MSSP2 interrupts are enabled
BCL2IE_bit = 0 ' I2C-2 Bus collision interrupts disabled
SSP2IP_bit = 0 ' I2C-2 MSSP2 interrupts priority is not high
BCL1IP_bit = 0 ' I2C-2 Bus collision interrupts priority is not high
SSP2IF_bit = 0 ' I2C-2 MSSP2 interrupts flag cleared
BCL2IF_bit = 0 ' I2C-2 Bus collision flag cleared
PEIE_bit = 1 ' Peripheral interrupts enabled
GIE_bit = 1 ' Global interrupts enabled
End sub
'------------------------------------------------------------------------------'
Code: Select all
'==============================================================================' Interrupts
Sub procedure Interrupt() ' Handle interrupts here
If (PIR2.SSP2IF = 1) then '
PIR2.SSP2IF = 0 '
'***********************************************************************' Master Reads from Slave (BF Set)
If ((SSP2STAT.BF = 1) And (SSP2STAT.S = 1) '
And (SSP2STAT.R_Not_W = 1)) then '
'********************************************************************' Address Last
If (SSP2STAT.D_Not_A = 0) then '
Received = SSP2BUF ' Clears BF
SSP2BUF = Switch_Flip ' Sets BF
SSP2CON1.CKP = 1 ' Allows transmission
RGB_LED_Red = 1 ' Indicator for testing, remove when all is working
Goto EndOfI2C2 '
End if '
'********************************************************************' Data Last
If (SSP2STAT.D_Not_A = 1) then ' Per datasheet, should not happen
'"Figure 21-10: I2C Slave Mode Timing (Transmission 7-bit address)"
Received = SSP2BUF '
SSP2BUF = Switch_Flip '
SSP2CON1.CKP = 1 '
RGB_LED_Green = 1 ' Indicator for testing, remove when all is working
Goto EndOfI2C2 '
End if '
End if '
'***********************************************************************' Master Reads from Slave (BF Not Set)
If ((SSP2STAT.BF = 0) And (SSP2STAT.R_Not_W = 1)) then '
'********************************************************************' Data Last
If (SSP2STAT.D_Not_A = 1) then '
SSP2BUF = Switch_Flip ' Sets BF
SSP2CON1.CKP = 1 '
RGB_LED_Blue = 1 ' Indicator for testing, remove when all is working
End if '
End if '
EndOfI2C2: '
End if '
'--------------------------------------------------------------------------'
End sub
And I suppose I'm less confident in the I2C-2 set-up code being right, but after reading and reading again (several times) the datasheet, I'm here for a second set of eyes to see if I have things right or wrong, or am missing something altogether?
So would like it if someone can see if the Set-Up and ISR code is okay too please?
TL;DR
- Why is the Master sending a Stop-bit after the Slave-Address, and not reading a byte from the Slave-MCU?
- Is my Slave-MCU 'set-up' code correct?
- Is my Slave-MCU interrupt code correct?
Chris