mcu: Support config mechanism for translating seconds to clock ticks

Introduce a TICKS() macro during config parsing that will translate
time in seconds to time in clock ticks.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2017-03-12 19:55:56 -04:00
parent 8e6d5efdac
commit 1d796a4e24
4 changed files with 32 additions and 27 deletions

View File

@ -33,7 +33,11 @@ low-level firmware uses integer encodings of the hardware pin numbers,
but to make things more readable the host will translate human
readable pin names (eg, "PA3") to their equivalent integer
encodings. By convention, any parameter named "pin" or that has a
"_pin" suffix will use pin name translation by the host.
"_pin" suffix will use pin name translation by the host. Similarly,
several commands take time parameters specified in clock ticks. One
can specify a value for these parameters in seconds using the
"TICKS()" macro - for example "cycle_ticks=TICKS(0.001)" would result
in "cycle_ticks=16000" on a micro-controller with a 16Mhz clock.
Common startup commands:

View File

@ -16,6 +16,7 @@ class KeyboardReader:
self.reactor = reactor
self.fd = sys.stdin.fileno()
util.set_nonblock(self.fd)
self.mcu_freq = 0
self.pins = None
self.data = ""
reactor.register_fd(self.fd, self.process_kbd)
@ -24,15 +25,14 @@ class KeyboardReader:
self.eval_globals = {}
def connect(self, eventtime):
self.ser.connect()
self.mcu_freq = int(self.ser.msgparser.get_constant_float('CLOCK_FREQ'))
mcu = self.ser.msgparser.get_constant('MCU')
self.pins = pins.get_pin_map(mcu)
self.reactor.unregister_timer(self.connect_timer)
return self.reactor.NEVER
def update_evals(self, eventtime):
f = int(self.ser.msgparser.config.get('CLOCK_FREQ', 1))
c = self.ser.get_clock(eventtime)
self.eval_globals['freq'] = f
self.eval_globals['clock'] = int(c)
self.eval_globals['freq'] = self.mcu_freq
self.eval_globals['clock'] = int(self.ser.get_clock(eventtime))
def set_pin_map(self, parts):
mcu = self.ser.msgparser.get_constant('MCU')
self.pins = pins.get_pin_map(mcu, parts[1])
@ -60,7 +60,8 @@ class KeyboardReader:
print "Eval:", line
if self.pins is not None:
try:
line = pins.update_command(line, self.pins).strip()
line = pins.update_command(
line, self.mcu_freq, self.pins).strip()
except:
print "Unable to map pin: ", line
return None

View File

