Skip to content

Commit

Permalink
I2C Mux feature
Browse files Browse the repository at this point in the history
* I2C Mux feature introduced
* xI2CWrite/xI2CRead mutex handling changed
* board_defs.h modified
  • Loading branch information
qermit committed Sep 7, 2015
1 parent 74b619c commit 49c5959
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 17 deletions.
28 changes: 25 additions & 3 deletions inc/board_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,29 @@
#define BOARD_DEFS_H_

//#ifndef BOARD
#define BOARD MBED
#define BOARD_MBED 0
#define BOARD_AFC 1
#define BOARD_AFCK 2

#ifdef BOARD
#undef BOARD
#endif

#define BOARD_VERSION_MBED 1

#define BOARD_VERSION_AFC_V1 1
#define BOARD_VERSION_AFC_V2 2
#define BOARD_VERSION_AFC_V3 3
#define BOARD_VERSION_AFC_V3_1 4

#define BOARD BOARD_MBED
#define BOARD_VERSION BOARD_VERSION_AFC_V3


//#endif

#if (BOARD == AFC_V3)
#if (BOARD == BOARD_AFC)
#if (BOARD_VERSION == BOARD_VERSION_AFC_V3)

/* I2C Pins definitions */

Expand Down Expand Up @@ -62,7 +81,8 @@
#define ledRED_PORT 1
#define ledRED_PIN 25

#elif (BOARD == MBED)
#endif
#elif (BOARD == BOARD_MBED)

/* I2C Pins definitions */

Expand Down Expand Up @@ -95,6 +115,8 @@
#define ledRED_PORT 1
#define ledRED_PIN 21

#else
#error "Unknown board"
#endif

#endif
46 changes: 45 additions & 1 deletion inc/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@
*/
#define IPMBL_TABLE_SIZE 27

struct xI2C_Config;
typedef void (*MuxHandler_t)(I2C_ID_T i2c_id, struct xI2C_Config* i2c_config, int8_t value);


