1.. _bus_emul: 2 3External Bus and Bus Connected Peripherals Emulators 4#################################################### 5 6Overview 7======== 8 9Zephyr supports a simple emulator framework to support testing of external peripheral drivers 10without requiring real hardware. 11 12Emulators are used to emulate external hardware devices, to support testing of 13various subsystems. For example, it is possible to write an emulator 14for an I2C compass such that it appears on the I2C bus and can be used 15just like a real hardware device. 16 17Emulators often implement special features for testing. For example a 18compass may support returning bogus data if the I2C bus speed is too 19high, or may return invalid measurements if calibration has not yet 20been completed. This allows for testing that high-level code can 21handle these situations correctly. Test coverage can therefore 22approach 100% if all failure conditions are emulated. 23 24Concept 25======= 26 27The diagram below shows application code / high-level tests at the top. 28This is the ultimate application we want to run. 29 30.. figure:: img/arch.svg 31 :align: center 32 :alt: Emulator architecture showing tests, emulators and drivers 33 34Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test 35peripheral drivers using an emulation driver connected via a emulated I2C 36controller/emulator which passes I2C traffic from the AT24 driver to the AT24 37simulator. 38 39Separately we can test the STM32 and NXP I2C drivers on real hardware using API 40tests. These require some sort of device attached to the bus, but with this, we 41can validate much of the driver functionality. 42 43Putting the two together, we can test the application and peripheral code 44entirely on native_sim. Since we know that the I2C driver on the real hardware 45works, we should expect the application and peripheral drivers to work on the 46real hardware also. 47 48Using the above framework we can test an entire application (e.g. Embedded 49Controller) on native_sim using emulators for all non-chip drivers. 50 51With this approach we can: 52 53* Write individual tests for each driver (green), covering all failure modes, 54 error conditions, etc. 55 56* Ensure 100% test coverage for drivers (green) 57 58* Write tests for combinations of drivers, such as GPIOs provided by an I2C GPIO 59 expander driver talking over an I2C bus, with the GPIOs controlling a charger. 60 All of this can work in the emulated environment or on real hardware. 61 62* Write a complex application that ties together all of these pieces and runs on 63 native_sim. We can develop on a host, use source-level debugging, etc. 64 65* Transfer the application to any board which provides the required features 66 (e.g. I2C, enough GPIOs), by adding Kconfig and devicetree fragments. 67 68Creating a Device Driver Emulator 69================================= 70 71The emulator subsystem is modeled on the :ref:`device_model_api`. You create 72an emulator instance using one of the :c:func:`EMUL_DT_DEFINE()` or 73:c:func:`EMUL_DT_INST_DEFINE()` APIs. 74 75Emulators for peripheral devices reuse the same devicetree node as the real 76device driver. This means that your emulator defines ``DT_DRV_COMPAT`` using the 77same ``compat`` value from the real driver. 78 79.. code-block:: C 80 81 /* From drivers/sensor/bm160/bm160.c */ 82 #define DT_DRV_COMPAT bosch_bmi160 83 84 /* From drivers/sensor/bmi160/emul_bmi160.c */ 85 #define DT_DRV_COMPAT bosch_bmi160 86 87The ``EMUL_DT_DEFINE()`` function accepts two API types: 88 89 #. ``bus_api`` - This points to the API for the upstream bus that the emulator 90 connects to. The ``bus_api`` parameter is required. The supported 91 emulated bus types include I2C, SPI, eSPI, and MSPI. 92 #. ``_backend_api`` - This points to the device-class specific backend API for 93 the emulator. The ``_backend_api`` parameter is optional. 94 95The diagram below demonstrates the logical organization of the ``bus_api`` and 96``_backend_api`` using the BC1.2 charging detector driver as the model 97device-class. 98 99.. figure:: img/device_class_emulator.svg 100 :align: center 101 :alt: Device class example, demonstrating BC1.2 charging detectors. 102 103The real code is shown in green, while the emulator code is shown in yellow. 104 105The ``bus_api`` connects the BC1.2 emulators to the ``native_sim`` I2C 106controller. The real BC1.2 drivers are unchanged and operate exactly as if there 107was a physical I2C controller present in the system. The ``native_sim`` I2C 108controller uses the ``bus_api`` to initiate register reads and writes to the 109emulator. 110 111The ``_backend_api`` provides a mechanism for tests to manipulate the emulator 112out of band. Each device class defines it's own API functions. The backend API 113functions focus on high-level behavior and do not provide hooks for specific 114emulators. 115 116In the case of the BC1.2 charging detector the backend API provides functions 117to simulate connecting and disconnecting a charger to the emulated BC1.2 device. 118Each emulator is responsible for updating the correct vendor specific registers 119and potentially signalling an interrupt. 120 121Example test flow: 122 123 #. Test registers BC1.2 detection callback using the Zephyr BC1.2 driver API. 124 #. Test connects a charger using the BC1.2 emulator backend. 125 #. Test verifies B1.2 detection callback invoked with correct charger type. 126 #. Test disconnects a charger using the BC1.2 emulator backend. 127 128With this architecture, the same test can be used will all supported drivers in 129the same driver class. 130 131Available Emulators 132=================== 133 134Zephyr includes the following emulators: 135 136* I2C emulator driver, allowing drivers to be connected to an emulator so that 137 tests can be performed without access to the real hardware 138 139* SPI emulator driver, which does the same for SPI 140 141* eSPI emulator driver, which does the same for eSPI. The emulator is being 142 developed to support more functionalities. 143 144* MSPI emulator driver, allowing drivers to be connected to an emulator so that 145 tests can be performed without access to the real hardware. 146 147I2C Emulation features 148---------------------- 149 150In the binding of the I2C emulated bus, there's a custom property for address 151based forwarding. Given the following devicetree node: 152 153.. code-block:: devicetree 154 155 i2c0: i2c@100 { 156 status = "okay"; 157 compatible = "zephyr,i2c-emul-controller"; 158 clock-frequency = <I2C_BITRATE_STANDARD>; 159 #address-cells = <1>; 160 #size-cells = <0>; 161 #forward-cells = <1>; 162 reg = <0x100 4>; 163 forwards = <&i2c1 0x20>; 164 }; 165 166The final property, ``forwards`` indicates that any read/write requests sent to 167address ``0x20`` should be sent to ``i2c1`` with the same address. This allows 168us to test both the controller and the target end of the communication on the 169same image. 170 171.. note:: 172 The ``#forward-cells`` attribute should always be 1. Each entry in the 173 ``forwards`` attribute consists of the phandle followed by the address. In 174 the example above, ``<&i2c1 0x20>`` will forward all read/write operations 175 made to ``i2c0`` at port ``0x20`` to ``i2c1`` on the same port. Since no 176 additional cells are used by the emulated controller, the number of cells 177 should remain 1. 178 179Samples 180======= 181 182Here are some examples present in Zephyr: 183 184#. Bosch BMI160 sensor driver connected via both I2C and SPI to an emulator: 185 186 .. zephyr-app-commands:: 187 :zephyr-app: tests/drivers/sensor/bmi160 188 :board: native_sim 189 :goals: build 190 191#. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver 192 connected via I2C an emulator: 193 194 .. zephyr-app-commands:: 195 :zephyr-app: tests/drivers/eeprom/api 196 :board: native_sim 197 :goals: build 198 :gen-args: -DDTC_OVERLAY_FILE=at2x_emul.overlay -DEXTRA_CONF_FILE=at2x_emul.conf 199 200API Reference 201============= 202 203.. doxygengroup:: io_emulators 204