i2c timeout

General discussion on mikroBasic PRO for dsPIC30/33 and PIC24.
Post Reply
Author
Message
arco
Posts: 312
Joined: 15 Apr 2008 13:54
Location: The Netherlands

i2c timeout

#1 Post by arco » 07 Mar 2017 17:04

I read that all i2c libraries now have a timout. How do you use that? Is it a setting?
(my code still hangs if the i2c bus has problems, not acceptable...)
Regards,

Peter.

arco
Posts: 312
Joined: 15 Apr 2008 13:54
Location: The Netherlands

Re: i2c timeout

#2 Post by arco » 08 Mar 2017 00:39

I tried to build muy own (non-blocking) i2c library, but somehow it doesn't work. (for the PIC24FJ256GA108, i2c port #1):
(AFAIK I've followed the guidlines in the Microchip AN's)

Code: Select all

module __lib_i2c_nb

Const I2CTimeOut = 100

Sub Procedure I2CInit()
Sub Function I2CStart() As Byte
Sub Function I2CRestart() As Byte
Sub Function I2CIdle() As Byte
Sub Function I2CRead(Dim pAck As Byte) As Byte
Sub Function I2CWrite(Dim pDat As Byte) As Byte
Sub Function I2CStop() As Byte
Sub Procedure I2CClose()

implements

'--------------------------------------------------------------------------------------------------
Sub Procedure I2Cinit()
'--------------------------------------------------------------------------------------------------
  I2CEN_bit = 1
  I2C1BRG   = 37
End Sub

'--------------------------------------------------------------------------------------------------
Sub Function I2CStart() As Byte                                     ' OK
'--------------------------------------------------------------------------------------------------
  Result = I2CIdle()
  If Result Then SEN_bit = 1 End If
End Sub

'--------------------------------------------------------------------------------------------------
Sub Function I2CRestart() As Byte                                   ' OK
'--------------------------------------------------------------------------------------------------
  Result = I2CIdle()
  If Result Then delay_us(10) RSEN_bit = 1 End If
End Sub

'--------------------------------------------------------------------------------------------------
Sub Function I2CIdle() As Byte                                      ' OK
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Byte
  For lCnt = 0 To I2CTimeOut
    If (I2C1Con And 0x001F) = 0 Then Break End If
    delay_us(5)
  Next lCnt
  Result = (I2C1Con And 0x1F) Xor 1
End Sub

'--------------------------------------------------------------------------------------------------
Sub Function I2CRead(Dim pAck As Byte) As Byte                      ' OK
'--------------------------------------------------------------------------------------------------
  If I2CIdle() Then
    delay_us(10)
    RCEN_bit = 1
    If I2CIdle Then
      Result = I2C1RCV
      If I2CIdle() Then
        If pAck Then ACKDT_bit = 0 Else ACKDT_bit = 1 End If
        ACKEN_bit = 1
        I2CIdle()
      End If
    End If
  End If
End Sub

'--------------------------------------------------------------------------------------------------
Sub Function I2CWrite(Dim pDat As Byte) As Byte                     ' OK
'--------------------------------------------------------------------------------------------------
  Result = I2CIdle()
  If Result Then delay_us(10) I2C1TRN = pDat End If
End Sub

'--------------------------------------------------------------------------------------------------
Sub Function I2CStop() As Byte                                      ' OK
'--------------------------------------------------------------------------------------------------
  Result = I2CIdle()
  If Result Then delay_us(10) PEN_bit = 1 End If
End Sub

'--------------------------------------------------------------------------------------------------
Sub Procedure I2CClose()                                            ' OK
'--------------------------------------------------------------------------------------------------
  I2CEN_bit = 0
End Sub

end.
Regards,

Peter.

User avatar
dusan.poluga
mikroElektronika team
Posts: 780
Joined: 02 Feb 2017 14:21

Re: i2c timeout

#3 Post by dusan.poluga » 09 Mar 2017 16:47

Hi,

It stops at the function because when you debug your code it is easier to find where your code isn't working.
Most times it stops at the i2c function when the i2c bus address is wrong or when you do not receive the ACK signal from the chip you are trying to talk to.

Regards,
Dusan Poluga.

arco
Posts: 312
Joined: 15 Apr 2008 13:54
Location: The Netherlands

Re: i2c timeout

#4 Post by arco » 09 Mar 2017 17:51

Yes,

