diff --git a/klippy/pins.py b/klippy/pins.py index 20f78295..9a3f1ccf 100644 --- a/klippy/pins.py +++ b/klippy/pins.py @@ -40,6 +40,7 @@ MCU_PINS = { "at90usb1286": port_pins(6), "at90usb646": port_pins(6), "atmega1280": port_pins(12), "atmega2560": port_pins(12), "sam3x8e": port_pins(4, 32), + "samd21g": port_pins(2, 32), "stm32f103": port_pins(5, 16), "lpc176x": lpc_pins(), "pru": beaglebone_pins(), diff --git a/src/samd21/Kconfig b/src/samd21/Kconfig index afdd3dc0..d8108f71 100644 --- a/src/samd21/Kconfig +++ b/src/samd21/Kconfig @@ -5,6 +5,7 @@ if MACH_SAMD21 config SAMD_SELECT bool default y + select HAVE_GPIO config BOARD_DIRECTORY string diff --git a/src/samd21/gpio.c b/src/samd21/gpio.c index 3ae51f74..cf2d6618 100644 --- a/src/samd21/gpio.c +++ b/src/samd21/gpio.c @@ -4,8 +4,17 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. +#include "board/irq.h" // irq_save +#include "command.h" // shutdown +#include "gpio.h" // gpio_out_setup #include "internal.h" // gpio_peripheral #include "samd21.h" // PORT +#include "sched.h" // sched_shutdown + + +/**************************************************************** + * Pin multiplexing + ****************************************************************/ void gpio_peripheral(char bank, uint32_t bit, char ptype, uint32_t pull_up) @@ -20,3 +29,81 @@ gpio_peripheral(char bank, uint32_t bit, char ptype, uint32_t pull_up) pg->PINCFG[bit].reg = ((ptype ? PORT_PINCFG_PMUXEN : 0) | (pull_up ? PORT_PINCFG_PULLEN : 0)); } + + +/**************************************************************** + * General Purpose Input Output (GPIO) pins + ****************************************************************/ + +#define GPIO(PORT, NUM) (((PORT)-'A') * 32 + (NUM)) +#define GPIO2PORT(PIN) ((PIN) / 32) +#define GPIO2NUM(PIN) ((PIN) % 32) +#define GPIO2BIT(PIN) (1<<((PIN) % 32)) +#define NUM_PORT 2 + +struct gpio_out +gpio_out_setup(uint8_t pin, uint8_t val) +{ + if (GPIO2PORT(pin) >= NUM_PORT) + goto fail; + PortGroup *pg = &PORT->Group[GPIO2PORT(pin)]; + uint32_t bit = GPIO2BIT(pin); + irqstatus_t flag = irq_save(); + if (val) + pg->OUTSET.reg = bit; + else + pg->OUTCLR.reg = bit; + pg->DIRSET.reg = bit; + pg->PINCFG[GPIO2NUM(pin)].reg = 0; + irq_restore(flag); + return (struct gpio_out){ .regs=pg, .bit=bit }; +fail: + shutdown("Not an output pin"); +} + +void +gpio_out_toggle_noirq(struct gpio_out g) +{ + PortGroup *pg = g.regs; + pg->OUTTGL.reg = g.bit; +} + +void +gpio_out_toggle(struct gpio_out g) +{ + gpio_out_toggle_noirq(g); +} + +void +gpio_out_write(struct gpio_out g, uint8_t val) +{ + PortGroup *pg = g.regs; + if (val) + pg->OUTSET.reg = g.bit; + else + pg->OUTCLR.reg = g.bit; +} + + +struct gpio_in +gpio_in_setup(uint8_t pin, int8_t pull_up) +{ + if (GPIO2PORT(pin) >= NUM_PORT) + goto fail; + PortGroup *pg = &PORT->Group[GPIO2PORT(pin)]; + uint32_t bit = GPIO2BIT(pin); + irqstatus_t flag = irq_save(); + pg->PINCFG[GPIO2NUM(pin)].reg = pull_up > 0 ? PORT_PINCFG_PULLEN : 0; + pg->DIRCLR.reg = bit; + irq_restore(flag); + return (struct gpio_in){ .regs=pg, .bit=bit }; +fail: + shutdown("Not an input pin"); +} + +uint8_t +gpio_in_read(struct gpio_in g) +{ + PortGroup *pg = g.regs; + return !!(pg->IN.reg & g.bit); +} diff --git a/src/samd21/gpio.h b/src/samd21/gpio.h new file mode 100644 index 00000000..0cba5dba --- /dev/null +++ b/src/samd21/gpio.h @@ -0,0 +1,22 @@ +#ifndef __SAM3X8E_GPIO_H +#define __SAM3X8E_GPIO_H + +#include + +struct gpio_out { + void *regs; + uint32_t bit; +}; +struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); +void gpio_out_toggle_noirq(struct gpio_out g); +void gpio_out_toggle(struct gpio_out g); +void gpio_out_write(struct gpio_out g, uint8_t val); + +struct gpio_in { + void *regs; + uint32_t bit; +}; +struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up); +uint8_t gpio_in_read(struct gpio_in g); + +#endif // gpio.h