Scenic with Nerves Rpi3 with HDMI output: Possible?

I just installed Scenic + Nerves, I can run the basic example on my laptop fine, I can successfully build fw images. But when I boot the Rpi, I can see all boot log messages scroll by and then it finally switches to a blank screen with nothing to show :confused:

I can see log messages via a remote IEx session on the device, there is nothing dramatic to be seen (Processes crashing or something). But the screen stays blank.

Should HDMI output work with the default Scenic + Nerves project setup? Is there something special to set in the /boot/config.txt or somewhere else?

Any help very much appreciated!

1 Like

I don’t know about RPi3, but on Pi0 you can use the Pi in ‘gadget mode’; run the Pi from a terminal.

1 Like

Unfortunately I dont have a zero at hand, but tailing the logs with RingLogger and IEx via ssh does the job for now. To clarify, plain nerves stuff runs just fine, it is the Scenic part that leaves me puzzled.

I’ve not had to much time with it, but I was running scenic + nerves on a rpi3 + hdmi display right when the scenic update was published.

OK, thats good to hear. So it should work!

Ah, finally some light. The primary problem is that the Rpi does not render text/fonts. The minimal default scene only displays text, so thats the blank screen problem solved. Drawing a simple rectangle is fine! :upside_down_face:

I tried to use a custom font (which works well on the desktop), but still no text rendering on the Rpi :disappointed:

1 Like

Solved the font problem: The hashing scheme described in the docs does evaluate the paths at compile time, which is usually the development machine’s paths and not the deployed (nerves) one.

I “fixed” it for now by differentiating a bit more and hardcoding the nerves path (bad!):

  @font_hash_path :code.priv_dir(:my_app) |> Path.join("/static/fonts/myfont.otf")

  if @target == "host" do
    @font_path @font_hash_path
    @font_path "/srv/erlang/lib/my_app-0.1.0/priv/static/fonts/myfont.otf"

  @font_hash Scenic.Cache.Hash.file!(@font_hash_path, :sha)

and in init/2

def init(_, opts) do
  Scenic.Cache.File.load(@font_path, @font_hash)

I guess thats also the problem with the built-in fonts not showing in nerves


Hmmm, I would expect that :code.priv_dir(:my_app) |> Path.join("/static/fonts/myfont.otf") would work as long as you call it at run-time and not compile time (i.e. do not place it in a module attribute)

1 Like

Thanks, I also got this working on a RPi 3 today thanks to your post. I would have never figured out that there’s a problem drawing text.

@axelson Yes you are right. The canonical examples try to build the graph at compile time for performance and other reasons. And hashing resources like custom fonts at runtime does not feel right.

@thovoll Nice! I also discovered that using really large fonts (>500) crashes the renderer on the RPi. It is also having a hard time on the desktop where all textures are wrong for a second after starting up. Also, line breaks in the text suddenly appear when using large fonts. (for example, rendering a screen-filling clock on a 1920x1050 display).

All in all, small things that can be resolved. I really like Scenic, thanks @boydm !


Good to know! Any tips for getting just the default text to render?

Uh, right I did not try that… Pulling them out of the dependency and treat them as custom fonts is your best bet for now I guess. I also guess that currently the default fonts are also hashed at (dependency) compile time when the path is different to the release on the RPi.

All said, using a good non-default font will get you 50% of the way to a descent design :wink:

1 Like

Ok, thanks! Where does the code you posted go, and how do I reference the font in the scene graph? I’m super new to Scenic.

I see where the font file goes, and I can probably dig one up on the web :slight_smile:

I am currently using something like this in my scene:

define @fonts map at compile time…

@fonts [
     |> Enum.reduce(%{}, fn f, acc ->
       hash_path = :code.priv_dir(:b22) |> Path.join("/static/fonts/#{f}")
       font_path =
         case @target do
           "host" -> hash_path
           _ -> "/srv/erlang/lib/#{Mix.Project.config()[:app]}-#{Mix.Project.config()[:version]}/priv/static/fonts/#{f}"

       font_hash = Scenic.Cache.Hash.file!(hash_path, :sha)
       acc |> Map.put(f, %{hash: font_hash, path: font_path})

…define the @graph at compile time using these font hashes…

       font_size: 24,
       font: @fonts["Font-Regular.ttf"].hash,
       fill: :white,
       text_align: :left_top
     |> group(
       fn g ->
         |> text("Test Text", id: :test_text)
       t: {10, 10}

… and finally load fonts, push graph in the init function of the scene

 def init(_, opts) do
   Scenic.Cache.File.load( @fonts["Font-Regular.ttf"].path, @fonts["Font-Regular.ttf"].hash)
   Scenic.Cache.File.load( @fonts["Font-Bold.ttf"].path, @fonts["Font-Bold.ttf"].hash)
   graph = @graph |> push_graph()
   {:ok, graph}

Thank you @argl, I got this to work!

For any other passersby who are interested, here’s my code:



I’ll get into the example app and fix it up too.

Just published scenic_driver_nerves_rpi 0.9.2 to hex.

This fixes the issue where the default font was not rendering on the Raspberry Pi via Nerves.