.. _rigs4zephyr_tutorials_give-a-board-a-socket: Giving a board a socket ========================= .. admonition:: Prerequisites - :ref:`rigs4zephyr_tutorials_build-a-rig-that-exists`, so the vocabulary is familiar. - A west workspace with ``btr-shields``, able to build for ``nucleo_f411re``. - No hardware needed to follow along; two Grove connectors soldered to the Arduino header if you want to run the result. .. note:: This tutorial's board and rig names come from btr-shields, the harness repository the rig model comes from, not from bridle's own corpus — see :ref:`rigs4zephyr_tutorials_build-a-rig-that-exists`'s own note. Read it for the mechanism; bridle's own boards and shields are ``seeeduino_lotus`` and ``grove_btn``/``grove_led``, as used there. Rae has a NUCLEO-F411RE and two Grove connectors wired to its Arduino header — a completely ordinary prototype. Zephyr knows the board; it does not know about those two connectors. This tutorial tells it. **One new concept: a socket is a devicetree node the board declares.** Declaring one is how a board opts in to rigs. Everything else in this series depends on it, and nothing in this tutorial mentions a module. Make a place to work ---------------------- Board extensions live in a Zephyr module, and the one you are about to write is yours, not ``btr-shields``'s. Create a small module beside it in the workspace: .. code-block:: console $ mkdir -p acme-rigs/zephyr acme-rigs/boards/extend/st/nucleo_f411re .. code-block:: yaml # acme-rigs/zephyr/module.yml name: acme-rigs build: settings: board_root: . ``board_root: .`` is what makes ``boards/extend/`` under this module discoverable. Point Zephyr at the module with ``-DEXTRA_ZEPHYR_MODULES=/acme-rigs`` on the build command line, or add it to your manifest. Extend the board ------------------ You are not editing ``nucleo_f411re``. You are adding a **variant** of it — a :term:`board extension`. Upstream's board stays untouched, and both the plain board and your rig-enabled one remain buildable. .. code-block:: yaml # acme-rigs/boards/extend/st/nucleo_f411re/board.yml board: extend: nucleo_f411re variants: - name: rig qualifier: stm32f411xe ``extend:`` names the base board; the variant adds the target ``nucleo_f411re/stm32f411xe/rig``. That third segment is the one you will type from now on, and it is the same shape you saw in the previous tutorial's configure output. The variant needs its own devicetree, which pulls in the real board and layers your sockets on top: .. code-block:: devicetree /* acme-rigs/boards/extend/st/nucleo_f411re/nucleo_f411re_stm32f411xe_rig.dts */ #include "nucleo_f411re.dts" #include "grove_sockets.dtsi" Two lines. The first is the upstream board, verbatim — every peripheral, pinctrl and alias it already had. The second is the only thing you are adding. Declare the socket -------------------- Here is the whole new concept: .. code-block:: devicetree /* acme-rigs/boards/extend/st/nucleo_f411re/grove_sockets.dtsi */ #include / { grove_d2: connector_grove_d2 { compatible = "socket,grove"; #gpio-cells = <2>; gpio-map-mask = <0xffffffff 0xffffffc0>; gpio-map-pass-thru = <0 0x3f>; gpio-map = , ; }; }; Read it line by line, because every line is a decision you will make again for every board you rig-enable: ``compatible = "socket,grove"`` This is the opt-in. It says the node is a socket of the :term:`connector type` ``grove``, whose contract is already authored in ``btr-shields`` (``dts/bindings/connectors/grove.yaml``). You are *using* a connector type here, not defining one — a Grove connector means the same thing on every board, which is exactly what makes modules portable. ``grove_d2:`` The label. This is the name a rig will use to say "plug it in here", so pick one a human recognises from the silkscreen. The convention is ```` for a board's only socket of that type and ``_`` for a family — so ``grove_d2``, because the connector sits on the D2/D3 pins. ``gpio-map`` The physical truth, written down once. ``GROVE_SIG0`` and ``GROVE_SIG1`` are :term:`position`\ s — ``#define``\ s from the connector type's header, not pin numbers. The map says *this board* routes SIG0 to ``gpioa`` pin 10 and SIG1 to ``gpiob`` pin 3. That last one is the load-bearing one. A module will later say "I drive SIG0"; it will never say ``gpioa 10``. The board is the only thing that knows the pin, this file is the only place it is written, and every rig on this board reuses it. The tedium is paid once per board, not once per placement — which is precisely the difference between this and the 64 overlays. Add the variant's defconfig, mirroring the base board's: .. code-block:: cfg # acme-rigs/boards/extend/st/nucleo_f411re/nucleo_f411re_stm32f411xe_rig_defconfig CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y Check that it took -------------------- There is no module to plug in yet, so there is no rig to build. What you *can in principle* confirm is that the board now advertises a socket, by asking which boards satisfy a Grove rig that already exists: .. code-block:: console $ west rigs --boards-for lotus_buttons In a corpus where boards declare their sockets through a ``board.yml`` ``extend:``/``variants`` board rig-extension, that command lists every board whose declared sockets satisfy ``lotus_buttons`` — ``grove_d2``, ``grove_d6`` and ``grove_a0`` — and excludes one like yours-so-far, carrying only the first, until you add the other two. .. note:: None of bridle's own real boards, ``seeeduino_lotus`` included, carry that ``board.yml`` declaration today — it is unrelated to the ``socket,*`` devicetree nodes this tutorial has you add, and bridle's own boards use ``extend:``/``variants`` only for its own ``bbe`` variants. So in *this* workspace the command above prints nothing for any target, not a verdict on this board's sockets specifically — a gap in bridle's own board corpus, not in ``--boards-for`` itself. .. note:: ``--boards-for`` answers whether a board's *sockets* satisfy a rig. It is not a promise the rig builds there — pin routing, chip-select allocation and address conflicts are decided per build, by the :term:`expander`. What you have --------------- A board that is rig-enabled. It declares, in its own devicetree, that a Grove connector exists and where its two signals go. Nothing about modules, nothing about applications, and nothing that any particular rig depends on. Next ------ :ref:`rigs4zephyr_tutorials_write-a-shield-template` builds the other half: a module that says what it needs in positions, so it can land on this socket or any other Grove socket anywhere.