Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i2c SLAVE #437

Closed
mik00 opened this issue Nov 13, 2017 · 20 comments
Closed

i2c SLAVE #437

mik00 opened this issue Nov 13, 2017 · 20 comments
Assignees
Milestone

Comments

@mik00
Copy link

mik00 commented Nov 13, 2017

One of the useful features of the Feather (and it's ilk) is that it can be used as one of many I2C slaves. It would be cool if the i2c drivers covered that case.

Thankyou for all the excellent, and hard work you have put into supporting CP.

@tannewt tannewt added this to the Long term milestone Nov 14, 2017
@tannewt
Copy link
Member

tannewt commented Nov 14, 2017

I'm going to mark this long term. We'll have to figure out a sane API for it. We're trying to avoid requiring knowledge of concurrency which could make acting as an I2C slave a bit challenging.

@Anton-2
Copy link

Anton-2 commented Nov 14, 2017

A few days ago, I was sure that I needed I2C Slave on a trinket M0.
Then I discovered the current state of ASF4, and the on going migration of CP to it, and decided that I could do without...

I was thinking of a very simple API : expose a bytearray as a small memory device thu I2C.
The master could read/write bytes on it, and CP would provide (soft) callbacks to know when something was read or written.

This way, there is no python code when the timing is critical. Simple cases could be used without callback by simply polling some location and observing changes done by the master or the slave.

But, clearly, for more complicated tasks concurency will be a subject (eg accessing a multi-byte value while the master is writing it...)

@mik00 Does such a API cover your needs ? I may try to implement it if there is interest, and after trying simpler things with ASF4 first...

@tannewt
Copy link
Member

tannewt commented Nov 14, 2017

@Anton-2 I like that API!

@mik00
Copy link
Author

mik00 commented Nov 14, 2017 via email

@deshipu
Copy link

deshipu commented Nov 27, 2017

@tannewt I think we can avoid concurrency with the slave if we make a blocking method that simply waits for the start condition and the address on the bus. Then you can execute the rest of your loop, read/write all the data you need, and go back to waiting for a command. The clock is stretched while your code runs, of course. I have done something like this on an attiny (where I needed to avoid interrupts to have precise timings), and it works quite well.

This restricts the use cases a bit, because you can't do anything else while waiting for the command. You could however alleviate it a little, by also having a timeout on it, so then you can run your LED animations or whatever else you need, and wait for the I2C commands instead of doing time.sleep in between the frames.

@deshipu
Copy link

deshipu commented Nov 27, 2017

An example program could look like this:

import board
import busio

slave_bus = busio.I2CSlave(sda=board.SDA, scl=board.SCL)
register = 0
registers = [0] * 8

while True:
    with slave_bus.wait(0x11, 0x33, timeout=None) as i2c_request:
        if i2c_request.is_write:
           register = slave_bus.read(1)[0]
        else:
           slave_bus.write(registers[register])

Explanation:

First we define which bus we want to use as the slave, and some helper variables. Then in an infinite loop, we wait for a start condition and one of two addresses (we could have any number of them), with an optional timeout. Once there comes a request, we can process it. A request would have a flag telling if it's a write or read request, and the address for which it was received. Then we can read or write bytes to the bus — there is an ACK sent between every two bytes transmitted. At the end of the context manager, a NACK is sent.

@tannewt
Copy link
Member

tannewt commented Nov 28, 2017

@deshipu I like that! Now we need someone to implement it. ;-)

@mik00
Copy link
Author

mik00 commented Nov 28, 2017 via email

@tuupola
Copy link

tuupola commented Feb 6, 2018

I am currently evaluating moving to CircuitPython from vanilla MicroPython. Slave I2c would be perfect for my needs too.

@marauder37
Copy link

I'd like to +1 this... I wanted to use my Circuit Playground Express as a tilt sensor for a Raspberry Pi because those are the items on my desk and the CPE is actually cheaper than the real-deal BNO055 plus I can echo the current tilt on the CPE's LEDs. So I want to move a number from the CPE to the Pi maybe 10 times a second and timing isn't critical. It's turned out to be surprisingly hard! This will probably end with me going to the store for an MCP3008 but I2C would be cooler, easier, cheaper, more educational.

@mik00 if your C could be useful for someone else maybe share it? 😄

I'm in no position to move to MicroPython (because noob) but fwiw they have something that does i2c slave: https://docs.micropython.org/en/latest/pyboard/library/pyb.I2C.html#pyb-i2c

@tannewt
Copy link
Member

tannewt commented Jul 3, 2018

@notro you are looking into this right?

@tannewt tannewt modified the milestones: Long term, 3.x Jul 3, 2018
@notro
Copy link
Collaborator

notro commented Jul 3, 2018

Yes, I have something working already, just need to write tests to make sure all cases do work. I'm currently trying to use pytest as a test runner for running tests on the board.

@notro notro self-assigned this Jul 3, 2018
@arturo182
Copy link
Collaborator

Very cool! Let me know if any help is needed with the nRF port :)

@notro
Copy link
Collaborator

notro commented Jul 23, 2018

Progress report:

I'm done with the pytest plugin: https://github.com/notro/pytest-circuitpython

bus.I2CSlave are passing most tests.
smbuslave.py pass all tests.
ds1307slave.py pass tests.
at24slave.py pass tests.

The tests are run on a Raspberry Pi connected to a Feather M0 Express through usb and i2c. The slave is set up through the REPL and tested from Linux over i2c.
The hwclock command and the sysfs nvram file are used to test ds1307 and the sysfs eeprom file for the at24c01.

Next up is an ads1015. It uses smbus word transfers so I'm aiming to stress that part of the library.

Here's how one of the test files look: test_ds1307_linux.py

@tannewt
Copy link
Member

tannewt commented Jul 24, 2018

Awesome! I'm excited to see a PR!

@notro
Copy link
Collaborator

notro commented Jul 24, 2018

Will this go into 3.x or 4.x?

@tannewt
Copy link
Member

tannewt commented Jul 25, 2018

Up to you if you want to submit to the 3.x branch as well. I think we'll jump to 4.x alphas pretty fast though.

@notro
Copy link
Collaborator

notro commented Jul 26, 2018

I've made a PR: #1064
Comments are welcome. I haven't got much experience working with I2C devices.

@dhalbert dhalbert modified the milestones: 3.x, 4.0 Alpha Aug 24, 2018
@ladyada
Copy link
Member

ladyada commented Aug 29, 2018

i think perhaps this can be closed?

@dhalbert
Copy link
Collaborator

i think perhaps this can be closed?

Righto! Closed by #1064.

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

No branches or pull requests

10 participants