@ -28,13 +28,12 @@ class MCU_stepper:
step_pin, pullup, invert_step = parse_pin_extras(step_pin)
dir_pin, pullup, self._invert_dir = parse_pin_extras(dir_pin)
self._mcu_freq = mcu.get_mcu_freq()
min_stop_interval = int(min_stop_interval * self._mcu_freq)
max_error = int(max_error * self._mcu_freq)
self.commanded_position = 0
self._mcu_position_offset = 0
mcu.add_config_cmd(
"config_stepper oid=%d step_pin=%s dir_pin=%s"
" min_stop_interval=%d invert_step=%d" % (
" min_stop_interval=TICKS(%.9f) invert_step=%d" % (
self._oid, step_pin, dir_pin, min_stop_interval, invert_step))
mcu.register_stepper(self)
self._step_cmd = mcu.lookup_command(
@ -233,7 +232,8 @@ class MCU_digital_out:
self._cmd_queue = mcu.alloc_command_queue()
mcu.add_config_cmd(
"config_digital_out oid=%d pin=%s default_value=%d"
" max_duration=%d" % (self._oid, pin, self._invert, max_duration))
" max_duration=TICKS(%f)" % (
self._oid, pin, self._invert, max_duration))
self._set_cmd = mcu.lookup_command(
"schedule_digital_out oid=%c clock=%u value=%c")
self.print_to_mcu_time = mcu.print_to_mcu_time
@ -254,25 +254,26 @@ class MCU_digital_out:
class MCU_pwm:
PWM_MAX = 255.
def __init__(self, mcu, pin, cycle_ticks, max_duration, hard_pwm=False):
def __init__(self, mcu, pin, cycle_time, hard_cycle_ticks, max_duration):
self._mcu = mcu
self._oid = mcu.create_oid()
pin, pullup, self._invert = parse_pin_extras(pin)
self._last_clock = 0
self._mcu_freq = mcu.get_mcu_freq()
self._cmd_queue = mcu.alloc_command_queue()
if hard_pwm:
if hard_cycle_ticks:
mcu.add_config_cmd(
"config_pwm_out oid=%d pin=%s cycle_ticks=%d default_value=%d"
" max_duration=%d" % (
self._oid, pin, cycle_ticks, self._invert, max_duration))
" max_duration=TICKS(%f)" % (
self._oid, pin, hard_cycle_ticks, self._invert,
max_duration))
self._set_cmd = mcu.lookup_command(
"schedule_pwm_out oid=%c clock=%u value=%c")
else:
mcu.add_config_cmd(
"config_soft_pwm_out oid=%d pin=%s cycle_ticks=%d"
" default_value=%d max_duration=%d" % (
self._oid, pin, cycle_ticks, self._invert, max_duration))
"config_soft_pwm_out oid=%d pin=%s cycle_ticks=TICKS(%f)"
" default_value=%d max_duration=TICKS(%f)" % (
self._oid, pin, cycle_time, self._invert, max_duration))
self._set_cmd = mcu.lookup_command(
"schedule_soft_pwm_out oid=%c clock=%u value=%c")
self.print_to_mcu_time = mcu.print_to_mcu_time
@ -461,7 +462,8 @@ class MCU:
updated_cmds = []
for cmd in self._config_cmds:
try:
updated_cmds.append(pins.update_command(cmd, pnames))
updated_cmds.append(pins.update_command(
cmd, self._mcu_freq, pnames))
except:
raise self._config.error("Unable to translate pin name: %s" % (
cmd,))
@ -531,16 +533,11 @@ class MCU:
def create_endstop(self, pin, stepper):
return MCU_endstop(self, pin, stepper)
def create_digital_out(self, pin, max_duration=2.):
max_duration = int(max_duration * self._mcu_freq)
return MCU_digital_out(self, pin, max_duration)
def create_pwm(self, pin, cycle_time, hard_cycle_ticks=0, max_duration=2.):
max_duration = int(max_duration * self._mcu_freq)
if hard_cycle_ticks:
return MCU_pwm(self, pin, hard_cycle_ticks, max_duration, True)
if hard_cycle_ticks < 0:
return MCU_digital_out(self, pin, max_duration)
cycle_ticks = int(cycle_time * self._mcu_freq)
return MCU_pwm(self, pin, cycle_ticks, max_duration, False)
return MCU_pwm(self, pin, cycle_time, hard_cycle_ticks, max_duration)
def create_adc(self, pin):
return MCU_adc(self, pin)
# Clock syncing

View File

@ -100,9 +100,12 @@ def get_pin_map(mcu, mapping_name=None):
pins['analog%d' % (i,)] = pins[apins[i]]
return pins
# Translate pin names in a firmware command
# Translate pin names and tick times in a firmware command
re_pin = re.compile(r'(?P<prefix>[ _]pin=)(?P<name>[^ ]*)')
def update_command(cmd, pmap):
def fixup(m):
re_ticks = re.compile(r'TICKS\((?P<ticks>[^)]*)\)')
def update_command(cmd, mcu_freq, pmap):
def pin_fixup(m):
return m.group('prefix') + str(pmap[m.group('name')])
return re_pin.sub(fixup, cmd)
def ticks_fixup(m):
return str(int(mcu_freq * float(m.group('ticks'))))
return re_ticks.sub(ticks_fixup, re_pin.sub(pin_fixup, cmd))