initial_pins: Port initial_pins capability from Klipper

Some boards require an initial gpio state in order to start USB.  Port
the initial_pins capability from Klipper to provide that support.

This also synchronizes scripts/buildcommands.py with the latest code
from Klipper.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-05-16 09:28:00 -04:00 committed by Eric Callahan
parent 1ae63dfbd8
commit 24d4eb16c9
5 changed files with 114 additions and 23 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2 #!/usr/bin/env python2
# Script to handle build time requests embedded in C code. # Script to handle build time requests embedded in C code.
# #
# Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net> # Copyright (C) 2016-2021 Kevin O'Connor <kevin@koconnor.net>
# #
# This file may be distributed under the terms of the GNU GPLv3 license. # This file may be distributed under the terms of the GNU GPLv3 license.
import sys, optparse, logging import sys, optparse, logging
@ -11,7 +11,9 @@ FILEHEADER = """
#include <stdint.h> #include <stdint.h>
#include "board/irq.h" #include "board/irq.h"
#include "board/pgm.h"
#include "compiler.h" #include "compiler.h"
#include "initial_pins.h"
""" """
def error(msg): def error(msg):
@ -98,7 +100,6 @@ class HandleEnumerations:
def generate_code(self, options): def generate_code(self, options):
return "" return ""
HandlerEnumerations = HandleEnumerations() HandlerEnumerations = HandleEnumerations()
Handlers.append(HandlerEnumerations) Handlers.append(HandlerEnumerations)
@ -136,13 +137,63 @@ class HandleConstants:
rpins = [v.strip() for v in val.split(',') if v.strip()] rpins = [v.strip() for v in val.split(',') if v.strip()]
reserved_pins.extend(rpins) reserved_pins.extend(rpins)
return reserved_pins return reserved_pins
def lookup_pin(self, pin):
avail_pins = HandlerEnumerations.get_available_pins()
gpio = avail_pins.get(pin)
if gpio is None:
error("Pin %s is not available for this build" % (pin,))
reserved_pins = self.get_reserved_pins()
if pin in reserved_pins:
error("Pin %s is reserved by an active MCU peripheral" % (pin,))
return gpio
def generate_code(self, options): def generate_code(self, options):
return "" return ""
HandlerConstants = HandleConstants() HandlerConstants = HandleConstants()
Handlers.append(HandlerConstants) Handlers.append(HandlerConstants)
######################################################################
# Initial pins
######################################################################
class HandleInitialPins:
def __init__(self):
self.initial_pins = []
self.ctr_dispatch = { 'DECL_INITIAL_PINS': self.decl_initial_pins }
def decl_initial_pins(self, req):
pins = req.split(None, 1)[1].strip()
if pins.startswith('"') and pins.endswith('"'):
pins = pins[1:-1]
if pins:
self.initial_pins = [p.strip() for p in pins.split(',')]
HandlerConstants.decl_constant_str(
"_DECL_CONSTANT_STR INITIAL_PINS "
+ ','.join(self.initial_pins))
def map_pins(self):
if not self.initial_pins:
return []
out = []
for p in self.initial_pins:
flag = "IP_OUT_HIGH"
if p.startswith('!'):
flag = "0"
p = p[1:].strip()
gpio = HandlerConstants.lookup_pin(p)
out.append("\n {%d, %s}, // %s" % (gpio, flag, p))
return out
def generate_code(self, options):
out = self.map_pins()
fmt = """
const struct initial_pin_s initial_pins[] PROGMEM = {%s
};
const int initial_pins_size PROGMEM = ARRAY_SIZE(initial_pins);
"""
return fmt % (''.join(out),)
Handlers.append(HandleInitialPins())
###################################################################### ######################################################################
# ARM IRQ vector table generation # ARM IRQ vector table generation
###################################################################### ######################################################################
@ -182,9 +233,9 @@ const void *VectorTable[] __visible __section(".vector_table") = {
""" """
return fmt % (''.join(defs), ''.join(table)) return fmt % (''.join(defs), ''.join(table))
Handlers.append(Handle_arm_irq()) Handlers.append(Handle_arm_irq())
###################################################################### ######################################################################
# Status LED Functionality # Status LED Functionality
###################################################################### ######################################################################
@ -206,21 +257,15 @@ class HandleStatusLED:
if pin[0] == "!": if pin[0] == "!":
led_gpio_high = 0 led_gpio_high = 0
pin = pin[1:].strip() pin = pin[1:].strip()
avail_pins = HandlerEnumerations.get_available_pins() led_gpio = HandlerConstants.lookup_pin(pin)
reserved_pins = HandlerConstants.get_reserved_pins()
led_gpio = avail_pins.get(pin)
if led_gpio is None:
error("Pin %s is not available for this build" % pin)
if pin in reserved_pins:
error("Pin %s is reserved by an active MCU peripheral" % pin)
fmt = """ fmt = """
uint32_t led_gpio = %d, led_gpio_high = %d; // "%s" uint32_t led_gpio = %d, led_gpio_high = %d; // "%s"
""" """
return fmt % (led_gpio, led_gpio_high, self.pin) return fmt % (led_gpio, led_gpio_high, self.pin)
Handlers.append(HandleStatusLED()) Handlers.append(HandleStatusLED())
###################################################################### ######################################################################
# Button entry functionality # Button entry functionality
###################################################################### ######################################################################
@ -247,21 +292,15 @@ class HandleButton:
if pin[0] == "!": if pin[0] == "!":
button_high = 0 button_high = 0
pin = pin[1:].strip() pin = pin[1:].strip()
avail_pins = HandlerEnumerations.get_available_pins() button_gpio = HandlerConstants.lookup_pin(pin)
reserved_pins = HandlerConstants.get_reserved_pins()
button_gpio = avail_pins.get(pin)
if button_gpio is None:
error("Pin %s is not available for this build" % pin)
if pin in reserved_pins:
error("Pin %s is reserved by an active MCU peripheral" % pin)
fmt = """ fmt = """
int32_t button_gpio = %d, button_high = %d, button_pullup = %d; // "%s" int32_t button_gpio = %d, button_high = %d, button_pullup = %d; // "%s"
""" """
return fmt % (button_gpio, button_high, button_pullup, self.pin) return fmt % (button_gpio, button_high, button_pullup, self.pin)
Handlers.append(HandleButton()) Handlers.append(HandleButton())
###################################################################### ######################################################################
# Main code # Main code
###################################################################### ######################################################################
@ -271,6 +310,7 @@ def main():
opts = optparse.OptionParser(usage) opts = optparse.OptionParser(usage)
opts.add_option("-v", action="store_true", dest="verbose", opts.add_option("-v", action="store_true", dest="verbose",
help="enable debug messages") help="enable debug messages")
options, args = opts.parse_args() options, args = opts.parse_args()
if len(args) != 2: if len(args) != 2:
opts.error("Incorrect arguments") opts.error("Incorrect arguments")
@ -280,7 +320,7 @@ def main():
# Parse request file # Parse request file
ctr_dispatch = { k: v for h in Handlers for k, v in h.ctr_dispatch.items() } ctr_dispatch = { k: v for h in Handlers for k, v in h.ctr_dispatch.items() }
f = open(incmdfile, 'rb') f = open(incmdfile, 'r')
data = f.read() data = f.read()
f.close() f.close()
for req in data.split('\n'): for req in data.split('\n'):
@ -294,7 +334,7 @@ def main():
# Write output # Write output
code = "".join([FILEHEADER] + [h.generate_code(options) for h in Handlers]) code = "".join([FILEHEADER] + [h.generate_code(options) for h in Handlers])
f = open(outcfile, 'wb') f = open(outcfile, 'w')
f.write(code) f.write(code)
f.close() f.close()

View File

@ -44,6 +44,17 @@ config USB_SERIAL_NUMBER
string "USB serial number" if !USB_SERIAL_NUMBER_CHIPID string "USB serial number" if !USB_SERIAL_NUMBER_CHIPID
endmenu endmenu
config INITIAL_PINS
string "GPIO pins to set on bootloader entry"
depends on LOW_LEVEL_OPTIONS
help
One may specify a comma separated list of gpio pins to set
during bootloader entry (these gpio pins are not set if the
main application is started nor are they set while checking
for a bootloader request). By default the pins will be set to
output high - preface a pin with a '!' character to set that
pin to output low.
config ENABLE_DOUBLE_RESET config ENABLE_DOUBLE_RESET
bool "Support bootloader entry on rapid double click of reset button" bool "Support bootloader entry on rapid double click of reset button"
default y default y

View File

@ -1,4 +1,4 @@
# Main code build rules # Main code build rules
src-y += sched.c bootentry.c command.c flashcmd.c src-y += sched.c bootentry.c command.c flashcmd.c initial_pins.c
src-$(CONFIG_ENABLE_LED) += led.c src-$(CONFIG_ENABLE_LED) += led.c

25
src/initial_pins.c Normal file
View File

@ -0,0 +1,25 @@
// Support setting gpio pins at mcu start
//
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "autoconf.h" // CONFIG_INITIAL_PINS
#include "board/gpio.h" // gpio_out_setup
#include "board/pgm.h" // READP
#include "ctr.h" // DECL_CTR
#include "initial_pins.h" // initial_pins
#include "sched.h" // DECL_INIT
DECL_CTR("DECL_INITIAL_PINS " __stringify(CONFIG_INITIAL_PINS));
void
initial_pins_setup(void)
{
int i;
for (i=0; i<initial_pins_size; i++) {
const struct initial_pin_s *ip = &initial_pins[i];
gpio_out_setup(READP(ip->pin), READP(ip->flags) & IP_OUT_HIGH);
}
}
DECL_INIT(initial_pins_setup);

15
src/initial_pins.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __INITIAl_PINS_H
#define __INITIAl_PINS_H
struct initial_pin_s {
int pin;
uint8_t flags;
};
enum { IP_OUT_HIGH = 1 };
// out/compile_time_request.c (auto generated file)
extern const struct initial_pin_s initial_pins[];
extern const int initial_pins_size;
#endif // initial_pins.h