Skip to content

Instantly share code, notes, and snippets.

@hierophect
Created February 23, 2021 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hierophect/f3b0752ee854880971ec2e33b991915f to your computer and use it in GitHub Desktop.
Save hierophect/f3b0752ee854880971ec2e33b991915f to your computer and use it in GitHub Desktop.
Notes about I2C failures

Problem: as per #4046, (and maybe #4079), using board.I2C() causes a hard reboot after the first run. It doesn't show an error message or anything.

  • Test sketch:

    import board
    import busio
    i2c = board.I2C()
    #i2c = busio.I2C(board.IO5, board.IO6)
    def printdevices():
        i2c.try_lock()
        devices = i2c.scan()
        print("I2C devices:", len(devices))
        for device in devices:
            print(hex(device))
        i2c.unlock()
    printdevices()
  • Note, the WROVER doesn't normally have a board.I2C so I added one with arbitrary pins 5 and 6

  • JTAG debugging:

    • JTAG had a few hiccups, needed VCC, and also the addition of never_resets on 39 through 42

    • I see the target reset, but it doesn't ever hit a reset controller so a where is not possible by default. The below, which appears every time the I2C sketch is run past the first, does not break into GDB

      esp32s2: Debug controller 0 was reset.
      esp32s2: Core 0 was reset.
      
    • How to break on reset so I can find this thing?

  • Recreating issue:

    • Start up chip with reset
    • enable JTAG
    • break on common_hal_busio_i2c_probe but disable it
    • gdb r to restart
    • after sketch is finished, break, enable breakpoint, and then continue. Soft reboot with ctr-d
    • Should fail on the second probe.
  • Weirdness with the return of i2c_cmd_link_create

    • default cmd is 0x3fffc2a0. This stays the same between all of the individual probes within scan()
    • After rebooting, the broken value of cmd is 0x3fffc2b0. This also stays the same
    • This might be a red herring? When using actual pin values instead of board.I2C(), value under reset is still 0x3fffc2b0, but it doesn't fail.
  • Some kinda breakage in the ISR?

    #0  0x4001a8d7 in ?? ()
    #1  0x4003017c in vPortExitCritical (mux=0x3fffc388) at ../../esp-idf/components/freertos/xtensa/port.c:419
    #2  0x40032593 in xQueueGenericSendFromISR (xQueue=0x3fffc33c, pvItemToQueue=<optimized out>, pxHigherPriorityTaskWoken=0x3ffce808, xCopyPosition=<optimized out>)
        at ../../esp-idf/components/freertos/queue.c:1287
    #3  0x4002bd7e in i2c_isr_handler_default (arg=0x3fffc238) at ../../esp-idf/components/driver/i2c.c:463
    #4  0x400294a1 in _xt_lowint1 () at ../../esp-idf/components/freertos/xtensa/xtensa_vectors.S:1105
    #5  0x40031378 in ?? () at ../../esp-idf/components/esp_timer/src/esp_timer_impl_systimer.c:153
    Backtrace stopped: previous frame identical to this frame (corrupt stack?)
    
  • What is different about board.I2C()?

  • Adding i2c_driver_delete() to i2c_reset solves the reset, but it makes the probes fail

    • Returns error 259, which is ESP_ERR_INVALID_STATE, probably from this:

    • I2C_CHECK(p_i2c_obj[i2c_num] != NULL, I2C_DRIVER_NOT_INSTALL_ERR_STR, ESP_ERR_INVALID_STATE);
      
  • Should board.I2C be getting deleted, given the reset? How is this supposed to work?

  • i2c_master_cmd_begin is where things actually have to fail

  • why does mp_load_method_maybe sometimes come up after the debugger is connected?

  • Reverting this PR (by re-enabling the driver delete in I2C) fixes the immediate issue but causes a hang when using WIFI adafruit/circuitpython#3803

    • What is going on during the hang in GDB?

    • Seems to get stuck here:

      esp32s2: Target halted, PC=0x400A1142, debug_reason=00000001
      run_code_py (safe_mode=NO_SAFE_MODE) at ../../main.c:330
      330	        RUN_BACKGROUND_TASKS;
      (gdb) n
      esp32s2: Target halted, PC=0x400A025F, debug_reason=00000001
      331	        if (reload_requested) {
      (gdb) n
      main () at ../../main.c:600
      600	            skip_repl = run_code_py(safe_mode);
      (gdb) n
      esp32s2: Target halted, PC=0x400A028B, debug_reason=00000001
      esp32s2: Target halted, PC=0x400A0291, debug_reason=00000001
      ^Cesp32s2: Target halted, PC=0x400A02F2, debug_reason=00000001
      
      Thread 1 received signal SIGINT, Interrupt.
      
    • This isn't that useful though since it seems to be skipping around a lot, so it's clearly optimized. Re-building in debug mode.

    • Debug mode stays entirely in run_code_py, doesn't show the main.c step, but it still doesn't explain why usb has disconnected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment