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. 

Comments

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.
Anonymous said…
Thank you for your help.
I tried to use this function to read the raw angle from my AS5600, but I just received 0. Can you imagine why?
misan said…
Have you tried one of the Arduino libraries? This is what I would try first.
I need to connect 4 magnet encoders to one Arduino UNO, that's why I'm trying to use de SoftI2CMaster.h. I want to use unconventional pins for I2C communication.
misan said…
That is what my post was about. My guess is that my code is giving you a zero value all the time. I have no idea why. Maybe changes made to the library since I have used it. Maybe you no longer need to shift the address to the left one bit?

Popular posts from this blog

VFD control with Arduino using RS485 link

How to get sinusoidal s-curve for a stepper motor

Stepper motor step signal timing calculation