Fighting with computers

Computers are not always friendly.

Tuesday, March 29, 2016

Software I2C for Arduino

While the Wire library allows you to get I2C working right off the bat with Arduino, there are times when the built-in Wire library does not do it. For some people this happens because they need to do a repeated start condition or to receive a large number of bytes, tasks that seemed to be not possible with Wire library. But for me the problem this time is a bit odd: I had to overcome the limitation of each I2C device to have a different address.

It turns out that I am using a magnetic encoder chip that responds to a given address that cannot be changed. Because I want to be able to access at least two similar encoders from on Arduino board I find myself in the unlikely situation where I have to use two different I2C buses, one per device. However, I2C interface was designed to do the exact opposite thing, allowing several devices to communicate over the same bus (provided each one had a different address of course).

As second detail I have been interested is to speed up the communication, as the current request takes almost 1 millisecond (to read a 16 bit number). It may not seem much but as I wanted to keep a constant frequency of 1Khz on my main loop, that reading time was definitely too long. When using the Wire library I learned that setting TWR=1 will offer me the fastest communication of about 170 microseconds, so that problem was also taken care of. But I still needed to get a I2C second bus running.

There are several Soft I2C libraries for Arduino, but the one that worked for me is the SoftI2CMaster, which I could see is available as simple C library or as C++ class wrapping it all nicely. I settled with the former that hopefully gives me an edge in communication time. It all should had been very simple if somebody told me I should shift left one bit the address value, but because I did not know that, I wasted a couple of hours till I figured that out.

Once set properly, the library allowed me to read one sensor value in 164 microseconds. The code below reads one angle value from the AS5600 sensor using this library.


So now, even if I read two values, one from each sensor, it will take me less that 400 microseconds, leaving room for additional processing while still keeping my 1Khz loop time. Now I only need to figure the same out for other platforms like ESP8266, Nucleo STM32 and MKR1000. 

2 Comments:

  • At 10:02 am, Blogger Sancho said…

    I find this a SERIOUS design flaw of the chip.
    The DIR input could be done using a single bit in one of the registers and they can implement address pin - there are even i2c devices, that use single pin for 4+ addresses (using different voltage input values).
    I'd suggest to contact AMS and give them feedback regarding the design :(
    Nice idea how to overcome the limitation, though.

     
  • At 10:28 am, Anonymous Anonymous said…

    Thank you for your help.

     

Post a Comment

<< Home