1
0
mirror of https://github.com/SMFSW/cI2C synced 2024-11-25 11:14:21 +01:00

v0.5: speed enum names change

This commit is contained in:
SMFSW 2017-02-02 00:03:07 +01:00
parent b50281b841
commit 52b3885bfc
10 changed files with 138 additions and 133 deletions

View File

@ -32,19 +32,19 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places. # title of most generated pages and in a few other places.
# The default value is: My Project. # The default value is: My Project.
PROJECT_NAME = "Arduino Hardware I2C for AVR (plain c)" PROJECT_NAME = "Arduino Hardware I2C for AVR MCUs (plain c)"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This # The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.3 PROJECT_NUMBER = 0.5
# Using the PROJECT_BRIEF tag one can provide an optional one line description # 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 # for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short. # quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Arduino Hardware I2C for AVR (plain c) documentation" PROJECT_BRIEF = "Arduino Hardware I2C for AVR MCUs (plain c) documentation"
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included # With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55 # in the documentation. The maximum height of the logo should not exceed 55

View File

@ -1,6 +1,20 @@
# cI2C # cI2C
Arduino Hardware I2C for AVR (plain c) Arduino Hardware I2C for AVR (plain c)
Hardware I2C library for AVR µcontrollers (lib intended for I2C protocols development in c, for easier ports to other µcontrollers)
Hardware I2C library for AVR MCUs (lib intended for I2C protocols development in c, for easier ports to other MCUs)
## Library choice:
* cI2C library implements I2C bus for AVR tagets (Uno, Nano, Mega...)
* you may prefer this one when:
* working on AVR targets
* interrupts are not needed
* WireWrapper implements I2C bus for every platform that includes Wire library
* you would have to use this one when:
* working on non-AVR targets
* portability is needed (using Wire library)
No refactoring is required when switching between **cI2C** & **WireWrapper** libs;
Both libs share same Typedefs, Functions & Parameters.
## Notes: ## Notes:
* cI2C is written in plain c (intentionally) * cI2C is written in plain c (intentionally)
@ -8,11 +22,38 @@ Hardware I2C library for AVR
* cI2C is designed to act as bus Master (Slave mode will be considered in future releases) * cI2C is designed to act as bus Master (Slave mode will be considered in future releases)
* cI2C is set to work on AVR targets only * cI2C is set to work on AVR targets only
* for other targets, you may use **WireWrapper** instead (will be using Wire) * for other targets, you may use **WireWrapper** instead (will be using Wire)
* **cI2C** & **WireWrapper** libs declare same structures & functions as seen from the outside
(switch between libs without changing anyhting but the include)
## Usage: ## Usage:
refer to Doxygen generated documentation & example sketches This library is intended to be able to work with multiple slaves connected on the same I2C bus.
Thus, the I2C bus and Slaves are defined separately.
* On one hand, I2C bus has to be initialised with appropriate speed:
* use I2C_init(speed): speed can be choosen from I2C_SPEED enum for convenience, or passing an integer as parameter
* On the other hand, Slave(s) have to be defined and initialised too:
* use I2C_SLAVE typedef to declare slaves structs
* use I2C_slave_init(pSlave, addr, regsize)
* **pSlave** is a pointer to the slave struct to initialise
* **addr** is the slave I2C address (don't shift addr, lib takes care of that)
* **regsize** is the width of internal slave registers (to be choosen from I2C_INT_SIZE)
* in case you need to use custom R/W procedures for a particular slave:
* use I2C_slave_set_rw_func(pSlave, pFunc, rw)
* **pSlave** is a pointer to the slave declaration to initialise
* **pFunc** is a pointer to the Read or Write bypass function
* **rw** can be choosen from I2C_RW enum (wr=0, rd=1)
After all inits are done, the lib can basically be used this way:
* I2C_read(pSlave, regaddr, pData, bytes)
* **pSlave** is a pointer to the slave struct to read from
* **regaddr** is the start address to read from
* **pData** is a pointer to the place where datas read will be stored
* **bytes** number of bytes to read from slave
* returns true if read is ok, false otherwise
* I2C_write(pSlave, regaddr, pData, bytes)
* **pSlave** is a pointer to the slave struct to write to
* **regaddr** is the start address to write to
* **pData** is a pointer to the block of datas to write to slave
* **bytes** number of bytes to write to slave
* returns true if write is ok, false otherwise
## Examples included: ## Examples included:
following examples should work with any I2C EEPROM/FRAM with address 0x50 following examples should work with any I2C EEPROM/FRAM with address 0x50
@ -24,7 +65,6 @@ following examples should work with any I2C EEPROM/FRAM with address 0x50
Doxygen doc can be generated for the library using doxyfile Doxygen doc can be generated for the library using doxyfile
## Links: ## Links:
Feel free to share your thoughts @ xgarmanboziax@gmail.com about: Feel free to share your thoughts @ xgarmanboziax@gmail.com about:
* issues encountered * issues encountered
* optimisations * optimisations

View File

@ -1,6 +1,12 @@
Arduino Hardware I2C for AVR (plain c) Arduino Hardware I2C for AVR (plain c)
2017-2017 SMFSW 2017-2017 SMFSW
- cI2C is set to work on AVR targets only
-> for other targets, you may use WireWrapper instead (will be using Wire)
-> cI2C & WireWrapper libs declare same structures & functions as seen from the outside
(switch between libs without changing anyhting but the include)
Feel free to share your thoughts @ xgarmanboziax@gmail.com about: Feel free to share your thoughts @ xgarmanboziax@gmail.com about:
- issues encountered - issues encountered
- optimisations - optimisations
@ -9,6 +15,16 @@ Feel free to share your thoughts @ xgarmanboziax@gmail.com about:
------------ ------------
** Actual: ** Actual:
v0.5 31 Jan 2017:
- refactored I2C_SPEED enum names for coherence with I2C specifications
- High Speed mode added in I2C_SPEED enum
v0.4 23 Jan 2017:
- less inlines (less warnings)
- inlines put into header (compatibility with WireWrapper)
- other common code between cI2C and WireWrapper changes
- README.md updated to tell about WireWrapper library
v0.3 22 Jan 2017: v0.3 22 Jan 2017:
- used function pointer in function parameters for convenience - used function pointer in function parameters for convenience
- fixed read bug for devices without register address - fixed read bug for devices without register address

99
ci2c.c
View File

@ -1,6 +1,6 @@
/*!\file ci2c.c /*!\file ci2c.c
** \author SMFSW ** \author SMFSW
** \version 0.3 ** \version 0.5
** \copyright MIT SMFSW (2017) ** \copyright MIT SMFSW (2017)
** \brief arduino master i2c in plain c code ** \brief arduino master i2c in plain c code
**/ **/
@ -35,9 +35,6 @@
#define clrRegBit(r, b) r &= (uint8_t) (~(1 << b)) //!< clear bit \b b in register \b r #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 #define invRegBit(r, b) r ^= (1 << b) //!< invert bit \b b in register \b r
#define binEval(exp) ((exp) ? true : false) //!< boolean evaluation of expression \b exp
#define nbinEval(exp) (!binEval(exp)) //!< complemented boolean evaluation of expression \b exp
/*! \struct i2c /*! \struct i2c
* \brief static ci2c bus config and control parameters * \brief static ci2c bus config and control parameters
*/ */
@ -52,7 +49,7 @@ static struct {
} cfg; } cfg;
uint16_t start_wait; //!< time start waiting for acknowledge uint16_t start_wait; //!< time start waiting for acknowledge
bool busy; //!< true if already busy (in case of interrupts implementation) bool busy; //!< true if already busy (in case of interrupts implementation)
} i2c = { {0, DEF_CI2C_NB_RETRIES, DEF_CI2C_TIMEOUT }, 0, false }; } i2c = { { (I2C_SPEED) 0, DEF_CI2C_NB_RETRIES, DEF_CI2C_TIMEOUT }, 0, false };
// Needed prototypes // Needed prototypes
@ -70,8 +67,8 @@ void I2C_slave_init(I2C_SLAVE * slave, uint8_t sl_addr, I2C_INT_SIZE reg_sz)
{ {
(void) I2C_slave_set_addr(slave, sl_addr); (void) I2C_slave_set_addr(slave, sl_addr);
(void) I2C_slave_set_reg_size(slave, reg_sz); (void) I2C_slave_set_reg_size(slave, reg_sz);
I2C_slave_set_rw_func(slave, I2C_wr, I2C_WRITE); I2C_slave_set_rw_func(slave, (ci2c_fct_ptr) I2C_wr, I2C_WRITE);
I2C_slave_set_rw_func(slave, I2C_rd, I2C_READ); I2C_slave_set_rw_func(slave, (ci2c_fct_ptr) I2C_rd, I2C_READ);
slave->reg_addr = 0; slave->reg_addr = 0;
slave->status = I2C_OK; slave->status = I2C_OK;
} }
@ -89,12 +86,11 @@ void I2C_slave_set_rw_func(I2C_SLAVE * slave, ci2c_fct_ptr func, I2C_RW rw)
} }
/*! \brief Change I2C slave address /*! \brief Change I2C slave address
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure to init * \param [in, out] slave - pointer to the I2C slave structure to init
* \param [in] sl_addr - I2C slave address * \param [in] sl_addr - I2C slave address
* \return true if new address set (false if address is >7Fh) * \return true if new address set (false if address is >7Fh)
*/ */
inline bool __attribute__((__always_inline__)) I2C_slave_set_addr(I2C_SLAVE * slave, uint8_t sl_addr) bool I2C_slave_set_addr(I2C_SLAVE * slave, uint8_t sl_addr)
{ {
if (sl_addr > 0x7F) { return false; } if (sl_addr > 0x7F) { return false; }
slave->cfg.addr = sl_addr; slave->cfg.addr = sl_addr;
@ -102,12 +98,11 @@ inline bool __attribute__((__always_inline__)) I2C_slave_set_addr(I2C_SLAVE * sl
} }
/*! \brief Change I2C registers map size (for access) /*! \brief Change I2C registers map size (for access)
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure * \param [in, out] slave - pointer to the I2C slave structure
* \param [in] reg_sz - internal register map size * \param [in] reg_sz - internal register map size
* \return true if new size is correct (false otherwise and set to 16bit by default) * \return true if new size is correct (false otherwise and set to 16bit by default)
*/ */
inline bool __attribute__((__always_inline__)) I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz) bool I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz)
{ {
slave->cfg.reg_size = reg_sz > I2C_16B_REG ? I2C_16B_REG : reg_sz; slave->cfg.reg_size = reg_sz > I2C_16B_REG ? I2C_16B_REG : reg_sz;
return !(reg_sz > I2C_16B_REG); return !(reg_sz > I2C_16B_REG);
@ -124,35 +119,6 @@ static inline void __attribute__((__always_inline__)) I2C_slave_set_reg_addr(I2C
slave->reg_addr = reg_addr; slave->reg_addr = reg_addr;
} }
/*! \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(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)
*/
inline bool __attribute__((__always_inline__)) I2C_slave_get_reg_size(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
*/
inline uint16_t __attribute__((__always_inline__)) I2C_slave_get_reg_addr(I2C_SLAVE * slave)
{
return slave->reg_addr;
}
/*! \brief Enable I2c module on arduino board (including pull-ups, /*! \brief Enable I2c module on arduino board (including pull-ups,
@ -208,7 +174,7 @@ void I2C_reset(void)
*/ */
bool I2C_set_speed(uint16_t speed) bool I2C_set_speed(uint16_t speed)
{ {
i2c.cfg.speed = (I2C_SPEED) ((speed == 0) ? I2C_SLOW : ((speed > I2C_FAST) ? I2C_SLOW : speed)); i2c.cfg.speed = (I2C_SPEED) ((speed == 0) ? (uint16_t) I2C_STD : ((speed > (uint16_t) I2C_HS) ? (uint16_t) I2C_STD : speed));
clrRegBit(TWCR, TWEN); // Ensure i2c module is disabled clrRegBit(TWCR, TWEN); // Ensure i2c module is disabled
@ -245,10 +211,9 @@ bool I2C_set_retries(uint8_t retries)
} }
/*! \brief Get I2C busy status /*! \brief Get I2C busy status
* \attribute inline
* \return true if busy * \return true if busy
*/ */
inline bool __attribute__((__always_inline__)) I2C_is_busy(void) bool I2C_is_busy(void)
{ {
return i2c.busy; return i2c.busy;
} }
@ -286,58 +251,30 @@ static I2C_STATUS I2C_comm(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data,
} }
/*! \brief This function writes the provided data to the address specified. /*! \brief This function writes the provided data to the address specified.
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure * \param [in, out] slave - pointer to the I2C slave structure
* \param [in] reg_addr - register address in register map * \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] 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] bytes - indicates how many bytes of data to write
* \return I2C_STATUS status of write attempt * \return I2C_STATUS status of write attempt
*/ */
inline I2C_STATUS __attribute__((__always_inline__)) I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes) I2C_STATUS I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
return I2C_comm(slave, reg_addr, data, bytes, I2C_WRITE); return I2C_comm(slave, reg_addr, data, bytes, I2C_WRITE);
} }
/*! \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, 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 /*! \brief This function reads data from the address specified and stores this
* data in the area provided by the pointer. * data in the area provided by the pointer.
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure * \param [in, out] slave - pointer to the I2C slave structure
* \param [in] reg_addr - register address in register map * \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, 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 * \param [in] bytes - indicates how many bytes of data to read
* \return I2C_STATUS status of read attempt * \return I2C_STATUS status of read attempt
*/ */
inline I2C_STATUS __attribute__((__always_inline__)) I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes) I2C_STATUS I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
return I2C_comm(slave, reg_addr, data, bytes, I2C_READ); return I2C_comm(slave, reg_addr, data, bytes, I2C_READ);
} }
/*! \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, 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);
}
/*! \brief Start i2c_timeout timer /*! \brief Start i2c_timeout timer
* \attribute inline * \attribute inline
@ -394,7 +331,7 @@ bool I2C_stop(void)
* \param [in] dat - data to be sent * \param [in] dat - data to be sent
* \return true if data sent acknowledged (false otherwise) * \return true if data sent acknowledged (false otherwise)
*/ */
bool I2C_snd8(uint8_t dat) bool I2C_wr8(uint8_t dat)
{ {
TWDR = dat; TWDR = dat;
@ -417,7 +354,7 @@ bool I2C_snd8(uint8_t dat)
* \param [in] ack - true if wait for ack * \param [in] ack - true if wait for ack
* \return true if data reception acknowledged (false otherwise) * \return true if data reception acknowledged (false otherwise)
*/ */
uint8_t I2C_rcv8(bool ack) uint8_t I2C_rd8(bool ack)
{ {
I2C_start_timeout(); I2C_start_timeout();
@ -474,14 +411,14 @@ static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_
{ {
if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used
{ {
if (I2C_snd8((uint8_t) (reg_addr >> 8)) == false) { return false; } if (I2C_wr8((uint8_t) (reg_addr >> 8)) == false) { return false; }
} }
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_wr8((uint8_t) reg_addr) == false) { return false; }
} }
for (uint16_t cnt = 0; cnt < bytes; cnt++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_snd8(*(data++)) == false) { return false; } if (I2C_wr8(*data++) == false) { return false; }
slave->reg_addr++; slave->reg_addr++;
} }
@ -510,16 +447,16 @@ static bool I2C_rd(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_
if (I2C_sndAddr(slave, I2C_WRITE) == false) { return false; } if (I2C_sndAddr(slave, I2C_WRITE) == false) { return false; }
if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used
{ {
if (I2C_snd8((uint8_t) (reg_addr >> 8)) == false) { return false; } if (I2C_wr8((uint8_t) (reg_addr >> 8)) == false) { return false; }
} }
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_wr8((uint8_t) reg_addr) == false) { return false; }
} }
if (I2C_start() == false) { return false; } if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave, I2C_READ) == false) { return false; } if (I2C_sndAddr(slave, I2C_READ) == false) { return false; }
for (uint16_t cnt = 0; cnt < bytes; cnt++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_rcv8((cnt == (bytes - 1)) ? false : true) == false) { return false; } if (I2C_rd8((cnt == (bytes - 1)) ? false : true) == false) { return false; }
*data++ = TWDR; *data++ = TWDR;
slave->reg_addr++; slave->reg_addr++;
} }

