You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2018/12/04 13:10:22 UTC

[mynewt-core] 04/04: hw/mcu/nordic: Fix check for unresponsive TWI on read_op

This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit ce9e4c95d14a0b9d3c58b67c3ade181a15c16fed
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Fri Nov 30 16:12:57 2018 +0100

    hw/mcu/nordic: Fix check for unresponsive TWI on read_op
    
    When reading single byte on TWI it may happen that checks for SCL
    line will start after this byte is received so SCL will never go to
    low state because activity already happened on bus. To avoid this we'll
    also check BB event which will also indicate that some activity on bus
    happened.
    
    For write ops there's no problem since after writing START and address
    on bus controller will keep SCL low until we write 1st byte of data to
    TXD.
---
 hw/mcu/nordic/nrf52xxx/src/hal_i2c.c | 63 +++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 29 deletions(-)

diff --git a/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c b/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c
index 301dcd5..cb23a0f 100644
--- a/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c
+++ b/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c
@@ -413,35 +413,10 @@ hal_i2c_config(uint8_t i2c_num, const struct hal_i2c_settings *cfg)
     return 0;
 }
 
-static bool
-hal_i2c_check_scl(int pin_scl)
-{
-    uint32_t end_ticks;
-    int toggled = 0;
-
-    /*
-     * Wait a bit for low state on SCL as this indicates that controller has
-     * started writing something one the bus. It does not matter whether low
-     * state is due to START condition on bus or one of clock cycles when
-     * writing address on bus - in any case this means controller seems to
-     * write something on bus.
-     */
-
-    end_ticks = os_cputime_get32() +
-                os_cputime_usecs_to_ticks(MYNEWT_VAL(MCU_I2C_RECOVERY_DELAY_USEC));
-
-    do {
-        if (!hal_gpio_read(pin_scl)) {
-            toggled = 1;
-        }
-    } while (!toggled && CPUTIME_LT(os_cputime_get32(), end_ticks));
-
-    return toggled;
-}
-
 static inline void
 hal_i2c_trigger_start(NRF_TWI_Type *twi, __O uint32_t *task)
 {
+    uint32_t end_ticks;
     int retry = 2;
 
     /*
@@ -456,10 +431,40 @@ hal_i2c_trigger_start(NRF_TWI_Type *twi, __O uint32_t *task)
      */
 
     do {
+        twi->EVENTS_BB = 0;
         *task = 1;
-        if (hal_i2c_check_scl(twi->PSELSCL)) {
-            break;
-        }
+
+        /*
+         * Wait a bit for low state on SCL as this indicates that controller has
+         * started writing something one the bus. It does not matter whether low
+         * state is due to START condition on bus or one of clock cycles when
+         * writing address on bus - in any case this means controller seems to
+         * write something on bus.
+         */
+
+        end_ticks = os_cputime_get32() +
+                    os_cputime_usecs_to_ticks(MYNEWT_VAL(MCU_I2C_RECOVERY_DELAY_USEC));
+
+        do {
+            /*
+             * For write op controller will always keep SCL low after writing
+             * START and address on bus and until we write 1st byte of data to
+             * TXD. This allows to reliably detect activity on bus by using SCL
+             * only.
+             *
+             * For read op with only single byte to read it's possible that it
+             * will be read before we start checking SCL line and thus we'll
+             * never detect any activity this way. To avoid this, we'll also
+             * check BB event which in such case indicates that some activity
+             * on bus happened. This won't work for writes since BB is generated
+             * after byte is transmitted, so we need to use both methods to be
+             * able to handle unresponsive TWI controller for both reads and
+             * writes.
+             */
+            if (!hal_gpio_read(twi->PSELSCL) || twi->EVENTS_BB) {
+                return;
+            }
+        } while (CPUTIME_LT(os_cputime_get32(), end_ticks));
 
         twi->ENABLE = TWI_ENABLE_ENABLE_Disabled;
         /*