Left here for archival purposes.

User avatar
By sancho
#3545 Hello.

I used the latest nodeMCU firmware and coded a small program to work with i2c device.
I have MCP23017 connected to GPIO0 and GPIO2 (data+clock).
I connected few leds to port A of MCP23017 and set the address to 0x20.
I tried few writes and everything was just fine.
But than I coded a simple main.lua like this:
Code: Select all    id=0
    sda=8
    scl=9

    -- initialize i2c, set pin1 as sda, set pin0 as scl
    i2c.setup(id,sda,scl,i2c.SLOW)

    -- user defined function: read from reg_addr content of dev_addr
    function read_reg(dev_addr, reg_addr)
      i2c.start(id)
      i2c.address(id, dev_addr ,i2c.TRANSMITTER)
      i2c.write(id,reg_addr)
      i2c.stop(id)
      i2c.start(id)
      i2c.address(id, dev_addr,i2c.RECEIVER)
      c=i2c.read(id,1)
      i2c.stop(id)
      return c
    end

    function write_reg(dev_addr, reg_addr, reg_val)
      i2c.start(id)
      i2c.address(id, dev_addr, i2c.TRANSMITTER)
      i2c.write(id, reg_addr)
      i2c.write(id, reg_val)
      i2c.stop(id)
    end

    -- get content of register 0xAA of device 0x77
    write_reg(0x20, 0x00, 0x00) -- set bank A to output
    for i=0,255 do
      print(i)
      write_reg(0x20, 0x12, i)
    end

When executed, it works as expected.
But than I added a delay after the writing to the i2c, before the end statement of the for loop, so now the for loop looks like this:
Code: Select all    for i=0,255 do
      print("Setting bank A to value " .. i)
      write_reg(0x20, 0x12, i)
      tmr.delay(200000)
    end

With this delay, the script runs until 10-15 and than the device restarts.
Even when removing the delay and with the longer "print" statement, the script runs only until i=~100.
Shortening the print statement and removing the delay, the script again runs until 255.
Any advice, what am I doing wrong?
User avatar
By gerardwr
#3549 Great that you get the I2C running and thanks for sharing it.

The tmr.delay is probably hampering you, it's a known problem. It seems that the WDT timer of the ESP kicks in after a delay of "some" seconds. Read that this is caused by the SDK, not nodeMcu. Some improvements were made to the latest versions of nodeMcu in this respect.

Common solution is to replace tmrdelay with a timer function that fires every #secs.

BTW : The use of the FOR loop is also known to have a similar result, and cause. Just a friendly warning :D

Hope this helps.
User avatar
By sancho
#3551 Thanks for the hint.
I modified the script a bit:
Code: Select all    -- get content of register 0xAA of device 0x77
    write_reg(0x20, 0x00, 0x00) -- set bank A to output
    i=0
    print("")

    tmr.alarm(250,1,function()
      write_reg(0x20, 0x12, i)
      print("I = " .. i)
      if (i == 255) then
        tmr.stop()
      end
      i = i + 1
      end
    )

Now it runs smoothly until 255 :)
However, the for loop is quite important for me, so is the delay.
Is there any chance to fix it somehow?
User avatar
By gerardwr
#3553
sancho wrote:Now it runs smoothly until 255 :)
However, the for loop is quite important for me, so is the delay.
Is there any chance to fix it somehow?


I'm just here to declare your problems, now you're asking me for solutions ……. ;)

I guess a real fix can only be done in the SDK and/or Lua firmware.

I saw somewhere on this board a "workaround" with a statement to reset the WDT timer. But where ….?

Got it : look in the nodeMCU API description, there's an example there. I believe there are some posts from zeroday on this topic, search the forum for it:
Code: Select alltmr.wdclr()


Good luck, let us know how it goes, keep posting your working code, that helps others.