59
ci2c.h
View File

@ -1,12 +1,12 @@
/*!\file ci2c.h /*!\file ci2c.h
** \author SMFSW ** \author SMFSW
** \version 0.3 ** \version 0.5
** \copyright MIT SMFSW (2017) ** \copyright MIT SMFSW (2017)
** \brief arduino i2c in plain c declarations ** \brief arduino i2c in plain c declarations
**/ **/
/****************************************************************/ /****************************************************************/
#ifndef __CI2C_H__ #ifndef __CI2C_H__
#define __CI2C_H__ "v0.3" #define __CI2C_H__ "v0.5"
/****************************************************************/ /****************************************************************/
#if defined(DOXY) #if defined(DOXY)
@ -47,9 +47,10 @@ typedef enum __attribute__((__packed__)) enI2C_RW {
* \attribute packed enum * \attribute packed enum
*/ */
typedef enum __attribute__((__packed__)) enI2C_SPEED { typedef enum __attribute__((__packed__)) enI2C_SPEED {
I2C_SLOW = 100, //!< I2C Slow speed (100KHz) I2C_STD = 100, //!< I2C Standard (100KHz)
I2C_LOW = 400, //!< I2C Low speed (400KHz) I2C_FM = 400, //!< I2C Fast Mode (400KHz)
I2C_FAST = 1000 //!< I2C Fast mode (1MHz) I2C_FMP = 1000, //!< I2C Fast mode + (1MHz)
I2C_HS = 3400 //!< I2C High Speed (3.4MHz)
} I2C_SPEED; } I2C_SPEED;
@ -116,42 +117,48 @@ extern void I2C_slave_init(I2C_SLAVE * slave, uint8_t sl_addr, I2C_INT_SIZE reg_
extern void I2C_slave_set_rw_func(I2C_SLAVE * slave, ci2c_fct_ptr func, I2C_RW rw); extern void I2C_slave_set_rw_func(I2C_SLAVE * slave, ci2c_fct_ptr func, I2C_RW rw);
/*! \brief Change I2C slave address /*! \brief Change I2C slave address
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure to init * \param [in, out] slave - pointer to the I2C slave structure to init
* \param [in] sl_addr - I2C slave address * \param [in] sl_addr - I2C slave address
* \return true if new address set (false if address is >7Fh) * \return true if new address set (false if address is >7Fh)
*/ */
extern inline bool __attribute__((__always_inline__)) I2C_slave_set_addr(I2C_SLAVE * slave, uint8_t sl_addr); extern bool I2C_slave_set_addr(I2C_SLAVE * slave, uint8_t sl_addr);
/*! \brief Change I2C registers map size (for access) /*! \brief Change I2C registers map size (for access)
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure * \param [in, out] slave - pointer to the I2C slave structure
* \param [in] reg_sz - internal register map size * \param [in] reg_sz - internal register map size
* \return true if new size is correct (false otherwise and set to 16bit by default) * \return true if new size is correct (false otherwise and set to 16bit by default)
*/ */
extern inline bool __attribute__((__always_inline__)) I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz); extern bool I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz);
/*! \brief Get I2C slave address /*! \brief Get I2C slave address
* \attribute inline * \attribute inline
* \param [in] slave - pointer to the I2C slave structure * \param [in] slave - pointer to the I2C slave structure
* \return I2C slave address * \return I2C slave address
*/ */
extern inline uint8_t __attribute__((__always_inline__)) I2C_slave_get_addr(I2C_SLAVE * slave); inline uint8_t __attribute__((__always_inline__)) I2C_slave_get_addr(I2C_SLAVE * slave)
{
return slave->cfg.addr;
}
/*! \brief Get I2C register map size (for access) /*! \brief Get I2C register map size (for access)
* \attribute inline * \attribute inline
* \param [in] slave - pointer to the I2C slave structure * \param [in] slave - pointer to the I2C slave structure
* \return register map using 16bits if true (1Byte otherwise) * \return register map using 16bits if true (1Byte otherwise)
*/ */
extern inline bool __attribute__((__always_inline__)) I2C_slave_get_reg_size(I2C_SLAVE * slave); inline bool __attribute__((__always_inline__)) I2C_slave_get_reg_size(I2C_SLAVE * slave)
{
return slave->cfg.reg_size;
}
/*! \brief Get I2C current register address (addr may passed this way in procedures if contigous accesses) /*! \brief Get I2C current register address (addr may passed this way in procedures if contigous accesses)
* \attribute inline * \attribute inline
* \param [in] slave - pointer to the I2C slave structure * \param [in] slave - pointer to the I2C slave structure
* \return current register map address * \return current register map address
*/ */
extern inline uint16_t __attribute__((__always_inline__)) I2C_slave_get_reg_addr(I2C_SLAVE * slave); inline uint16_t __attribute__((__always_inline__)) I2C_slave_get_reg_addr(I2C_SLAVE * slave)
{
return slave->reg_addr;
}
/*************************/ /*************************/
/*** I2C BUS FUNCTIONS ***/ /*** I2C BUS FUNCTIONS ***/
@ -188,20 +195,18 @@ extern bool I2C_set_timeout(uint16_t timeout);
extern bool I2C_set_retries(uint8_t retries); extern bool I2C_set_retries(uint8_t retries);
/*! \brief Get I2C busy status /*! \brief Get I2C busy status
* \attribute inline
* \return true if busy * \return true if busy
*/ */
extern inline bool __attribute__((__always_inline__)) I2C_is_busy(void); extern bool I2C_is_busy(void);
/*! \brief This function writes the provided data to the address specified. /*! \brief This function writes the provided data to the address specified.
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure * \param [in, out] slave - pointer to the I2C slave structure
* \param [in] reg_addr - register address in register map * \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] 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] bytes - indicates how many bytes of data to write
* \return I2C_STATUS status of write attempt * \return I2C_STATUS status of write attempt
*/ */
extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes); extern I2C_STATUS I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes);
/*! \brief This inline is a wrapper to I2C_write in case of contigous operations /*! \brief This inline is a wrapper to I2C_write in case of contigous operations
* \attribute inline * \attribute inline
@ -210,19 +215,21 @@ extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_write(I2C_SLAVE
* \param [in] bytes - indicates how many bytes of data to write * \param [in] bytes - indicates how many bytes of data to write
* \return I2C_STATUS status of write attempt * \return I2C_STATUS status of write attempt
*/ */
extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_write_next(I2C_SLAVE * slave, uint8_t * data, uint16_t bytes); inline I2C_STATUS __attribute__((__always_inline__)) I2C_write_next(I2C_SLAVE * slave, uint8_t * data, 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 /*! \brief This function reads data from the address specified and stores this
* data in the area provided by the pointer. * data in the area provided by the pointer.
* \attribute inline
* \param [in, out] slave - pointer to the I2C slave structure * \param [in, out] slave - pointer to the I2C slave structure
* \param [in] reg_addr - register address in register map * \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, 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 * \param [in] bytes - indicates how many bytes of data to read
* \return I2C_STATUS status of read attempt * \return I2C_STATUS status of read attempt
*/ */
extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes); extern I2C_STATUS I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes);
/*! \brief This inline is a wrapper to I2C_read in case of contigous operations /*! \brief This inline is a wrapper to I2C_read in case of contigous operations
* \attribute inline * \attribute inline
@ -231,7 +238,11 @@ extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_read(I2C_SLAVE *
* \param [in] bytes - indicates how many bytes of data to read * \param [in] bytes - indicates how many bytes of data to read
* \return I2C_STATUS status of read attempt * \return I2C_STATUS status of read attempt
*/ */
extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_read_next(I2C_SLAVE * slave, uint8_t * data, uint16_t bytes); inline I2C_STATUS __attribute__((__always_inline__)) I2C_read_next(I2C_SLAVE * slave, uint8_t * data, 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);
}
/***********************************/ /***********************************/
@ -254,12 +265,12 @@ extern bool I2C_stop(void);
* \param [in] dat - data to be sent * \param [in] dat - data to be sent
* \return true if data sent acknowledged (false otherwise) * \return true if data sent acknowledged (false otherwise)
*/ */
extern bool I2C_snd8(uint8_t dat); extern bool I2C_wr8(uint8_t dat);
/*! \brief Receive byte from bus /*! \brief Receive byte from bus
* \param [in] ack - true if wait for ack * \param [in] ack - true if wait for ack
* \return true if data reception acknowledged (false otherwise) * \return true if data reception acknowledged (false otherwise)
*/ */
extern uint8_t I2C_rcv8(bool ack); extern uint8_t I2C_rd8(bool ack);
/*! \brief Send I2C address /*! \brief Send I2C address
* \param [in] slave - pointer to the I2C slave structure * \param [in] slave - pointer to the I2C slave structure
* \param [in] rw - read/write transaction * \param [in] rw - read/write transaction

View File

@ -7,7 +7,7 @@
This example code is in the public domain. This example code is in the public domain.
created Jan 12 2017 created Jan 12 2017
latest mod Jan 22 2017 latest mod Jan 31 2017
by SMFSW by SMFSW
*/ */
@ -22,7 +22,7 @@ void setup() {
memset(&str, blank, sizeof(str)); memset(&str, blank, sizeof(str));
Serial.begin(115200); // start serial for output Serial.begin(115200); // start serial for output
I2C_init(I2C_LOW); // init with low speed (400KHz) I2C_init(I2C_FM); // init with Fast Mode (400KHz)
I2C_slave_init(&FRAM, 0x50, I2C_16B_REG); I2C_slave_init(&FRAM, 0x50, I2C_16B_REG);
I2C_slave_set_rw_func(&FRAM, I2C_wr_advanced, I2C_WRITE); I2C_slave_set_rw_func(&FRAM, I2C_wr_advanced, I2C_WRITE);
I2C_slave_set_rw_func(&FRAM, I2C_rd_advanced, I2C_READ); I2C_slave_set_rw_func(&FRAM, I2C_rd_advanced, I2C_READ);
@ -72,14 +72,14 @@ bool I2C_wr_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint1
{ {
if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used
{ {
if (I2C_snd8((uint8_t) (reg_addr >> 8)) == false) { return false; } if (I2C_wr8((uint8_t) (reg_addr >> 8)) == false) { return false; }
} }
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_wr8((uint8_t) reg_addr) == false) { return false; }
} }
for (uint16_t cnt = 0; cnt < bytes; cnt++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_snd8(*(data++)) == false) { return false; } if (I2C_wr8(*(data++)) == false) { return false; }
slave->reg_addr++; slave->reg_addr++;
} }
@ -108,16 +108,16 @@ bool I2C_rd_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint1
if (I2C_sndAddr(slave, I2C_WRITE) == false) { return false; } if (I2C_sndAddr(slave, I2C_WRITE) == false) { return false; }
if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used if (slave->cfg.reg_size >= I2C_16B_REG) // if size >2, 16bit address is used
{ {
if (I2C_snd8((uint8_t) (reg_addr >> 8)) == false) { return false; } if (I2C_wr8((uint8_t) (reg_addr >> 8)) == false) { return false; }
} }
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_wr8((uint8_t) reg_addr) == false) { return false; }
} }
if (I2C_start() == false) { return false; } if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave, I2C_READ) == false) { return false; } if (I2C_sndAddr(slave, I2C_READ) == false) { return false; }
for (uint16_t cnt = 0; cnt < bytes; cnt++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_rcv8((cnt == (bytes - 1)) ? false : true) == false) { return false; } if (I2C_rd8((cnt == (bytes - 1)) ? false : true) == false) { return false; }
*data++ = TWDR; *data++ = TWDR;
slave->reg_addr++; slave->reg_addr++;
} }
@ -142,13 +142,13 @@ bool I2C_get_chip_id(I2C_SLAVE * slave, uint8_t * data)
if (I2C_start() == false) { return false; } if (I2C_start() == false) { return false; }
if (I2C_sndAddr(&FRAM_ID, I2C_WRITE) == false) { return false; } if (I2C_sndAddr(&FRAM_ID, I2C_WRITE) == false) { return false; }
if (I2C_snd8(slave->cfg.addr << 1) == false) { return false; } if (I2C_wr8(slave->cfg.addr << 1) == false) { return false; }
if (I2C_start() == false) { return false; } if (I2C_start() == false) { return false; }
if (I2C_sndAddr(&FRAM_ID, I2C_READ) == false) { return false; } if (I2C_sndAddr(&FRAM_ID, I2C_READ) == false) { return false; }
for (uint16_t cnt = 0; cnt < bytes; cnt++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_rcv8((cnt == (bytes - 1)) ? false : true) == false) { return false; } if (I2C_rd8((cnt == (bytes - 1)) ? false : true) == false) { return false; }
*data++ = TWDR; *data++ = TWDR;
} }