But I read that the 7.0 libraries have a time out on errors? (it doesn't work here...)
Without a time-out your whole application is dead/frozen if a bus error occurs, that's not acceptable in most cases...
Regards,

Peter.

User avatar
dusan.poluga
mikroElektronika team
Posts: 780
Joined: 02 Feb 2017 14:21

Re: i2c timeout

#5 Post by dusan.poluga » 13 Mar 2017 15:54

Hi,

I have tested this with a couple click boards but did not come across a timeout error.
Only time the error gets presented when i make an error by changing the i2c address to something that does not exist on the bus or i unplug the board from the bus.

Regards,
Dusan Poluga.

arco
Posts: 312
Joined: 15 Apr 2008 13:54
Location: The Netherlands

Re: i2c timeout

#6 Post by arco » 13 Mar 2017 16:34

I had a broken pull-up resistor on the i2c bus, this will hang the system indefinitely.
Whatever error occurs on the i2c bus, the system should never hang.
(you can't even warn the user in that case that something is wrong)
Working non-blocking version (I2C1, 16MHz Fcy, 400kHz i2c, i2cstatus holds errors on exit):

Code: Select all

module lib_i2c

Const I2CTimeOut = 200
Dim I2cStatus As Byte

'Statusbits:    00000001 - Start
'               00000010 - Restart
'               00000100 - Stop
'               00001000 - Write
'               00010000 - Read
'               00100000 - Idle
'               01000000 - Receive buffer

Sub Procedure I2CInit()
Sub Procedure I2CStart()
Sub Procedure I2CRestart()
Sub Procedure I2CStop()
Sub Procedure I2CWrite(Dim pDat As Byte)
Sub Procedure I2CIdle()
Sub Function I2CRead(Dim pAck As Byte) As Byte

implements

'==================================================================================================
Sub Procedure I2CIdle()                                             'Wait for bus idle
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  For lCnt = 0 To I2CTimeout                                        '
    If (I2C1CON And 0x1F) = 0  then break end if                    '
  Next lCnt                                                         '
  I2cStatus.5 = (I2C1CON And 0x1F)                                   '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2Cinit()                                             'Init I2C1 peripheral (400kHz)
'--------------------------------------------------------------------------------------------------
  I2C1BRG   = 0x0025                                                '(Fcy/scl)-(Fcy/10000000) -1
  I2CEN_Bit = 1                                                     'Enable I2C1
  Delay_ms(10)                                                      '
  I2C1STAT = 0                                                      '
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CStart()                                            'Start bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  SEN_Bit = 1                                                       'Set start bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (SEN_Bit = 0) Then Break End If                              '
  Next lCnt                                                         '
  I2cStatus = SEN_bit                                               'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CRestart()                                          'Restart bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  RSEN_Bit = 1                                                      'Set repeated start bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (RSEN_Bit = 0) Then Break End If                             '
  Next lCnt                                                         '
  I2cStatus.1 = RSEN_bit                                            'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CStop()                                             'Stop bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  PEN_Bit = 1                                                       'Set stop bit
  For lCnt = 0 To I2CTimeout                                        'Wait for bit to clear
    If (PEN_Bit = 0) Then Break End If                              '
  Next lCnt                                                         '
  I2cStatus.2 = PEN_Bit                                             'Errorstatus
End Sub                                                             '

'==================================================================================================
Sub Procedure I2CWrite(Dim pDat As Byte)                            'Write byte pDat to bus
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  MI2C1IF_Bit = 0                                                   'Clear interruptflag
  I2C1TRN = pDat                                                    'Data to send into buffer
  For lCnt = 0 To I2CTimeout                                        'Wait for interruptflag to
    If MI2C1IF_bit Then Break End If                                'get set
  Next lCnt                                                         '
  I2cStatus.3 = MI2C1IF_Bit Xor 1                                   'Errorstatus
End Sub

'==================================================================================================
Sub Function I2CRead(Dim pAck As Byte) As Byte                      'Read byte of bus(1=Nack/0=Ack)
'--------------------------------------------------------------------------------------------------
  Dim lCnt As Word                                                  '
  I2CIdle()                                                         'Wait for bus idle
  MI2C1IF_Bit = 0                                                   'Clear interruptflag
  RCEN_Bit = 1                                                      '
  For lCnt = 0 To I2cTimeout                                        'Wait for buffer
    If RBF_Bit Then Break End If                                    '
  Next lCnt                                                         '
  I2cStatus.6 = RBF_Bit Xor 1                                       'Errorstatus
  Result = I2C1RCV                                                  'Get received byte
  ACKDT_Bit = pAck                                                  'Send Ack/Nack
  ACKEN_Bit = 1                                                     '
  For lCnt = 0 To I2CTimeout                                        '
    If MI2C1IF_Bit Then Break End If                                '
  Next lCnt                                                         '
  I2cStatus.4 = MI2C1IF_Bit Xor 1                                   'Errorstatus
End Sub                                                             '
end.

'==================================================================================================
Last edited by arco on 14 Mar 2017 18:00, edited 1 time in total.
Regards,

Peter.

User avatar
dusan.poluga
mikroElektronika team
Posts: 780
Joined: 02 Feb 2017 14:21

Re: i2c timeout

#7 Post by dusan.poluga » 13 Mar 2017 17:50

Hi,

Yes you are correct. The system should not stop working.
Our libraries are written for ease of use and for ease for debugging.
For that some sacrifices need to be made.

Regards,
Dusan Poluga.

arco
Posts: 312
Joined: 15 Apr 2008 13:54
Location: The Netherlands

Re: i2c timeout

#8 Post by arco » 13 Mar 2017 18:22

Sacrifices aren't nessecairy. My code is non-blocking and sets errorflags if something goes wrong... :)
Regards,

Peter.

User avatar
dusan.poluga
mikroElektronika team
Posts: 780
Joined: 02 Feb 2017 14:21

Re: i2c timeout

#9 Post by dusan.poluga » 14 Mar 2017 15:59

Hi,

Yes that is one way of solving the problem.
Thank you for sharing.

Regards,
Dusan Poluga.

Post Reply

Return to “mikroBasic PRO for dsPIC30/33 and PIC24 General”