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 but to make things more readable the host will translate human
readable pin names (eg, "PA3") to their equivalent integer readable pin names (eg, "PA3") to their equivalent integer
encodings. By convention, any parameter named "pin" or that has a 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: Common startup commands:

View File

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

View File

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

View File

@ -100,9 +100,12 @@ def get_pin_map(mcu, mapping_name=None):
pins['analog%d' % (i,)] = pins[apins[i]] pins['analog%d' % (i,)] = pins[apins[i]]
return pins 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>[^ ]*)') re_pin = re.compile(r'(?P<prefix>[ _]pin=)(?P<name>[^ ]*)')
def update_command(cmd, pmap): re_ticks = re.compile(r'TICKS\((?P<ticks>[^)]*)\)')
def fixup(m): def update_command(cmd, mcu_freq, pmap):
def pin_fixup(m):
return m.group('prefix') + str(pmap[m.group('name')]) 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))