Help: PIC18F87K22 I2C2 Read Master and Slave issues

General discussion on mikroBasic PRO for PIC.
Post Reply
Author
Message
chris11jed
Posts: 156
Joined: 15 Jun 2011 06:37

Help: PIC18F87K22 I2C2 Read Master and Slave issues

#1 Post by chris11jed » 27 Dec 2020 04:19

Hello all, best wishes for the end of 2020...

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. :D
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
'
...and...

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
So, I see that the Master-MCU sends the correct I2C-Slave-Address on the bus, ending with the Read-Bit, and a 'high' ACK bit, before a Stop-bit.
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
'------------------------------------------------------------------------------'
In the main project space, I press a button to call the Slave-MCU;

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
  '----------------------------------------------------------------------------'
If all were to go well in this test-code, some LEDs would light or turn off, depending upon what byte value the Slave sends back.

When I look at what's happening on an oscilloscope, I get this;

Image

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
'
...And...

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
'------------------------------------------------------------------------------'
And here is the Interrupt Service Routine;

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
I am 99% confident the Interrupt code will work, as I used similar code for I2C-2 communication between two PIC18F45K22 MCU's, and that code works well.
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?
Thank you and sorry for the wall-o-text post here :D :wink: :lol: 8)
Chris

Post Reply

Return to “mikroBasic PRO for PIC General”