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

v0.3: bugfixes and refactoring

This commit is contained in:
SMFSW 2017-01-22 18:32:00 +01:00
parent 588c8106a3
commit 4728577666
11 changed files with 536 additions and 350 deletions

43
Doxyfile Normal file → Executable file
View File

@ -1,4 +1,4 @@
# Doxyfile 1.8.10 # Doxyfile 1.8.11
# This file describes the settings to be used by the documentation system # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # doxygen (www.doxygen.org) for a project.
@ -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 (in plain c)" PROJECT_NAME = "Arduino Hardware I2C for AVR (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.2 PROJECT_NUMBER = 0.3
# 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 (in plain c) documentation" PROJECT_BRIEF = "Arduino Hardware I2C for AVR (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
@ -229,7 +229,8 @@ TAB_SIZE = 4
# newlines. # newlines.
ALIASES = "issue=\xrefitem issue \"Issue\" \"Issues List\"" \ ALIASES = "issue=\xrefitem issue \"Issue\" \"Issues List\"" \
"isr=\xrefitem isr \"Interrupt\" \"ISR List\"" "isr=\xrefitem isr \"Interrupt\" \"ISR List\"" \
"attribute=\xrefitem attribute \"GCC Attributes\" \"GCC Attributes List\""
# This tag can be used to specify a number of word-keyword mappings (TCL only). # This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class" # A mapping has the form "name=value". For example adding "class=itcl::class"
@ -740,6 +741,12 @@ WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# The default value is: NO.
WARN_AS_ERROR = NO
# The WARN_FORMAT tag determines the format of the warning messages that doxygen # The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which # can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated # will be replaced by the file and line number from which the warning originated
@ -788,8 +795,8 @@ INPUT_ENCODING = UTF-8
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
# *.vhdl, *.ucf, *.qsf, *.as and *.js. # *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
FILE_PATTERNS = *.c \ FILE_PATTERNS = *.c \
*.cpp \ *.cpp \
@ -878,6 +885,10 @@ IMAGE_PATH =
# Note that the filter must not add or remove lines; it is applied before the # Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added # code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly. # or removed, the anchors will not be placed correctly.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
INPUT_FILTER = INPUT_FILTER =
@ -887,6 +898,10 @@ INPUT_FILTER =
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the # filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied. # patterns match the file name, INPUT_FILTER is applied.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
FILTER_PATTERNS = FILTER_PATTERNS =
@ -1004,7 +1019,7 @@ VERBATIM_HEADERS = YES
# rich C++ code for which doxygen's built-in parser lacks the necessary type # rich C++ code for which doxygen's built-in parser lacks the necessary type
# information. # information.
# Note: The availability of this option depends on whether or not doxygen was # Note: The availability of this option depends on whether or not doxygen was
# compiled with the --with-libclang option. # generated with the -Duse-libclang=ON option for CMake.
# The default value is: NO. # The default value is: NO.
CLANG_ASSISTED_PARSING = NO CLANG_ASSISTED_PARSING = NO
@ -1748,6 +1763,14 @@ LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the RTF output # Configuration options related to the RTF output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -1979,7 +2002,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and # the macro expansion is limited to the macros specified with the PREDEFINED and
@ -2020,7 +2043,7 @@ INCLUDE_FILE_PATTERNS = *.h
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = ARDUINO=10506 \ PREDEFINED = ARDUINO=10506 \
DBG_SEQTIMER DOXY=1
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The # tag can be used to specify a list of macro names that should be expanded. The

0
LICENSE Normal file → Executable file
View File

View File

@ -1,2 +1,28 @@
# 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)
notes:
- cI2C is written in plain c (intentionally)
- cI2C does not use any interrupt (yet, but soon will have to)
- 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
-> port to SAM &(|) ESP8266 targets would have to be considered, yet the lib is not multi-cores approach designed
Usage:
refer to Doxygen generated documentation & example sketches
examples included:
following examples should work with any I2C EEPROM/FRAM with address 0x50
(yet function to get Chip ID are device dependant (and will probably only work on FUJITSU devices))
ci2c_master_write.ino: Write some bytes to FRAM and compare them with what's read afterwards
ci2c_master_read.ino: Read some bytes in FRAM
ci2c_advanced.ino: Redirecting slave write & read functions (to custom functions following typedef)
Doxygen doc can be generated for the library using doxyfile
Feel free to share your thoughts @ xgarmanboziax@gmail.com about:
- issues encountered
- optimisations
- improvements & new functionalities

23
Release Notes.txt Executable file
View File

@ -0,0 +1,23 @@
Arduino Hardware I2C for AVR (plain c)
2017-2017 SMFSW
Feel free to share your thoughts @ xgarmanboziax@gmail.com about:
- issues encountered
- optimisations
- improvements & new functionalities
------------
** Actual:
v0.3 22 Jan 2017:
- used function pointer in function parameters for convenience
- fixed read bug for devices without register address
- refactored rw booleans with enum instead (implied logic change)
- I2C_sndAddr function parameters changed
- added I2C_uninit function to release i2c bus
- refactoring & optimisations
- doxygen pass without warnings/errors now
- examples updated to test more of the library
v0.2 16 Jan 2017:
- First release

406
ci2c.c Normal file → Executable file
View File

@ -1,12 +1,13 @@
/*!\file ci2c.c /*!\file ci2c.c
** \author SMFSW ** \author SMFSW
** \version 0.2 ** \version 0.3
** \copyright MIT SMFSW (2017) ** \copyright MIT SMFSW (2017)
** \brief arduino master i2c in plain c code ** \brief arduino master i2c in plain c code
**/ **/
// TODO: add interrupt vector / callback for it operations (if not too messy) // TODO: add interrupt vector / callback for it operations (if not too messy)
// TODO: consider interrupts at least for RX when slave (and TX when master) // TODO: consider interrupts at least for RX when slave (and TX when master)
// TODO: change contigous r/w operations so it doesn't send internal address again // TODO: change contigous r/w operations so it doesn't send internal address again
// TODO: split functions & headers // TODO: split functions & headers
@ -27,63 +28,73 @@
#define LOST_ARBTRTN 0x38 #define LOST_ARBTRTN 0x38
#define TWI_STATUS (TWSR & 0xF8) #define TWI_STATUS (TWSR & 0xF8)
//#define isSetBitReg(v, b) ((v & (1 << b)) != 0) //#define isSetRegBit(r, b) ((r & (1 << b)) != 0)
//#define isClrBitReg(v, b) ((v & (1 << b)) == 0) //#define isClrRegBit(r, b) ((r & (1 << b)) == 0)
#define setBitReg(v, b) v |= (1 << b) #define setRegBit(r, b) r |= (1 << b) //!< set bit \b b in register \b r
#define clrBitReg(v, b) v &= (uint8_t) (~(1 << b)) #define clrRegBit(r, b) r &= (uint8_t) (~(1 << b)) //!< clear bit \b b in register \b r
#define invBitReg(v, b) v ^= (1 << b) #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
* \brief static ci2c bus config and control parameters
*/
static struct { static struct {
/*! \struct cfg
* \brief ci2c bus parameters
*/
struct { struct {
I2C_SPEED speed; //!< i2c bus speed I2C_SPEED speed; //!< i2c bus speed
uint8_t retries; //!< i2c message retries when fail uint8_t retries; //!< i2c message retries when fail
uint16_t timeout; //!< i2c timeout (ms) uint16_t timeout; //!< i2c timeout (ms)
} cfg; } cfg;
uint16_t start_wait; uint16_t start_wait; //!< time start waiting for acknowledge
bool busy; bool busy; //!< true if already busy (in case of interrupts implementation)
} i2c = { {0, DEF_CI2C_NB_RETRIES, DEF_CI2C_TIMEOUT }, 0, false }; } i2c = { {0, DEF_CI2C_NB_RETRIES, DEF_CI2C_TIMEOUT }, 0, false };
// Needed prototypes // Needed prototypes
static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes); static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes);
static bool I2C_rd(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes); static bool I2C_rd(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes);
/*! \brief Init an I2C slave structure for cMI2C communication /*! \brief Init an I2C slave structure for cMI2C communication
*! \param [in] slave - pointer to the I2C slave structure to init * \param [in] slave - pointer to the I2C slave structure to init
*! \param [in] sl_addr - I2C slave address * \param [in] sl_addr - I2C slave address
*! \param [in] reg_sz - internal register map size * \param [in] reg_sz - internal register map size
*! \return nothing * \return nothing
*/ */
void I2C_slave_init(I2C_SLAVE * slave, uint8_t sl_addr, I2C_INT_SIZE reg_sz) 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_rd, 0); I2C_slave_set_rw_func(slave, I2C_wr, I2C_WRITE);
I2C_slave_set_rw_func(slave, I2C_wr, 1); I2C_slave_set_rw_func(slave, I2C_rd, I2C_READ);
slave->reg_addr = 0; slave->reg_addr = 0;
slave->status = I2C_OK; slave->status = I2C_OK;
} }
/*! \brief Redirect slave I2C read/write function (if needed for advanced use) /*! \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] slave - pointer to the I2C slave structure to init
*! \param [in] func - pointer to read/write function to affect * \param [in] func - pointer to read/write function to affect
*! \param [in] rw - 0 = read function, 1 = write function * \param [in] rw - 0 = write function, 1 = read function
*! \return nothing * \return nothing
*/ */
void I2C_slave_set_rw_func(I2C_SLAVE * slave, void * func, bool rw) void I2C_slave_set_rw_func(I2C_SLAVE * slave, ci2c_fct_ptr func, I2C_RW rw)
{ {
ci2c_fct_ptr * pfc = (ci2c_fct_ptr*) (rw ? &slave->cfg.wr : &slave->cfg.rd); ci2c_fct_ptr * pfc = (ci2c_fct_ptr*) (rw ? &slave->cfg.rd : &slave->cfg.wr);
*pfc = func; *pfc = func;
} }
/*! \brief Change I2C slave address /*! \brief Change I2C slave address
*! \param [in, out] slave - pointer to the I2C slave structure to init * \attribute inline
*! \param [in] sl_addr - I2C slave address * \param [in, out] slave - pointer to the I2C slave structure to init
*! \return true if new address set (false if address is >7Fh) * \param [in] sl_addr - I2C slave address
* \return true if new address set (false if address is >7Fh)
*/ */
inline bool I2C_slave_set_addr(I2C_SLAVE * slave, uint8_t sl_addr) inline bool __attribute__((__always_inline__)) 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;
@ -91,160 +102,182 @@ inline 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)
*! \param [in, out] slave - pointer to the I2C slave structure * \attribute inline
*! \param [in] reg_sz - internal register map size * \param [in, out] slave - pointer to the I2C slave structure
*! \return true if new size is correct (false otherwise and set to 16bit by default) * \param [in] reg_sz - internal register map size
* \return true if new size is correct (false otherwise and set to 16bit by default)
*/ */
inline bool I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz) inline bool __attribute__((__always_inline__)) 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;
if (reg_sz > I2C_16B_REG) { return false; } return !(reg_sz > I2C_16B_REG);
else { return true; }
} }
/*! \brief Set I2C current register address /*! \brief Set I2C current register address
*! \param [in, out] slave - pointer to the I2C slave structure * \attribute inline
*! \param [in] reg_addr - register address * \param [in, out] slave - pointer to the I2C slave structure
*! \return nothing * \param [in] reg_addr - register address
* \return nothing
*/ */
static inline void I2C_slave_set_reg_addr(I2C_SLAVE * slave, uint16_t reg_addr) static inline void __attribute__((__always_inline__)) I2C_slave_set_reg_addr(I2C_SLAVE * slave, uint16_t reg_addr)
{ {
slave->reg_addr = reg_addr; slave->reg_addr = reg_addr;
} }
/*! \brief Get I2C slave address /*! \brief Get I2C slave address
*! \param [in] slave - pointer to the I2C slave structure * \attribute inline
*! \return I2C slave address * \param [in] slave - pointer to the I2C slave structure
* \return I2C slave address
*/ */
inline uint8_t I2C_slave_get_addr(I2C_SLAVE * slave) inline uint8_t __attribute__((__always_inline__)) I2C_slave_get_addr(I2C_SLAVE * slave)
{ {
return slave->cfg.addr; return slave->cfg.addr;
} }
/*! \brief Get I2C register map size (for access) /*! \brief Get I2C register map size (for access)
*! \param [in] slave - pointer to the I2C slave structure * \attribute inline
*! \return register map using 16bits if true (1Byte otherwise) * \param [in] slave - pointer to the I2C slave structure
* \return register map using 16bits if true (1Byte otherwise)
*/ */
inline bool 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; 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)
*! \param [in] slave - pointer to the I2C slave structure * \attribute inline
*! \return current register map address * \param [in] slave - pointer to the I2C slave structure
* \return current register map address
*/ */
inline uint16_t 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; return slave->reg_addr;
} }
/*! \brief Enable I2c module on arduino board (including pull-ups, /*! \brief Enable I2c module on arduino board (including pull-ups,
*! enabling of ACK, and setting clock frequency) * enabling of ACK, and setting clock frequency)
*! \param [in] speed - I2C bus speed in KHz * \param [in] speed - I2C bus speed in KHz
*! \return nothing * \return nothing
*/ */
void I2C_init(uint16_t speed) void I2C_init(uint16_t speed)
{ {
// Set SDA and SCL to ports // Set SDA and SCL to ports with pull-ups
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
setBitReg(PORTC, 4); setRegBit(PORTC, 4);
setBitReg(PORTC, 5); setRegBit(PORTC, 5);
#else #else
setBitReg(PORTD, 0); setRegBit(PORTD, 0);
setBitReg(PORTD, 1); setRegBit(PORTD, 1);
#endif #endif
(void) I2C_set_speed(speed); (void) I2C_set_speed(speed);
} }
/*! \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
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
clrRegBit(PORTC, 4);
clrRegBit(PORTC, 5);
#else
clrRegBit(PORTD, 0);
clrRegBit(PORTD, 1);
#endif
TWCR = 0;
}
/*! \brief I2C bus reset (Release SCL and SDA lines and re-enable module) /*! \brief I2C bus reset (Release SCL and SDA lines and re-enable module)
*! \return nothing * \return nothing
*/ */
void I2C_reset(void) void I2C_reset(void)
{ {
TWCR = 0; TWCR = 0;
setBitReg(TWCR, TWEA); setRegBit(TWCR, TWEA);
setBitReg(TWCR, TWEN); setRegBit(TWCR, TWEN);
} }
/*! \brief Change I2C frequency /*! \brief Change I2C frequency
*! \param [in] speed - I2C speed in kHz (max 1MHz) * \param [in] speed - I2C speed in kHz (max 1MHz)
*! \return true if change is successful (false otherwise) * \return true if change is successful (false otherwise)
*/ */
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) ? I2C_SLOW : ((speed > I2C_FAST) ? I2C_SLOW : speed));
// Ensure i2c module is disabled clrRegBit(TWCR, TWEN); // Ensure i2c module is disabled
clrBitReg(TWCR, TWEN);
// Set prescaler and clock frequency // Set prescaler and clock frequency
clrBitReg(TWSR, TWPS0); clrRegBit(TWSR, TWPS0);
clrBitReg(TWSR, TWPS1); clrRegBit(TWSR, TWPS1);
TWBR = ((F_CPU / (i2c.cfg.speed * 1000)) - 16) / 2; // TODO: check speed and make it a param TWBR = ((F_CPU / (i2c.cfg.speed * 1000)) - 16) / 2;
// re-enable module I2C_reset(); // re-enable module
I2C_reset();
return i2c.cfg.speed == speed ? true : false; return (i2c.cfg.speed == speed);
} }
/*! \brief Change I2C ack timeout /*! \brief Change I2C ack timeout
*! \param [in] timeout - I2C ack timeout (500 ms max) * \param [in] timeout - I2C ack timeout (500 ms max)
*! \return true if change is successful (false otherwise) * \return true if change is successful (false otherwise)
*/ */
inline bool I2C_set_timeout(uint16_t timeout) bool I2C_set_timeout(uint16_t timeout)
{ {
i2c.cfg.timeout = timeout > 500 ? 500 : timeout; static const uint16_t max_timeout = 500;
return i2c.cfg.timeout == timeout ? true : false; i2c.cfg.timeout = (timeout > max_timeout) ? max_timeout : timeout;
return (i2c.cfg.timeout == timeout);
} }
/*! \brief Change I2C message retries (in case of failure) /*! \brief Change I2C message retries (in case of failure)
*! \param [in] retries - I2C number of retries (max of 8) * \param [in] retries - I2C number of retries (max of 8)
*! \return true if change is successful (false otherwise) * \return true if change is successful (false otherwise)
*/ */
inline bool I2C_set_retries(uint8_t retries) bool I2C_set_retries(uint8_t retries)
{ {
i2c.cfg.retries = retries > 8 ? 8 : retries; static const uint16_t max_retries = 8;
return i2c.cfg.retries == retries ? true : false; i2c.cfg.retries = (retries > max_retries) ? max_retries : retries;
return (i2c.cfg.retries == retries);
} }
/*! \brief Get I2C busy status /*! \brief Get I2C busy status
*! \return true if busy * \attribute inline
* \return true if busy
*/ */
inline bool I2C_is_busy(void) inline bool __attribute__((__always_inline__)) I2C_is_busy(void)
{ {
return i2c.busy; return i2c.busy;
} }
/*! \brief This function reads or writes the provided data to/from the address specified. /*! \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 * If anything in the write process is not successful, then it will be repeated
*! repeated up till 3 more times (default). If still not successful, returns NACK * 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, out] slave - pointer to the I2C slave structure to init * \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] nb_bytes - indicates how many bytes of data to write * \param [in] rw - 0 = write, 1 = read operation
*! \param [in] wr - 0 = read, 1 = write operation * \return I2C_STATUS status of write attempt
*! \return I2C_STATUS status of write attempt
*/ */
static I2C_STATUS I2C_comm(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes, bool wr) static I2C_STATUS I2C_comm(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes, I2C_RW rw)
{ {
uint8_t retry = i2c.cfg.retries; uint8_t retry = i2c.cfg.retries;
bool ack = false; bool ack = false;
ci2c_fct_ptr fc = (ci2c_fct_ptr) (wr ? slave->cfg.wr : slave->cfg.rd); ci2c_fct_ptr fc = (ci2c_fct_ptr) (rw ? slave->cfg.rd : slave->cfg.wr);
if (I2C_is_busy()) { return slave->status = I2C_BUSY; } if (I2C_is_busy()) { return slave->status = I2C_BUSY; }
i2c.busy = true; i2c.busy = true;
ack = fc(slave, reg_addr, data, nb_bytes); ack = fc(slave, reg_addr, data, bytes);
while ((!ack) && (retry != 0)) // If com not successful, retry some more times while ((!ack) && (retry != 0)) // If com not successful, retry some more times
{ {
delay(5); delay(5);
ack = fc(slave, reg_addr, data, nb_bytes); ack = fc(slave, reg_addr, data, bytes);
retry--; retry--;
} }
@ -253,77 +286,79 @@ 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 to init * \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] nb_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 I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes) inline I2C_STATUS __attribute__((__always_inline__)) I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
return I2C_comm(slave, reg_addr, data, nb_bytes, 1); return I2C_comm(slave, reg_addr, data, bytes, I2C_WRITE);
} }
/*! \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
*! \param [in, out] slave - pointer to the I2C slave structure to init * \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] data - pointer to the first byte of a block of data to write
*! \param [in] nb_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 I2C_write_next(I2C_SLAVE * slave, uint8_t * data, uint16_t nb_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 // TODO: implement read next so that it doesn't have to send start register address again
return I2C_write(slave, slave->reg_addr, data, nb_bytes); 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 to init * \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] nb_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 I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes) inline I2C_STATUS __attribute__((__always_inline__)) I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
return I2C_comm(slave, reg_addr, data, nb_bytes, 0); return I2C_comm(slave, reg_addr, data, bytes, I2C_READ);
} }
/*! \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
*! \param [in, out] slave - pointer to the I2C slave structure to init * \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] data - pointer to the first byte of a block of data to read
*! \param [in] nb_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 I2C_read_next(I2C_SLAVE * slave, uint8_t * data, uint16_t nb_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 // TODO: implement read next so that it doesn't have to send start register address again
return I2C_read(slave, slave->reg_addr, data, nb_bytes); return I2C_read(slave, slave->reg_addr, data, bytes);
} }
/*! \brief Start i2c_timeout timer /*! \brief Start i2c_timeout timer
*! \return nothing * \attribute inline
* \return nothing
*/ */
static inline void I2C_start_timeout(void) static inline void __attribute__((__always_inline__)) I2C_start_timeout(void)
{ {
i2c.start_wait = (uint16_t) millis(); i2c.start_wait = (uint16_t) millis();
} }
/*! \brief Test i2c_timeout /*! \brief Test i2c_timeout
*! \return true if i2c_timeout occured (false otherwise) * \attribute inline
* \return true if i2c_timeout occured (false otherwise)
*/ */
static inline uint8_t I2C_timeout(void) static inline uint8_t __attribute__((__always_inline__)) I2C_timeout(void)
{ {
return (((uint16_t) millis() - i2c.start_wait) >= i2c.cfg.timeout); return (((uint16_t) millis() - i2c.start_wait) >= i2c.cfg.timeout);
} }
/*! \brief Send start condition /*! \brief Send start condition
*! \return true if start condition acknowledged (false otherwise) * \return true if start condition acknowledged (false otherwise)
*/ */
bool I2C_start(void) bool I2C_start(void)
{ {
@ -341,7 +376,7 @@ bool I2C_start(void)
} }
/*! \brief Send stop condition /*! \brief Send stop condition
*! \return true if stop condition acknowledged (false otherwise) * \return true if stop condition acknowledged (false otherwise)
*/ */
bool I2C_stop(void) bool I2C_stop(void)
{ {
@ -355,32 +390,9 @@ bool I2C_stop(void)
return true; return true;
} }
/*! \brief Send I2C address
*! \param [in] sl_addr - I2C slave address
*! \return true if I2C slave address sent acknowledged (false otherwise)
*/
bool I2C_sndAddr(uint8_t sl_addr)
{
TWDR = sl_addr;
I2C_start_timeout();
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)))
{ if (I2C_timeout()) { I2C_reset(); return false; } }
if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK)) { return true; }
if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK)) { I2C_stop(); }
else { I2C_reset(); }
return false;
}
/*! \brief Send byte on bus /*! \brief Send byte on bus
*! \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_snd8(uint8_t dat)
{ {
@ -402,8 +414,8 @@ bool I2C_snd8(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)
*/ */
uint8_t I2C_rcv8(bool ack) uint8_t I2C_rcv8(bool ack)
{ {
@ -417,26 +429,47 @@ uint8_t I2C_rcv8(bool ack)
if (TWI_STATUS == LOST_ARBTRTN) { I2C_reset(); return false; } if (TWI_STATUS == LOST_ARBTRTN) { I2C_reset(); return false; }
if (((TWI_STATUS == MR_DATA_NACK) && (!ack)) || ((TWI_STATUS == MR_DATA_ACK) && (ack))) { return true; } return ((((TWI_STATUS == MR_DATA_NACK) && (!ack)) || ((TWI_STATUS == MR_DATA_ACK) && (ack))) ? true : false);
else { return 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)
*/
bool I2C_sndAddr(I2C_SLAVE * slave, I2C_RW rw)
{
TWDR = (slave->cfg.addr << 1) | rw;
I2C_start_timeout();
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)))
{ if (I2C_timeout()) { I2C_reset(); return false; } }
if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK)) { return true; }
if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK)) { I2C_stop(); }
else { I2C_reset(); }
return false;
} }
/*! \brief This procedure calls appropriate functions to perform a proper send transaction on I2C bus. /*! \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, out] slave - pointer to the I2C slave structure to init * \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] nb_bytes - indicates how many bytes of data to write * \return Boolean indicating success/fail of write attempt
*! \return Boolean indicating success/fail of write attempt
*/ */
static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes) static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
uint16_t ct_w;
(void) I2C_slave_set_reg_addr(slave, reg_addr); (void) I2C_slave_set_reg_addr(slave, reg_addr);
if (I2C_start() == false) { return false; } if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave->cfg.addr << 1) == false) { return false; } if (I2C_sndAddr(slave, I2C_WRITE) == false) { return false; }
if (slave->cfg.reg_size) if (slave->cfg.reg_size)
{ {
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
@ -446,7 +479,7 @@ static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_snd8((uint8_t) reg_addr) == false) { return false; }
} }
for (ct_w = 0; ct_w < nb_bytes; ct_w++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_snd8(*(data++)) == false) { return false; } if (I2C_snd8(*(data++)) == false) { return false; }
slave->reg_addr++; slave->reg_addr++;
@ -459,43 +492,34 @@ static bool I2C_wr(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_
/*! \brief This procedure calls appropriate functions to perform a proper receive transaction on I2C bus. /*! \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, out] slave - pointer to the I2C slave structure to init * \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] nb_bytes - indicates how many bytes of data to read * \return Boolean indicating success/fail of read attempt
*! \return Boolean indicating success/fail of read attempt
*/ */
static bool I2C_rd(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes) static bool I2C_rd(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
uint16_t ct_r;
(void) I2C_slave_set_reg_addr(slave, reg_addr); (void) I2C_slave_set_reg_addr(slave, reg_addr);
if (nb_bytes == 0) { nb_bytes++; } if (bytes == 0) { bytes = 1; }
if (I2C_start() == false) { return false; } if (slave->cfg.reg_size) // If start register has to be sent first
if (I2C_sndAddr(slave->cfg.addr << 1) == false) { return false; }
if (slave->cfg.reg_size)
{ {
if (I2C_start() == 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_snd8((uint8_t) (reg_addr >> 8)) == false) { return false; }
} }
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_snd8((uint8_t) reg_addr) == false) { return false; }
if (I2C_start() == false) { return false; }
if (I2C_sndAddr((slave->cfg.addr << 1) | 0x01) == false) { return false; }
} }
if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave, I2C_READ) == false) { return false; }
for (ct_r = 0; ct_r < nb_bytes; ct_r++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (ct_r == (nb_bytes - 1)) if (I2C_rcv8((cnt == (bytes - 1)) ? false : true) == false) { return false; }
{
if (I2C_rcv8(false) == false) { return false; }
}
else
{
if (I2C_rcv8(true) == false) { return false; }
}
*data++ = TWDR; *data++ = TWDR;
slave->reg_addr++; slave->reg_addr++;
} }

