Skip to content

Commit a75f441

Browse files
aescolardleach02
authored andcommitted
docs: emulators: Created new emulators page
Created new emulators page, and moved the current page to be a page dedicated to bus emulators. Signed-off-by: Alberto Escolar Piedras <[email protected]>
1 parent 74468eb commit a75f441

File tree

3 files changed

+266
-174
lines changed

3 files changed

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

0 commit comments

Comments
 (0)