diff options
| author | flabbergast <s3+flabbergast@sdfeu.org> | 2016-04-19 21:51:34 +0100 | 
|---|---|---|
| committer | flabbergast <s3+flabbergast@sdfeu.org> | 2016-04-25 11:53:55 +0100 | 
| commit | 9107b150b0d1fd5a2bdcc080b3493aefd8c56b46 (patch) | |
| tree | 80f4134a89d7abc457d887d826124da4951d95d1 | |
| parent | 2897589bf3b8fbbc2bfbda787bd42aa6b71b7bff (diff) | |
| download | ChibiOS-Contrib-9107b150b0d1fd5a2bdcc080b3493aefd8c56b46.tar.gz ChibiOS-Contrib-9107b150b0d1fd5a2bdcc080b3493aefd8c56b46.tar.bz2 ChibiOS-Contrib-9107b150b0d1fd5a2bdcc080b3493aefd8c56b46.zip  | |
[KINETIS] Add I2C workaround for KL27Z.
| -rw-r--r-- | os/hal/ports/KINETIS/LLD/hal_i2c_lld.c | 67 | ||||
| -rw-r--r-- | os/hal/ports/KINETIS/LLD/hal_i2c_lld.h | 10 | 
2 files changed, 74 insertions, 3 deletions
diff --git a/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c b/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c index ce59627..c6b3d11 100644 --- a/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c +++ b/os/hal/ports/KINETIS/LLD/hal_i2c_lld.c @@ -127,8 +127,20 @@ static void serve_interrupt(I2CDriver *i2cp) {        i2c->S |= I2Cx_S_ARBL;
        /* TODO: may need to do more here, reset bus? */
        /* Perhaps clear MST? */
 +    }
 +
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +    else if ((i2cp->rsta_workaround == RSTA_WORKAROUND_ON) && (i2cp->i2c->FLT & I2Cx_FLT_STARTF)) {
 +      i2cp->rsta_workaround = RSTA_WORKAROUND_OFF;
 +      /* clear+disable STARTF/STOPF interrupts and wake up the thread */
 +      i2cp->i2c->FLT |= I2Cx_FLT_STOPF|I2Cx_FLT_STARTF;
 +      i2cp->i2c->FLT &= ~I2Cx_FLT_SSIE;
 +      i2c->S |= I2Cx_S_IICIF;
 +      _i2c_wakeup_isr(i2cp);
 +    }
 +#endif /* KL27Z RST workaround */
 -    } else if (i2c->S & I2Cx_S_TCF) {
 +    else if (i2c->S & I2Cx_S_TCF) {
        /* just completed byte transfer */
        if (i2c->C1 & I2Cx_C1_TX) {
          /* the byte was transmitted */
 @@ -213,7 +225,6 @@ static void serve_interrupt(I2CDriver *i2cp) {        }
      } /* possibly check other interrupt flags here */
 -
    } else {
      /* slave */
 @@ -379,6 +390,10 @@ static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,    i2cp->rxbytes = rxbytes;
    i2cp->rxidx = 0;
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +  i2cp->rsta_workaround = RSTA_WORKAROUND_OFF;
 +#endif /* KL27Z RST workaround */
 +
    /* clear status flags */
  #if defined(I2Cx_FLT_STOPF) /* extra flags on KL26Z and KL27Z */
    i2cp->i2c->FLT |= I2Cx_FLT_STOPF;
 @@ -391,8 +406,34 @@ static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,    /* acquire the bus */
    /* check to see if we already have the bus */
    if(i2cp->i2c->C1 & I2Cx_C1_MST) {
 +
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +    /* need to wait for STARTF interrupt after issuing repeated start,
 +     * otherwise the double buffering mechanism sends the last sent byte
 +     * instead of the slave address.
 +     * https://community.freescale.com/thread/377611
 +     */
 +    i2cp->rsta_workaround = RSTA_WORKAROUND_ON;
 +    /* clear any interrupt bits and enable STARTF/STOPF interrupts */
 +    i2cp->i2c->FLT |= I2Cx_FLT_STOPF|I2Cx_FLT_STARTF;
 +    i2cp->i2c->S |= I2Cx_S_IICIF|I2Cx_S_ARBL;
 +    i2cp->i2c->FLT |= I2Cx_FLT_SSIE;
 +#endif /* KL27Z RST workaround */
 +
      /* send repeated start */
      i2cp->i2c->C1 |= I2Cx_C1_RSTA | I2Cx_C1_TX;
 +
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +    /* wait for the STARTF interrupt */
 +    msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
 +    /* abort if this didn't go well (timed out) */
 +    if (msg != MSG_OK) {
 +      /* release bus - RX mode, send STOP */
 +      i2cp->i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
 +      return msg;
 +    }
 +#endif /* KL27Z RST workaround */
 +
    } else {
      /* unlock during the wait, so that tasks with
       * higher priority can get attention */
 @@ -434,8 +475,30 @@ static inline msg_t _i2c_txrx_timeout(I2CDriver *i2cp, i2caddr_t addr,    /* the transmitting (or receiving if no transmission) phase has finished,
     * do we expect to receive something? */
    if (msg == MSG_OK && rxbuf != NULL && rxbytes > 0 && i2cp->rxidx < rxbytes) {
 +
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +    /* the same KL27Z RST workaround as above */
 +    i2cp->rsta_workaround = RSTA_WORKAROUND_ON;
 +    /* clear any interrupt bits and enable STARTF/STOPF interrupts */
 +    i2cp->i2c->FLT |= I2Cx_FLT_STOPF|I2Cx_FLT_STARTF;
 +    i2cp->i2c->S |= I2Cx_S_IICIF|I2Cx_S_ARBL;
 +    i2cp->i2c->FLT |= I2Cx_FLT_SSIE;
 +#endif /* KL27Z RST workaround */
 +
      /* send repeated start */
      i2cp->i2c->C1 |= I2Cx_C1_RSTA;
 +
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +    /* wait for the STARTF interrupt */
 +    msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout);
 +    /* abort if this didn't go well (timed out) */
 +    if (msg != MSG_OK) {
 +      /* release bus - RX mode, send STOP */
 +      i2cp->i2c->C1 &= ~(I2Cx_C1_TX | I2Cx_C1_MST);
 +      return msg;
 +    }
 +#endif /* KL27Z RST workaround */
 +
      /* FIXME */
      // while (!(i2cp->i2c->S & I2Cx_S_BUSY));
 diff --git a/os/hal/ports/KINETIS/LLD/hal_i2c_lld.h b/os/hal/ports/KINETIS/LLD/hal_i2c_lld.h index 2b25df2..3576b60 100644 --- a/os/hal/ports/KINETIS/LLD/hal_i2c_lld.h +++ b/os/hal/ports/KINETIS/LLD/hal_i2c_lld.h @@ -34,7 +34,11 @@  #define STATE_STOP    0x00
  #define STATE_SEND    0x01
  #define STATE_RECV    0x02
 -#define STATE_DUMMY   0x03
 +
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +#define RSTA_WORKAROUND_OFF    0x00
 +#define RSTA_WORKAROUND_ON     0x01
 +#endif /* KL27Z RST workaround */
  /*===========================================================================*/
  /* Driver pre-compile time settings.                                         */
 @@ -188,6 +192,10 @@ struct I2CDriver {    intstate_t                intstate;
    /* @brief Low-level register access. */
    I2C_TypeDef               *i2c;
 +#if defined(KL27Zxxx) || defined(KL27Zxx) /* KL27Z RST workaround */
 +  /* @brief Auxiliary variable for KL27Z repeated start workaround. */
 +  intstate_t                rsta_workaround;
 +#endif /* KL27Z RST workaround */
  };
  /*===========================================================================*/
  | 
