You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

423 lines
12 KiB

/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/*
Slave I2C support contributed by Brent Roman of the
Monterey Bay Aquarium Research Institute
*/
/**
* @file i2cslave.h
* @brief Slave Mode for the I2C Driver.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2CSLAVE_H_
#define _I2CSLAVE_H_
#if HAL_USE_I2C_SLAVE || defined(__DOXYGEN__)
#include <hal_i2c.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configure to respond to messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @return Length of message OR the type of event received
* @retval I2C_OK Success
* @retval I2C_ERROR Cannot match address in addition of those already
*
* @details MatchAddress calls are cumulative.
* Specify address zero to match I2C "all call"
* Most hardware supports matching only a signle nonzero address.
*
* @api
*/
int i2cMatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
/**
* @brief Configure to ignore messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @details A message being transferred that has already matched the
* specified address will continue being processed.
* Requests to unmatch an address that is not currently being matched
* are ignored.
*
* @api
*/
void i2cUnmatchAddress(I2CDriver *i2cp, i2caddr_t i2cadr);
/**
* @brief Configure to ignore all messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @details A message being transferred that has already matched the
* specified address will continue being processed.
*
* @api
*/
void i2cUnmatchAll(I2CDriver *i2cp);
/**
* @brief Configure to respond to messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @return non-zero implies failure.
*
* @details Identical to i2cMatchAddress(), but called from interrupt context
*
* @api
*/
static inline msg_t
i2cMatchAddressI(I2CDriver *i2cp, i2caddr_t i2cadr)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_matchAddress(i2cp, i2cadr);
}
/**
* @brief Configure to ignore messages directed to the given i2cadr
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] i2cadr I2C bus address
* - @a 0 matches "all call"
* .
* @details Identical to i2cUnmatchAddress(), but called from interrupt context
*
* @api
*/
static inline void
i2cUnmatchAddressI(I2CDriver *i2cp, i2caddr_t i2cadr)
{
osalDbgCheck(i2cp != NULL);
i2c_lld_unmatchAddress(i2cp, i2cadr);
}
/**
* @brief Configure to ignore all messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @details Identical to i2cUnmatchAll(), but called from interrupt context
*
* @api
*/
static inline void
i2cUnmatchAllI(I2CDriver *i2cp)
/*
Notes:
Must be called from interrupt context
Does not affect the processing of any message currently being received
*/
{
osalDbgCheck(i2cp != NULL);
i2c_lld_unmatchAll(i2cp);
}
/* I2C Bus activity timeout configuration */
/**
* @brief return maximum number of ticks a slave bus transaction may last
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return maximum number of ticks a slave bus transaction my last
*
* @details initialized to TIME_INFINITE (disabling slave mode bus timeouts)
*
* @api
*/
static inline
systime_t i2cSlaveTimeout(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveTimeout(i2cp);
}
/**
* @brief set the maximum number of ticks a slave bus transaction may last
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] ticks maximum number of ticks a slave bus transaction my last
* - @a TIME_INFINITE disables slave mode bus timeouts
* - @a TIME_IMMEDIATE is invalid
* .
*
* @api
*/
static inline
void i2cSlaveSetTimeout(I2CDriver *i2cp, systime_t ticks)
{
osalDbgCheck(i2cp != NULL && ticks != TIME_IMMEDIATE);
i2c_lld_set_slaveTimeout(i2cp, ticks);
}
/* bus transaction attributes */
/**
* @brief return bit mask of errors associated with this slave transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return I2C bus error conditions described in i2c.h
*
* @api
*/
static inline
i2cflags_t i2cSlaveErrors(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveErrors(i2cp);
}
/**
* @brief return number of bytes transferred during this slave transaction
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return number of bytes actually transferred on the bus
*
* @api
*/
static inline
size_t i2cSlaveBytes(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveBytes(i2cp);
}
/**
* @brief return i2c address to which this message was targetted
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @return i2c address to which this message was targetted
*
* @details The address returns will be one of those
* specified earlier as an argument to i2cMatchAddress()
*
* @api
*/
static inline
i2caddr_t i2cSlaveTargetAdr(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveTargetAdr(i2cp);
}
/*
An event service thread based API library called i2cevent supports processing
slave messages on a dedicated thread. This facility is built upon the
low-level driver's asynchronous callback functions described below:
Each callback function may alter the processing of subsequent I2C
messages and read requests by calling i2cSlaveReceive() and
i2cSlaveReply(), respectively. Further, callbacks may alter their
i2cSlaveMsg structs in RAM, but only those for their own channel.
Such changes take immediate affect. This facility can be used to
avoid copying message buffers.
If receive buffers become full or a reply to a read request cannot be
generated immediately, the relevant I2CSlaveMsg struct may be substituted
for another whose body pointer is NULL or whose body size is zero.
Note that, I2CSlaveMsg structs may be modified
in place within a channel's callbacks to the same effect.
A NULL body pointer or zero size causes the slave to signal the master node
to wait by holding the I2C clock signal low, "stretching it", during the next
transaction to which that I2CSlaveMsg applies.
The I2C clock resumes only after a i2cSlaveSetReceive() or SetReply() is
called with an I2CSlaveMsg containing a non-NULL body,
or after the transaction timeout expires.
Therefore, if a NULL body pointer is replaced with a non-NULL one or
a zero length is replaced with a non-zero one, i2cSlaveReceive() or
i2cSlaveReply() MUST be called -- even if with the same pointer values --
to inform the i2c driver that the transaction may resume.
Note that Receive and Reply processing is initially "locked".
*/
/**
* @brief Configure callbacks & buffers for message reception & query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveConfigure(I2CDriver *i2cp,
const I2CSlaveMsg *rxMsg, const I2CSlaveMsg *replyMsg);
/**
* @brief Configure callbacks & buffers for message reception
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveReceive(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg);
/**
* @brief return @p I2CSlaveMsg for processing received messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @returns @p I2CSlaveMsg struct for processing subsequent messages
*
* @api
*/
static inline
const I2CSlaveMsg *i2cSlaveReceiveMsg(I2CDriver *i2cp)
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveReceive(i2cp);
}
/**
* @brief Configure callbacks & buffers for query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent queries
*
* @details Must be called from a thread
* Call i2cMatchAddress() after this to start processing
* Enabling match addresses before installing handler callbacks can
* result in locking the I2C bus when a master accesses those
* unconfigured slave addresses
*
* @api
*/
void i2cSlaveReply(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg);
/**
* @brief return @p I2CSlaveMsg for processing received messages
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @returns @p I2CSlaveMsg struct for processing subsequent messages
*
* @api
*/
static inline
const I2CSlaveMsg *i2cSlaveReplyMsg(I2CDriver *i2cp)
/*
processing descriptor for the next reply message
*/
{
osalDbgCheck(i2cp != NULL);
return i2c_lld_get_slaveReply(i2cp);
}
/**
* @brief Configure callbacks & buffers for message reception
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] rxMsg @p I2CSlaveMsg struct for processing subsequent messages
*
* @details Must be called from an interrupt context
*
* @api
*/
static inline void
i2cSlaveReceiveI(I2CDriver *i2cp, const I2CSlaveMsg *rxMsg)
{
osalDbgCheck(i2cp != NULL && rxMsg != NULL);
i2c_lld_slaveReceive(i2cp, rxMsg);
}
/**
* @brief Configure callbacks & buffers for query reply
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] replyMsg @p I2CSlaveMsg struct for processing subsequent messages
*
* @details Must be called from an interrupt context
*
* @api
*/
static inline void
i2cSlaveReplyI(I2CDriver *i2cp, const I2CSlaveMsg *replyMsg)
/*
Prepare to reply to I2C read requests from bus masters
according to the replyMsg configuration.
Notes:
Must be called from interrupt context
Does not affect the processing of any message reply being sent
*/
{
osalDbgCheck(i2cp != NULL && replyMsg != NULL);
i2c_lld_slaveReply(i2cp, replyMsg);
}
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C_SLAVE */
#endif /* _I2CSLAVE_H_ */