From a5fdacd410b2eee7e5f20a6d39c096c4778ca87e Mon Sep 17 00:00:00 2001 From: rmirault Date: Mon, 2 Sep 2013 17:09:21 +0200 Subject: [PATCH 1/8] i2c: add i2c slave, first build ok --- modules/i2c/i2c.h | 18 ++-- modules/i2c/i2cs.h | 54 ++++++++++ modules/i2c/slavex.inc.c | 212 ++++++++++++++++++++++++++++++++++++++- modules/i2c/slavex.inc.h | 26 +++++ 4 files changed, 301 insertions(+), 9 deletions(-) create mode 100644 modules/i2c/i2cs.h create mode 100644 modules/i2c/slavex.inc.h diff --git a/modules/i2c/i2c.h b/modules/i2c/i2c.h index 5b7ac68..f7f05c6 100644 --- a/modules/i2c/i2c.h +++ b/modules/i2c/i2c.h @@ -12,7 +12,9 @@ #include #include #include +#include #include "i2c_config.h" +#include "i2cs.h" #ifdef DOXYGEN @@ -22,13 +24,9 @@ typedef struct i2cm_struct i2cm_t; /// I2C slave state typedef struct i2cs_struct i2cs_t; -/// State of i2cx -extern i2cT_t *const i2cx; - #else typedef struct TWI_MASTER_struct i2cm_t; -typedef struct i2cs_struct i2cs_t; // Check for I2C enabled as both master and slave // Define pointers to internal structures @@ -42,7 +40,8 @@ typedef struct i2cs_struct i2cs_t; #elif (defined I2CC_MASTER) # define i2cC (&TWIC.MASTER) #elif (defined I2CC_SLAVE) -extern i2cs_t *const i2cC; +# define X_(p,s) p ## C ## s +#include "slavex.inc.h" #endif #if (defined I2CD_MASTER) && (defined I2CD_SLAVE) @@ -50,7 +49,8 @@ extern i2cs_t *const i2cC; #elif (defined I2CD_MASTER) # define i2cD (&TWID.MASTER) #elif (defined I2CD_SLAVE) -extern i2cs_t *const i2cD; +# define X_(p,s) p ## D ## s +#include "slavex.inc.h" #endif #if (defined I2CE_MASTER) && (defined I2CE_SLAVE) @@ -58,7 +58,8 @@ extern i2cs_t *const i2cD; #elif (defined I2CE_MASTER) # define i2cE (&TWIE.MASTER) #elif (defined I2CE_SLAVE) -extern i2cs_t *const i2cE; +# define X_(p,s) p ## E ## s +#include "slavex.inc.h" #endif #if (defined I2CF_MASTER) && (defined I2CF_SLAVE) @@ -66,7 +67,8 @@ extern i2cs_t *const i2cE; #elif (defined I2CF_MASTER) # define i2cF (&TWIF.MASTER) #elif (defined I2CF_SLAVE) -extern i2cs_t *const i2cF; +# define X_(p,s) p ## F ## s +#include "slavex.inc.h" #endif #endif diff --git a/modules/i2c/i2cs.h b/modules/i2c/i2cs.h new file mode 100644 index 0000000..c828226 --- /dev/null +++ b/modules/i2c/i2cs.h @@ -0,0 +1,54 @@ +/** @defgroup i2c I2C + * @brief I2C module + */ +//@{ +/** + * @file + * @brief I2C definitions + */ +#ifndef I2CS_H__ +#define I2CS_H__ + +#include +#include +#include +#include "i2c_config.h" + +/* Transaction status defines.*/ +#define I2CS_STATUS_READY 0 +#define I2CS_STATUS_BUSY 1 + +/* Transaction result enumeration */ +typedef enum { + I2CS_RESULT_UNKNOWN = (0x00<<0), + I2CS_RESULT_OK = (0x01<<0), + I2CS_RESULT_BUFFER_OVERFLOW = (0x02<<0), + I2CS_RESULT_TRANSMIT_COLLISION = (0x03<<0), + I2CS_RESULT_BUS_ERROR = (0x04<<0), + I2CS_RESULT_FAIL = (0x05<<0), + I2CS_RESULT_ABORTED = (0x06<<0), +} i2c_result_t; + +/* Buffer size defines. */ +#define I2CS_RECEIVE_BUFFER_SIZE 8 +#define I2CS_SEND_BUFFER_SIZE 8 + + + +/*! \brief i2c slave driver struct. + * + * i2c slave struct. Buffers and necessary varibles. + */ +typedef struct { + void (*process_data) (void); /*!< Pointer to process data function*/ + uint8_t received_data[I2CS_RECEIVE_BUFFER_SIZE]; /*!< Read data*/ + uint8_t transmit_data[I2CS_SEND_BUFFER_SIZE]; /*!< Data to write*/ + uint8_t bytes_received; /*!< Number of bytes received*/ + uint8_t bytes_transmit; /*!< Number of bytes sent*/ + uint8_t status; /*!< Status of transaction*/ + uint8_t result; /*!< Result of transaction*/ +} i2cs_t; + + +#endif +//@} diff --git a/modules/i2c/slavex.inc.c b/modules/i2c/slavex.inc.c index bcdd946..df18e77 100644 --- a/modules/i2c/slavex.inc.c +++ b/modules/i2c/slavex.inc.c @@ -6,7 +6,217 @@ * The X_(p,s) macro must be defined before including. * It is automatically undefined at the end of this file. */ +#include -#error Slave mode not supported yet +#define I2CX(s) X_(I2C,s) +#define i2cX(s) X_(i2c,s) +#define i2cs X_(i2cs,) +#define TWIX X_(TWI,) +#define twiX(s) X_(TWI,s) +i2cs_t *i2csX; + +void i2cX(_init)(void) +{ +} + + +/*! \brief Initialize the I2C module. + */ +void i2cX(s_init)(i2cs_t *p, + uint8_t address, + void (*process_data_function)(void)) { + i2csX = p; + i2csX->process_data = process_data_function; + i2csX->bytes_received = 0; + i2csX->bytes_transmit = 0; + i2csX->status = I2CS_STATUS_READY; + i2csX->result = I2CS_RESULT_UNKNOWN; + + TWIX.SLAVE.CTRLA = (I2C_INTLVL<result = result; + i2csX->status = I2CS_STATUS_READY; +} + +/*! \brief i2c slave transmit interrupt handler. + * + * Handles i2c slave transmit transactions and responses. + * + * \param i2c The i2cs_t struct instance. + */ +void i2cX(_transmit_handler(void)) { + /* If NACK, slave transmit transaction finished. */ + if ((i2csX->bytes_transmit > 0) && (TWIX.SLAVE.STATUS & + TWI_SLAVE_RXACK_bm)) { + + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + i2cX(_transaction_finished(I2CS_RESULT_OK)); + } + /* If ACK, master expects more data. */ + else { + if (i2csX->bytes_transmit < I2CS_SEND_BUFFER_SIZE) { + uint8_t data = i2csX->transmit_data[i2csX->bytes_transmit]; + TWIX.SLAVE.DATA = data; + i2csX->bytes_transmit++; + + /* Send data, wait for data interrupt. */ + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + /* If buffer overflow. */ + else { + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + i2cX(_transaction_finished(I2CS_RESULT_BUFFER_OVERFLOW)); + } + } +} + +/*! \brief TWI slave recieve interrupt handler. + * + * Handles TWI slave recieve transactions and responses. + * + * \param twi The TWI_Slave_t struct instance. + */ +void i2cX(_receive_handler(void)) { + /* Enable stop interrupt. */ + uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; + TWIX.SLAVE.CTRLA = currentCtrlA | TWI_SLAVE_PIEN_bm; + + /* If free space in buffer. */ + if (i2csX->bytes_received < I2CS_RECEIVE_BUFFER_SIZE) { + /* Fetch data */ + uint8_t data = TWIX.SLAVE.DATA; + i2csX->received_data[i2csX->bytes_received] = data; + + /* Process data. */ + if(i2csX->process_data != NULL) + i2csX->process_data(); + + i2csX->bytes_received++; + + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + /* If buffer overflow, send NACK and wait for next START. Set + * result buffer overflow. + */ + else { + TWIX.SLAVE.CTRLB = TWI_SLAVE_ACKACT_bm | + TWI_SLAVE_CMD_COMPTRANS_gc; + i2cX(_transaction_finished(I2CS_RESULT_BUFFER_OVERFLOW)); + } +} + +/*! \brief TWI address match interrupt handler. + * + * Prepares TWI module for transaction when an address match occures. + * + * \param twi The TWI_Slave_t struct instance. + */ +void i2cX(_address_match_handler(void)) { + i2csX->status = I2CS_STATUS_BUSY; + i2csX->result = I2CS_RESULT_UNKNOWN; + i2csX->bytes_received = 0; + i2csX->bytes_transmit = 0; + + /* Disable stop interrupt. */ + uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; + TWIX.SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; + + + /* Send ACK, wait for data interrupt. */ + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; +} + + +/*! \brief I2C stop condition interrupt handler. + * + * \param i2c The i2cs_t struct instance. + */ +void i2cX(_stop_handler(void)) { + /* Disable stop interrupt. */ + uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; + TWIX.SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; + + /* Clear APIF, according to flowchart don't ACK or NACK */ + uint8_t currentStatus = TWIX.SLAVE.STATUS; + TWIX.SLAVE.STATUS = currentStatus | TWI_SLAVE_APIF_bm; + + i2cX(_transaction_finished(I2CS_RESULT_OK)); + +} + +/*! \brief TWI data interrupt handler. + * + * Calls the appropriate slave receive or transmit handler. + * + * \param twi The TWI_Slave_t struct instance. + */ +void i2cX(_data_handler(void)) { + if (TWIX.SLAVE.STATUS & TWI_SLAVE_DIR_bm) { + i2cX(_transmit_handler()); + } else { + i2cX(_receive_handler()); + } +} + +/// Interrupt handler +ISR(twiX(_TWIS_vect)) { + uint8_t current_status = TWIX.SLAVE.STATUS; + + /* If bus error. */ + if (current_status & TWI_SLAVE_BUSERR_bm) { + i2csX->bytes_received = 0; + i2csX->bytes_transmit = 0; + i2csX->result = I2CS_RESULT_BUS_ERROR; + i2csX->status = I2CS_STATUS_READY; + } + + /* If transmit collision. */ + else if (current_status & TWI_SLAVE_COLL_bm) { + i2csX->bytes_received = 0; + i2csX->bytes_transmit = 0; + i2csX->result = I2CS_RESULT_TRANSMIT_COLLISION; + i2csX->status = I2CS_STATUS_READY; + } + + /* If address match. */ + else if ((current_status & TWI_SLAVE_APIF_bm) && + (current_status & TWI_SLAVE_AP_bm)) { + i2cX(_address_match_handler()); + } + + /* If stop (only enabled through slave receive transaction). */ + else if (current_status & TWI_SLAVE_APIF_bm) { + i2cX(_stop_handler()); + } + + /* If data interrupt. */ + else if (current_status & TWI_SLAVE_DIF_bm) { + i2cX(_data_handler()); + } + + /* If unexpected state. */ + else { + i2cX(_transaction_finished(I2CS_RESULT_FAIL)); + } +} + +#undef I2CX +#undef i2cX +#undef i2csX +#undef TWIX +#undef twiX #undef X_ diff --git a/modules/i2c/slavex.inc.h b/modules/i2c/slavex.inc.h new file mode 100644 index 0000000..55a4a0f --- /dev/null +++ b/modules/i2c/slavex.inc.h @@ -0,0 +1,26 @@ +/** @defgroup i2c I2C + * @brief I2C module + */ +//@{ +/** + * @file + * @brief I2C definitions + */ +#ifndef SLAVEX_INC_H__ +#define SLAVEX_INC_H__ + +#define i2cX(s) X_(i2c,s) +/*! \brief Initialize the I2C module. + * + * Enables interrupts on address recognition and data available. + * Remember to enable interrupts globally from the main application. + * + * \param address Slave address for this module. + * \param process_data_function Pointer to the function that handles incoming data. + */ +void i2cX(s_init)(i2cs_t *p , + uint8_t address, + void (*process_data_function)(void)); + +#undef i2cX +#endif//SLAVEX_INC_H__ From 256601a91c2bbebf908f1d8a4be462499e6cb58e Mon Sep 17 00:00:00 2001 From: rmirault Date: Thu, 3 Oct 2013 11:55:08 +0200 Subject: [PATCH 2/8] i2c: I2cX data structure singleton changed and callback added for all data receive or transmit --- modules/i2c/i2cs.h | 36 +++++----- modules/i2c/slavex.inc.c | 141 +++++++++++++++++---------------------- modules/i2c/slavex.inc.h | 23 +++---- 3 files changed, 87 insertions(+), 113 deletions(-) diff --git a/modules/i2c/i2cs.h b/modules/i2c/i2cs.h index c828226..50e614a 100644 --- a/modules/i2c/i2cs.h +++ b/modules/i2c/i2cs.h @@ -20,33 +20,29 @@ /* Transaction result enumeration */ typedef enum { - I2CS_RESULT_UNKNOWN = (0x00<<0), - I2CS_RESULT_OK = (0x01<<0), - I2CS_RESULT_BUFFER_OVERFLOW = (0x02<<0), - I2CS_RESULT_TRANSMIT_COLLISION = (0x03<<0), - I2CS_RESULT_BUS_ERROR = (0x04<<0), - I2CS_RESULT_FAIL = (0x05<<0), - I2CS_RESULT_ABORTED = (0x06<<0), + I2CS_RESULT_UNKNOWN = 0, + I2CS_RESULT_RECEIVED , + I2CS_RESULT_TRANSMIT , + I2CS_RESULT_OK , + I2CS_RESULT_BUFFER_OVERFLOW , + I2CS_RESULT_TRANSMIT_COLLISION, + I2CS_RESULT_BUS_ERROR , + I2CS_RESULT_FAIL , + I2CS_RESULT_ABORTED } i2c_result_t; -/* Buffer size defines. */ -#define I2CS_RECEIVE_BUFFER_SIZE 8 -#define I2CS_SEND_BUFFER_SIZE 8 - - - /*! \brief i2c slave driver struct. * * i2c slave struct. Buffers and necessary varibles. */ typedef struct { - void (*process_data) (void); /*!< Pointer to process data function*/ - uint8_t received_data[I2CS_RECEIVE_BUFFER_SIZE]; /*!< Read data*/ - uint8_t transmit_data[I2CS_SEND_BUFFER_SIZE]; /*!< Data to write*/ - uint8_t bytes_received; /*!< Number of bytes received*/ - uint8_t bytes_transmit; /*!< Number of bytes sent*/ - uint8_t status; /*!< Status of transaction*/ - uint8_t result; /*!< Result of transaction*/ + void (*process_data) (void); /*!< Pointer to process data function*/ + uint8_t received_data[I2CS_RECEIVE_BUFFER_SIZE]; /*!< Read data*/ + uint8_t transmit_data[I2CS_SEND_BUFFER_SIZE]; /*!< Data to write*/ + uint8_t bytes_received; /*!< Number of bytes received*/ + uint8_t bytes_transmit; /*!< Number of bytes sent*/ + uint8_t status; /*!< Status of transaction*/ + uint8_t result; /*!< Result of transaction*/ } i2cs_t; diff --git a/modules/i2c/slavex.inc.c b/modules/i2c/slavex.inc.c index df18e77..44239e8 100644 --- a/modules/i2c/slavex.inc.c +++ b/modules/i2c/slavex.inc.c @@ -10,57 +10,47 @@ #define I2CX(s) X_(I2C,s) #define i2cX(s) X_(i2c,s) -#define i2cs X_(i2cs,) #define TWIX X_(TWI,) #define twiX(s) X_(TWI,s) -i2cs_t *i2csX; +// I2cX singleton +i2cs_t i2cX(); -void i2cX(_init)(void) -{ -} - - -/*! \brief Initialize the I2C module. - */ -void i2cX(s_init)(i2cs_t *p, - uint8_t address, - void (*process_data_function)(void)) { - i2csX = p; - i2csX->process_data = process_data_function; - i2csX->bytes_received = 0; - i2csX->bytes_transmit = 0; - i2csX->status = I2CS_STATUS_READY; - i2csX->result = I2CS_RESULT_UNKNOWN; +void i2cX(_init)(void) { + i2cX().process_data = NULL; + i2cX().bytes_received = 0; + i2cX().bytes_transmit = 0; + i2cX().status = I2CS_STATUS_READY; + i2cX().result = I2CS_RESULT_UNKNOWN; TWIX.SLAVE.CTRLA = (I2C_INTLVL<result = result; - i2csX->status = I2CS_STATUS_READY; +static void i2cX(_transaction_finished(uint8_t result)) { + i2cX().result = result; + i2cX().status = I2CS_STATUS_READY; } -/*! \brief i2c slave transmit interrupt handler. - * +/* @brief i2c slave transmit interrupt handler. * Handles i2c slave transmit transactions and responses. - * - * \param i2c The i2cs_t struct instance. */ -void i2cX(_transmit_handler(void)) { +static void i2cX(_transmit_handler(void)) { /* If NACK, slave transmit transaction finished. */ - if ((i2csX->bytes_transmit > 0) && (TWIX.SLAVE.STATUS & + if ((i2cX().bytes_transmit > 0) && (TWIX.SLAVE.STATUS & TWI_SLAVE_RXACK_bm)) { TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; @@ -68,10 +58,11 @@ void i2cX(_transmit_handler(void)) { } /* If ACK, master expects more data. */ else { - if (i2csX->bytes_transmit < I2CS_SEND_BUFFER_SIZE) { - uint8_t data = i2csX->transmit_data[i2csX->bytes_transmit]; + if (i2cX().bytes_transmit < I2CS_SEND_BUFFER_SIZE) { + uint8_t data = i2cX().transmit_data[i2cX().bytes_transmit]; TWIX.SLAVE.DATA = data; - i2csX->bytes_transmit++; + i2cX().bytes_transmit++; + i2cX().result = I2CS_RESULT_TRANSMIT; /* Send data, wait for data interrupt. */ TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; @@ -84,28 +75,22 @@ void i2cX(_transmit_handler(void)) { } } -/*! \brief TWI slave recieve interrupt handler. - * - * Handles TWI slave recieve transactions and responses. - * - * \param twi The TWI_Slave_t struct instance. +/* @brief i2c slave recieve interrupt handler. + * Handles i2c slave recieve transactions and responses. */ -void i2cX(_receive_handler(void)) { +static void i2cX(_receive_handler(void)) { /* Enable stop interrupt. */ uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; TWIX.SLAVE.CTRLA = currentCtrlA | TWI_SLAVE_PIEN_bm; /* If free space in buffer. */ - if (i2csX->bytes_received < I2CS_RECEIVE_BUFFER_SIZE) { + if (i2cX().bytes_received < I2CS_RECEIVE_BUFFER_SIZE) { /* Fetch data */ uint8_t data = TWIX.SLAVE.DATA; - i2csX->received_data[i2csX->bytes_received] = data; - - /* Process data. */ - if(i2csX->process_data != NULL) - i2csX->process_data(); + i2cX().received_data[i2cX().bytes_received] = data; - i2csX->bytes_received++; + i2cX().bytes_received++; + i2cX().result = I2CS_RESULT_RECEIVED; TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; } @@ -119,33 +104,28 @@ void i2cX(_receive_handler(void)) { } } -/*! \brief TWI address match interrupt handler. - * - * Prepares TWI module for transaction when an address match occures. - * - * \param twi The TWI_Slave_t struct instance. +/* @brief i2c address match interrupt handler. + * Prepares i2c module for transaction when an address match occures. */ -void i2cX(_address_match_handler(void)) { - i2csX->status = I2CS_STATUS_BUSY; - i2csX->result = I2CS_RESULT_UNKNOWN; - i2csX->bytes_received = 0; - i2csX->bytes_transmit = 0; +static void i2cX(_address_match_handler(void)) { + i2cX().status = I2CS_STATUS_BUSY; + i2cX().result = I2CS_RESULT_UNKNOWN; + i2cX().bytes_received = 0; + i2cX().bytes_transmit = 0; /* Disable stop interrupt. */ uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; TWIX.SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; - /* Send ACK, wait for data interrupt. */ TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; } -/*! \brief I2C stop condition interrupt handler. - * - * \param i2c The i2cs_t struct instance. +/* @brief I2C stop condition interrupt handler. + * @bparam i2c The i2cs_t struct instance. */ -void i2cX(_stop_handler(void)) { +static void i2cX(_stop_handler(void)) { /* Disable stop interrupt. */ uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; TWIX.SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; @@ -158,13 +138,10 @@ void i2cX(_stop_handler(void)) { } -/*! \brief TWI data interrupt handler. - * +/* @brief i2c data interrupt handler. * Calls the appropriate slave receive or transmit handler. - * - * \param twi The TWI_Slave_t struct instance. */ -void i2cX(_data_handler(void)) { +static void i2cX(_data_handler(void)) { if (TWIX.SLAVE.STATUS & TWI_SLAVE_DIR_bm) { i2cX(_transmit_handler()); } else { @@ -178,34 +155,43 @@ ISR(twiX(_TWIS_vect)) { /* If bus error. */ if (current_status & TWI_SLAVE_BUSERR_bm) { - i2csX->bytes_received = 0; - i2csX->bytes_transmit = 0; - i2csX->result = I2CS_RESULT_BUS_ERROR; - i2csX->status = I2CS_STATUS_READY; + i2cX().bytes_received = 0; + i2cX().bytes_transmit = 0; + i2cX().result = I2CS_RESULT_BUS_ERROR; + i2cX().status = I2CS_STATUS_READY; } /* If transmit collision. */ else if (current_status & TWI_SLAVE_COLL_bm) { - i2csX->bytes_received = 0; - i2csX->bytes_transmit = 0; - i2csX->result = I2CS_RESULT_TRANSMIT_COLLISION; - i2csX->status = I2CS_STATUS_READY; + i2cX().bytes_received = 0; + i2cX().bytes_transmit = 0; + i2cX().result = I2CS_RESULT_TRANSMIT_COLLISION; + i2cX().status = I2CS_STATUS_READY; } /* If address match. */ else if ((current_status & TWI_SLAVE_APIF_bm) && (current_status & TWI_SLAVE_AP_bm)) { i2cX(_address_match_handler()); + /* Process data. */ + if(i2cX().process_data != NULL) + i2cX().process_data(); } /* If stop (only enabled through slave receive transaction). */ else if (current_status & TWI_SLAVE_APIF_bm) { i2cX(_stop_handler()); + /* Process data. */ + if(i2cX().process_data != NULL) + i2cX().process_data(); } /* If data interrupt. */ else if (current_status & TWI_SLAVE_DIF_bm) { i2cX(_data_handler()); + /* Process data. */ + if(i2cX().process_data != NULL) + i2cX().process_data(); } /* If unexpected state. */ @@ -216,7 +202,6 @@ ISR(twiX(_TWIS_vect)) { #undef I2CX #undef i2cX -#undef i2csX #undef TWIX #undef twiX #undef X_ diff --git a/modules/i2c/slavex.inc.h b/modules/i2c/slavex.inc.h index 55a4a0f..80a6992 100644 --- a/modules/i2c/slavex.inc.h +++ b/modules/i2c/slavex.inc.h @@ -6,21 +6,14 @@ * @file * @brief I2C definitions */ -#ifndef SLAVEX_INC_H__ -#define SLAVEX_INC_H__ - #define i2cX(s) X_(i2c,s) -/*! \brief Initialize the I2C module. - * - * Enables interrupts on address recognition and data available. - * Remember to enable interrupts globally from the main application. - * - * \param address Slave address for this module. - * \param process_data_function Pointer to the function that handles incoming data. - */ -void i2cX(s_init)(i2cs_t *p , - uint8_t address, - void (*process_data_function)(void)); + + +/* I2cX Register callback */ +void i2cX(s_register_callback)( void (*process_data_function)(void)); + +// I2cX singleton +extern i2cs_t i2cX(); #undef i2cX -#endif//SLAVEX_INC_H__ +#undef X_ From 92712d1f46cc0d117053d99edaea5eb5b18f7cbe Mon Sep 17 00:00:00 2001 From: Augustin Date: Wed, 22 Feb 2017 09:47:33 +0100 Subject: [PATCH 3/8] clock : add run-time autocalibration option --- modules/clock/config/clock_config.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/clock/config/clock_config.h b/modules/clock/config/clock_config.h index b5dbb58..ef31d07 100644 --- a/modules/clock/config/clock_config.h +++ b/modules/clock/config/clock_config.h @@ -31,12 +31,10 @@ #define CLOCK_PER2_FREQ CLOCK_CPU_FREQ #define CLOCK_PER4_FREQ CLOCK_CPU_FREQ -/** @brief Enable automatic run-time calibration of internal clock - * - * Only usable with 2MHz or 32Mhz internal clocks. - * It will use the 32768kHz calibrated clock as the adjustement source. - */ -#undef CLOCK_AUTO_RUN_TIME_CALIBRATION +// uncomment the following line to activate automatic run-time calibration of internal clock +// only usable with 2MHz or 32Mhz internal clocks +// it will use the 32,768kHz calibrated clock as the adjustement source +//#define CLOCK_AUTOMATIC_RUN_TIME_CALIBRATION ///@endcond //@} From a12d18aed761d52d1162db0e0a07b1c8281125e6 Mon Sep 17 00:00:00 2001 From: Augustin Date: Mon, 24 Jul 2017 13:11:07 +0200 Subject: [PATCH 4/8] coding style corrections #1 --- modules/clock/config/clock_config.h | 9 +++--- modules/i2c/i2c.h | 9 +++--- modules/i2c/i2cs.h | 44 ++++++++++++++--------------- modules/i2c/slavex.inc.c | 19 +++++++------ 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/modules/clock/config/clock_config.h b/modules/clock/config/clock_config.h index ef31d07..e51175d 100644 --- a/modules/clock/config/clock_config.h +++ b/modules/clock/config/clock_config.h @@ -31,10 +31,11 @@ #define CLOCK_PER2_FREQ CLOCK_CPU_FREQ #define CLOCK_PER4_FREQ CLOCK_CPU_FREQ -// uncomment the following line to activate automatic run-time calibration of internal clock -// only usable with 2MHz or 32Mhz internal clocks -// it will use the 32,768kHz calibrated clock as the adjustement source -//#define CLOCK_AUTOMATIC_RUN_TIME_CALIBRATION +/** @brief Activates automatic run-time calibration of internal clock + * only usable with 2MHz or 32Mhz internal clocks + * it will use the 32,768kHz calibrated clock as the adjustement source + */ +#undef CLOCK_AUTOMATIC_RUN_TIME_CALIBRATION ///@endcond //@} diff --git a/modules/i2c/i2c.h b/modules/i2c/i2c.h index f7f05c6..debf3f0 100644 --- a/modules/i2c/i2c.h +++ b/modules/i2c/i2c.h @@ -12,7 +12,6 @@ #include #include #include -#include #include "i2c_config.h" #include "i2cs.h" @@ -41,7 +40,7 @@ typedef struct TWI_MASTER_struct i2cm_t; # define i2cC (&TWIC.MASTER) #elif (defined I2CC_SLAVE) # define X_(p,s) p ## C ## s -#include "slavex.inc.h" +# include "slavex.inc.h" #endif #if (defined I2CD_MASTER) && (defined I2CD_SLAVE) @@ -50,7 +49,7 @@ typedef struct TWI_MASTER_struct i2cm_t; # define i2cD (&TWID.MASTER) #elif (defined I2CD_SLAVE) # define X_(p,s) p ## D ## s -#include "slavex.inc.h" +# include "slavex.inc.h" #endif #if (defined I2CE_MASTER) && (defined I2CE_SLAVE) @@ -59,7 +58,7 @@ typedef struct TWI_MASTER_struct i2cm_t; # define i2cE (&TWIE.MASTER) #elif (defined I2CE_SLAVE) # define X_(p,s) p ## E ## s -#include "slavex.inc.h" +# include "slavex.inc.h" #endif #if (defined I2CF_MASTER) && (defined I2CF_SLAVE) @@ -68,7 +67,7 @@ typedef struct TWI_MASTER_struct i2cm_t; # define i2cF (&TWIF.MASTER) #elif (defined I2CF_SLAVE) # define X_(p,s) p ## F ## s -#include "slavex.inc.h" +# include "slavex.inc.h" #endif #endif diff --git a/modules/i2c/i2cs.h b/modules/i2c/i2cs.h index 50e614a..4e1edd6 100644 --- a/modules/i2c/i2cs.h +++ b/modules/i2c/i2cs.h @@ -4,7 +4,7 @@ //@{ /** * @file - * @brief I2C definitions + * @brief I2Cs definitions */ #ifndef I2CS_H__ #define I2CS_H__ @@ -14,35 +14,35 @@ #include #include "i2c_config.h" -/* Transaction status defines.*/ -#define I2CS_STATUS_READY 0 -#define I2CS_STATUS_BUSY 1 +// Transaction status defines +#define I2CS_STATUS_READY 0 +#define I2CS_STATUS_BUSY 1 -/* Transaction result enumeration */ +// Transaction result enumeration typedef enum { - I2CS_RESULT_UNKNOWN = 0, - I2CS_RESULT_RECEIVED , - I2CS_RESULT_TRANSMIT , - I2CS_RESULT_OK , - I2CS_RESULT_BUFFER_OVERFLOW , + I2CS_RESULT_UNKNOWN = 0, + I2CS_RESULT_RECEIVED, + I2CS_RESULT_TRANSMIT, + I2CS_RESULT_OK, + I2CS_RESULT_BUFFER_OVERFLOW, I2CS_RESULT_TRANSMIT_COLLISION, - I2CS_RESULT_BUS_ERROR , - I2CS_RESULT_FAIL , - I2CS_RESULT_ABORTED + I2CS_RESULT_BUS_ERROR, + I2CS_RESULT_FAIL, + I2CS_RESULT_ABORTED } i2c_result_t; -/*! \brief i2c slave driver struct. +/* @brief I2C slave driver struct. * - * i2c slave struct. Buffers and necessary varibles. + * I2C slave struct. Buffers and necessary varibles. */ typedef struct { - void (*process_data) (void); /*!< Pointer to process data function*/ - uint8_t received_data[I2CS_RECEIVE_BUFFER_SIZE]; /*!< Read data*/ - uint8_t transmit_data[I2CS_SEND_BUFFER_SIZE]; /*!< Data to write*/ - uint8_t bytes_received; /*!< Number of bytes received*/ - uint8_t bytes_transmit; /*!< Number of bytes sent*/ - uint8_t status; /*!< Status of transaction*/ - uint8_t result; /*!< Result of transaction*/ + void (*process_data) (void); // Pointer to process data function + uint8_t received_data[I2CS_RECEIVE_BUFFER_SIZE]; // Read data + uint8_t transmit_data[I2CS_SEND_BUFFER_SIZE]; // Data to write + uint8_t bytes_received; // Number of bytes received + uint8_t bytes_transmit; // Number of bytes sent + uint8_t status; // Status of transaction + uint8_t result; // Result of transaction } i2cs_t; diff --git a/modules/i2c/slavex.inc.c b/modules/i2c/slavex.inc.c index 44239e8..4e9bf21 100644 --- a/modules/i2c/slavex.inc.c +++ b/modules/i2c/slavex.inc.c @@ -7,13 +7,14 @@ * It is automatically undefined at the end of this file. */ #include +#include #define I2CX(s) X_(I2C,s) #define i2cX(s) X_(i2c,s) #define TWIX X_(TWI,) #define twiX(s) X_(TWI,s) -// I2cX singleton +// i2cX singleton i2cs_t i2cX(); void i2cX(_init)(void) { @@ -31,7 +32,7 @@ void i2cX(_init)(void) { } -// Register callback +// Register callback void i2cX(s_register_callback)( void (*process_data_function)(void) ) { i2cX().process_data = process_data_function; } @@ -80,8 +81,8 @@ static void i2cX(_transmit_handler(void)) { */ static void i2cX(_receive_handler(void)) { /* Enable stop interrupt. */ - uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; - TWIX.SLAVE.CTRLA = currentCtrlA | TWI_SLAVE_PIEN_bm; + uint8_t currentctrla = TWIX.SLAVE.CTRLA; + TWIX.SLAVE.CTRLA = currentctrla | TWI_SLAVE_PIEN_bm; /* If free space in buffer. */ if (i2cX().bytes_received < I2CS_RECEIVE_BUFFER_SIZE) { @@ -114,8 +115,8 @@ static void i2cX(_address_match_handler(void)) { i2cX().bytes_transmit = 0; /* Disable stop interrupt. */ - uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; - TWIX.SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; + uint8_t currentctrla = TWIX.SLAVE.CTRLA; + TWIX.SLAVE.CTRLA = currentctrla & ~TWI_SLAVE_PIEN_bm; /* Send ACK, wait for data interrupt. */ TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; @@ -127,8 +128,8 @@ static void i2cX(_address_match_handler(void)) { */ static void i2cX(_stop_handler(void)) { /* Disable stop interrupt. */ - uint8_t currentCtrlA = TWIX.SLAVE.CTRLA; - TWIX.SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; + uint8_t currentctrla = TWIX.SLAVE.CTRLA; + TWIX.SLAVE.CTRLA = currentctrla & ~TWI_SLAVE_PIEN_bm; /* Clear APIF, according to flowchart don't ACK or NACK */ uint8_t currentStatus = TWIX.SLAVE.STATUS; @@ -149,7 +150,7 @@ static void i2cX(_data_handler(void)) { } } -/// Interrupt handler +// Interrupt handler ISR(twiX(_TWIS_vect)) { uint8_t current_status = TWIX.SLAVE.STATUS; From 504bae67d4a96c00a565b2aa1a2c521dd622645b Mon Sep 17 00:00:00 2001 From: JD Date: Sat, 26 May 2018 23:24:44 +0200 Subject: [PATCH 5/8] i2c slave reworked, more documentation needed --- modules/i2c/i2c.c | 4 + modules/i2c/i2c.h | 45 +++++- modules/i2c/i2cs.h | 50 ------- modules/i2c/slavex.inc.c | 302 +++++++++++++++++++-------------------- modules/i2c/slavex.inc.h | 10 +- 5 files changed, 198 insertions(+), 213 deletions(-) delete mode 100644 modules/i2c/i2cs.h diff --git a/modules/i2c/i2c.c b/modules/i2c/i2c.c index 1c47559..e474b8a 100644 --- a/modules/i2c/i2c.c +++ b/modules/i2c/i2c.c @@ -151,5 +151,9 @@ int8_t i2cm_recv(i2cm_t *m, uint8_t addr, uint8_t *data, uint8_t n) return i; } +int8_t i2cs_send_async(i2cs_t *s, uint8_t *data, uint8_t n) { + + return 0; +} ///@endcond diff --git a/modules/i2c/i2c.h b/modules/i2c/i2c.h index debf3f0..deda09f 100644 --- a/modules/i2c/i2c.h +++ b/modules/i2c/i2c.h @@ -13,8 +13,6 @@ #include #include #include "i2c_config.h" -#include "i2cs.h" - #ifdef DOXYGEN @@ -27,6 +25,48 @@ typedef struct i2cs_struct i2cs_t; typedef struct TWI_MASTER_struct i2cm_t; +typedef enum { + I2CS_STATE_NONE, + I2CS_STATE_READ, + I2CS_STATE_WRITE, + +} i2cs_state_t; + +#ifndef I2CS_RECV_BUFFER_SIZE +#define I2CS_RECV_BUFFER_SIZE 32 +#endif + +#ifndef I2CS_SEND_BUFFER_SIZE +#define I2CS_SEND_BUFFER_SIZE 32 +#endif + +struct i2cs; + +typedef void (*i2cs_recv_callback_t)(uint8_t *data, int n); + +typedef int (*i2cs_send_callback_t)(uint8_t *data, int n); + +typedef void (*i2cs_reset_callback_t)(void); + +typedef struct i2cs { + + i2cs_state_t state; + + int recvd_bytes; + uint8_t recv_buffer[I2CS_RECV_BUFFER_SIZE]; + + int sent_bytes; + int bytes_to_send; + uint8_t send_buffer[I2CS_SEND_BUFFER_SIZE]; + + i2cs_recv_callback_t recv_callback; + + i2cs_send_callback_t send_callback; + + i2cs_reset_callback_t reset_callback; + +} i2cs_t; + // Check for I2C enabled as both master and slave // Define pointers to internal structures @@ -104,6 +144,5 @@ int8_t i2cm_send(i2cm_t *m, uint8_t addr, const uint8_t *data, uint8_t n); */ int8_t i2cm_recv(i2cm_t *m, uint8_t addr, uint8_t *data, uint8_t n); - #endif //@} diff --git a/modules/i2c/i2cs.h b/modules/i2c/i2cs.h deleted file mode 100644 index 4e1edd6..0000000 --- a/modules/i2c/i2cs.h +++ /dev/null @@ -1,50 +0,0 @@ -/** @defgroup i2c I2C - * @brief I2C module - */ -//@{ -/** - * @file - * @brief I2Cs definitions - */ -#ifndef I2CS_H__ -#define I2CS_H__ - -#include -#include -#include -#include "i2c_config.h" - -// Transaction status defines -#define I2CS_STATUS_READY 0 -#define I2CS_STATUS_BUSY 1 - -// Transaction result enumeration -typedef enum { - I2CS_RESULT_UNKNOWN = 0, - I2CS_RESULT_RECEIVED, - I2CS_RESULT_TRANSMIT, - I2CS_RESULT_OK, - I2CS_RESULT_BUFFER_OVERFLOW, - I2CS_RESULT_TRANSMIT_COLLISION, - I2CS_RESULT_BUS_ERROR, - I2CS_RESULT_FAIL, - I2CS_RESULT_ABORTED -} i2c_result_t; - -/* @brief I2C slave driver struct. - * - * I2C slave struct. Buffers and necessary varibles. - */ -typedef struct { - void (*process_data) (void); // Pointer to process data function - uint8_t received_data[I2CS_RECEIVE_BUFFER_SIZE]; // Read data - uint8_t transmit_data[I2CS_SEND_BUFFER_SIZE]; // Data to write - uint8_t bytes_received; // Number of bytes received - uint8_t bytes_transmit; // Number of bytes sent - uint8_t status; // Status of transaction - uint8_t result; // Result of transaction -} i2cs_t; - - -#endif -//@} diff --git a/modules/i2c/slavex.inc.c b/modules/i2c/slavex.inc.c index 4e9bf21..20609f0 100644 --- a/modules/i2c/slavex.inc.c +++ b/modules/i2c/slavex.inc.c @@ -6,6 +6,7 @@ * The X_(p,s) macro must be defined before including. * It is automatically undefined at the end of this file. */ +#include #include #include @@ -14,191 +15,180 @@ #define TWIX X_(TWI,) #define twiX(s) X_(TWI,s) -// i2cX singleton +// declare i2cX singleton i2cs_t i2cX(); void i2cX(_init)(void) { - i2cX().process_data = NULL; - i2cX().bytes_received = 0; - i2cX().bytes_transmit = 0; - i2cX().status = I2CS_STATUS_READY; - i2cX().result = I2CS_RESULT_UNKNOWN; - - TWIX.SLAVE.CTRLA = (I2C_INTLVL< 0) && (TWIX.SLAVE.STATUS & - TWI_SLAVE_RXACK_bm)) { - - TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; - i2cX(_transaction_finished(I2CS_RESULT_OK)); - } - /* If ACK, master expects more data. */ - else { - if (i2cX().bytes_transmit < I2CS_SEND_BUFFER_SIZE) { - uint8_t data = i2cX().transmit_data[i2cX().bytes_transmit]; - TWIX.SLAVE.DATA = data; - i2cX().bytes_transmit++; - i2cX().result = I2CS_RESULT_TRANSMIT; - - /* Send data, wait for data interrupt. */ - TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; - } - /* If buffer overflow. */ - else { - TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; - i2cX(_transaction_finished(I2CS_RESULT_BUFFER_OVERFLOW)); - } +void i2cX(s_register_reset_callback)(i2cs_reset_callback_t f) { + INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { + i2cX().reset_callback = f; } } -/* @brief i2c slave recieve interrupt handler. - * Handles i2c slave recieve transactions and responses. - */ -static void i2cX(_receive_handler(void)) { - /* Enable stop interrupt. */ - uint8_t currentctrla = TWIX.SLAVE.CTRLA; - TWIX.SLAVE.CTRLA = currentctrla | TWI_SLAVE_PIEN_bm; - - /* If free space in buffer. */ - if (i2cX().bytes_received < I2CS_RECEIVE_BUFFER_SIZE) { - /* Fetch data */ - uint8_t data = TWIX.SLAVE.DATA; - i2cX().received_data[i2cX().bytes_received] = data; - - i2cX().bytes_received++; - i2cX().result = I2CS_RESULT_RECEIVED; - - TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; - } - /* If buffer overflow, send NACK and wait for next START. Set - * result buffer overflow. - */ - else { - TWIX.SLAVE.CTRLB = TWI_SLAVE_ACKACT_bm | - TWI_SLAVE_CMD_COMPTRANS_gc; - i2cX(_transaction_finished(I2CS_RESULT_BUFFER_OVERFLOW)); +void i2cX(s_register_recv_callback)(i2cs_recv_callback_t f) { + INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { + i2cX().recv_callback = f; } } -/* @brief i2c address match interrupt handler. - * Prepares i2c module for transaction when an address match occures. - */ -static void i2cX(_address_match_handler(void)) { - i2cX().status = I2CS_STATUS_BUSY; - i2cX().result = I2CS_RESULT_UNKNOWN; - i2cX().bytes_received = 0; - i2cX().bytes_transmit = 0; - - /* Disable stop interrupt. */ - uint8_t currentctrla = TWIX.SLAVE.CTRLA; - TWIX.SLAVE.CTRLA = currentctrla & ~TWI_SLAVE_PIEN_bm; - - /* Send ACK, wait for data interrupt. */ - TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; +void i2cX(s_register_send_callback)(i2cs_send_callback_t f) { + INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { + i2cX().send_callback = f; + } } +// Interrupt handler +ISR(twiX(_TWIS_vect)) { -/* @brief I2C stop condition interrupt handler. - * @bparam i2c The i2cs_t struct instance. - */ -static void i2cX(_stop_handler(void)) { - /* Disable stop interrupt. */ - uint8_t currentctrla = TWIX.SLAVE.CTRLA; - TWIX.SLAVE.CTRLA = currentctrla & ~TWI_SLAVE_PIEN_bm; - - /* Clear APIF, according to flowchart don't ACK or NACK */ - uint8_t currentStatus = TWIX.SLAVE.STATUS; - TWIX.SLAVE.STATUS = currentStatus | TWI_SLAVE_APIF_bm; - - i2cX(_transaction_finished(I2CS_RESULT_OK)); + i2cs_t *i2cs = &i2cX(); -} + uint8_t status = TWIX.SLAVE.STATUS; -/* @brief i2c data interrupt handler. - * Calls the appropriate slave receive or transmit handler. - */ -static void i2cX(_data_handler(void)) { - if (TWIX.SLAVE.STATUS & TWI_SLAVE_DIR_bm) { - i2cX(_transmit_handler()); - } else { - i2cX(_receive_handler()); + if(status & TWI_SLAVE_BUSERR_bm) { + // bus error happened + i2cs->state = I2CS_STATE_NONE; + if(i2cs->reset_callback) + i2cs->reset_callback(); + return; } -} -// Interrupt handler -ISR(twiX(_TWIS_vect)) { - uint8_t current_status = TWIX.SLAVE.STATUS; - - /* If bus error. */ - if (current_status & TWI_SLAVE_BUSERR_bm) { - i2cX().bytes_received = 0; - i2cX().bytes_transmit = 0; - i2cX().result = I2CS_RESULT_BUS_ERROR; - i2cX().status = I2CS_STATUS_READY; + else if(status & TWI_SLAVE_COLL_bm) { + // collision happened + i2cs->state = I2CS_STATE_NONE; + if(i2cs->reset_callback) + i2cs->reset_callback(); + return; } - /* If transmit collision. */ - else if (current_status & TWI_SLAVE_COLL_bm) { - i2cX().bytes_received = 0; - i2cX().bytes_transmit = 0; - i2cX().result = I2CS_RESULT_TRANSMIT_COLLISION; - i2cX().status = I2CS_STATUS_READY; - } + else if(status & TWI_SLAVE_APIF_bm) { + // address / stop interrupt - /* If address match. */ - else if ((current_status & TWI_SLAVE_APIF_bm) && - (current_status & TWI_SLAVE_AP_bm)) { - i2cX(_address_match_handler()); - /* Process data. */ - if(i2cX().process_data != NULL) - i2cX().process_data(); - } + // check previous state, call recvd callback + // if previous frame was a master-write + if(i2cs->state == I2CS_STATE_WRITE) { + if(i2cs->recv_callback) { + i2cs->recv_callback(i2cs->recv_buffer, i2cs->recvd_bytes); + } + } - /* If stop (only enabled through slave receive transaction). */ - else if (current_status & TWI_SLAVE_APIF_bm) { - i2cX(_stop_handler()); - /* Process data. */ - if(i2cX().process_data != NULL) - i2cX().process_data(); - } + if(status & TWI_SLAVE_AP_bm) { + // valid address interrupt + if(status & TWI_SLAVE_DIR_bm) { + // master read operation + + i2cs->state = I2CS_STATE_READ; + if(i2cs->send_callback) { + + i2cs->sent_bytes = 0; + + // ask user to provision send buffer + int rsz = i2cs->send_callback(i2cs->send_buffer, + sizeof(i2cs->send_buffer)); + if(rsz > 0) { + // user got some data to send + i2cs->bytes_to_send = MIN(rsz,I2CS_SEND_BUFFER_SIZE); + // ACK + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + return; + } + i2cs->bytes_to_send = 0; + } + + // NACK, refuse read + TWIX.SLAVE.CTRLB = TWI_SLAVE_ACKACT_bm | TWI_SLAVE_CMD_RESPONSE_gc; + return; + } + else { + // master write operation + i2cs->state = I2CS_STATE_WRITE; + + // clear recv buffer + i2cs->recvd_bytes = 0; + // confirm operation + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + return; + } + else { + // STOP condition interrupt + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; - /* If data interrupt. */ - else if (current_status & TWI_SLAVE_DIF_bm) { - i2cX(_data_handler()); - /* Process data. */ - if(i2cX().process_data != NULL) - i2cX().process_data(); + i2cs->state = I2CS_STATE_NONE; + if(i2cs->reset_callback) + i2cs->reset_callback(); + return; + } } - /* If unexpected state. */ - else { - i2cX(_transaction_finished(I2CS_RESULT_FAIL)); + else if(status & TWI_SLAVE_DIF_bm) { + // data interruption + if(status & TWI_SLAVE_DIR_bm) { + // master read operation + + if(i2cs->sent_bytes > 0 && (status & TWI_SLAVE_RXACK_bm)) { + // previous byte was NACKed by master + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + i2cs->state = I2CS_STATE_NONE; + return; + } + + if(i2cs->sent_bytes < i2cs->bytes_to_send) { + // push byte + uint8_t byte = i2cs->send_buffer[i2cs->sent_bytes++]; + TWIX.SLAVE.DATA = byte; + + // ACK read, continue transmission + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + else { + // ACK read, end transmission + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + } + + return; + } + else { + // master write operation + uint8_t byte = TWIX.SLAVE.DATA; + + if(i2cs->recvd_bytes < I2CS_RECV_BUFFER_SIZE) { + i2cs->recv_buffer[i2cs->recvd_bytes++] = byte; + + // ACK write + TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + else { + // NACK write, buffer is full + TWIX.SLAVE.CTRLB = TWI_SLAVE_ACKACT_bm | TWI_SLAVE_CMD_COMPTRANS_gc; + } + + return; + } } + + // we encounter an unmanaged case + i2cs->state = I2CS_STATE_NONE; + i2cs->recvd_bytes = 0; + i2cs->sent_bytes = 0; + // reset client-side state + if(i2cs->reset_callback) + i2cs->reset_callback(); } #undef I2CX diff --git a/modules/i2c/slavex.inc.h b/modules/i2c/slavex.inc.h index 80a6992..a40b10e 100644 --- a/modules/i2c/slavex.inc.h +++ b/modules/i2c/slavex.inc.h @@ -8,12 +8,14 @@ */ #define i2cX(s) X_(i2c,s) - -/* I2cX Register callback */ -void i2cX(s_register_callback)( void (*process_data_function)(void)); - // I2cX singleton extern i2cs_t i2cX(); +void i2cX(s_register_send_callback)(i2cs_send_callback_t f); + +void i2cX(s_register_recv_callback)(i2cs_recv_callback_t f); + +void i2cX(s_register_reset_callback)(i2cs_reset_callback_t f); + #undef i2cX #undef X_ From 2052d1fffcd34a9dcc4a757a3d0121b4593366ba Mon Sep 17 00:00:00 2001 From: JD Date: Sun, 27 May 2018 21:26:15 +0200 Subject: [PATCH 6/8] LENGTHOF() added to avarix.h --- include/avarix.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/avarix.h b/include/avarix.h index 2b45d3b..283c758 100644 --- a/include/avarix.h +++ b/include/avarix.h @@ -12,7 +12,8 @@ #define MAX(x,y) ((x) > (y) ? (x) : (y)) /// Clamp a value to range [x;y] #define CLAMP(v,x,y) ((v) < (x) ? (x) : (v) > (y) ? (y) : (v)) - +/// Get number of elements in an array +#define LENGTHOF(a) (sizeof(a)/sizeof((a)[0])) #endif //@} From 32fb9f0f8347a83858bc46d8ce4d6bb4bc2d1321 Mon Sep 17 00:00:00 2001 From: JD Date: Fri, 1 Jun 2018 13:21:39 +0200 Subject: [PATCH 7/8] i2cs: fixes from PR --- include/avarix.h | 2 +- modules/clock/config/clock_config.h | 9 ++++--- modules/i2c/i2c.c | 5 ---- modules/i2c/i2c.h | 40 +++++++++++++++++++++-------- modules/i2c/slavex.inc.c | 22 +++++----------- modules/i2c/slavex.inc.h | 8 ++++-- 6 files changed, 48 insertions(+), 38 deletions(-) diff --git a/include/avarix.h b/include/avarix.h index 283c758..b1fc199 100644 --- a/include/avarix.h +++ b/include/avarix.h @@ -13,7 +13,7 @@ /// Clamp a value to range [x;y] #define CLAMP(v,x,y) ((v) < (x) ? (x) : (v) > (y) ? (y) : (v)) /// Get number of elements in an array -#define LENGTHOF(a) (sizeof(a)/sizeof((a)[0])) +#define LENGTHOF(a) ((sizeof(a)/sizeof((a)[0]))/(sizeof(a)%sizeof((a)[0]) == 0)) #endif //@} diff --git a/modules/clock/config/clock_config.h b/modules/clock/config/clock_config.h index e51175d..b5dbb58 100644 --- a/modules/clock/config/clock_config.h +++ b/modules/clock/config/clock_config.h @@ -31,11 +31,12 @@ #define CLOCK_PER2_FREQ CLOCK_CPU_FREQ #define CLOCK_PER4_FREQ CLOCK_CPU_FREQ -/** @brief Activates automatic run-time calibration of internal clock - * only usable with 2MHz or 32Mhz internal clocks - * it will use the 32,768kHz calibrated clock as the adjustement source +/** @brief Enable automatic run-time calibration of internal clock + * + * Only usable with 2MHz or 32Mhz internal clocks. + * It will use the 32768kHz calibrated clock as the adjustement source. */ -#undef CLOCK_AUTOMATIC_RUN_TIME_CALIBRATION +#undef CLOCK_AUTO_RUN_TIME_CALIBRATION ///@endcond //@} diff --git a/modules/i2c/i2c.c b/modules/i2c/i2c.c index e474b8a..0c031ea 100644 --- a/modules/i2c/i2c.c +++ b/modules/i2c/i2c.c @@ -151,9 +151,4 @@ int8_t i2cm_recv(i2cm_t *m, uint8_t addr, uint8_t *data, uint8_t n) return i; } -int8_t i2cs_send_async(i2cs_t *s, uint8_t *data, uint8_t n) { - - return 0; -} - ///@endcond diff --git a/modules/i2c/i2c.h b/modules/i2c/i2c.h index deda09f..58c0ef6 100644 --- a/modules/i2c/i2c.h +++ b/modules/i2c/i2c.h @@ -33,35 +33,53 @@ typedef enum { } i2cs_state_t; #ifndef I2CS_RECV_BUFFER_SIZE -#define I2CS_RECV_BUFFER_SIZE 32 +# define I2CS_RECV_BUFFER_SIZE 32 #endif #ifndef I2CS_SEND_BUFFER_SIZE -#define I2CS_SEND_BUFFER_SIZE 32 +# define I2CS_SEND_BUFFER_SIZE 32 #endif -struct i2cs; - -typedef void (*i2cs_recv_callback_t)(uint8_t *data, int n); +/** @brief I2C slave master-write frame received + * + * @param buffer buffer containing the received bytes + * @param n number of bytes received from master + * + * This function is called when a master-write operation has completed + */ +typedef void (*i2cs_recv_callback_t)(uint8_t *buffer, uint8_t n); -typedef int (*i2cs_send_callback_t)(uint8_t *data, int n); +/** @brief I2C slave master-read operation was requested + * + * @param buffer buffer to provision + * @param maxsz maximum number of bytes which can be written to buffer + * @return number of bytes to send, returning 0 will result in a NACK from slave. + * + * This function is called when a master-read operation was requested by master + * and ask user to provision the buffer which will be sent. + */ +typedef uint8_t (*i2cs_prepare_send_callback_t)(uint8_t *buffer, uint8_t maxsz); +/** @brief I2C slave transaction finished successfully or not + * + * This function is called when a STOP condition or any bus error has ended current transaction + */ typedef void (*i2cs_reset_callback_t)(void); -typedef struct i2cs { +typedef struct { i2cs_state_t state; - int recvd_bytes; + uint8_t recvd_bytes; uint8_t recv_buffer[I2CS_RECV_BUFFER_SIZE]; - int sent_bytes; - int bytes_to_send; + uint8_t sent_bytes; + uint8_t bytes_to_send; uint8_t send_buffer[I2CS_SEND_BUFFER_SIZE]; i2cs_recv_callback_t recv_callback; - i2cs_send_callback_t send_callback; + i2cs_prepare_send_callback_t prepare_send_callback; i2cs_reset_callback_t reset_callback; diff --git a/modules/i2c/slavex.inc.c b/modules/i2c/slavex.inc.c index 20609f0..5f9e24f 100644 --- a/modules/i2c/slavex.inc.c +++ b/modules/i2c/slavex.inc.c @@ -23,7 +23,7 @@ void i2cX(_init)(void) { i2cX().state = I2CS_STATE_NONE; i2cX().reset_callback = NULL; - i2cX().send_callback = NULL; + i2cX().prepare_send_callback = NULL; i2cX().recv_callback = NULL; // initialize hardware @@ -47,9 +47,9 @@ void i2cX(s_register_recv_callback)(i2cs_recv_callback_t f) { } } -void i2cX(s_register_send_callback)(i2cs_send_callback_t f) { +void i2cX(s_register_prepare_send_callback)(i2cs_prepare_send_callback_t f) { INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { - i2cX().send_callback = f; + i2cX().prepare_send_callback = f; } } @@ -60,7 +60,7 @@ ISR(twiX(_TWIS_vect)) { uint8_t status = TWIX.SLAVE.STATUS; - if(status & TWI_SLAVE_BUSERR_bm) { + if(status & TWI_SLAVE_BUSERR_bm || status & TWI_SLAVE_COLL_bm) { // bus error happened i2cs->state = I2CS_STATE_NONE; if(i2cs->reset_callback) @@ -68,14 +68,6 @@ ISR(twiX(_TWIS_vect)) { return; } - else if(status & TWI_SLAVE_COLL_bm) { - // collision happened - i2cs->state = I2CS_STATE_NONE; - if(i2cs->reset_callback) - i2cs->reset_callback(); - return; - } - else if(status & TWI_SLAVE_APIF_bm) { // address / stop interrupt @@ -93,16 +85,16 @@ ISR(twiX(_TWIS_vect)) { // master read operation i2cs->state = I2CS_STATE_READ; - if(i2cs->send_callback) { + if(i2cs->prepare_send_callback) { i2cs->sent_bytes = 0; // ask user to provision send buffer - int rsz = i2cs->send_callback(i2cs->send_buffer, + uint8_t rsz = i2cs->prepare_send_callback(i2cs->send_buffer, sizeof(i2cs->send_buffer)); if(rsz > 0) { // user got some data to send - i2cs->bytes_to_send = MIN(rsz,I2CS_SEND_BUFFER_SIZE); + i2cs->bytes_to_send = MIN(rsz, sizeof(i2cs->send_buffer)); // ACK TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; return; diff --git a/modules/i2c/slavex.inc.h b/modules/i2c/slavex.inc.h index a40b10e..9189b4a 100644 --- a/modules/i2c/slavex.inc.h +++ b/modules/i2c/slavex.inc.h @@ -4,17 +4,21 @@ //@{ /** * @file - * @brief I2C definitions + * @brief I2C slave definitions */ #define i2cX(s) X_(i2c,s) // I2cX singleton extern i2cs_t i2cX(); -void i2cX(s_register_send_callback)(i2cs_send_callback_t f); +/** @brief Register f to be called whenever a master-read operation was requested and user need + * to provision the send buffer */ +void i2cX(s_register_prepare_send_callback)(i2cs_prepare_send_callback_t f); +/** @brief Register f to be called whenever a master-write operation as finished */ void i2cX(s_register_recv_callback)(i2cs_recv_callback_t f); +/** @brief Register f to be called whenever the i2c transaction was terminated (on STOP or ERROR) */ void i2cX(s_register_reset_callback)(i2cs_reset_callback_t f); #undef i2cX From 258733f90c4c29831a226aaa4c95223d6a0474b8 Mon Sep 17 00:00:00 2001 From: JD Date: Fri, 1 Jun 2018 13:33:31 +0200 Subject: [PATCH 8/8] i2cs: more fixes from PR --- modules/i2c/i2c.h | 2 ++ modules/i2c/slavex.inc.c | 24 ++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/modules/i2c/i2c.h b/modules/i2c/i2c.h index 58c0ef6..b27c458 100644 --- a/modules/i2c/i2c.h +++ b/modules/i2c/i2c.h @@ -14,6 +14,7 @@ #include #include "i2c_config.h" + #ifdef DOXYGEN /// I2C master state @@ -162,5 +163,6 @@ int8_t i2cm_send(i2cm_t *m, uint8_t addr, const uint8_t *data, uint8_t n); */ int8_t i2cm_recv(i2cm_t *m, uint8_t addr, uint8_t *data, uint8_t n); + #endif //@} diff --git a/modules/i2c/slavex.inc.c b/modules/i2c/slavex.inc.c index 5f9e24f..d0b457b 100644 --- a/modules/i2c/slavex.inc.c +++ b/modules/i2c/slavex.inc.c @@ -18,7 +18,8 @@ // declare i2cX singleton i2cs_t i2cX(); -void i2cX(_init)(void) { +void i2cX(_init)(void) +{ i2cX().state = I2CS_STATE_NONE; @@ -35,26 +36,30 @@ void i2cX(_init)(void) { TWIX.SLAVE.ADDR = I2CX(_ADDRESS) << 1; } -void i2cX(s_register_reset_callback)(i2cs_reset_callback_t f) { +void i2cX(s_register_reset_callback)(i2cs_reset_callback_t f) +{ INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { i2cX().reset_callback = f; } } -void i2cX(s_register_recv_callback)(i2cs_recv_callback_t f) { +void i2cX(s_register_recv_callback)(i2cs_recv_callback_t f) +{ INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { i2cX().recv_callback = f; } } -void i2cX(s_register_prepare_send_callback)(i2cs_prepare_send_callback_t f) { +void i2cX(s_register_prepare_send_callback)(i2cs_prepare_send_callback_t f) +{ INTLVL_DISABLE_BLOCK(I2CX(_INTLVL)) { i2cX().prepare_send_callback = f; } } // Interrupt handler -ISR(twiX(_TWIS_vect)) { +ISR(twiX(_TWIS_vect)) +{ i2cs_t *i2cs = &i2cX(); @@ -63,8 +68,9 @@ ISR(twiX(_TWIS_vect)) { if(status & TWI_SLAVE_BUSERR_bm || status & TWI_SLAVE_COLL_bm) { // bus error happened i2cs->state = I2CS_STATE_NONE; - if(i2cs->reset_callback) + if(i2cs->reset_callback) { i2cs->reset_callback(); + } return; } @@ -122,8 +128,9 @@ ISR(twiX(_TWIS_vect)) { TWIX.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; i2cs->state = I2CS_STATE_NONE; - if(i2cs->reset_callback) + if(i2cs->reset_callback) { i2cs->reset_callback(); + } return; } } @@ -179,8 +186,9 @@ ISR(twiX(_TWIS_vect)) { i2cs->recvd_bytes = 0; i2cs->sent_bytes = 0; // reset client-side state - if(i2cs->reset_callback) + if(i2cs->reset_callback) { i2cs->reset_callback(); + } } #undef I2CX