I2C protocol refactor, Meson driver rewrite, added libi2c #434 < 8000 /h1>
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR is a complete rewrite of our I2C protocol and all extant code for it. The old I2C abstraction was essentially just a recycled version of the ODROID C4's internal i2c hardware protocol, and had a variety of issues. This change will close
This PR depends upon a corresponding change in SDFgen and must be merged in lockstep with it: au-ts/microkit_sdf_gen#15
Protocol
The new protocol is more complex and is designed to offer abstractions familiar to embedded systems engineers as commonly seen in HALs for other platforms. The guiding principle for this design is to offer a friendly interface and corresponding interface library for new users to our ecosystem. I2C requests now describe a single transaction - i.e. a series of operations which are executed together. Each transaction is composed of some number of commands. Commands define a read, write or write-read operation paired with a buffer mapped from the client to operate on.
E.g. a read command includes some buffer and length mapped to the client - the driver will read directly into that buffer without any copying.
Commands exist in the data region** (formerly used for everything) as a simple list. Commands reference a buffer in a new region, the meta** region, which is mapped between the driver and the client. Logically, the meta region is identical to the data region and their separation is just for clarity. Separating meta has benefits for clarity for end users who need to write complex i2c applications - they can treat meta as a safe, self-controlled region of buffers - this means that simply reading i2c/queue.h should be enough context to write a complex application even without libi2c, since data transmission is now fully abstracted to queue operations and installing buffers in meta as you would in a typical embedded HAL.
When clients make requests, they pass a pointer to the meta region in their virtual address space as a destination. The virt translates this address to the corresponding address in the driver using the mappings in the config struct defined by sdfgen.
Note; the current solution for this is suboptimal in my opinion. We could just pass an index to the correct meta region instead of transmitting it from the client every request.
**should consider renaming
libi2c
Libi2c is a user-facing library implementing a blocking API for i2c calls. It uses the new meta region to back buffers - when making requests the end user must offer up any buffer from within the region. Coroutines are used for the blocking aspect: the client using libi2c must set up libco and call
libi2c_init
to create a configuration structure before use.Libi2c offers the following core operations:
i2c_write(libi2c_conf, i2c_address, buf, len)
- write the contents of buffer buf to i2c_addressi2c_read(libi2c_conf, i2c_address, buf, len)
- read from i2c_address into buffer bufi2c_writeread(libi2c_conf, i2c_address, reg_address, buf, len)
- read from register reg_address of i2c_address into buffer bufLibi2c can work with raw libco or libmicrokitco.
Writing to a register is accomplished by simply putting the register address into the first byte of a write, if only writing.
Users need only worry about supplying valid meta bufs, all other operation is automated using an allocator for commands.
Meson driver rewrite
The meson driver has been fully rewritten for the new protocol and implements a new FSM-based design. The driver now operates entirely around a finite state machine which mirrors handling different parts of the protocol. At a high level, the state machine is summarised as follows:
This design change makes the driver faster, more readable and eliminates a tremendous amount of fragile code. Additionally, this driver structure should trivially work on most other platforms, only requiring changes to s_cmd and s_cmd_ret to match the functionality of the i2c ip block.