Skip to content

Commit

Permalink
i2cslave: Add timeout parameter (#379)
Browse files Browse the repository at this point in the history
* Comment for Doxygen
* Add note on General Call Address 0 (#383)
  • Loading branch information
rsta2 committed Jun 22, 2023
1 parent 9d8d9f2 commit d5882ff
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 14 deletions.
30 changes: 23 additions & 7 deletions include/circle/i2cslave.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// i2cslave.h
//
// Circle - A C++ bare metal environment for Raspberry Pi
// Copyright (C) 2014-2015 R. Stange <[email protected]>
// Copyright (C) 2014-2023 R. Stange <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
Expand All @@ -23,19 +23,35 @@
#include <circle/gpiopin.h>
#include <circle/types.h>

class CI2CSlave
class CI2CSlave /// Driver for I2C slave device
{
public:
static const unsigned TimeoutNone = 0; ///< Return immediately
static const unsigned TimeoutForEver = -1; ///< Timeout never occurs

public:
/// \param ucAddress 7-bit device address
CI2CSlave (u8 ucAddress);

~CI2CSlave (void);

/// \return Operation successful?
boolean Initialize (void);

// returns number of read bytes or < 0 on failure
int Read (void *pBuffer, unsigned nCount);

// returns number of written bytes or < 0 on failure
int Write (const void *pBuffer, unsigned nCount);
/// \param pBuffer Pointer to data buffer
/// \param nCount Number of bytes to be read
/// \param nTimeout_us Return after given number of us, when less than nCount bytes read
/// \return Number of read bytes or < 0 on failure\n
/// When a timeout occurs, the result is smaller than nCount (or 0).
/// \note Broadcasts to the General Call Address 0 will not be received.
int Read (void *pBuffer, unsigned nCount, unsigned nTimeout_us = TimeoutForEver);

/// \param pBuffer Pointer to data buffer
/// \param nCount Number of bytes to be written
/// \param nTimeout_us Return after given number of us, when less than nCount bytes written
/// \return Number of written bytes or < 0 on failure\n
/// When a timeout occurs, the result is smaller than nCount (or 0).
int Write (const void *pBuffer, unsigned nCount, unsigned nTimeout_us = TimeoutForEver);

private:
u8 m_ucAddress;
Expand Down
33 changes: 26 additions & 7 deletions lib/i2cslave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// i2cslave.cpp
//
// Circle - A C++ bare metal environment for Raspberry Pi
// Copyright (C) 2014-2020 R. Stange <[email protected]>
// Copyright (C) 2014-2023 R. Stange <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
Expand All @@ -21,6 +21,7 @@
#include <circle/memio.h>
#include <circle/bcm2835.h>
#include <circle/synchronize.h>
#include <circle/timer.h>
#include <assert.h>

#define DR_DATA__MASK 0xFF
Expand Down Expand Up @@ -97,7 +98,7 @@ boolean CI2CSlave::Initialize (void)
return TRUE;
}

int CI2CSlave::Read (void *pBuffer, unsigned nCount)
int CI2CSlave::Read (void *pBuffer, unsigned nCount, unsigned nTimeout_us)
{
if (nCount == 0)
{
Expand All @@ -114,11 +115,18 @@ int CI2CSlave::Read (void *pBuffer, unsigned nCount)

int nResult = 0;

while (nCount-- > 0)
unsigned nTimeoutTicks = nTimeout_us * (CLOCKHZ / 1000000U);
unsigned nStartTicks = CTimer::GetClockTicks ();

while (nCount > 0)
{
while (read32 (ARM_BSC_SPI_SLAVE_FR) & FR_RXFE)
{
// do nothing
if ( nTimeout_us != TimeoutForEver
&& CTimer::GetClockTicks () - nStartTicks >= nTimeoutTicks)
{
goto Timeout;
}
}

if (read32 (ARM_BSC_SPI_SLAVE_RSR) & RSR_OE)
Expand All @@ -131,8 +139,10 @@ int CI2CSlave::Read (void *pBuffer, unsigned nCount)
*pData++ = read32 (ARM_BSC_SPI_SLAVE_DR) & DR_DATA__MASK;

nResult++;
nCount--;
}

Timeout:
if (nResult > 0)
{
// wait for transfer to stop
Expand All @@ -154,7 +164,7 @@ int CI2CSlave::Read (void *pBuffer, unsigned nCount)
return nResult;
}

int CI2CSlave::Write (const void *pBuffer, unsigned nCount)
int CI2CSlave::Write (const void *pBuffer, unsigned nCount, unsigned nTimeout_us)
{
if (nCount == 0)
{
Expand All @@ -172,7 +182,10 @@ int CI2CSlave::Write (const void *pBuffer, unsigned nCount)
int nResult = 0;
boolean bTxActive = FALSE;

while (nCount-- > 0)
unsigned nTimeoutTicks = nTimeout_us * (CLOCKHZ / 1000000U);
unsigned nStartTicks = CTimer::GetClockTicks ();

while (nCount > 0)
{
if (read32 (ARM_BSC_SPI_SLAVE_FR) & FR_TXBUSY)
{
Expand All @@ -181,7 +194,11 @@ int CI2CSlave::Write (const void *pBuffer, unsigned nCount)

while (read32 (ARM_BSC_SPI_SLAVE_FR) & FR_TXFF)
{
// do nothing
if ( nTimeout_us != TimeoutForEver
&& CTimer::GetClockTicks () - nStartTicks >= nTimeoutTicks)
{
goto Timeout;
}
}

write32 (ARM_BSC_SPI_SLAVE_DR, *pData++);
Expand All @@ -194,8 +211,10 @@ int CI2CSlave::Write (const void *pBuffer, unsigned nCount)
}

nResult++;
nCount--;
}

Timeout:
if (nResult > 0)
{
if (!bTxActive)
Expand Down

0 comments on commit d5882ff

Please sign in to comment.