module Beaglebone::PWM

PWM

procedural methods for PWM control

Summary

start is called to enable a PWM pin

Constants

POLARITIES

Polarity hash

Public Class Methods

cleanup() click to toggle source

reset all PWM pins we’ve used to IN and unexport them

# File lib/beaglebone/pwm.rb, line 286
def cleanup
  get_pwm_pins.each { |x| disable_pwm_pin(x) }
end
disable_pwm_pin(pin) click to toggle source

Disable a PWM pin

@param pin should be a symbol representing the header pin

# File lib/beaglebone/pwm.rb, line 303
def disable_pwm_pin(pin)
  Beaglebone::check_valid_pin(pin, :pwm)
  Beaglebone::delete_pin_status(pin) if Beaglebone::device_tree_unload("#{TREES[:PWM][:pin]}#{pin}")
end
enabled?(pin) click to toggle source

Returns true if specified pin is enabled in PWM mode, else false

# File lib/beaglebone/pwm.rb, line 73
def enabled?(pin)
  return true if Beaglebone::get_pin_status(pin, :type) == :pwm

  return false unless valid?(pin)
  if Dir.exists?(pwm_directory(pin))

    start(pin, nil, nil, nil, false)
    return true
  end
  false
end
get_pwm_pins() click to toggle source

Return an array of PWM pins in use

@return [Array<Symbol>]

@example

PWM.get_pwm_pins => [:P9_13, :P9_14]
# File lib/beaglebone/pwm.rb, line 296
def get_pwm_pins
  Beaglebone.pinstatus.clone.select { |x,y| x if y[:type] == :pwm}.keys
end
run(pin) click to toggle source

Start PWM output on specified pin. Pin must have been previously started

@param pin should be a symbol representing the header pin

# File lib/beaglebone/pwm.rb, line 109
def run(pin)
  Beaglebone::check_valid_pin(pin, :pwm)

  return false unless enabled?(pin)

  raise StandardError, "Pin is not PWM enabled: #{pin}" unless Beaglebone::get_pin_status(pin, :type) == :pwm

  run_fd = Beaglebone::get_pin_status(pin, :fd_run)

  raise StandardError, "Pin is not PWM enabled: #{pin}" unless run_fd

  run_fd.write('1')
  run_fd.flush

  raise StandardError, "Could not start PWM: #{pin}" unless read_run_value(pin) == 1
  true

end
set_duty_cycle(pin, duty, newperiod=nil) click to toggle source

Set duty cycle of specified pin in percentage

@param pin should be a symbol representing the header pin @param duty should specify the duty cycle in percentage @example

PWM.set_duty_cycle(:P9_14, 25)
# File lib/beaglebone/pwm.rb, line 154
def set_duty_cycle(pin, duty, newperiod=nil)

  raise ArgumentError, "Duty cycle must be >= 0 and <= 100, #{duty} invalid" if duty < 0 || duty > 100
  check_pwm_enabled(pin)


  fd = Beaglebone::get_pin_status(pin, :fd_duty)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  period = newperiod || Beaglebone::get_pin_status(pin, :period)

  value = ((duty * period) / 100.0).round

  fd.write(value.to_s)
  fd.flush

  raise StandardError, "Could not set duty cycle: #{pin} (#{value})" unless read_duty_value(pin) == value

  Beaglebone::set_pin_status(pin, :duty_pct, duty)
  value

end
set_duty_cycle_ns(pin, duty) click to toggle source

Set duty cycle of specified pin in nanoseconds

@param pin should be a symbol representing the header pin @param duty should specify the duty cycle in nanoseconds @example

PWM.set_duty_cycle_ns(:P9_14, 2500000)
# File lib/beaglebone/pwm.rb, line 184
def set_duty_cycle_ns(pin, duty)

  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_duty)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  period = Beaglebone::get_pin_status(pin, :period)

  duty = duty.to_i

  if duty < 0 || duty > period
    raise ArgumentError, "Duty cycle ns must be >= 0 and <= #{period} (current period), #{duty} invalid"
  end

  value = duty

  fd.write(value.to_s)
  fd.flush

  #since we're setting the duty_ns, we want to update the duty_pct value as well here.
  raise StandardError, "Could not set duty cycle: #{pin} (#{value})" unless read_duty_value(pin, true) == value

  value
end
set_frequency(pin, frequency) click to toggle source

Set frequency of specified pin in cycles per second

@param pin should be a symbol representing the header pin @param frequency should specify the frequency in cycles per second @example

