View Source Multi Display and Nerves
Probably the most common use case for the MultiDisplay
module is in a Nerves project where it invokes the virtual display
during local development and both virtual and hardware display on the device.
This way, a potential web interface could always provide a preview of the image on the display. To build the actual virtual display using Phoenix LiveView, check out this guide.
project-setup
Project Setup
For this guide, we use a Nerves typical poncho structure.
my_app
|-- firmware
`-- my_app
The inner my_app
folder contains a normal Phoenix project and the firmware
folder the Nerves project.
For a more in-depth guide on this setup, refer to the official Nerves + Phoenix guide.
The additional dependencies for both projects are as follows:
# my_app/firmware/mix.exs
defp deps do
[
...
{:oled, "~> 0.3.5"},
{:circuits_i2c, "~> 1.0", override: true}
]
end
# my_app/my_app/mix.exs
defp deps do
[
...
{:oled_virtual, "~> 1.0"}
]
end
adding-the-oled-display
Adding the OLED Display
The OLED display will be created inside the firmware
project because it needs to interact with
the real hardware which is not available during local development.
# my_app/firmware/lib/my_app_firmware/oled_display.ex
defmodule MyAppFirmware.OledDisplay do
use OLED.Display, app: :my_app_firmware
end
# my_app/firmware/config/target.exs
config :my_app_firmware, MyAppFirmware.OledDisplay,
device: "i2c-1",
driver: :ssd1306,
type: :i2c,
width: 128,
height: 64,
rst_pin: 25,
dc_pin: 24,
address: 0x3C
This configuration is specific to the OLED Bonnet display.
Your OLED display might need a slightly different configuration.
Please refer to the OLED
documentation.
The MyAppFirmware.OledDisplay
module needs to be added to the supervision tree.
# my_app/firmware/lib/my_app_firmware/application.ex
def children(_target) do
[
MyAppFirmware.OledDisplay
]
end
adding-the-virtual-oled-display
Adding the Virtual OLED Display
The virtual OLED display will be part of the my_app
Phoenix project.
# my_app/my_app/lib/my_app/oled_virtual_display.ex
defmodule MyApp.OledVirtualDisplay do
use OLEDVirtual.Display, app: :my_app
def on_display(data, dimensions) do
# React to new frames
end
end
# my_app/my_app/config/config.exs
config :my_app, MyApp.OledVirtualDisplay,
width: 128,
height: 64
Make sure that the configured resolution is the same as on the hardware display.
The MyApp.OledVirtualDisplay
module needs to be added to the supervision tree.
# my_app/my_app/lib/my_app/application.ex
@impl true
def start(_type, _args) do
children = [
...
MyApp.OledVirtualDisplay
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
adding-the-multi-display
Adding the Multi Display
The multi display will also be part of the my_app
Phoenix project,
and invoke either the virtual display or both displays,
based on the specific configuration that is loaded during runtime.
# my_app/my_app/lib/my_app/multi_display.ex
defmodule MyApp.MultiDisplay do
use OLEDVirtual.MultiDisplay, app: :my_app
end
Now, we need to configure it in both projects.
# my_app/my_app/config/config.exs
config :my_app, MyApp.MultiDisplay,
displays: [
MyApp.OledVirtualDisplay
]
# my_app/firmware/config/target.exs
config :my_app, MyApp.MultiDisplay,
displays: [
MyApp.OledVirtualDisplay,
MyAppFirmware.OledDisplay
]
This is all it takes. From now on, all display interactions can be made through
the MyApp.MultiDisplay
module, which invokes the configured display modules.
If the Nerves firmware is built using the firmware
project, the multi display will
invoke both displays. And if the my_app
Phoenix project is started locally for development,
only the virtual display will be invoked.