Skip to content

Commit

Permalink
I2C bus occupation handling
Browse files Browse the repository at this point in the history
* iicmb_fsm: in case of bus occupation is I2C bus released by iicmb
* add iicmb_bus_state to check I2C bus state
* minor comments
  • Loading branch information
andkae committed Feb 9, 2024
1 parent d4bb6dc commit c3e5712
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 35 deletions.
79 changes: 53 additions & 26 deletions software/irq/iicmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,14 +385,22 @@ void iicmb_fsm(t_iicmb *self)
iicmb_printf("__FUNCTION__ = %s\n", __FUNCTION__);
/* read command register */
uint8_t uint8CmdReg = self->iicmb->CMDR; // clears IRQ, and read data
/* check if we are still own the bus
* @see https://github.com/sshuv/iicmb/issues/8#issuecomment-1922086049
*/
if ( (0 != (self->iicmb->CSR & IICMB_CSR_BB)) && (0 == (self->iicmb->CSR & IICMB_CSR_BC)) ) { // bus captured by another master
self->fsm = IICMB_IDLE; // sent to idle
self->error = IICMB_E_BUSOCC; // bus by other master occupied
(void) iicmb_stop_bit(self); // release bus
return; // leave
}
/* read/write/idle */
switch (self->fsm) {
/*
* IDLE States
* nothing to do
*/
case IICMB_IDLE:
iicmb_status_decode(self, uint8CmdReg);
return; // clears only last IRQ after stopbit
/* stop bit succesfull sent? */
case IICMB_WT_IDLE:
Expand Down Expand Up @@ -545,6 +553,7 @@ void iicmb_fsm(t_iicmb *self)
*/
int iicmb_busy(t_iicmb *self)
{
iicmb_printf("__FUNCTION__ = %s\n", __FUNCTION__);
if ( IICMB_IDLE == self->fsm ) {
return 0;
}
Expand All @@ -554,11 +563,12 @@ int iicmb_busy(t_iicmb *self)


/**
* icmb_is_error
* iicmb_is_error
* return ero code
*/
int iicmb_is_error(t_iicmb *self)
{
iicmb_printf("__FUNCTION__ = %s\n", __FUNCTION__);
if ( IICMB_E_NO == self->error ) {
return 0;
}
Expand All @@ -567,6 +577,26 @@ int iicmb_is_error(t_iicmb *self)



/**
* iicmb_bus_state
* check I2C bus state
* @see https://github.com/sshuv/iicmb/issues/8#issuecomment-1922086049
*/
int iicmb_bus_state(t_iicmb *self)
{
iicmb_printf("__FUNCTION__ = %s\n", __FUNCTION__);
if ( 0 != (self->iicmb->CSR & IICMB_CSR_BB) ) { // I2C Bus is busy
if ( 0 == (self->iicmb->CSR & IICMB_CSR_BC) ) { // Bus by other Master captured
return IICMB_EXIT_OCC; // bus occupied
} else { // IICMB owns the bus
return IICMB_EXIT_BUSY; // IICMB transfer active
}
}
return IICMB_EXIT_OK; // I2C bus is free
}



/**
* iicm_write
* I2C write
Expand All @@ -581,6 +611,10 @@ int iicmb_write(t_iicmb *self, uint8_t adr7, void* data, uint16_t len)
if ( IICMB_IDLE != self->fsm ) {
return IICMB_EXIT_BUSY; // iicmb is busy with last request
}
/* check for bus occupation */
if ( (0 != (self->iicmb->CSR & IICMB_CSR_BB)) && (0 == (self->iicmb->CSR & IICMB_CSR_BC)) ) {
return IICMB_EXIT_OCC; // i2c by other master occupied
}
/* set-up next request */
self->error = IICMB_E_NO;
self->uint8Adr = (uint8_t) (adr7 << 1); // prepare address for Read/Write bit set
Expand All @@ -589,14 +623,9 @@ int iicmb_write(t_iicmb *self, uint8_t adr7, void* data, uint16_t len)
self->uint8PtrData = (uint8_t*) data;
self->uint8WrRd = 0; // only read is performed
self->fsm= IICMB_WR_ADR_SET;
/* check for free I2C bus */
if ( 0 == (self->iicmb->CSR & IICMB_CSR_BB) ) { // bus is free
(void) iicmb_start_bit(self); // sent start bit, triggers first IRQ
return IICMB_EXIT_OK; // normale end
}
/* bus not free, wait is needed */
self->fsm = IICMB_IDLE;
return IICMB_EXIT_I2C_OCC; // i2c by other master occupied
/* issue request */
(void) iicmb_start_bit(self); // sent start bit, triggers first IRQ
return IICMB_EXIT_OK; // normal end
}


Expand All @@ -615,6 +644,10 @@ int iicmb_read(t_iicmb *self, uint8_t adr7, void* data, uint16_t len)
if ( IICMB_IDLE != self->fsm ) {
return IICMB_EXIT_BUSY; // iicmb is busy with last request
}
/* check for bus occupation */
if ( (0 != (self->iicmb->CSR & IICMB_CSR_BB)) && (0 == (self->iicmb->CSR & IICMB_CSR_BC)) ) {
return IICMB_EXIT_OCC; // i2c by other master occupied
}
/* set-up next request */
self->error = IICMB_E_NO;
self->uint8Adr = (uint8_t) (adr7 << 1);
Expand All @@ -623,14 +656,9 @@ int iicmb_read(t_iicmb *self, uint8_t adr7, void* data, uint16_t len)
self->uint8PtrData = (uint8_t*) data;
self->uint8WrRd = 0; // only read is performed
self->fsm = IICMB_RD_ADR_SET;
/* check for free I2C bus */
if ( 0 == (self->iicmb->CSR & IICMB_CSR_BB) ) { // bus is free
(void) iicmb_start_bit(self); // sent start bit, triggers first IRQ
return IICMB_EXIT_OK; // normal end
}
/* bus not free, wait is needed */
self->fsm = IICMB_IDLE;
return IICMB_EXIT_I2C_OCC; // i2c by other master occupied
/* issue request */
(void) iicmb_start_bit(self); // sent start bit, triggers first IRQ
return IICMB_EXIT_OK; // normal end
}


Expand All @@ -649,6 +677,10 @@ int iicmb_wr_rd(t_iicmb *self, uint8_t adr7, void* data, uint16_t wrLen, uint16_
if ( IICMB_IDLE != self->fsm ) {
return IICMB_EXIT_BUSY; // iicmb is busy with last request
}
/* check for bus occupation */
if ( (0 != (self->iicmb->CSR & IICMB_CSR_BB)) && (0 == (self->iicmb->CSR & IICMB_CSR_BC)) ) {
return IICMB_EXIT_OCC; // i2c by other master occupied
}
/* except only write-read transfers, otherwise use dedicated function */
if ( !((0 != wrLen) && (0 != rdLen)) ) {
return IICMB_EXIT_ERROR;
Expand All @@ -664,12 +696,7 @@ int iicmb_wr_rd(t_iicmb *self, uint8_t adr7, void* data, uint16_t wrLen, uint16_
self->uint16RdByteIs = 0;
self->uint8WrRd = 1; // read after write is performed
self->fsm = IICMB_WR_ADR_SET;
/* check for free I2C bus */
if ( 0 == (self->iicmb->CSR & IICMB_CSR_BB) ) { // bus is free
(void) iicmb_start_bit(self); // sent start bit, triggers first IRQ
return IICMB_EXIT_OK; // normale end
}
/* bus not free, wait is needed */
self->fsm = IICMB_IDLE;
return IICMB_EXIT_I2C_OCC; // i2c by other master occupied
/* issue request */
(void) iicmb_start_bit(self); // sent start bit, triggers first IRQ
return IICMB_EXIT_OK; // normal end
}
39 changes: 30 additions & 9 deletions software/irq/iicmb.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@
* @{
*/
#define IICMB_EXIT_OK (0) /**< Function ended normally */
#define IICMB_EXIT_BUSY (1) /**< IICMB busy with last request, please wait */
#define IICMB_EXIT_I2C_OCC (2) /**< I2C bus is occupied by another master, please wait */
#define IICMB_EXIT_BUSY (1<<0) /**< IICMB busy with last request, please wait */
#define IICMB_EXIT_OCC (1<<1) /**< Occupied by another master, please wait */

#define IICMB_EXIT_ERROR (-1) /**< Something went wrong */
/** @} */

Expand Down Expand Up @@ -164,6 +165,7 @@ typedef enum
IICMB_E_IICMB, /**< I2C controller encoutered issue */
IICMB_E_ICTF, /**< Transfer incomplete */
IICMB_E_FSM, /**< non designed path of FSM used */
IICMB_E_BUSOCC, /**< I2C bus occupied by another slave */
IICMB_E_UNKNOWN /**< Something went wrong */
} t_iicmb_ero;

Expand Down Expand Up @@ -323,6 +325,22 @@ int iicmb_is_error(t_iicmb *self);



/** @brief I2C bus state
*
* checks I2C bus state
*
* @param[in,out] self storage element
* @return int state, #I2C_SW_FUNC
* @retval IICMB_EXIT_OK I2C Bus is free
* @retval IICMB_EXIT_BUSY I2C bus is busy caused by IICMB
* @retval IICMB_EXIT_OCC I2C bus is occupied by another master
* @since 2024-02-09
* @author Andreas Kaeberlein
*/
int iicmb_bus_state(t_iicmb *self);



/** @brief write
*
* write to I2C slave
Expand All @@ -332,8 +350,9 @@ int iicmb_is_error(t_iicmb *self);
* @param[in] *data data buffer
* @param[in] len size of *data in byte
* @return int state
* @retval 0 OK: Transfer request accepted
* @retval 1 FAIL: Transfer request not accepted, wait for finish before next request
* @retval IICMB_EXIT_OK OK: Transfer request accepted
* @retval IICMB_EXIT_BUSY FAIL: Transfer request not accepted, wait for finish before next request
* @retval IICMB_EXIT_OCC FAIL: I2C bus is occupied by another master
* @since 2022-06-14
* @author Andreas Kaeberlein
*/
Expand All @@ -350,8 +369,9 @@ int iicmb_write(t_iicmb *self, uint8_t adr7, void* data, uint16_t len);
* @param[out] *data data buffer
* @param[in] len size of *data in byte
* @return int state
* @retval 0 OK: Transfer request accepted
* @retval 1 FAIL: Transfer request not accepted, wait for finish before next request
* @retval IICMB_EXIT_OK OK: Transfer request accepted
* @retval IICMB_EXIT_BUSY FAIL: Transfer request not accepted, wait for finish before next request
* @retval IICMB_EXIT_OCC FAIL: I2C bus is occupied by another master
* @since 2022-06-14
* @author Andreas Kaeberlein
*/
Expand All @@ -369,9 +389,10 @@ int iicmb_read(t_iicmb *self, uint8_t adr7, void* data, uint16_t len);
* @param[in] wrLen number of bytes to write in *data
* @param[in] rdLen number of bytes to read in *data
* @return int state
* @retval 0 OK: Transfer request accepted
* @retval 1 FAIL: Transfer request not accepted, wait for finish before next request
* @retval 2 FAIL: Read or Write only requested
* @retval IICMB_EXIT_OK OK: Transfer request accepted
* @retval IICMB_EXIT_BUSY FAIL: Transfer request not accepted, wait for finish before next request
* @retval IICMB_EXIT_OCC FAIL: I2C bus is occupied by another master
* @retval IICMB_EXIT_ERROR FAIL: RSomething went wrong
* @since 2022-06-14
* @author Andreas Kaeberlein
*/
Expand Down

0 comments on commit c3e5712

Please sign in to comment.