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

New I2c slave driver (IDFGH-2501) #2096

Closed
wants to merge 3 commits into from
Closed

Conversation

loboris
Copy link

@loboris loboris commented Jun 24, 2018

This PR proposes a different, in my opinion better and more convinient, way of handling ESP32 I2C slave device.

In slave mode i2c device with 128-4096 memory is emulated, via the slave buffer.
All master's read/write requests for data are handled by the driver's interrupt routine. The user only needs to provide the initial buffer content and, optionally, to handle the master's request from the slave task.

Master can read from or write to the ESP32 i2c device, providing the memory (buffer) address to read from or write to.

For buffer sizes 128-256 bytes, 8-bit addressing is used, for buffer sizes >256 bytes, 16-bit addressing is used.


Typical master write sequence is as follows:

For slave buffer size <= 256 8-bit addressing is used

_____________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr + ack | write n bytes + ack  | stop |
--------|---------------------------|-----------------|----------------------|------|

For slave buffer size > 256 16-bit addressing is used

_____________________________________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr_hi + ack | buff_addr_lo + ack | write n bytes + ack  | stop |
--------|---------------------------|--------------------|--------------------|----------------------|------|

Typical master read sequence is as follows:

For slave buffer size <= 256 8-bit addressing is used

_________________________________________________________________________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr + ack | start | slave_addr + rd_bit + ack | read n-1 bytes + ack | read n-th byte + nack | stop |
--------|---------------------------|-----------------|-------|---------------------------|----------------------|-----------------------|------|

For slave buffer size > 256 16-bit addressing is used

_________________________________________________________________________________________________________________________________________________________________________
| start | slave_addr + wr_bit + ack | buff_addr_hi + ack | buff_addr_lo + ack | start | slave_addr + rd_bit + ack | read n-1 bytes + ack | read n-th byte + nack | stop |
--------|---------------------------|--------------------|--------------------|-------|---------------------------|---------  -----------|-----------------------|------|

Optional read only area at the end of the slave buffer can be set. Master can only read from that area, writing to it by the master will be ignored.

The API provides functions to read and write data from/to the slave buffer at any time: i2c_slave_read_buffer() and i2c_slave_write_buffer.

I2C slave task can be created which receives notifications from the i2c driver about the slave events: address set, data sent to master, data received from master.
Slave buffer address, number of bytes sent or received and overflow status are available to the slave task to take some action on slave events.

It is up to the user to organize the slave buffer in a way most appropriate for the application.
Writting to some addresses can, for example, be treated by the slave task as commands with optional arguments and some action taken.
Read only area can contain the slave ID, revision number, sensor data etc.


I2C example and documentation are updated for the new driver.


The driver was extensively tested with ESP32 i2c master (on the same and different board), STM32F4 hardware and software I2C driver and Atmel xmega chip's i2c driver with clock frequencies of 100000 and 400000.

@loboris loboris changed the title I2c slave New I2c slave driver Jun 24, 2018
@antonio-fiol
Copy link

antonio-fiol commented Sep 11, 2018

I tried to use this new driver in my project (because I found that it must be much better than the default one), by patching the current master.
Unfortunately ...

Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x400eefac  PS      : 0x00060b30  A0      : 0x800d3c92  A1      : 0x3ffc7dc0  
0x400eefac: i2c_master_cmd_begin at /media/esp/esp-idf/components/driver/i2c.c:1209 (discriminator 4)

A2      : 0x00000001  A3      : 0x3ffb4264  A4      : 0x00000020  A5      : 0x00000008  
A6      : 0x00000000  A7      : 0x00000001  A8      : 0x3ffb4d70  A9      : 0x3ffc7db0  
A10     : 0x00000000  A11     : 0x00000000  A12     : 0x00000064  A13     : 0x3ffc7aa0  
A14     : 0x3ffc7aa0  A15     : 0x00000001  SAR     : 0x00000019  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000004  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  

Backtrace: 0x400eefac:0x3ffc7dc0 0x400d3c8f:0x3ffc7df0
0x400eefac: i2c_master_cmd_begin at /media/esp/esp-idf/components/driver/i2c.c:1209 (discriminator 4)

0x400d3c8f: readRegister(unsigned char, unsigned char) at /media/esp/vias/main/Adafruit_ADS1015.cpp:75

Weirdly enough, it seems that the problem comes up when using the MASTER code, which @loboris did not change.

EDIT: Completely forget that. It was me being dumb. The new driver is working like a charm.

@tuupola
Copy link

tuupola commented Sep 16, 2018

I also found this more convenient way to handle i2c slaves than the current driver. Any change this is going to be merged?

@antonio-fiol
Copy link

@loboris Is it possible that your sample design for the slave might ignore some notifications?
It always had been my idea to do exactly as you described: "Writting to some addresses can, for example, be treated by the slave task as commands with optional arguments and some action taken."
I based my code on the same pattern from the sample, where xTaskNotifyWait is used to receive the notification from the task, then processing happens (including my custom code) but it would seem that before I ended up my processing the slave_state already changed value.
The only explanation I found so far is the fact that all the printing takes time and another I2C transaction from the master might come and overwrite the state.
Wondering if a better pattern would be queuing copies of the slave_state (advantage: quick operation, disadvantage: memory usage).
Maybe a better pattern is keeping the slave task processing time under 20 "bit-time" (shortest possible I2C message, right?) that is, under 50 microseconds... which feels like an eternity unless you're printing or doing other slow stuff.

