mirror of
https://github.com/SMFSW/cI2C
synced 2024-12-22 04:49:59 +01:00
v1.1: fixed bus speed calc & returning configuration value applied instead of bool
This commit is contained in:
parent
ed7030cffc
commit
a44abc72ec
2
Doxyfile
2
Doxyfile
@ -38,7 +38,7 @@ PROJECT_NAME = "Arduino Hardware I2C for AVR MCUs (plain c)"
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.0
|
||||
PROJECT_NUMBER = 1.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
@ -15,6 +15,11 @@ Feel free to share your thoughts @ xgarmanboziax@gmail.com about:
|
||||
------------
|
||||
|
||||
** Actual:
|
||||
v1.1 29 Nov 2017:
|
||||
- Frequency calculation fix (thanks to TonyWilk)
|
||||
- Set Frequency higher than Fast Mode (400KHz) will set bus to Fast Mode (frequency is up to 400KHz on AVR)
|
||||
- I2C_set_xxx now returns values applied, not bool
|
||||
|
||||
v1.0 21 Nov 2017:
|
||||
- Added const qualifier for function parameters
|
||||
- Return from comm functions if bytes to R/W set to 0
|
||||
|
@ -64,7 +64,7 @@ void loop() {
|
||||
*/
|
||||
bool I2C_wr_advanced(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes)
|
||||
{
|
||||
if (bytes == 0) { return false; }
|
||||
if (bytes == 0) { return false; }
|
||||
|
||||
slave->reg_addr = reg_addr;
|
||||
|
||||
@ -100,7 +100,7 @@ bool I2C_wr_advanced(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data,
|
||||
*/
|
||||
bool I2C_rd_advanced(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes)
|
||||
{
|
||||
if (bytes == 0) { return false; }
|
||||
if (bytes == 0) { return false; }
|
||||
|
||||
slave->reg_addr = reg_addr;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=cI2C
|
||||
version=1.0
|
||||
version=1.1
|
||||
author=SMFSW <xgarmanboziax@gmail.com>
|
||||
maintainer=SMFSW <xgarmanboziax@gmail.com>
|
||||
sentence=Arduino Hardware I2C for AVR (in plain c)
|
||||
|
280
src/ci2c.c
280
src/ci2c.c
@ -1,6 +1,6 @@
|
||||
/*!\file ci2c.c
|
||||
** \author SMFSW
|
||||
** \version 1.0
|
||||
** \version 1.1
|
||||
** \copyright MIT SMFSW (2017)
|
||||
** \brief arduino master i2c in plain c code
|
||||
**/
|
||||
@ -35,13 +35,13 @@
|
||||
#define clrRegBit(r, b) r &= (uint8_t) (~(1 << b)) //!< clear bit \b b in register \b r
|
||||
#define invRegBit(r, b) r ^= (1 << b) //!< invert bit \b b in register \b r
|
||||
|
||||
/*! \struct i2c
|
||||
* \brief static ci2c bus config and control parameters
|
||||
*/
|
||||
/*!\struct i2c
|
||||
** \brief static ci2c bus config and control parameters
|
||||
**/
|
||||
static struct {
|
||||
/*! \struct cfg
|
||||
* \brief ci2c bus parameters
|
||||
*/
|
||||
/*!\struct cfg
|
||||
** \brief ci2c bus parameters
|
||||
**/
|
||||
struct {
|
||||
I2C_SPEED speed; //!< i2c bus speed
|
||||
uint8_t retries; //!< i2c message retries when fail
|
||||
@ -57,12 +57,12 @@ static bool I2C_wr(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, c
|
||||
static bool I2C_rd(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes);
|
||||
|
||||
|
||||
/*! \brief Init an I2C slave structure for cMI2C communication
|
||||
* \param [in] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] sl_addr - I2C slave address
|
||||
* \param [in] reg_sz - internal register map size
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Init an I2C slave structure for cMI2C communication
|
||||
** \param [in] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] sl_addr - I2C slave address
|
||||
** \param [in] reg_sz - internal register map size
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_slave_init(I2C_SLAVE * slave, const uint8_t sl_addr, const I2C_INT_SIZE reg_sz)
|
||||
{
|
||||
(void) I2C_slave_set_addr(slave, sl_addr);
|
||||
@ -73,23 +73,23 @@ void I2C_slave_init(I2C_SLAVE * slave, const uint8_t sl_addr, const I2C_INT_SIZE
|
||||
slave->status = I2C_OK;
|
||||
}
|
||||
|
||||
/*! \brief Redirect slave I2C read/write function (if needed for advanced use)
|
||||
* \param [in] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] func - pointer to read/write function to affect
|
||||
* \param [in] rw - 0 = write function, 1 = read function
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Redirect slave I2C read/write function (if needed for advanced use)
|
||||
** \param [in] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] func - pointer to read/write function to affect
|
||||
** \param [in] rw - 0 = write function, 1 = read function
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_slave_set_rw_func(I2C_SLAVE * slave, const ci2c_fct_ptr func, const I2C_RW rw)
|
||||
{
|
||||
ci2c_fct_ptr * pfc = (ci2c_fct_ptr*) (rw ? &slave->cfg.rd : &slave->cfg.wr);
|
||||
*pfc = func;
|
||||
}
|
||||
|
||||
/*! \brief Change I2C slave address
|
||||
* \param [in, out] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] sl_addr - I2C slave address
|
||||
* \return true if new address set (false if address is >7Fh)
|
||||
*/
|
||||
/*!\brief Change I2C slave address
|
||||
** \param [in, out] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] sl_addr - I2C slave address
|
||||
** \return true if new address set (false if address is >7Fh)
|
||||
**/
|
||||
bool I2C_slave_set_addr(I2C_SLAVE * slave, const uint8_t sl_addr)
|
||||
{
|
||||
if (sl_addr > 0x7F) { return false; }
|
||||
@ -97,33 +97,33 @@ bool I2C_slave_set_addr(I2C_SLAVE * slave, const uint8_t sl_addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Change I2C registers map size (for access)
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_sz - internal register map size
|
||||
* \return true if new size is correct (false otherwise and set to 16bit by default)
|
||||
*/
|
||||
/*!\brief Change I2C registers map size (for access)
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_sz - internal register map size
|
||||
** \return true if new size is correct (false otherwise and set to 16bit by default)
|
||||
**/
|
||||
bool I2C_slave_set_reg_size(I2C_SLAVE * slave, const I2C_INT_SIZE reg_sz)
|
||||
{
|
||||
slave->cfg.reg_size = reg_sz > I2C_16B_REG ? I2C_16B_REG : reg_sz;
|
||||
return !(reg_sz > I2C_16B_REG);
|
||||
}
|
||||
|
||||
/*! \brief Set I2C current register address
|
||||
* \attribute inline
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Set I2C current register address
|
||||
** \attribute inline
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address
|
||||
** \return nothing
|
||||
**/
|
||||
static inline void __attribute__((__always_inline__)) I2C_slave_set_reg_addr(I2C_SLAVE * slave, const uint16_t reg_addr) {
|
||||
slave->reg_addr = reg_addr; }
|
||||
|
||||
|
||||
|
||||
/*! \brief Enable I2c module on arduino board (including pull-ups,
|
||||
* enabling of ACK, and setting clock frequency)
|
||||
* \param [in] speed - I2C bus speed in KHz
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Enable I2c module on arduino board (including pull-ups,
|
||||
* enabling of ACK, and setting clock frequency)
|
||||
** \param [in] speed - I2C bus speed in KHz
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_init(const uint16_t speed)
|
||||
{
|
||||
// Set SDA and SCL to ports with pull-ups
|
||||
@ -138,9 +138,9 @@ void I2C_init(const uint16_t speed)
|
||||
(void) I2C_set_speed(speed);
|
||||
}
|
||||
|
||||
/*! \brief Disable I2c module on arduino board (releasing pull-ups, and TWI control)
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Disable I2c module on arduino board (releasing pull-ups, and TWI control)
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_uninit()
|
||||
{
|
||||
// Release SDA and SCL ports pull-ups
|
||||
@ -156,9 +156,9 @@ void I2C_uninit()
|
||||
}
|
||||
|
||||
|
||||
/*! \brief I2C bus reset (Release SCL and SDA lines and re-enable module)
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief I2C bus reset (Release SCL and SDA lines and re-enable module)
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_reset(void)
|
||||
{
|
||||
TWCR = 0;
|
||||
@ -166,70 +166,70 @@ void I2C_reset(void)
|
||||
setRegBit(TWCR, TWEN);
|
||||
}
|
||||
|
||||
/*! \brief Change I2C frequency
|
||||
* \param [in] speed - I2C speed in kHz (max 1MHz)
|
||||
* \return true if change is successful (false otherwise)
|
||||
*/
|
||||
bool I2C_set_speed(const uint16_t speed)
|
||||
/*!\brief Change I2C frequency
|
||||
** \param [in] speed - I2C speed in KHz (max 400KHz on avr)
|
||||
** \return Configured bus speed
|
||||
**/
|
||||
uint16_t I2C_set_speed(const uint16_t speed)
|
||||
{
|
||||
i2c.cfg.speed = (I2C_SPEED) ((speed == 0) ? (uint16_t) I2C_STD : ((speed > (uint16_t) I2C_HS) ? (uint16_t) I2C_STD : speed));
|
||||
i2c.cfg.speed = (I2C_SPEED) ((speed == 0) ? (uint16_t) I2C_STD : ((speed > (uint16_t) I2C_FM) ? (uint16_t) I2C_FM : speed));
|
||||
|
||||
clrRegBit(TWCR, TWEN); // Ensure i2c module is disabled
|
||||
|
||||
// Set prescaler and clock frequency
|
||||
clrRegBit(TWSR, TWPS0);
|
||||
clrRegBit(TWSR, TWPS1);
|
||||
TWBR = ((F_CPU / (i2c.cfg.speed * 1000)) - 16) / 2;
|
||||
TWBR = (((F_CPU / 1000) / i2c.cfg.speed) - 16) / 2;
|
||||
|
||||
I2C_reset(); // re-enable module
|
||||
|
||||
return (i2c.cfg.speed == speed);
|
||||
return i2c.cfg.speed;
|
||||
}
|
||||
|
||||
/*! \brief Change I2C ack timeout
|
||||
* \param [in] timeout - I2C ack timeout (500 ms max)
|
||||
* \return true if change is successful (false otherwise)
|
||||
*/
|
||||
bool I2C_set_timeout(const uint16_t timeout)
|
||||
/*!\brief Change I2C ack timeout
|
||||
** \param [in] timeout - I2C ack timeout (500 ms max)
|
||||
** \return Configured timeout
|
||||
**/
|
||||
uint16_t I2C_set_timeout(const uint16_t timeout)
|
||||
{
|
||||
static const uint16_t max_timeout = 500;
|
||||
i2c.cfg.timeout = (timeout > max_timeout) ? max_timeout : timeout;
|
||||
return (i2c.cfg.timeout == timeout);
|
||||
return i2c.cfg.timeout;
|
||||
}
|
||||
|
||||
/*! \brief Change I2C message retries (in case of failure)
|
||||
* \param [in] retries - I2C number of retries (max of 8)
|
||||
* \return true if change is successful (false otherwise)
|
||||
*/
|
||||
bool I2C_set_retries(const uint8_t retries)
|
||||
/*!\brief Change I2C message retries (in case of failure)
|
||||
** \param [in] retries - I2C number of retries (max of 8)
|
||||
** \return Configured number of retries
|
||||
**/
|
||||
uint8_t I2C_set_retries(const uint8_t retries)
|
||||
{
|
||||
static const uint16_t max_retries = 8;
|
||||
i2c.cfg.retries = (retries > max_retries) ? max_retries : retries;
|
||||
return (i2c.cfg.retries == retries);
|
||||
return i2c.cfg.retries;
|
||||
}
|
||||
|
||||
/*! \brief Get I2C busy status
|
||||
* \return true if busy
|
||||
*/
|
||||
/*!\brief Get I2C busy status
|
||||
** \return true if busy
|
||||
**/
|
||||
bool I2C_is_busy(void) {
|
||||
return i2c.busy; }
|
||||
|
||||
|
||||
/*! \brief This function reads or writes the provided data to/from the address specified.
|
||||
* If anything in the write process is not successful, then it will be repeated
|
||||
* up till 3 more times (default). If still not successful, returns NACK
|
||||
* \param [in, out] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in] data - pointer to the first byte of a block of data to write
|
||||
* \param [in] bytes - indicates how many bytes of data to write
|
||||
* \param [in] rw - 0 = write, 1 = read operation
|
||||
* \return I2C_STATUS status of write attempt
|
||||
*/
|
||||
/*!\brief This function reads or writes the provided data to/from the address specified.
|
||||
* If anything in the write process is not successful, then it will be repeated
|
||||
* up till 3 more times (default). If still not successful, returns NACK
|
||||
** \param [in, out] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in] data - pointer to the first byte of a block of data to write
|
||||
** \param [in] bytes - indicates how many bytes of data to write
|
||||
** \param [in] rw - 0 = write, 1 = read operation
|
||||
** \return I2C_STATUS status of write attempt
|
||||
**/
|
||||
static I2C_STATUS I2C_comm(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes, const I2C_RW rw)
|
||||
{
|
||||
uint8_t retry = i2c.cfg.retries;
|
||||
bool ack = false;
|
||||
ci2c_fct_ptr fc = (ci2c_fct_ptr) (rw ? slave->cfg.rd : slave->cfg.wr);
|
||||
uint8_t retry = i2c.cfg.retries;
|
||||
bool ack = false;
|
||||
ci2c_fct_ptr fc = (ci2c_fct_ptr) (rw ? slave->cfg.rd : slave->cfg.wr);
|
||||
|
||||
if (I2C_is_busy()) { return slave->status = I2C_BUSY; }
|
||||
i2c.busy = true;
|
||||
@ -246,45 +246,45 @@ static I2C_STATUS I2C_comm(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t *
|
||||
return slave->status = ack ? I2C_OK : I2C_NACK;
|
||||
}
|
||||
|
||||
/*! \brief This function writes the provided data to the address specified.
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in] data - pointer to the first byte of a block of data to write
|
||||
* \param [in] bytes - indicates how many bytes of data to write
|
||||
* \return I2C_STATUS status of write attempt
|
||||
*/
|
||||
/*!\brief This function writes the provided data to the address specified.
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in] data - pointer to the first byte of a block of data to write
|
||||
** \param [in] bytes - indicates how many bytes of data to write
|
||||
** \return I2C_STATUS status of write attempt
|
||||
**/
|
||||
I2C_STATUS I2C_write(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes) {
|
||||
return I2C_comm(slave, reg_addr, data, bytes, I2C_WRITE); }
|
||||
|
||||
/*! \brief This function reads data from the address specified and stores this
|
||||
* data in the area provided by the pointer.
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in, out] data - pointer to the first byte of a block of data to read
|
||||
* \param [in] bytes - indicates how many bytes of data to read
|
||||
* \return I2C_STATUS status of read attempt
|
||||
*/
|
||||
/*!\brief This function reads data from the address specified and stores this
|
||||
* data in the area provided by the pointer.
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in, out] data - pointer to the first byte of a block of data to read
|
||||
** \param [in] bytes - indicates how many bytes of data to read
|
||||
** \return I2C_STATUS status of read attempt
|
||||
**/
|
||||
I2C_STATUS I2C_read(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes) {
|
||||
return I2C_comm(slave, reg_addr, data, bytes, I2C_READ); }
|
||||
|
||||
|
||||
/*! \brief Start i2c_timeout timer
|
||||
* \attribute inline
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Start i2c_timeout timer
|
||||
** \attribute inline
|
||||
** \return nothing
|
||||
**/
|
||||
static inline void __attribute__((__always_inline__)) I2C_start_timeout(void) {
|
||||
i2c.start_wait = (uint16_t) millis(); }
|
||||
|
||||
/*! \brief Test i2c_timeout
|
||||
* \attribute inline
|
||||
* \return true if i2c_timeout occured (false otherwise)
|
||||
*/
|
||||
/*!\brief Test i2c_timeout
|
||||
** \attribute inline
|
||||
** \return true if i2c_timeout occured (false otherwise)
|
||||
**/
|
||||
static inline uint8_t __attribute__((__always_inline__)) I2C_timeout(void) {
|
||||
return (((uint16_t) millis() - i2c.start_wait) >= i2c.cfg.timeout); }
|
||||
|
||||
/*! \brief Send start condition
|
||||
* \return true if start condition acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send start condition
|
||||
** \return true if start condition acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_start(void)
|
||||
{
|
||||
I2C_start_timeout();
|
||||
@ -300,9 +300,9 @@ bool I2C_start(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! \brief Send stop condition
|
||||
* \return true if stop condition acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send stop condition
|
||||
** \return true if stop condition acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_stop(void)
|
||||
{
|
||||
I2C_start_timeout();
|
||||
@ -315,10 +315,10 @@ bool I2C_stop(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! \brief Send byte on bus
|
||||
* \param [in] dat - data to be sent
|
||||
* \return true if data sent acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send byte on bus
|
||||
** \param [in] dat - data to be sent
|
||||
** \return true if data sent acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_wr8(const uint8_t dat)
|
||||
{
|
||||
TWDR = dat;
|
||||
@ -338,10 +338,10 @@ bool I2C_wr8(const uint8_t dat)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! \brief Receive byte from bus
|
||||
* \param [in] ack - true if wait for ack
|
||||
* \return true if data reception acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Receive byte from bus
|
||||
** \param [in] ack - true if wait for ack
|
||||
** \return true if data reception acknowledged (false otherwise)
|
||||
**/
|
||||
uint8_t I2C_rd8(const bool ack)
|
||||
{
|
||||
I2C_start_timeout();
|
||||
@ -357,11 +357,11 @@ uint8_t I2C_rd8(const bool ack)
|
||||
return ((((TWI_STATUS == MR_DATA_NACK) && (!ack)) || ((TWI_STATUS == MR_DATA_ACK) && (ack))) ? true : false);
|
||||
}
|
||||
|
||||
/*! \brief Send I2C address
|
||||
* \param [in] slave - pointer to the I2C slave structure
|
||||
* \param [in] rw - read/write transaction
|
||||
* \return true if I2C chip address sent acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send I2C address
|
||||
** \param [in] slave - pointer to the I2C slave structure
|
||||
** \param [in] rw - read/write transaction
|
||||
** \return true if I2C chip address sent acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_sndAddr(I2C_SLAVE * slave, const I2C_RW rw)
|
||||
{
|
||||
TWDR = (slave->cfg.addr << 1) | rw;
|
||||
@ -382,16 +382,16 @@ bool I2C_sndAddr(I2C_SLAVE * slave, const I2C_RW rw)
|
||||
}
|
||||
|
||||
|
||||
/*! \brief This procedure calls appropriate functions to perform a proper send transaction on I2C bus.
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in] data - pointer to the first byte of a block of data to write
|
||||
* \param [in] bytes - indicates how many bytes of data to write
|
||||
* \return Boolean indicating success/fail of write attempt
|
||||
*/
|
||||
/*!\brief This procedure calls appropriate functions to perform a proper send transaction on I2C bus.
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in] data - pointer to the first byte of a block of data to write
|
||||
** \param [in] bytes - indicates how many bytes of data to write
|
||||
** \return Boolean indicating success/fail of write attempt
|
||||
**/
|
||||
static bool I2C_wr(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes)
|
||||
{
|
||||
if (bytes == 0) { return false; }
|
||||
if (bytes == 0) { return false; }
|
||||
|
||||
(void) I2C_slave_set_reg_addr(slave, reg_addr);
|
||||
|
||||
@ -418,16 +418,16 @@ static bool I2C_wr(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, c
|
||||
}
|
||||
|
||||
|
||||
/*! \brief This procedure calls appropriate functions to perform a proper receive transaction on I2C bus.
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in, out] data - pointer to the first byte of a block of data to read
|
||||
* \param [in] bytes - indicates how many bytes of data to read
|
||||
* \return Boolean indicating success/fail of read attempt
|
||||
*/
|
||||
/*!\brief This procedure calls appropriate functions to perform a proper receive transaction on I2C bus.
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in, out] data - pointer to the first byte of a block of data to read
|
||||
** \param [in] bytes - indicates how many bytes of data to read
|
||||
** \return Boolean indicating success/fail of read attempt
|
||||
**/
|
||||
static bool I2C_rd(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes)
|
||||
{
|
||||
if (bytes == 0) { return false; }
|
||||
if (bytes == 0) { return false; }
|
||||
|
||||
(void) I2C_slave_set_reg_addr(slave, reg_addr);
|
||||
|
||||
|
283
src/ci2c.h
283
src/ci2c.h
@ -1,6 +1,6 @@
|
||||
/*!\file ci2c.h
|
||||
** \author SMFSW
|
||||
** \version 1.0
|
||||
** \version 1.1
|
||||
** \copyright MIT SMFSW (2017)
|
||||
** \brief arduino i2c in plain c declarations
|
||||
**/
|
||||
@ -25,49 +25,49 @@
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DEF_CI2C_NB_RETRIES 3 //!< Default cI2C transaction retries
|
||||
#define DEF_CI2C_TIMEOUT 100 //!< Default cI2C timeout
|
||||
|
||||
|
||||
/*! \enum enI2C_RW
|
||||
* \brief I2C RW bit enumeration
|
||||
* \attribute packed enum
|
||||
*/
|
||||
/*!\enum enI2C_RW
|
||||
** \brief I2C RW bit enumeration
|
||||
** \attribute packed enum
|
||||
**/
|
||||
typedef enum __attribute__((__packed__)) enI2C_RW {
|
||||
I2C_WRITE = 0, //!< I2C rw bit (write)
|
||||
I2C_READ //!< I2C rw bit (read)
|
||||
} I2C_RW;
|
||||
|
||||
|
||||
/*! \enum enI2C_SPEED
|
||||
* \brief I2C bus speed
|
||||
* \attribute packed enum
|
||||
*/
|
||||
/*!\enum enI2C_SPEED
|
||||
** \brief I2C bus speed
|
||||
** \attribute packed enum
|
||||
**/
|
||||
typedef enum __attribute__((__packed__)) enI2C_SPEED {
|
||||
I2C_STD = 100, //!< I2C Standard (100KHz)
|
||||
I2C_FM = 400, //!< I2C Fast Mode (400KHz)
|
||||
I2C_FMP = 1000, //!< I2C Fast mode + (1MHz)
|
||||
I2C_HS = 3400 //!< I2C High Speed (3.4MHz)
|
||||
I2C_FMP = 1000, //!< I2C Fast mode + (1MHz): will set speed to Fast Mode (up to 400KHz on avr)
|
||||
I2C_HS = 3400 //!< I2C High Speed (3.4MHz): will set speed to Fast Mode (up to 400KHz on avr)
|
||||
} I2C_SPEED;
|
||||
|
||||
|
||||
/*! \enum enI2C_STATUS
|
||||
* \brief I2C slave status
|
||||
* \attribute packed enum
|
||||
*/
|
||||
/*!\enum enI2C_STATUS
|
||||
** \brief I2C slave status
|
||||
** \attribute packed enum
|
||||
**/
|
||||
typedef enum __attribute__((__packed__)) enI2C_STATUS {
|
||||
I2C_OK = 0x00, //!< I2C OK
|
||||
I2C_BUSY, //!< I2C Bus busy
|
||||
I2C_NACK //!< I2C Not Acknowledge
|
||||
} I2C_STATUS;
|
||||
|
||||
/*! \enum enI2C_INT_SIZE
|
||||
* \brief I2C slave internal address registers size
|
||||
* \attribute packed enum
|
||||
*/
|
||||
/*!\enum enI2C_INT_SIZE
|
||||
** \brief I2C slave internal address registers size
|
||||
** \attribute packed enum
|
||||
**/
|
||||
typedef enum __attribute__((__packed__)) enI2C_INT_SIZE {
|
||||
I2C_NO_REG = 0x00, //!< Internal address registers not applicable for slave
|
||||
I2C_8B_REG, //!< Slave internal address registers space is 8bits wide
|
||||
@ -78,14 +78,14 @@ typedef enum __attribute__((__packed__)) enI2C_INT_SIZE {
|
||||
typedef bool (*ci2c_fct_ptr) (void*, const uint16_t, uint8_t*, const uint16_t); //!< i2c read/write function pointer typedef
|
||||
|
||||
|
||||
/*! \struct StructI2CSlave
|
||||
* \brief ci2c slave config and control parameters
|
||||
* \attribute packed struct
|
||||
*/
|
||||
/*!\struct StructI2CSlave
|
||||
** \brief ci2c slave config and control parameters
|
||||
** \attribute packed struct
|
||||
**/
|
||||
typedef struct __attribute__((__packed__)) StructI2CSlave {
|
||||
/*! \struct cfg
|
||||
* \brief ci2c slave parameters
|
||||
*/
|
||||
/*!\struct cfg
|
||||
** \brief ci2c slave parameters
|
||||
**/
|
||||
struct {
|
||||
uint8_t addr; //!< Slave address
|
||||
I2C_INT_SIZE reg_size; //!< Slave internal registers size
|
||||
@ -101,136 +101,137 @@ typedef struct __attribute__((__packed__)) StructI2CSlave {
|
||||
/*** I2C SLAVE FUNCTIONS ***/
|
||||
/***************************/
|
||||
|
||||
/*! \brief Init an I2C slave structure for cMI2C communication
|
||||
* \param [in] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] sl_addr - I2C slave address
|
||||
* \param [in] reg_sz - internal register map size
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Init an I2C slave structure for cMI2C communication
|
||||
** \param [in] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] sl_addr - I2C slave address
|
||||
** \param [in] reg_sz - internal register map size
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_slave_init(I2C_SLAVE * slave, const uint8_t sl_addr, const I2C_INT_SIZE reg_sz);
|
||||
|
||||
/*! \brief Redirect slave I2C read/write function (if needed for advanced use)
|
||||
* \param [in] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] func - pointer to read/write function to affect
|
||||
* \param [in] rw - 0 = write function, 1 = read function
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Redirect slave I2C read/write function (if needed for advanced use)
|
||||
** \param [in] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] func - pointer to read/write function to affect
|
||||
** \param [in] rw - 0 = write function, 1 = read function
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_slave_set_rw_func(I2C_SLAVE * slave, const ci2c_fct_ptr func, const I2C_RW rw);
|
||||
|
||||
/*! \brief Change I2C slave address
|
||||
* \param [in, out] slave - pointer to the I2C slave structure to init
|
||||
* \param [in] sl_addr - I2C slave address
|
||||
* \return true if new address set (false if address is >7Fh)
|
||||
*/
|
||||
/*!\brief Change I2C slave address
|
||||
** \param [in, out] slave - pointer to the I2C slave structure to init
|
||||
** \param [in] sl_addr - I2C slave address
|
||||
** \return true if new address set (false if address is >7Fh)
|
||||
**/
|
||||
bool I2C_slave_set_addr(I2C_SLAVE * slave, const uint8_t sl_addr);
|
||||
|
||||
/*! \brief Change I2C registers map size (for access)
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_sz - internal register map size
|
||||
* \return true if new size is correct (false otherwise and set to 16bit by default)
|
||||
*/
|
||||
/*!\brief Change I2C registers map size (for access)
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_sz - internal register map size
|
||||
** \return true if new size is correct (false otherwise and set to 16bit by default)
|
||||
**/
|
||||
bool I2C_slave_set_reg_size(I2C_SLAVE * slave, const I2C_INT_SIZE reg_sz);
|
||||
|
||||
/*! \brief Get I2C slave address
|
||||
* \attribute inline
|
||||
* \param [in] slave - pointer to the I2C slave structure
|
||||
* \return I2C slave address
|
||||
*/
|
||||
/*!\brief Get I2C slave address
|
||||
** \attribute inline
|
||||
** \param [in] slave - pointer to the I2C slave structure
|
||||
** \return I2C slave address
|
||||
**/
|
||||
inline uint8_t __attribute__((__always_inline__)) I2C_slave_get_addr(const I2C_SLAVE * slave) {
|
||||
return slave->cfg.addr; }
|
||||
|
||||
/*! \brief Get I2C register map size (for access)
|
||||
* \attribute inline
|
||||
* \param [in] slave - pointer to the I2C slave structure
|
||||
* \return register map using 16bits if true (1Byte otherwise)
|
||||
*/
|
||||
/*!\brief Get I2C register map size (for access)
|
||||
** \attribute inline
|
||||
** \param [in] slave - pointer to the I2C slave structure
|
||||
** \return register map using 16bits if true (1Byte otherwise)
|
||||
**/
|
||||
inline bool __attribute__((__always_inline__)) I2C_slave_get_reg_size(const I2C_SLAVE * slave) {
|
||||
return slave->cfg.reg_size; }
|
||||
|
||||
/*! \brief Get I2C current register address (addr may passed this way in procedures if contigous accesses)
|
||||
* \attribute inline
|
||||
* \param [in] slave - pointer to the I2C slave structure
|
||||
* \return current register map address
|
||||
*/
|
||||
/*!\brief Get I2C current register address (addr may passed this way in procedures if contigous accesses)
|
||||
** \attribute inline
|
||||
** \param [in] slave - pointer to the I2C slave structure
|
||||
** \return current register map address
|
||||
**/
|
||||
inline uint16_t __attribute__((__always_inline__)) I2C_slave_get_reg_addr(const I2C_SLAVE * slave) {
|
||||
return slave->reg_addr; }
|
||||
|
||||
|
||||
/*************************/
|
||||
/*** I2C BUS FUNCTIONS ***/
|
||||
/*************************/
|
||||
|
||||
/*! \brief Enable I2c module on arduino board (including pull-ups,
|
||||
* enabling of ACK, and setting clock frequency)
|
||||
* \param [in] speed - I2C bus speed in KHz
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Enable I2c module on arduino board (including pull-ups,
|
||||
* enabling of ACK, and setting clock frequency)
|
||||
** \param [in] speed - I2C bus speed in KHz
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_init(const uint16_t speed);
|
||||
|
||||
/*! \brief Disable I2c module on arduino board (releasing pull-ups, and TWI control)
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief Disable I2c module on arduino board (releasing pull-ups, and TWI control)
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_uninit();
|
||||
|
||||
/*! \brief Change I2C frequency
|
||||
* \param [in] speed - I2C bus speed in KHz
|
||||
* \return true if change is successful (false otherwise)
|
||||
*/
|
||||
bool I2C_set_speed(const uint16_t speed);
|
||||
/*!\brief Change I2C frequency
|
||||
** \param [in] speed - I2C bus speed in KHz (max 400KHz on AVR)
|
||||
** \return Configured bus speed
|
||||
**/
|
||||
uint16_t I2C_set_speed(const uint16_t speed);
|
||||
|
||||
/*! \brief Change I2C ack timeout
|
||||
* \param [in] timeout - I2C ack timeout (500 ms max)
|
||||
* \return true if change is successful (false otherwise)
|
||||
*/
|
||||
bool I2C_set_timeout(const uint16_t timeout);
|
||||
/*!\brief Change I2C ack timeout
|
||||
** \param [in] timeout - I2C ack timeout (500 ms max)
|
||||
** \return Configured timeout
|
||||
**/
|
||||
uint16_t I2C_set_timeout(const uint16_t timeout);
|
||||
|
||||
/*! \brief Change I2C message retries (in case of failure)
|
||||
* \param [in] retries - I2C number of retries (max of 8)
|
||||
* \return true if change is successful (false otherwise)
|
||||
*/
|
||||
bool I2C_set_retries(const uint8_t retries);
|
||||
/*!\brief Change I2C message retries (in case of failure)
|
||||
** \param [in] retries - I2C number of retries (max of 8)
|
||||
** \return Configured number of retries
|
||||
**/
|
||||
uint8_t I2C_set_retries(const uint8_t retries);
|
||||
|
||||
/*! \brief Get I2C busy status
|
||||
* \return true if busy
|
||||
*/
|
||||
/*!\brief Get I2C busy status
|
||||
** \return true if busy
|
||||
**/
|
||||
bool I2C_is_busy(void);
|
||||
|
||||
/*! \brief This function writes the provided data to the address specified.
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in] data - pointer to the first byte of a block of data to write
|
||||
* \param [in] bytes - indicates how many bytes of data to write
|
||||
* \return I2C_STATUS status of write attempt
|
||||
*/
|
||||
/*!\brief This function writes the provided data to the address specified.
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in] data - pointer to the first byte of a block of data to write
|
||||
** \param [in] bytes - indicates how many bytes of data to write
|
||||
** \return I2C_STATUS status of write attempt
|
||||
**/
|
||||
I2C_STATUS I2C_write(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes);
|
||||
|
||||
/*! \brief This inline is a wrapper to I2C_write in case of contigous operations
|
||||
* \attribute inline
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] data - pointer to the first byte of a block of data to write
|
||||
* \param [in] bytes - indicates how many bytes of data to write
|
||||
* \return I2C_STATUS status of write attempt
|
||||
*/
|
||||
/*!\brief This inline is a wrapper to I2C_write in case of contigous operations
|
||||
** \attribute inline
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] data - pointer to the first byte of a block of data to write
|
||||
** \param [in] bytes - indicates how many bytes of data to write
|
||||
** \return I2C_STATUS status of write attempt
|
||||
**/
|
||||
inline I2C_STATUS __attribute__((__always_inline__)) I2C_write_next(I2C_SLAVE * slave, uint8_t * data, const uint16_t bytes) {
|
||||
// TODO: implement read next so that it doesn't have to send start register address again
|
||||
return I2C_write(slave, slave->reg_addr, data, bytes); }
|
||||
|
||||
/*! \brief This function reads data from the address specified and stores this
|
||||
* data in the area provided by the pointer.
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] reg_addr - register address in register map
|
||||
* \param [in, out] data - pointer to the first byte of a block of data to read
|
||||
* \param [in] bytes - indicates how many bytes of data to read
|
||||
* \return I2C_STATUS status of read attempt
|
||||
*/
|
||||
/*!\brief This function reads data from the address specified and stores this
|
||||
* data in the area provided by the pointer.
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] reg_addr - register address in register map
|
||||
** \param [in, out] data - pointer to the first byte of a block of data to read
|
||||
** \param [in] bytes - indicates how many bytes of data to read
|
||||
** \return I2C_STATUS status of read attempt
|
||||
**/
|
||||
I2C_STATUS I2C_read(I2C_SLAVE * slave, const uint16_t reg_addr, uint8_t * data, const uint16_t bytes);
|
||||
|
||||
/*! \brief This inline is a wrapper to I2C_read in case of contigous operations
|
||||
* \attribute inline
|
||||
* \param [in, out] slave - pointer to the I2C slave structure
|
||||
* \param [in] data - pointer to the first byte of a block of data to read
|
||||
* \param [in] bytes - indicates how many bytes of data to read
|
||||
* \return I2C_STATUS status of read attempt
|
||||
*/
|
||||
/*!\brief This inline is a wrapper to I2C_read in case of contigous operations
|
||||
** \attribute inline
|
||||
** \param [in, out] slave - pointer to the I2C slave structure
|
||||
** \param [in] data - pointer to the first byte of a block of data to read
|
||||
** \param [in] bytes - indicates how many bytes of data to read
|
||||
** \return I2C_STATUS status of read attempt
|
||||
**/
|
||||
inline I2C_STATUS __attribute__((__always_inline__)) I2C_read_next(I2C_SLAVE * slave, uint8_t * data, const uint16_t bytes) {
|
||||
// TODO: implement read next so that it doesn't have to send start register address again
|
||||
return I2C_read(slave, slave->reg_addr, data, bytes); }
|
||||
@ -240,38 +241,38 @@ inline I2C_STATUS __attribute__((__always_inline__)) I2C_read_next(I2C_SLAVE * s
|
||||
/*** cI2C LOW LEVEL FUNCTIONS ***/
|
||||
/*** THAT MAY BE USEFUL FOR DVPT ***/
|
||||
/***********************************/
|
||||
/*! \brief I2C bus reset (Release SCL and SDA lines and re-enable module)
|
||||
* \return nothing
|
||||
*/
|
||||
/*!\brief I2C bus reset (Release SCL and SDA lines and re-enable module)
|
||||
** \return nothing
|
||||
**/
|
||||
void I2C_reset(void);
|
||||
|
||||
/*! \brief Send start condition
|
||||
* \return true if start condition acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send start condition
|
||||
** \return true if start condition acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_start(void);
|
||||
|
||||
/*! \brief Send stop condition
|
||||
* \return true if stop condition acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send stop condition
|
||||
** \return true if stop condition acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_stop(void);
|
||||
|
||||
/*! \brief Send byte on bus
|
||||
* \param [in] dat - data to be sent
|
||||
* \return true if data sent acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send byte on bus
|
||||
** \param [in] dat - data to be sent
|
||||
** \return true if data sent acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_wr8(const uint8_t dat);
|
||||
|
||||
/*! \brief Receive byte from bus
|
||||
* \param [in] ack - true if wait for ack
|
||||
* \return true if data reception acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Receive byte from bus
|
||||
** \param [in] ack - true if wait for ack
|
||||
** \return true if data reception acknowledged (false otherwise)
|
||||
**/
|
||||
uint8_t I2C_rd8(const bool ack);
|
||||
|
||||
/*! \brief Send I2C address
|
||||
* \param [in] slave - pointer to the I2C slave structure
|
||||
* \param [in] rw - read/write transaction
|
||||
* \return true if I2C chip address sent acknowledged (false otherwise)
|
||||
*/
|
||||
/*!\brief Send I2C address
|
||||
** \param [in] slave - pointer to the I2C slave structure
|
||||
** \param [in] rw - read/write transaction
|
||||
** \return true if I2C chip address sent acknowledged (false otherwise)
|
||||
**/
|
||||
bool I2C_sndAddr(I2C_SLAVE * slave, const I2C_RW rw);
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user