View File

@ -5,7 +5,7 @@
This example code is in the public domain. This example code is in the public domain.
created Jan 12 2017 created Jan 12 2017
latest mod Jan 22 2017 latest mod Jan 31 2017
by SMFSW by SMFSW
*/ */
@ -17,7 +17,7 @@ I2C_SLAVE FRAM; // slave declaration
void setup() { void setup() {
Serial.begin(115200); // start serial for output Serial.begin(115200); // start serial for output
I2C_init(I2C_LOW); // init with low speed (400KHz) I2C_init(I2C_FM); // init with Fast Mode (400KHz)
I2C_slave_init(&FRAM, 0x50, I2C_16B_REG); I2C_slave_init(&FRAM, 0x50, I2C_16B_REG);
} }

View File

@ -6,7 +6,7 @@
This example code is in the public domain. This example code is in the public domain.
created Jan 12 2017 created Jan 12 2017
latest mod Jan 22 2017 latest mod Jan 31 2017
by SMFSW by SMFSW
*/ */
@ -18,7 +18,7 @@ I2C_SLAVE FRAM; // slave declaration
void setup() { void setup() {
Serial.begin(115200); // start serial for output Serial.begin(115200); // start serial for output
I2C_init(I2C_LOW); // init with low speed (400KHz) I2C_init(I2C_FM); // init with Fast Mode (400KHz)
I2C_slave_init(&FRAM, 0x50, I2C_16B_REG); I2C_slave_init(&FRAM, 0x50, I2C_16B_REG);
} }

