Repository navigation
Conversation
The Feather nRF52840 and Feather Bluefruit Sense put the Zephyr console on UART0, which fixed TX/RX and kept them from busio.UART. UART0 is now a dynamic iobroker instance like UART1, and the console comes back only in CONSOLE=1 builds through the board's console.overlay and console.conf. DEBUG=1 implies CONSOLE=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The upstream Feather nRF52840 and Feather Bluefruit Sense boards fix I2C0 to SCL/SDA, so busio.I2C() on those pins failed with "SCL in use" and the pins could not be used as GPIO. I2C0 is now a dynamic TWIM instance like I2C1. The Sense drops its SHT3XD node, which sat on the fixed bus. The pinctrl entries and device nodes in both overlays are now in alphabetical order; the compiled devicetree is otherwise unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zephyr2cp.py named a board's main bus after the single enabled devicetree instance of each kind, which doesn't work once the instances are dynamic iobroker pools. A board now lists its buses as [[board_i2c]], [[board_spi]] and [[board_uart]] tables in circuitpython.toml, each with its board names and pins, and zephyr2cp.py generates the CIRCUITPY_BOARD_* pin tables for shared-module/board. As in the other ports, each bus is constructed on its pins on first use. The Feather nRF52840 and Feather Bluefruit Sense define I2C, SPI and UART this way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iobroker hands out the first free instance in a pool, and the pools were in devicetree order, so busio.SPI() on the nRF52840 got the 8 MHz SPIM2 before the 32 MHz SPIM3. zephyr2cp.py now orders each pool by the instances' max-frequency, highest first, keeping devicetree order among equals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add an "nRF serial instances" section to the iobroker README, the counterpart of the comments in ports/nordic's nrfx_config.h: I2C, SPI and UART modes share an instance, the board overlay picks each instance's mode, the Feather split matches ports/nordic, and pools are allocated fastest first. Each nRF board overlay points to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tannewt
left a comment
There was a problem hiding this comment.
Thanks for working on this. A couple Qs.
| # Board buses, as on the ports/ counterpart: board.I2C(), board.SPI() and | ||
| # board.UART(), constructed on these pins when first used. | ||
| [[board_i2c]] | ||
| names = ["I2C"] | ||
| scl = "SCL" | ||
| sda = "SDA" | ||
|
|
There was a problem hiding this comment.
Couldn't we auto-detect this?
I feel like this should be something we can gather from DTS. I guess the challenge is that we change the state of the DTS in order to make it dynamic.
There was a problem hiding this comment.
It appears we can only do this partly, because some of the board definitions don't have the labels we would need to do this automatically. I can look at this further in a later PR.
There was a problem hiding this comment.
Couldn't we add them where they are missing? I think it's a question of what is the source of truth for these buses. I know the arduino connector in zephyr should imply one set of these.
There was a problem hiding this comment.
We may be able to. Can I do that in a later PR? I have some other things backed up behind this.
There was a problem hiding this comment.
I'm hesitant to because code that's in the repo tends to be copied. What is blocked by this?
There was a problem hiding this comment.
I'll try doing it here. I was going to get the Feathers done and have their regular board. buses restored to normal and then do this as the next PR.
There was a problem hiding this comment.
I've removed the tables from the toml files and added some lookups in zephyr2cp.py. For example, for the Feathers, the feather_i2c bus label turns into board.I2C(). For boards with Arduino header labels and pin mappings, we will translate those. For boards that don't have such labels, we can add them in the .overlay file.
The Feather nRF52840 and Feather Bluefruit Sense had identical console.conf and console.overlay files, and board.overlay files that differed only in deleting the Sense's SHT3XD node. console.conf is now one port-level file, which the Makefile applies in CONSOLE=1 builds of any board that has a console.overlay. The Sense's console.overlay and board.overlay include the Feather's; its board.overlay then only deletes SHT3XD. The compiled devicetree is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
262d0e1 to
13cd72c
Compare
…console # Conflicts: # ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay
tannewt
left a comment
There was a problem hiding this comment.
I think we still need to settle on where the buses are defined.
CONSOLE=1 is fine with me. The intent is to not change the log level though right? I know changing the log level can require stack size increases too.
|
Right, no log level changes for CONSOLE=1. |
Replace the [[board_i2c]], [[board_spi]] and [[board_uart]] tables in circuitpython.toml with the devicetree as the source of truth. A board whose devicetree has a feather_i2c, feather_spi or feather_serial label gets board.I2C(), board.SPI() or board.UART() on the header pins named SCL/SDA, SCK/MOSI/MISO or TX/RX. The labeled node only marks that the board has the bus; iobroker picks the instance when the bus is constructed. The Feather nRF52840 boards' circuitpython.toml files are back to their main versions, and the generated board buses are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Constructing a board bus on its pins needs iobroker's runtime routing, which only nRF SoCs have. On other SoCs, such as the Feather RP2040, the labeled buses would raise NotImplementedError. Find board buses from devicetree labels only when CONFIG_PINCTRL_NRF is on, and leave other boards as before. The .config scan moves earlier so the board bus code can use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
busio.I2C(),busio.UART(), busio.SPI()` on boards where it disappeared #11598 (@dhalbert)Code and tests by Claude.
UART console on TX/RX
Problem: zephyr-cp's overlays for the Feather nRF52840 and Feather Bluefruit Sense put the Zephyr console on UART0, fixed to TX/RX, so
busio.UART()could not use those pins. (The upstreamuf2variants of these boards use USB CDC for the console, but CircuitPython takes over USB itself.)Fix: UART0 is now a dynamic iobroker instance. The console is now a build option:
CONSOLE=1(implied byDEBUG=1) applies the board'sconsole.overlayand the port'sconsole.conf, which put it back on TX/RX. It carries Zephyr's boot banner,printk()and warning/error logs; the REPL stays on USB.Fixed I2C0
Problem: The upstream boards also fix I2C0 to SCL/SDA with the legacy TWI driver, so
busio.I2C(board.SCL, board.SDA)failed with "SCL in use" and the pins could not be used for anything else.Fix: I2C0 is now a dynamic TWIM instance like I2C1. The Sense drops its
SHT3XDnode, which was on that bus; the sensor is still at 0x44. That node is the only difference between the two upstream boards that matters here, so the Sense'sboard.overlaynow includes the Feather's and only deletes it.board.I2C(),board.SPI(),board.UART()Problem:
zephyr2cp.pydefinesboard.I2C(),board.SPI()andboard.UART()only when a board's devicetree has exactly one device of that kind. In 10.3.x the Feather and Sense had one each, so the names existed. Since #11420, which isn't released yet, these boards also enable dynamic I2C, SPI and UART instances, somainlost the three names;boardonly hasI2C0,FEATHER_I2C,UART0andFEATHER_SERIAL.Fix: The devicetree is the source of truth. The upstream Feather board labels its header buses
feather_i2c,feather_spiandfeather_serial. On nRF boards, where iobroker can route buses at runtime,zephyr2cp.pydefinesboard.I2C(),board.SPI()orboard.UART()for each of these labels, on the header pins namedSCL/SDA,SCK/MOSI/MISOorTX/RX, which come from the board's Feather connector. Other SoCs keep their fixed devicetree buses. The labeled node only marks that the board has the bus; iobroker picks the instance when the bus is constructed.zephyr2cp.pygenerates theCIRCUITPY_BOARD_*pin tables forshared-module/board, so the buses are constructed on first use, as in the other ports. This restores the three names on the Feather and Sense. Other boards can get the same by adding labels, such as the Arduino header labels on the Nordic DKs (#11602).Bus instance order
Problem: iobroker hands out the first free instance in a pool, in devicetree order, so
busio.SPI()on the nRF52840 got the 8 MHz SPIM2 before the 32 MHz SPIM3.Fix:
zephyr2cp.pyorders each pool bymax-frequency, highest first, so SPIM3 is allocated first, as inports/nordic.Documentation
The iobroker README has a new "nRF serial instances" section: I2C, SPI and UART share an instance, the board overlay chooses each instance's mode, and pools are allocated fastest first. The nRF board overlays point to it.
Testing
board.I2C()with an MSA301,busio.I2C()on SCL/SDA and A2/A3 at once, SCL as GPIO afterdeinit(),board.SPI()loopback at 1 to 16 MHz,board.UART()loopback on TX/RX,CONSOLE=1output on TX.board.I2C()andbusio.I2C()find all five onboard sensors.cptools/tests/test_zephyr2cp.pypasses.The SPI loopback fails at 32 MHz on both this port and
ports/nordic10.3.1. A logic analyzer shows that SPIM3's default MISO sample delay (rx-delay = <2>) lands on the bit boundary when MISO has no output delay, as in a loopback, so this is likely a test artifact rather than a problem with real devices.