Skip to content

i2c_target: Add attribute that exposes the number of bytes transferred. - #18485

Open
alectric-tr wants to merge 3 commits into
micropython:masterfrom
alectric-tr:feat/i2c_target_num_bytes_attribute
Open

alectric-tr wants to merge 3 commits into
micropython:masterfrom
alectric-tr:feat/i2c_target_num_bytes_attribute

Conversation

@alectric-tr

@alectric-tr alectric-tr commented Nov 27, 2025 •

Copy link
Copy Markdown
Contributor

Summary

As mentioned in the issue, the I2CTarget class exposes the memaddr attribute which is first memory address read/written by the controller, but there is no way of knowing how many attributes were read or written. This patch series adds the implementation, documentation, and tests for the numbytes attribute to expose how many bytes were read/written in the last transaction.

It is supported only when the I2C target device is configured as a memory device, otherwise the numbytes attribute remains at 0.

Fixes: #17996

Testing

Esp32 WROOM as the controller.
RPI PICO 2W (RP2350) as the target.

Tested for cases when the target was configured as a memory device and as an arbitrary I2C device.

Trade-offs and Alternatives

Alternatively, numbytes can be split into 2 separate attributes, one for the number of bytes read and one for the number of bytes written after each transaction.

Another alternative is to configure the I2C target device as an arbitrary I2C device and keep track of the count of a read/write request event until its end event has occurred. However, this method comes with more python code and some potential overhead of clock stretching.

@github-actions

github-actions Bot commented Nov 27, 2025 •

Copy link
Copy Markdown

Code size report:

Reference:  stm32/boards/STM32F469DISC: Add board.json file. [22cff2f]
Comparison: tests: Add tests for i2c_target numbytes attribute. [merge of 075b090]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:  +124 +0.031% PYBV10[incl +16(bss)]
     mimxrt:   +72 +0.019% TEENSY40
        rp2:  +160 +0.017% RPI_PICO_W[incl +8(bss)]
       samd:  +112 +0.041% ADAFRUIT_ITSYBITSY_M4_EXPRESS[incl +24(bss)]
  qemu rv32:    +0 +0.000% VIRT_RV32

@codecov

codecov Bot commented Nov 27, 2025 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.38%. Comparing base (22cff2f) to head (075b090).
⚠️ Report is 1196 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #18485   +/-   ##
=======================================
  Coverage   98.38%   98.38%           
=======================================
  Files         171      171           
  Lines       22301    22301           
=======================================
  Hits        21940    21940           
  Misses        361      361           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alectric-tr
alectric-tr force-pushed the feat/i2c_target_num_bytes_attribute branch from ba5fc7f to a5994b4 Compare November 28, 2025 17:41
@alectric-tr
alectric-tr force-pushed the feat/i2c_target_num_bytes_attribute branch from a5994b4 to 075b090 Compare November 28, 2025 17:45
@dpgeorge dpgeorge added the extmod Relates to extmod/ directory in source label Dec 16, 2025
@dpgeorge dpgeorge added this to the release-1.29.0 milestone Mar 21, 2026
@dpgeorge

Copy link
Copy Markdown
Member

Thanks for the contribution. And thanks for making a good PR with updates to both the docs and tests. The feature you've added is definitely useful.

@projectgus and I discussed this PR and the main concerns we had were around atomicity: if another transaction comes in while the Python code is reading memaddr and numbytes, then those values won't match and/or won't be correct. memaddr may now be the address of the next transaction. numbytes may be reset to 0 or currently being incremented as part of the next transaction.

In most applications this probably won't matter, the I2C transactions will be slow/synchronous. But it would be good to try and improve the situation.

One idea is to have an attribute (eg I2CTarget.last_mem_transaction) return a tuple containing (transaction_count, read_write, mem_addr, num_bytes). That would be an atomic snapshot of the last transaction. But that's going to need to allocate memory which isn't great.

Instead, maybe it's enough to modify this PR to make it so that the new numbytes attribute is only updated at the end of the transaction, so it's always a proper value (never something that's part way through a transaction).

And then add another attribute txn_count (transaction count) that counts the number of mem transactions. Then if you want atomicity you can read txn_count first, then memaddr and numbytes, then txn_count again and make sure it hasn't changed. If it changed, repeat that reading sequence.

Or, maybe something simpler that would still allow atomicity would be the following:

  • when memaddr is changed, numbytes is set to -1 to indicate "transaction in progress"
  • when the transaction is done, numbytes is set to the number of bytes written/read
  • if a user wants to ensure atomicity (eg because they can't guarantee the controller will wait between transactions) then they can read memaddr and then numbytes and then memaddr again, and keep doing that until both memaddr values match, and numbytes is not -1

@ZodiusInfuser

Copy link
Copy Markdown
Contributor

After recently playing around with I2CTarget, I stumbled across a possible need for this feature. Glad to see there's a PR in progress already!

I wish to convert a Pimoroni RP2040 board into an I2CTarget and it seems configuring it as a memory device is the most performant option. For this I want some sections of memory to be read-only, where a write has no effect. If the host does a single byte write, then I can use the memaddr to check for a change and reload the stored value, but I cannot tell when multiple bytes are written in a row.

I only have two read-only registers for now, so I am just using the hard irq to reset them both on every IRQ_END_WRITE.

@dpgeorge

Copy link
Copy Markdown
Member

@alectric-tr are you still interested in working on this PR?

@dpgeorge dpgeorge modified the milestones: release-1.29.0, release-1.30 Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extmod Relates to extmod/ directory in source

Projects

None yet

Development

Successfully merging this pull request may close these issues.

I2CTarget: Add number of bytes read/written

3 participants