230
ci2c.h Normal file → Executable file
View File

@ -1,14 +1,19 @@
/*!\file ci2c.h /*!\file ci2c.h
** \author SMFSW ** \author SMFSW
** \version 0.2 ** \version 0.3
** \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.2" #define __CI2C_H__ "v0.3"
/****************************************************************/ /****************************************************************/
#if defined(DOXY)
// Define gcc __attribute__ as void when Doxygen runs
#define __attribute__(a) //!< GCC attribute (ignored by Doxygen)
#endif
#if (ARDUINO >= 100) #if (ARDUINO >= 100)
#include <Arduino.h> #include <Arduino.h>
#else #else
@ -23,16 +28,24 @@
extern "C"{ extern "C"{
#endif #endif
#define DEF_CI2C_SPEED 100000 #define DEF_CI2C_NB_RETRIES 3 //!< Default cI2C transaction retries
#define DEF_CI2C_NB_RETRIES 3 #define DEF_CI2C_TIMEOUT 100 //!< Default cI2C timeout
#define DEF_CI2C_TIMEOUT 100
typedef enum __attribute__((__packed__)) enI2C_STATUS {
I2C_OK = 0x00,
I2C_BUSY,
I2C_NACK
} I2C_STATUS;
/*! \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
*/
typedef enum __attribute__((__packed__)) enI2C_SPEED { typedef enum __attribute__((__packed__)) enI2C_SPEED {
I2C_SLOW = 100, //!< I2C Slow speed (100KHz) I2C_SLOW = 100, //!< I2C Slow speed (100KHz)
I2C_LOW = 400, //!< I2C Low speed (400KHz) I2C_LOW = 400, //!< I2C Low speed (400KHz)
@ -40,16 +53,37 @@ typedef enum __attribute__((__packed__)) enI2C_SPEED {
} I2C_SPEED; } I2C_SPEED;
/*! \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
*/
typedef enum __attribute__((__packed__)) enI2C_INT_SIZE { typedef enum __attribute__((__packed__)) enI2C_INT_SIZE {
I2C_NO_REG = 0x00, //!< Internal adress registers not applicable for slave I2C_NO_REG = 0x00, //!< Internal address registers not applicable for slave
I2C_8B_REG, //!< Slave internal adress registers space is 8bits wide I2C_8B_REG, //!< Slave internal address registers space is 8bits wide
I2C_16B_REG //!< Slave internal adress registers space is 16bits wide I2C_16B_REG //!< Slave internal address registers space is 16bits wide
} I2C_INT_SIZE; } I2C_INT_SIZE;
typedef bool (*ci2c_fct_ptr) (const void*, uint16_t, uint8_t*, uint16_t); //!< i2c read/write function typedef typedef bool (*ci2c_fct_ptr) (const void*, uint16_t, uint8_t*, uint16_t); //!< i2c read/write function pointer typedef
/*! \struct StructI2CSlave
* \brief ci2c slave config and control parameters
* \attribute packed struct
*/
typedef struct __attribute__((__packed__)) StructI2CSlave { typedef struct __attribute__((__packed__)) StructI2CSlave {
/*! \struct cfg
* \brief ci2c slave parameters
*/
struct { struct {
uint8_t addr; //!< Slave address uint8_t addr; //!< Slave address
I2C_INT_SIZE reg_size; //!< Slave internal registers size I2C_INT_SIZE reg_size; //!< Slave internal registers size
@ -66,52 +100,57 @@ typedef struct __attribute__((__packed__)) StructI2CSlave {
/***************************/ /***************************/
/*! \brief Init an I2C slave structure for cMI2C communication /*! \brief Init an I2C slave structure for cMI2C communication
*! \param [in] slave - pointer to the I2C slave structure to init * \param [in] slave - pointer to the I2C slave structure to init
*! \param [in] sl_addr - I2C slave address * \param [in] sl_addr - I2C slave address
*! \param [in] reg_sz - internal register map size * \param [in] reg_sz - internal register map size
*! \return nothing * \return nothing
*/ */
extern void I2C_slave_init(I2C_SLAVE * slave, uint8_t sl_addr, I2C_INT_SIZE reg_sz); extern void I2C_slave_init(I2C_SLAVE * slave, uint8_t sl_addr, I2C_INT_SIZE reg_sz);
/*! \brief Redirect slave I2C read/write function (if needed for advanced use) /*! \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] slave - pointer to the I2C slave structure to init
*! \param [in] func - pointer to read/write function to affect * \param [in] func - pointer to read/write function to affect
*! \param [in] rw - 0 = read function, 1 = write function * \param [in] rw - 0 = write function, 1 = read function
*! \return nothing * \return nothing
*/ */
extern void I2C_slave_set_rw_func(I2C_SLAVE * slave, void * func, bool 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
*! \param [in, out] slave - pointer to the I2C slave structure to init * \attribute inline
*! \param [in] sl_addr - I2C slave address * \param [in, out] slave - pointer to the I2C slave structure to init
*! \return true if new address set (false if address is >7Fh) * \param [in] sl_addr - I2C slave address
* \return true if new address set (false if address is >7Fh)
*/ */
extern inline bool I2C_slave_set_addr(I2C_SLAVE * slave, uint8_t sl_addr) __attribute__((__always_inline__)); extern inline bool __attribute__((__always_inline__)) 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)
*! \param [in, out] slave - pointer to the I2C slave structure * \attribute inline
*! \param [in] reg_sz - internal register map size * \param [in, out] slave - pointer to the I2C slave structure
*! \return true if new size is correct (false otherwise and set to 16bit by default) * \param [in] reg_sz - internal register map size
* \return true if new size is correct (false otherwise and set to 16bit by default)
*/ */
extern inline bool I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz) __attribute__((__always_inline__)); extern inline bool __attribute__((__always_inline__)) I2C_slave_set_reg_size(I2C_SLAVE * slave, I2C_INT_SIZE reg_sz);
/*! \brief Get I2C slave address /*! \brief Get I2C slave address
*! \param [in] slave - pointer to the I2C slave structure * \attribute inline
*! \return I2C slave address * \param [in] slave - pointer to the I2C slave structure
* \return I2C slave address
*/ */
extern inline uint8_t I2C_slave_get_addr(I2C_SLAVE * slave) __attribute__((__always_inline__)); extern inline uint8_t __attribute__((__always_inline__)) I2C_slave_get_addr(I2C_SLAVE * slave);
/*! \brief Get I2C register map size (for access) /*! \brief Get I2C register map size (for access)
*! \param [in] slave - pointer to the I2C slave structure * \attribute inline
*! \return register map using 16bits if true (1Byte otherwise) * \param [in] slave - pointer to the I2C slave structure
* \return register map using 16bits if true (1Byte otherwise)
*/ */
extern inline bool I2C_slave_get_reg_size(I2C_SLAVE * slave) __attribute__((__always_inline__)); extern inline bool __attribute__((__always_inline__)) I2C_slave_get_reg_size(I2C_SLAVE * slave);
/*! \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)
*! \param [in] slave - pointer to the I2C slave structure * \attribute inline
*! \return current register map address * \param [in] slave - pointer to the I2C slave structure
* \return current register map address
*/ */
extern inline uint16_t I2C_slave_get_reg_addr(I2C_SLAVE * slave) __attribute__((__always_inline__)); extern inline uint16_t __attribute__((__always_inline__)) I2C_slave_get_reg_addr(I2C_SLAVE * slave);
/*************************/ /*************************/
@ -119,74 +158,80 @@ extern inline uint16_t I2C_slave_get_reg_addr(I2C_SLAVE * slave) __attribute__((
/*************************/ /*************************/
/*! \brief Enable I2c module on arduino board (including pull-ups, /*! \brief Enable I2c module on arduino board (including pull-ups,
*! enabling of ACK, and setting clock frequency) * enabling of ACK, and setting clock frequency)
*! \param [in] speed - I2C bus speed in KHz * \param [in] speed - I2C bus speed in KHz
*! \return nothing * \return nothing
*/ */
extern void I2C_init(uint16_t speed); extern void I2C_init(uint16_t speed);
/*! \brief Disable I2c module on arduino board (releasing pull-ups, and TWI control)
* \return nothing
*/
extern void I2C_uninit();
/*! \brief Change I2C frequency /*! \brief Change I2C frequency
*! \param [in] speed - I2C bus speed in KHz * \param [in] speed - I2C bus speed in KHz
*! \return true if change is successful (false otherwise) * \return true if change is successful (false otherwise)
*/ */
extern bool I2C_set_speed(uint16_t speed); extern bool I2C_set_speed(uint16_t speed);
/*! \brief Change I2C ack timeout /*! \brief Change I2C ack timeout
*! \param [in] timeout - I2C ack timeout (500 ms max) * \param [in] timeout - I2C ack timeout (500 ms max)
*! \return true if change is successful (false otherwise) * \return true if change is successful (false otherwise)
*/ */
extern inline bool I2C_set_timeout(uint16_t timeout); extern bool I2C_set_timeout(uint16_t timeout);
/*! \brief Change I2C message retries (in case of failure) /*! \brief Change I2C message retries (in case of failure)
*! \param [in] retries - I2C number of retries (max of 8) * \param [in] retries - I2C number of retries (max of 8)
*! \return true if change is successful (false otherwise) * \return true if change is successful (false otherwise)
*/ */
extern inline 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
*! \return true if busy * \attribute inline
* \return true if busy
*/ */
extern inline bool I2C_is_busy(void); extern inline bool __attribute__((__always_inline__)) 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 to init * \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] nb_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 I2C_write(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes); extern inline I2C_STATUS __attribute__((__always_inline__)) 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
*! \param [in, out] slave - pointer to the I2C slave structure to init * \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] data - pointer to the first byte of a block of data to write
*! \param [in] nb_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 I2C_write_next(I2C_SLAVE * slave, uint8_t * data, uint16_t nb_bytes); extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_write_next(I2C_SLAVE * slave, uint8_t * data, uint16_t 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 to init * \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] nb_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 I2C_read(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes); extern inline I2C_STATUS __attribute__((__always_inline__)) 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
*! \param [in, out] slave - pointer to the I2C slave structure to init * \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] data - pointer to the first byte of a block of data to read
*! \param [in] nb_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 I2C_read_next(I2C_SLAVE * slave, uint8_t * data, uint16_t nb_bytes); extern inline I2C_STATUS __attribute__((__always_inline__)) I2C_read_next(I2C_SLAVE * slave, uint8_t * data, uint16_t bytes);
/***********************************/ /***********************************/
@ -194,32 +239,33 @@ extern inline I2C_STATUS I2C_read_next(I2C_SLAVE * slave, uint8_t * data, uint16
/*** THAT MAY BE USEFUL FOR DVPT ***/ /*** THAT MAY BE USEFUL FOR DVPT ***/
/***********************************/ /***********************************/
/*! \brief I2C bus reset (Release SCL and SDA lines and re-enable module) /*! \brief I2C bus reset (Release SCL and SDA lines and re-enable module)
*! \return nothing * \return nothing
*/ */
extern void I2C_reset(void); extern void I2C_reset(void);
/*! \brief Send start condition /*! \brief Send start condition
*! \return true if start condition acknowledged (false otherwise) * \return true if start condition acknowledged (false otherwise)
*/ */
extern bool I2C_start(void); extern bool I2C_start(void);
/*! \brief Send stop condition /*! \brief Send stop condition
*! \return true if stop condition acknowledged (false otherwise) * \return true if stop condition acknowledged (false otherwise)
*/ */
extern bool I2C_stop(void); extern bool I2C_stop(void);
/*! \brief Send I2C address
*! \param [in] sl_addr - I2C slave address
*! \return true if I2C chip address sent acknowledged (false otherwise)
*/
extern bool I2C_sndAddr(uint8_t sl_addr);
/*! \brief Send byte on bus /*! \brief Send byte on bus
*! \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_snd8(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_rcv8(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)
*/
extern bool I2C_sndAddr(I2C_SLAVE * slave, I2C_RW rw);
#ifdef __cplusplus #ifdef __cplusplus

117
examples/ci2c_advanced/ci2c_advanced.ino Normal file → Executable file
View File

@ -1,38 +1,53 @@
/* /*
Master i2c (advanced) Master i2c (advanced)
Redirecting write & read slave functions in setup (to custom functions following template) Redirecting slave write & read functions in setup (to custom functions following typedef)
Read and Write operations are then called using the same functions Read and Write operations are then called using the same functions
Function to get Chip ID are device dependant (and will probably only work on FUJITSU devices)
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 16 2017 latest mod Jan 22 2017
by SMFSW by SMFSW
*/ */
#include <ci2c.h> #include <ci2c.h>
I2C_SLAVE FRAM; const uint8_t blank = 0xEE; // blank tab filling value for test
I2C_SLAVE FRAM; // slave declaration
void setup() { void setup() {
uint8_t str[3];
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_LOW); // init with low speed (400KHz)
I2C_slave_init(&FRAM, 0x50, I2C_16B_REG); I2C_slave_init(&FRAM, 0x50, I2C_16B_REG);
I2C_slave_set_rw_func(&FRAM, I2C_rd_advanced, 0); I2C_slave_set_rw_func(&FRAM, I2C_wr_advanced, I2C_WRITE);
I2C_slave_set_rw_func(&FRAM, I2C_wr_advanced, 1); I2C_slave_set_rw_func(&FRAM, I2C_rd_advanced, I2C_READ);
I2C_get_chip_id(&FRAM, &str[0]);
Serial.println();
//for (uint8_t i = 0; i < sizeof(str); i++) { Serial.print(str[i], HEX); } // print hex values
Serial.print("\nManufacturer ID: ");
Serial.print((str[0] << 4) + (str[1] >> 4), HEX);
Serial.print("\nProduct ID: ");
Serial.print(((str[1] & 0x0F) << 8) + str[2], HEX);
} }
void loop() { void loop() {
const uint16_t reg_addr = 0; const uint16_t reg_addr = 0;
uint8_t str[7]; uint8_t str[7];
memset(&str, 0xEE, sizeof(str)); memset(&str, blank, sizeof(str));
I2C_read(&FRAM, reg_addr, &str[0], sizeof(str)); // Addr 0, 2bytes Addr size, str, read chars for size of str I2C_read(&FRAM, reg_addr, &str[0], sizeof(str)); // FRAM, Addr 0, str, read chars for size of str
Serial.println(); Serial.println();
for (uint8_t i = 0; i < sizeof(str); i++) for (uint8_t i = 0; i < sizeof(str); i++)
{ {
Serial.print(str[i], HEX); // receive a byte as character Serial.print(str[i], HEX); // print hex values
Serial.print(" "); Serial.print(" ");
} }
@ -41,21 +56,18 @@ void loop() {
/*! \brief This procedure calls appropriate functions to perform a proper send transaction on I2C bus. /*! \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, out] slave - pointer to the I2C slave structure to init * \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] nb_bytes - indicates how many bytes of data to write * \return Boolean indicating success/fail of write attempt
*! \return Boolean indicating success/fail of write attempt
*/ */
static bool I2C_wr_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes) bool I2C_wr_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
uint16_t ct_w;
slave->reg_addr = reg_addr; slave->reg_addr = reg_addr;
if (I2C_start() == false) { return false; } if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave->cfg.addr << 1) == false) { return false; } if (I2C_sndAddr(slave, I2C_WRITE) == false) { return false; }
if (slave->cfg.reg_size) if (slave->cfg.reg_size)
{ {
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
@ -65,7 +77,7 @@ static bool I2C_wr_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_snd8((uint8_t) reg_addr) == false) { return false; }
} }
for (ct_w = 0; ct_w < nb_bytes; ct_w++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (I2C_snd8(*(data++)) == false) { return false; } if (I2C_snd8(*(data++)) == false) { return false; }
slave->reg_addr++; slave->reg_addr++;
@ -78,44 +90,34 @@ static bool I2C_wr_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data
/*! \brief This procedure calls appropriate functions to perform a proper receive transaction on I2C bus. /*! \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, out] slave - pointer to the I2C slave structure to init * \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] nb_bytes - indicates how many bytes of data to read * \return Boolean indicating success/fail of read attempt
*! \return Boolean indicating success/fail of read attempt
*/ */
static bool I2C_rd_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t nb_bytes) bool I2C_rd_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data, uint16_t bytes)
{ {
uint16_t ct_r;
slave->reg_addr = reg_addr; slave->reg_addr = reg_addr;
if (nb_bytes == 0) { nb_bytes++; } if (bytes == 0) { bytes = 1; }
if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave->cfg.addr << 1) == false) { return false; }
if (slave->cfg.reg_size) if (slave->cfg.reg_size)
{ {
if (I2C_start() == 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_snd8((uint8_t) (reg_addr >> 8)) == false) { return false; }
} }
if (I2C_snd8((uint8_t) reg_addr) == false) { return false; } if (I2C_snd8((uint8_t) reg_addr) == false) { return false; }
if (I2C_start() == false) { return false; }
if (I2C_sndAddr((slave->cfg.addr << 1) | 0x01) == false) { return false; }
} }
if (I2C_start() == false) { return false; }
if (I2C_sndAddr(slave, I2C_READ) == false) { return false; }
for (ct_r = 0; ct_r < nb_bytes; ct_r++) for (uint16_t cnt = 0; cnt < bytes; cnt++)
{ {
if (ct_r == (nb_bytes - 1)) if (I2C_rcv8((cnt == (bytes - 1)) ? false : true) == false) { return false; }
{
if (I2C_rcv8(false) == false) { return false; }
}
else
{
if (I2C_rcv8(true) == false) { return false; }
}
*data++ = TWDR; *data++ = TWDR;
slave->reg_addr++; slave->reg_addr++;
} }
@ -125,3 +127,32 @@ static bool I2C_rd_advanced(I2C_SLAVE * slave, uint16_t reg_addr, uint8_t * data
return true; return true;
} }
/*! \brief This procedure calls appropriate functions to get chip ID of FUJITSU devices.
* \param [in, out] slave - pointer to the I2C slave structure
* \param [in, out] data - pointer to the first byte of a block of data to read
* \return Boolean indicating success/fail of read attempt
*/
bool I2C_get_chip_id(I2C_SLAVE * slave, uint8_t * data)
{
const uint16_t bytes = 3;
I2C_SLAVE FRAM_ID;
I2C_slave_init(&FRAM_ID, 0xF8 >> 1, I2C_16B_REG); // Dummy slave init for I2C_sndAddr
if (I2C_start() == 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_start() == false) { return false; }
if (I2C_sndAddr(&FRAM_ID, I2C_READ) == false) { return false; }
for (uint16_t cnt = 0; cnt < bytes; cnt++)
{
if (I2C_rcv8((cnt == (bytes - 1)) ? false : true) == false) { return false; }
*data++ = TWDR;
}
if (I2C_stop() == false) { return false; }
return true;
}

16
examples/ci2c_master_read/ci2c_master_read.ino Normal file → Executable file
View File

@ -5,13 +5,15 @@
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 16 2017 latest mod Jan 22 2017
by SMFSW by SMFSW
*/ */
#include <ci2c.h> #include <ci2c.h>
I2C_SLAVE FRAM; const uint8_t blank = 0xEE; // blank tab filling value for test
I2C_SLAVE FRAM; // slave declaration
void setup() { void setup() {
Serial.begin(115200); // start serial for output Serial.begin(115200); // start serial for output
@ -21,15 +23,17 @@ void setup() {
void loop() { void loop() {
const uint16_t reg_addr = 0; const uint16_t reg_addr = 0;
uint8_t str[7]; uint8_t str[8];
memset(&str, 0xEE, sizeof(str)); const uint8_t half_sz = sizeof(str) / 2;
memset(&str, blank, sizeof(str));
I2C_read(&FRAM, reg_addr, &str[0], sizeof(str)); // Addr 0, 2bytes Addr size, str, read chars for size of str I2C_read(&FRAM, reg_addr, &str[0], half_sz); // FRAM, Addr 0, str, read chars for size of half str
I2C_read_next(&FRAM, &str[half_sz], half_sz);
Serial.println(); Serial.println();
for (uint8_t i = 0; i < sizeof(str); i++) for (uint8_t i = 0; i < sizeof(str); i++)
{ {
Serial.print(str[i], HEX); // receive a byte as character Serial.print(str[i], HEX); // print hex values
Serial.print(" "); Serial.print(" ");
} }

12
examples/ci2c_master_write/ci2c_master_write.ino Normal file → Executable file
View File

@ -6,13 +6,15 @@
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 16 2017 latest mod Jan 22 2017
by SMFSW by SMFSW
*/ */
#include <ci2c.h> #include <ci2c.h>
I2C_SLAVE FRAM; const uint8_t blank = 0xEE; // blank tab filling value for test
I2C_SLAVE FRAM; // slave declaration
void setup() { void setup() {
Serial.begin(115200); // start serial for output Serial.begin(115200); // start serial for output
@ -25,9 +27,9 @@ void loop() {
uint8_t str[7] = { 0x55, 20, 30, 40, 50, 60, 0xAA }; uint8_t str[7] = { 0x55, 20, 30, 40, 50, 60, 0xAA };
bool match = true; bool match = true;
uint8_t str_out[7]; uint8_t str_out[7];
memset(&str_out, 0xEE, sizeof(str)); memset(&str_out, blank, sizeof(str));
I2C_write(&FRAM, reg_addr, &str[0], sizeof(str)); // Addr 0, 2bytes Addr size, str, read chars for size of str I2C_write(&FRAM, reg_addr, &str[0], sizeof(str)); // FRAM, Addr 0, str, read chars for size of str
Serial.println(); Serial.println();
@ -35,7 +37,7 @@ void loop() {
for (uint8_t i = 0; i < sizeof(str_out); i++) for (uint8_t i = 0; i < sizeof(str_out); i++)
{ {
if (str[i] != str_out[i]) { match = false; } if (str[i] != str_out[i]) { match = false; }
Serial.print(str_out[i], HEX); // receive a byte as character Serial.print(str_out[i], HEX); // print hex values
Serial.print(" "); Serial.print(" ");
} }
Serial.print("WRITE "); Serial.print("WRITE ");

7
keywords.txt Normal file → Executable file
View File

@ -22,6 +22,7 @@ I2C_slave_get_reg_size KEYWORD2
I2C_slave_get_reg_addr KEYWORD2 I2C_slave_get_reg_addr KEYWORD2
I2C_init KEYWORD2 I2C_init KEYWORD2
I2C_uninit KEYWORD2
I2C_set_timeout KEYWORD2 I2C_set_timeout KEYWORD2
I2C_set_retries KEYWORD2 I2C_set_retries KEYWORD2
I2C_set_speed KEYWORD2 I2C_set_speed KEYWORD2
@ -38,6 +39,8 @@ I2C_read_next KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
####################################### #######################################
I2C_READ LITERAL1
I2C_WRITE LITERAL1
I2C_OK LITERAL1 I2C_OK LITERAL1
I2C_BUSY LITERAL1 I2C_BUSY LITERAL1
I2C_NACK LITERAL1 I2C_NACK LITERAL1
@ -47,3 +50,7 @@ I2C_FAST 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
I2C_READ LITERAL1
DEF_CI2C_NB_RETRIES LITERAL1
DEF_CI2C_TIMEOUT LITERAL1

6
library.properties Normal file → Executable file
View File

@ -1,9 +1,9 @@
name=cI2C name=cI2C
version=0.2 version=0.3
author=SMFSW author=SMFSW
maintainer=SMFSW maintainer=SMFSW
sentence=Arduino Hardware Master 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 Master I2C protocols development in c, for easier ports to other µcontrollers) paragraph=Hardware I2C library for AVR µcontrollers (lib intended for I2C protocols development in c, for easier ports to other µcontrollers)
category=Communication category=Communication
url=http://playground.arduino.cc/code/CI2C url=http://playground.arduino.cc/code/CI2C
architectures=avr architectures=avr