@koobest
Copy link
Contributor

koobest commented Dec 18, 2018

Hi, @loboris
Thank you helping to improve our I2C driver, it's really a good implementation. But now I have some ideals. Since we are work in slave mode, so, how about to define our own protocol (of course only for our slave mode)? the users should to follow it (maybe not a protocol, but user can easily implement this framework)

write timing : |start| + |saddr+w+ack| + |cmd+ack| + |data+ack| + |stop|

read timing  : |start| + |saddr+w+ack| + |cmd+ack| + |stop|  (some_delay)  |start| + |saddr+r+ack| + |(n-1)data + ack| + |last 1 byte + nack|+ |stop|

I think the important field is cmd, which can be one or more bytes, it tells what the commucation purpose is, read or write, and the reg(Maybe ESP32 does not have this concept) can also be in this field. we only need to inform the user how many bytes were received (we can use a queue to notify the user), and other implementations depend on the users.
Do you have any ideals?
thanks !!

@antonio-fiol
Copy link

antonio-fiol commented Dec 18, 2018 via email

@koobest
Copy link
Contributor

koobest commented Dec 18, 2018

Yes, the address byte have the bit to distinguish between reading and writing, but this bit only

available for I2C hardware. So I think it is necessary to keep the CMD field.

@koobest
Copy link
Contributor

koobest commented Dec 28, 2018

Hi, @ loboris
Your PR is reviewing, we have made some changes and it will soon merged into master. thanks for your contribution.

@loboris
Copy link
Author

loboris commented Dec 28, 2018

Yes, the address byte have the bit to distinguish between reading and writing, but this bit only

available for I2C hardware. So I think it is necessary to keep the CMD field.

I don't think implementing the CMD field or any protocol specific field is a good idea.
All protocol related things can be easily handled by the i2c slave task, so the user can implement his own protocol.
In a proposed way the driver can emulate any existing I2C device, and limiting the user to use any specific protocol or timings would only make its usability worse.

@koobest
Copy link
Contributor

koobest commented Jan 2, 2019

Hi, @loboris
When the slave receives some bytes, the driver layer will inform the application layer of this event and data length. the same with your implementation :-).

@tuupola
Copy link

tuupola commented Feb 7, 2019

Any news about this?

@github-actions github-actions bot changed the title New I2c slave driver New I2c slave driver (IDFGH-2501) Jan 8, 2020
@CLAassistant
Copy link

CLAassistant commented Mar 13, 2020

CLA assistant check
All committers have signed the CLA.

@klaus-liebler
Copy link

Hopefully, this gets done soon. I am waiting eagerly...

@ftjuh
Copy link

ftjuh commented May 4, 2021

Can you please, please, please advance this issue?

It's such a shame that a wonderful device like the ESP32 is not able to do sth. as simple as implementing a proper I2C slave.

It seems there is a conceptually sound and well tested solution by @loboris that only needs to be merged, and it's only a contributor's Agreement that is missing? Please, whoever is responsible or capable, please do sth. about this issue after all these years, I'd hate to have to switch to another platform because of this situation.

@klaus-liebler
Copy link

I have just committed C++ implementation for a ESP32 I2C slave. It emulates a 256byte memory with callbacks before read transactions and after write transactions. I did a complete rewrite based on the recently published hal libraries. It is not really well tested, but basics are working. Feel free to use whatever you need.
https://github.com/klaus-liebler/sensactIO/blob/main/sensactIO_firmware/main/i2c_mem.hh

Regards, Klaus

@espressif-bot espressif-bot added the Status: Opened Issue is new label May 6, 2021
@0xjakob
Copy link
Contributor

0xjakob commented May 6, 2021

@loboris @klaus-liebler @ftjuh @tuupola We'll take a look at this PR during the next weeks. Thanks for this submission!
@loboris Could you please also sign the license/CLA, please? Otherwise we can't use the code in IDF since the licensing is unclear.

Best,
Jakob

@Alvin1Zhang
Copy link
Collaborator

@loboris Thanks for your contribution, could you please also sign the license/CLA? Thanks.

@0xjakob
Copy link
Contributor

0xjakob commented Mar 3, 2023

Sorry, as long as the licensing situation is not clear for us we won't be able to accept the code. In general, we highly welcome all contributions as long as the CLA has been signed. We are closing this for now since there hasn't been any activity related to the CLA signing recently.

@0xjakob 0xjakob closed this Mar 3, 2023
@espressif-bot espressif-bot added Resolution: Won't Do This will not be worked on Status: Done Issue is done internally and removed Status: Opened Issue is new labels Mar 10, 2023
@marciogranzotto
Copy link

@loboris could you take a look on this again please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Response awaiting a response from the author Resolution: Won't Do This will not be worked on Status: Done Issue is done internally
Projects
None yet
Development

Successfully merging this pull request may close these issues.