/*! @brief GA pins definition */
typedef enum {
GROUNDED = 0,
Expand Down Expand Up @@ -187,9 +191,11 @@ typedef enum {
i2c_err_SLA_W_SENT_NACK, /*!< SLA+R address transmitted, but no response has been received.
* Slave is either busy or unreachable.
* @see #I2C_STAT_SLA_W_SENT_NACK */
i2c_err_DATA_SENT_NACK /*!< DATA byte has been transmitted, but NACK has returned.
i2c_err_DATA_SENT_NACK, /*!< DATA byte has been transmitted, but NACK has returned.
* Slave is either busy or unreachable.
* @see #I2C_STAT_DATA_SENT_NACK */
i2c_err_UNKONWN_IFACE, /*!< Unknown interface id (I2C_ID_T i2c_id) */

} i2c_err;

/*! @brief I2C transaction parameter structure */
Expand Down Expand Up @@ -235,6 +241,10 @@ typedef struct xI2C_Config {
uint8_t rx_cnt; /*!< Received bytes counter */
uint8_t tx_cnt; /*!< Transmitted bytes counter */
xI2C_msg msg; /*!< Message body (tx and rx buffers) */
int8_t mux_state; /*!< Mux state, hold information
* -1 unknown state */
MuxHandler_t mux_handler; /*!< pointer to mux state changer function
* NULL: no mux registered */
} xI2C_Config;

/*! Global I2C Configuration struct array (1 item for each interface) */
Expand Down Expand Up @@ -380,4 +390,38 @@ uint8_t xI2CSlaveTransfer ( I2C_ID_T i2c_id, uint8_t * rx_data, uint32_t timeout
*/
uint8_t get_ipmb_addr( void );


/*! @brief Changes I2C mux state if registered
*
* @param i2c_id: Interface ID ( I2C0, I2C1, I2C2 ).
* @param value: new mux value.
*
* @param xBlockTime The time in ticks to wait for the semaphore to become
* available. The macro portTICK_PERIOD_MS can be used to convert this to a
* real time. A block time of zero can be used to poll the semaphore. A block
* time of portMAX_DELAY can be used to block indefinitely (provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).
*
* @return I2C Driver error
*
*/
i2c_err xI2CMuxSetState(I2C_ID_T i2c_id, int8_t value, TickType_t xBlockTime);

/*! @brief Registers i2c mux function handler
*
* @param i2c_id: Interface ID ( I2C0, I2C1, I2C2 ).
* @param handler: pointer to handler function.
*
* @param xBlockTime The time in ticks to wait for the semaphore to become
* available. The macro portTICK_PERIOD_MS can be used to convert this to a
* real time. A block time of zero can be used to poll the semaphore. A block
* time of portMAX_DELAY can be used to block indefinitely (provided
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h).
*
* @return I2C Driver error
*
*/
i2c_err xI2CMuxRegister(I2C_ID_T i2c_id, MuxHandler_t handler, TickType_t xBlockTime);


#endif /*I2C_H_*/
74 changes: 61 additions & 13 deletions src/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ xI2C_Config i2c_cfg[] = {
.slave_task_id = NULL,
.rx_cnt = 0,
.tx_cnt = 0,
.mux_handler = NULL,
.mux_state = -1,
},
{
.reg = LPC_I2C1,
Expand All @@ -83,6 +85,8 @@ xI2C_Config i2c_cfg[] = {
.slave_task_id = NULL,
.rx_cnt = 0,
.tx_cnt = 0,
.mux_handler = NULL,
.mux_state = -1,
},
{
.reg = LPC_I2C2,
Expand All @@ -99,16 +103,20 @@ xI2C_Config i2c_cfg[] = {
.slave_task_id = NULL,
.rx_cnt = 0,
.tx_cnt = 0,
.mux_handler = NULL,
.mux_state = -1,
}
};

#define I2C_IFACE_COUNT (sizeof(i2c_cfg)/sizeof(xI2C_Config))

/*! @brief Array of mutexes to access #i2c_cfg global struct
*
* Each I2C interface has its own mutex and it must be taken
* before setting/reading any field from #i2c_cfg struct,
* since it's used by multiple tasks simultaneously
*/
static SemaphoreHandle_t I2C_mutex[3];
static SemaphoreHandle_t I2C_mutex[I2C_IFACE_COUNT];

void vI2C_ISR( uint8_t i2c_id );

Expand Down Expand Up @@ -341,6 +349,7 @@ void vI2CInit( I2C_ID_T i2c_id, I2C_Mode mode )

} /* End of vI2C_Init */


i2c_err xI2CWrite( I2C_ID_T i2c_id, uint8_t addr, uint8_t * tx_data, uint8_t tx_len )
{
/* Checks if the message will fit in our buffer */
Expand All @@ -349,7 +358,9 @@ i2c_err xI2CWrite( I2C_ID_T i2c_id, uint8_t addr, uint8_t * tx_data, uint8_t tx_
}

/* Take the mutex to access the shared memory */
if (xSemaphoreTake( I2C_mutex[i2c_id], 10 ) == pdTRUE) {
if (xSemaphoreTake( I2C_mutex[i2c_id], 10 ) == pdFALSE) {
return i2c_err_FAILURE;
}

/* Populate the i2c config struct */
i2c_cfg[i2c_id].msg.i2c_id = i2c_id;
Expand All @@ -359,10 +370,6 @@ i2c_err xI2CWrite( I2C_ID_T i2c_id, uint8_t addr, uint8_t * tx_data, uint8_t tx_
i2c_cfg[i2c_id].msg.rx_len = 0;
i2c_cfg[i2c_id].master_task_id = xTaskGetCurrentTaskHandle();

xSemaphoreGive( I2C_mutex[i2c_id] );
} else {
return i2c_err_FAILURE;
}

/* Trigger the i2c interruption */
/* @bug Is it safe to set the flag right now? Won't it stop another ongoing message that is being received for example? */
Expand All @@ -371,26 +378,27 @@ i2c_err xI2CWrite( I2C_ID_T i2c_id, uint8_t addr, uint8_t * tx_data, uint8_t tx_

if ( ulTaskNotifyTake( pdTRUE, portMAX_DELAY ) == pdTRUE ){
/* Include the error in i2c_cfg global structure */
xSemaphoreGive( I2C_mutex[i2c_id] );

return i2c_cfg[i2c_id].msg.error;
}

/* Should not get here, so return failure */
return i2c_err_FAILURE;
xSemaphoreGive( I2C_mutex[i2c_id] );
}

i2c_err xI2CRead( I2C_ID_T i2c_id, uint8_t addr, uint8_t * rx_data, uint8_t rx_len )
{
/* Take the mutex to access shared memory */
xSemaphoreTake( I2C_mutex[i2c_id], portMAX_DELAY );
if (xSemaphoreTake( I2C_mutex[i2c_id], portMAX_DELAY ) == pdFALSE ) {
return i2c_err_FAILURE;
}

i2c_cfg[i2c_id].msg.i2c_id = i2c_id;
i2c_cfg[i2c_id].msg.addr = addr;
i2c_cfg[i2c_id].msg.tx_len = 0;
i2c_cfg[i2c_id].msg.rx_len = rx_len;
i2c_cfg[i2c_id].master_task_id = xTaskGetCurrentTaskHandle();

xSemaphoreGive( I2C_mutex[i2c_id] );

/* Trigger the i2c interruption */
/* Is it safe to set the flag right now? Won't it stop another ongoing message that is being received for example? */
I2CCONSET( i2c_id, ( I2C_I2EN | I2C_STA ) );
Expand All @@ -401,12 +409,14 @@ i2c_err xI2CRead( I2C_ID_T i2c_id, uint8_t addr, uint8_t * rx_data, uint8_t rx_l
configASSERT(rx_data);
configASSERT(i2c_cfg[i2c_id].msg.rx_data);

xSemaphoreTake( I2C_mutex[i2c_id], portMAX_DELAY );
/* Copy the received message to the given pointer */
memcpy (rx_data, i2c_cfg[i2c_id].msg.rx_data, i2c_cfg[i2c_id].msg.rx_len );
xSemaphoreGive( I2C_mutex[i2c_id] );
}

xSemaphoreGive( I2C_mutex[i2c_id] );

return i2c_cfg[i2c_id].msg.error;

}

uint8_t xI2CSlaveTransfer ( I2C_ID_T i2c_id, uint8_t * rx_data, uint32_t timeout )
Expand Down Expand Up @@ -553,3 +563,41 @@ uint8_t get_ipmb_addr( void )
}
#undef GPIO_GA_DELAY

i2c_err xI2CMuxSetState(I2C_ID_T i2c_id, int8_t value, TickType_t xBlockTime) {
if (i2c_id >= I2C_IFACE_COUNT) return i2c_err_UNKONWN_IFACE;
BaseType_t semaphore_success = pdFALSE;

xI2C_Config *p_i2c_config = &i2c_cfg[i2c_id];

if (xBlockTime != 0) {
semaphore_success = xSemaphoreTake(I2C_mutex[i2c_id], portMAX_DELAY);
if (semaphore_success == pdFALSE) return i2c_err_FAILURE;
}

if (p_i2c_config->mux_handler != NULL && value != p_i2c_config->mux_state) {
p_i2c_config->mux_handler(i2c_id, p_i2c_config, value);
}

if (xBlockTime != 0) xSemaphoreGive(I2C_mutex[i2c_id]);
return i2c_err_SUCCESS;
}


i2c_err xI2CMuxRegister(I2C_ID_T i2c_id, MuxHandler_t handler, TickType_t xBlockTime) {
if (i2c_id >= I2C_IFACE_COUNT) return i2c_err_UNKONWN_IFACE;
BaseType_t semaphore_success = pdFALSE;

xI2C_Config *p_i2c_config = &i2c_cfg[i2c_id];

if (xBlockTime != 0) {
semaphore_success = xSemaphoreTake(I2C_mutex[i2c_id], portMAX_DELAY);
if (semaphore_success == pdFALSE) return i2c_err_FAILURE;
}

p_i2c_config->mux_handler = handler;
p_i2c_config->mux_state = -1;

if (xBlockTime != 0) xSemaphoreGive(I2C_mutex[i2c_id]);
return i2c_err_SUCCESS;
}

0 comments on commit 49c5959

Please sign in to comment.