Pure Elixir library to interact with the sysfs interface to hardware PWM on Linux.

Installation

Add pwmx to your dependencies in mix.exs:

def deps do
  [
    {:pwmx, "~> 0.1.0"}
  ]
end

Usage

Fully manual

If you wish to just write and read to the sysfs Pwm interface, you can find path helpers in the Pwmx.Paths module.

File.read(Pwmx.Paths.duty_cycle_path("pwmchip0", "1"))

Helper functions

If you want an Elixir interface instead of calling File.write/2 or File.read/1 yourself, the module Pwmx.Backend.Sysfs.Ops has a stateless interface that actually performs the reads and writes.

Pwmx.Backend.Sysfs.Ops.get_duty_cycle("pwmchip0", "1")

Managed

The Pwmx.Output module can be used to spin up a genserver representing your output, managing its state.

{:ok, pid} = Pwmx.Output.start_link({"pwmchip0", 1})  
Pwmx.Output.enable(pid) |> Pwmx.Output.set_period(1_000_000, :us)  

Testing & non-linux hosts

In a test or non-linux environment, the Pwmx.Backend.Sysfs module is not used, and calls are instead dispatched to Pwmx.Backend.Virtual, which keeps track of your operations on PWM outputs with the Pwmx.State struct. This struct isn't meant to be used directly as it wouldn't be of particular help.

The application supervises a default backend registered as Pwmx.Backend. To test code that drives PWM outputs, start your own virtual backend and hand it to Pwmx.Output (or Pwmx.open/3). Each instance owns its state :

{:ok, backend} = Pwmx.Backend.start_link(mode: :virtual, virtual_chips: %{"virtualchip0" => 4})
{:ok, pid} = Pwmx.Output.start_link({"virtualchip0", 1}, backend: backend)
Pwmx.Output.enable(pid) |> Pwmx.Output.set_period(1_000, :ms)

You can also fix the virtual board globally via configuration:

# config/test.exs
config :pwmx, virtual_chips: %{"virtualchip0" => 4}

What PWM outputs do I have ?

An helper function can help you. Note that this function actually exports then closes each output as it seems that after a bit of testing, it cannot be taken for granted that every output reported by /sys/class/pwm/chip/npwm is able to be opened. Note that already exported outputs by something else in your system will not show up in this list as the export will fail.

Pwmx.list_available_outputs()
[
    {"virtualchip0", 0},
    {"virtualchip0", 1},
    {"virtualchip0", 2},
    {"virtualchip0", 3}
]

Todo

  • [ ] Sample project showing behavior on a host & on a board