View File

@ -44,9 +44,10 @@ I2C_WRITE LITERAL1
I2C_OK LITERAL1 I2C_OK LITERAL1
I2C_BUSY LITERAL1 I2C_BUSY LITERAL1
I2C_NACK LITERAL1 I2C_NACK LITERAL1
I2C_LOW LITERAL1 I2C_STD LITERAL1
I2C_SLOW LITERAL1 I2C_FM LITERAL1
I2C_FAST LITERAL1 I2C_FMP LITERAL1
I2C_HS LITERAL1
I2C_NO_REG LITERAL1 I2C_NO_REG LITERAL1
I2C_8B_REG LITERAL1 I2C_8B_REG LITERAL1
I2C_16B_REG LITERAL1 I2C_16B_REG LITERAL1

View File

@ -1,10 +1,10 @@
name=cI2C name=cI2C
version=0.3 version=0.5
author=SMFSW author=SMFSW
maintainer=SMFSW maintainer=SMFSW
sentence=Arduino Hardware I2C for AVR (in plain c) sentence=Arduino Hardware I2C for AVR (in plain c)
paragraph=Hardware I2C library for AVR µcontrollers (lib intended for I2C protocols development in c, for easier ports to other µcontrollers) paragraph=Hardware I2C library for AVR MCUs (lib intended for I2C protocols development in c, for easier ports to other MCUs)
category=Communication category=Communication
url=http://playground.arduino.cc/code/CI2C url=https://github.com/SMFSW/cI2C
architectures=avr architectures=avr