PWM.set_frequency(:P9_14, 100)
# File lib/beaglebone/pwm.rb, line 216
def set_frequency(pin, frequency)
  frequency = frequency.to_i
  raise ArgumentError, "Frequency must be > 0 and <= 1000000000, #{frequency} invalid" if frequency < 1 || frequency > 1000000000
  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_period)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  duty_ns = Beaglebone::get_pin_status(pin, :duty)
  duty_pct = Beaglebone::get_pin_status(pin, :duty_pct)

  value = (1000000000 / frequency).round

  #we can't set the frequency lower than the previous duty cycle
  #adjust if necessary
  if duty_ns > value
    set_duty_cycle(pin, Beaglebone::get_pin_status(pin, :duty_pct), value)
  end

  fd.write(value.to_s)
  fd.flush

  raise StandardError, "Could not set frequency: #{pin} (#{value})" unless read_period_value(pin) == value

  #adjust the duty cycle if we haven't already
  if duty_ns <= value
    set_duty_cycle(pin, duty_pct, value)
  end

  value
end
set_period_ns(pin, period) click to toggle source

Set frequency of specified pin based on period duration

@param pin should be a symbol representing the header pin @param period should specify the length of a cycle in nanoseconds

@example

PWM.set_frequency_ns(:P9_14, 100000000)
# File lib/beaglebone/pwm.rb, line 255
def set_period_ns(pin, period)
  period = period.to_i
  raise ArgumentError, "period must be > 0 and <= 1000000000, #{period} invalid" if period < 1 || period > 1000000000
  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_period)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  duty_ns = Beaglebone::get_pin_status(pin, :duty)
  value = period.to_i

  #we can't set the frequency lower than the previous duty cycle
  #adjust if necessary
  if duty_ns > value
    set_duty_cycle(pin, Beaglebone::get_pin_status(pin, :duty_pct), value)
  end

  fd.write(value.to_s)
  fd.flush

  raise StandardError, "Could not set period: #{pin} (#{value})" unless read_period_value(pin) == value

  #adjust the duty cycle if we haven't already
  if duty_ns <= value
    set_duty_cycle(pin, Beaglebone::get_pin_status(pin, :duty_pct), value)
  end

  value
end
set_polarity(pin, polarity) click to toggle source

Set polarity on specified pin

@param pin should be a symbol representing the header pin @param polarity should specify the polarity, :NORMAL or :INVERTED @example

PWM.set_polarity(:P9_14, :INVERTED)
# File lib/beaglebone/pwm.rb, line 134
def set_polarity(pin, polarity)
  check_valid_polarity(polarity)
  check_pwm_enabled(pin)

  polarity_fd = Beaglebone::get_pin_status(pin, :fd_polarity)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless polarity_fd

  polarity_fd.write(POLARITIES[polarity.to_sym].to_s)
  polarity_fd.flush

  raise StandardError, "Could not set polarity: #{pin}" unless read_polarity_value(pin) == POLARITIES[polarity.to_sym]

end
start(pin, duty=nil, frequency=nil, polarity=nil, run=true) click to toggle source

Initialize a PWM pin

@param pin should be a symbol representing the header pin @param duty should specify the duty cycle @param frequency should specify cycles per second @param polarity optional, should specify the polarity, :NORMAL or :INVERTED @param run optional, if false, pin will be configured but will not run

@example

PWM.start(:P9_14, 90, 10, :NORMAL)
# File lib/beaglebone/pwm.rb, line 25
def start(pin, duty=nil, frequency=nil, polarity=nil, run=true)
  #make sure the pwm controller dtb is loaded
  Beaglebone::device_tree_load(TREES[:PWM][:global])

  Beaglebone::check_valid_pin(pin, :pwm)

  #if pin is enabled for something else, disable it
  if Beaglebone::get_pin_status(pin) && Beaglebone::get_pin_status(pin, :type) != :pwm
    Beaglebone::disable_pin(pin)
  end

  #load device tree for pin if not already loaded
  unless Beaglebone::get_pin_status(pin, :type) == :pwm
    Beaglebone::device_tree_load("#{TREES[:PWM][:pin]}#{pin}", 0.5)
    Beaglebone::set_pin_status(pin, :type, :pwm)
  end

  duty_fd = File.open("#{pwm_directory(pin)}/duty", 'r+')
  period_fd = File.open("#{pwm_directory(pin)}/period", 'r+')
  polarity_fd = File.open("#{pwm_directory(pin)}/polarity", 'r+')
  run_fd = File.open("#{pwm_directory(pin)}/run", 'r+')

  Beaglebone::set_pin_status(pin, :fd_duty, duty_fd)
  Beaglebone::set_pin_status(pin, :fd_period, period_fd)
  Beaglebone::set_pin_status(pin, :fd_polarity, polarity_fd)
  Beaglebone::set_pin_status(pin, :fd_run, run_fd)

  read_period_value(pin)
  read_duty_value(pin)
  read_polarity_value(pin)

  run_fd.write('0')
  run_fd.flush

  set_polarity(pin, polarity) if polarity
  set_frequency(pin, frequency) if frequency
  set_duty_cycle(pin, duty) if duty

  if run
    run_fd.write('1')
    run_fd.flush
  end

  raise StandardError, "Could not start PWM: #{pin}" unless read_run_value(pin) == 1
  true
end
stop(pin) click to toggle source

Stop PWM output on specified pin

@param pin should be a symbol representing the header pin

# File lib/beaglebone/pwm.rb, line 88
def stop(pin)
  Beaglebone::check_valid_pin(pin, :pwm)

  return false unless enabled?(pin)

  raise StandardError, "Pin is not PWM enabled: #{pin}" unless Beaglebone::get_pin_status(pin, :type) == :pwm

  run_fd = Beaglebone::get_pin_status(pin, :fd_run)

  raise StandardError, "Pin is not PWM enabled: #{pin}" unless run_fd

  run_fd.write('0')
  run_fd.flush

  raise StandardError, "Could not stop PWM: #{pin}" unless read_run_value(pin) == 0
  true
end

Private Class Methods

check_pwm_enabled(pin) click to toggle source

ensure pin is pwm enabled

# File lib/beaglebone/pwm.rb, line 322
def check_pwm_enabled(pin)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless enabled?(pin)
end
check_valid_polarity(polarity) click to toggle source

ensure polarity is valid

# File lib/beaglebone/pwm.rb, line 393
def check_valid_polarity(polarity)
  #check to see if mode is valid
  polarity = polarity.to_sym
  raise ArgumentError, "No such polarity: #{polarity.to_s}" unless POLARITIES.include?(polarity)
end
pwm_directory(pin) click to toggle source

return sysfs directory for pwm control

# File lib/beaglebone/pwm.rb, line 387
def pwm_directory(pin)
  raise StandardError, 'Invalid Pin' unless valid?(pin)
  Dir.glob("/sys/devices/ocp.*/pwm_test_#{pin}.*").first
end
read_duty_value(pin, setpct=false) click to toggle source

read duty file

# File lib/beaglebone/pwm.rb, line 352
def read_duty_value(pin, setpct=false)
  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_duty)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  fd.rewind
  value = fd.read.strip.to_i

  Beaglebone::set_pin_status(pin, :duty, value)
  # only set duty_pct if it is unset or if we are forcing it.
  if setpct || Beaglebone::get_pin_status(pin, :duty_pct).nil?
    duty_pct = ((value * 100.0) / Beaglebone::get_pin_status(pin, :period)).round
    Beaglebone::set_pin_status(pin, :duty_pct, duty_pct)
  end

  value
end
read_period_value(pin) click to toggle source

read period file

# File lib/beaglebone/pwm.rb, line 372
def read_period_value(pin)
  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_period)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  fd.rewind
  value = fd.read.strip.to_i

  Beaglebone::set_pin_status(pin, :period, value)

  value
end
read_polarity_value(pin) click to toggle source

read polarity file

# File lib/beaglebone/pwm.rb, line 338
def read_polarity_value(pin)
  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_polarity)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  fd.rewind
  value = fd.read.strip.to_i

  Beaglebone::set_pin_status(pin, :polarity, value)

end
read_run_value(pin) click to toggle source

read run file

# File lib/beaglebone/pwm.rb, line 327
def read_run_value(pin)
  check_pwm_enabled(pin)

  fd = Beaglebone::get_pin_status(pin, :fd_run)
  raise StandardError, "Pin is not PWM enabled: #{pin}" unless fd

  fd.rewind
  fd.read.strip.to_i
end
valid?(pin) click to toggle source

ensure pin is valid pwm pin

# File lib/beaglebone/pwm.rb, line 311
def valid?(pin)
  #check to see if pin exists
  pin = pin.to_sym

  return false unless PINS[pin]
  return false unless PINS[pin][:pwm]

  true
end