diff options
Diffstat (limited to 'src/samd21')
-rw-r--r-- | src/samd21/Kconfig | 51 | ||||
-rw-r--r-- | src/samd21/Makefile | 54 | ||||
-rw-r--r-- | src/samd21/adc.c | 121 | ||||
-rw-r--r-- | src/samd21/clock.c | 77 | ||||
-rw-r--r-- | src/samd21/gpio.c | 141 | ||||
-rw-r--r-- | src/samd21/gpio.h | 55 | ||||
-rw-r--r-- | src/samd21/hard_pwm.c | 102 | ||||
-rw-r--r-- | src/samd21/i2c.c | 114 | ||||
-rw-r--r-- | src/samd21/internal.h | 14 | ||||
-rw-r--r-- | src/samd21/main.c | 52 | ||||
-rw-r--r-- | src/samd21/serial.c | 61 | ||||
-rw-r--r-- | src/samd21/spi.c | 92 | ||||
-rw-r--r-- | src/samd21/timer.c | 66 | ||||
-rw-r--r-- | src/samd21/usbserial.c | 246 |
14 files changed, 0 insertions, 1246 deletions
diff --git a/src/samd21/Kconfig b/src/samd21/Kconfig deleted file mode 100644 index 18bd7d81..00000000 --- a/src/samd21/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -# Kconfig settings for SAMD21 processors - -if MACH_SAMD21 - -config SAMD_SELECT - bool - default y - select HAVE_GPIO - select HAVE_GPIO_ADC - select HAVE_GPIO_I2C - select HAVE_GPIO_SPI - select HAVE_GPIO_HARD_PWM - select HAVE_GPIO_BITBANGING - -config BOARD_DIRECTORY - string - default "samd21" - -config CLOCK_FREQ - int - default 48000000 - -choice - prompt "Bootloader offset" - config FLASH_START_0000 - bool "No bootloader" - config FLASH_START_2000 - bool "8KiB bootloader (Arduino Zero)" - config FLASH_START_4000 - bool "16KiB bootloader (Arduino M0)" -endchoice - -config FLASH_START - hex - default 0x4000 if FLASH_START_4000 - default 0x2000 if FLASH_START_2000 - default 0x0000 - -config USBSERIAL - bool "Use USB for communication (instead of serial)" - default y -config SERIAL - depends on !USBSERIAL - bool - default y -config SERIAL_BAUD - depends on SERIAL - int "Baud rate for serial port" - default 250000 - -endif diff --git a/src/samd21/Makefile b/src/samd21/Makefile deleted file mode 100644 index 24ef1e49..00000000 --- a/src/samd21/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -# Additional samd21 build rules - -# Setup the toolchain -CROSS_PREFIX=arm-none-eabi- - -dirs-y += src/samd21 src/generic -dirs-y += lib/samd21/samd21a/gcc/gcc/ - -CFLAGS += -mthumb -mcpu=cortex-m0plus -CFLAGS += -Ilib/cmsis-core -Ilib/samd21/samd21a/include -CFLAGS += -D__SAMD21G18A__ - -CFLAGS_klipper.elf += -T $(OUT)samd21.ld -CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs - -# Add source files -src-y += samd21/main.c samd21/timer.c samd21/clock.c samd21/gpio.c -src-y += generic/crc16_ccitt.c generic/alloc.c -src-y += generic/armcm_irq.c generic/timer_irq.c -src-y += ../lib/samd21/samd21a/gcc/gcc/startup_samd21.c -src-$(CONFIG_USBSERIAL) += samd21/usbserial.c generic/usb_cdc.c -src-$(CONFIG_SERIAL) += samd21/serial.c generic/serial_irq.c -src-$(CONFIG_HAVE_GPIO_ADC) += samd21/adc.c -src-$(CONFIG_HAVE_GPIO_I2C) += samd21/i2c.c -src-$(CONFIG_HAVE_GPIO_SPI) += samd21/spi.c -src-$(CONFIG_HAVE_GPIO_HARD_PWM) += samd21/hard_pwm.c - -# Support bootloader offset address -target-y := $(OUT)samd21.ld $(target-y) - -$(OUT)samd21.ld: lib/samd21/samd21a/gcc/gcc/samd21g18a_flash.ld $(OUT)board-link - @echo " Preprocessing $@" - $(Q)$(CPP) -P -MD -MT $@ -DFLASH_START=$(CONFIG_FLASH_START) $< -o $@ - -# Build the additional hex and bin output files -target-y += $(OUT)klipper.bin $(OUT)klipper.elf.hex - -$(OUT)klipper.bin: $(OUT)klipper.elf - @echo " Creating hex file $@" - $(Q)$(OBJCOPY) -O binary $< $@ - -$(OUT)klipper.elf.hex: $(OUT)klipper.elf - @echo " Creating hex file $@" - $(Q)$(OBJCOPY) -j .text -j .relocate -O ihex $< $@ - -# Flash rules -lib/bossac/bin/bossac: - @echo " Building bossac" - $(Q)make -C lib/bossac bin/bossac - -flash: $(OUT)klipper.bin lib/bossac/bin/bossac - @echo " Flashing $^ to $(FLASH_DEVICE) via bossac" - $(Q)if [ -z $(FLASH_DEVICE) ]; then echo "Please specify FLASH_DEVICE"; exit 1; fi - $(Q)lib/bossac/bin/bossac -U -p "$(FLASH_DEVICE)" -a --offset=0x2000 -w $(OUT)klipper.bin -v -b -R diff --git a/src/samd21/adc.c b/src/samd21/adc.c deleted file mode 100644 index 38836592..00000000 --- a/src/samd21/adc.c +++ /dev/null @@ -1,121 +0,0 @@ -// Analog to Digital Converter support -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "command.h" // shutdown -#include "gpio.h" // gpio_adc_read -#include "internal.h" // GPIO -#include "samd21.h" // ADC -#include "sched.h" // sched_shutdown - -static const uint8_t adc_pins[] = { - GPIO('A', 2), GPIO('A', 3), GPIO('B', 8), GPIO('B', 9), GPIO('A', 4), - GPIO('A', 5), GPIO('A', 6), GPIO('A', 7), GPIO('B', 0), GPIO('B', 1), - GPIO('B', 2), GPIO('B', 3), GPIO('B', 4), GPIO('B', 5), GPIO('B', 6), - GPIO('B', 7), GPIO('A', 8), GPIO('A', 9), GPIO('A', 10), GPIO('A', 11) -}; - -DECL_CONSTANT(ADC_MAX, 4095); - -static void -adc_init(void) -{ - static uint8_t have_run_init; - if (have_run_init) - return; - have_run_init = 1; - - // Enable adc clock - enable_pclock(ADC_GCLK_ID, PM_APBCMASK_ADC); - - // Load calibraiton info - uint32_t v = *((uint32_t*)ADC_FUSES_BIASCAL_ADDR); - uint32_t bias = (v & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; - v = *((uint32_t*)ADC_FUSES_LINEARITY_0_ADDR); - uint32_t li0 = (v & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; - v = *((uint32_t*)ADC_FUSES_LINEARITY_1_ADDR); - uint32_t li5 = (v & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos; - uint32_t lin = li0 | (li5 << 5); - ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(lin); - - // Setup and enable adc - ADC->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC1; - ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV128; - ADC->SAMPCTRL.reg = 63; - ADC->CTRLA.reg = ADC_CTRLA_ENABLE; -} - -struct gpio_adc -gpio_adc_setup(uint8_t pin) -{ - // Find pin in adc_pins table - uint8_t chan; - for (chan=0; ; chan++) { - if (chan >= ARRAY_SIZE(adc_pins)) - shutdown("Not a valid ADC pin"); - if (adc_pins[chan] == pin) - break; - } - - // Enable ADC - adc_init(); - - // Set pin in ADC mode - gpio_peripheral(pin, 'B', 0); - - return (struct gpio_adc){ chan }; -} - -enum { ADC_DUMMY=0xff }; -static uint8_t last_analog_read = ADC_DUMMY; - -// Try to sample a value. Returns zero if sample ready, otherwise -// returns the number of clock ticks the caller should wait before -// retrying this function. -uint32_t -gpio_adc_sample(struct gpio_adc g) -{ - if (last_analog_read == g.chan) { - if (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY) - // Sample now ready - return 0; - // ADC is still busy - goto need_delay; - } - if (last_analog_read != ADC_DUMMY) - // Sample on another channel in progress - goto need_delay; - last_analog_read = g.chan; - - // Set the channel to sample - ADC->INPUTCTRL.reg = (ADC_INPUTCTRL_MUXPOS(g.chan) - | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_GAIN_DIV2); - - // Start the sample - ADC->SWTRIG.reg = ADC_SWTRIG_START; - - // Schedule next attempt after sample is likely to be complete -need_delay: - return 42 * 128 + 200; // 42 == 1 + (63+1)/2 + 1 + 12/2 + 1.5 -} - -// Read a value; use only after gpio_adc_sample() returns zero -uint16_t -gpio_adc_read(struct gpio_adc g) -{ - last_analog_read = ADC_DUMMY; - return ADC->RESULT.reg; -} - -// Cancel a sample that may have been started with gpio_adc_sample() -void -gpio_adc_cancel_sample(struct gpio_adc g) -{ - if (last_analog_read == g.chan) { - ADC->SWTRIG.reg = ADC_SWTRIG_FLUSH; - ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY; - last_analog_read = ADC_DUMMY; - } -} diff --git a/src/samd21/clock.c b/src/samd21/clock.c deleted file mode 100644 index ef0cd9bc..00000000 --- a/src/samd21/clock.c +++ /dev/null @@ -1,77 +0,0 @@ -// Code to setup peripheral clocks on the SAMD21 -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "compiler.h" // DIV_ROUND_CLOSEST -#include "internal.h" // enable_pclock -#include "samd21.h" // GCLK - -// The "generic clock generators" that are configured -#define CLKGEN_MAIN 0 -#define CLKGEN_32K 1 -#define CLKGEN_ULP32K 2 - -// Enable a peripheral clock and power to that peripheral -void -enable_pclock(uint32_t clock_id, uint32_t pmask) -{ - GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(clock_id) - | GCLK_CLKCTRL_GEN(CLKGEN_MAIN) | GCLK_CLKCTRL_CLKEN); - while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) - ; - PM->APBCMASK.reg |= pmask; -} - -#define FREQ_XOSC32K 32768 - -void -SystemInit(void) -{ - // Setup flash to work with 48Mhz clock - NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS_HALF; - - // Enable external 32Khz crystal - uint32_t val = (SYSCTRL_XOSC32K_STARTUP(6) - | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K); - SYSCTRL->XOSC32K.reg = val; - SYSCTRL->XOSC32K.reg = val | SYSCTRL_XOSC32K_ENABLE; - while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY)) - ; - - // Reset GCLK - GCLK->CTRL.reg = GCLK_CTRL_SWRST; - while (GCLK->CTRL.reg & GCLK_CTRL_SWRST) - ; - - // Route external 32Khz clock to DFLL48M (via CLKGEN_32K) - GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLKGEN_32K); - GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLKGEN_32K) - | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN); - GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(SYSCTRL_GCLK_ID_DFLL48) - | GCLK_CLKCTRL_GEN(CLKGEN_32K) | GCLK_CLKCTRL_CLKEN); - while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) - ; - - // Configure DFLL48M clock - SYSCTRL->DFLLCTRL.reg = 0; - uint32_t mul = DIV_ROUND_CLOSEST(CONFIG_CLOCK_FREQ, FREQ_XOSC32K); - SYSCTRL->DFLLMUL.reg = (SYSCTRL_DFLLMUL_CSTEP(31) - | SYSCTRL_DFLLMUL_FSTEP(511) - | SYSCTRL_DFLLMUL_MUL(mul)); - SYSCTRL->DFLLCTRL.reg = (SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK - | SYSCTRL_DFLLCTRL_QLDIS - | SYSCTRL_DFLLCTRL_ENABLE); - uint32_t ready = (SYSCTRL_PCLKSR_DFLLRDY | SYSCTRL_PCLKSR_DFLLLCKC - | SYSCTRL_PCLKSR_DFLLLCKF); - while ((SYSCTRL->PCLKSR.reg & ready) != ready) - ; - - // Switch main clock to DFLL48M clock - GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLKGEN_MAIN); - GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLKGEN_MAIN) - | GCLK_GENCTRL_SRC_DFLL48M - | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN); -} diff --git a/src/samd21/gpio.c b/src/samd21/gpio.c deleted file mode 100644 index 045dc003..00000000 --- a/src/samd21/gpio.c +++ /dev/null @@ -1,141 +0,0 @@ -// samd21 gpio functions -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include <string.h> // ffs -#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(uint32_t gpio, char ptype, int32_t pull_up) -{ - uint32_t bank = GPIO2PORT(gpio), bit = gpio % 32; - PortGroup *pg = &PORT->Group[bank]; - if (ptype) { - volatile uint8_t *pmux = &pg->PMUX[bit/2].reg; - uint8_t shift = (bit & 1) ? 4 : 0, mask = ~(0xf << shift); - *pmux = (*pmux & mask) | ((ptype - 'A') << shift); - } - if (pull_up) { - if (pull_up > 0) - pg->OUTSET.reg = (1<<bit); - else - pg->OUTCLR.reg = (1<<bit); - } - - pg->PINCFG[bit].reg = ((ptype ? PORT_PINCFG_PMUXEN : 0) - | (pull_up ? PORT_PINCFG_PULLEN : 0)); -} - - -/**************************************************************** - * General Purpose Input Output (GPIO) pins - ****************************************************************/ - -#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)]; - struct gpio_out g = { .regs=pg, .bit=GPIO2BIT(pin) }; - gpio_out_reset(g, val); - return g; -fail: - shutdown("Not an output pin"); -} - -static void -set_pincfg(PortGroup *pg, uint32_t bit, uint8_t cfg) -{ - pg->PINCFG[ffs(bit)-1].reg = cfg; -} - -void -gpio_out_reset(struct gpio_out g, uint8_t val) -{ - PortGroup *pg = g.regs; - irqstatus_t flag = irq_save(); - if (val) - pg->OUTSET.reg = g.bit; - else - pg->OUTCLR.reg = g.bit; - pg->DIRSET.reg = g.bit; - set_pincfg(pg, g.bit, 0); - irq_restore(flag); -} - -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)]; - struct gpio_in g = { .regs=pg, .bit=GPIO2BIT(pin) }; - gpio_in_reset(g, pull_up); - return g; -fail: - shutdown("Not an input pin"); -} - -void -gpio_in_reset(struct gpio_in g, int8_t pull_up) -{ - PortGroup *pg = g.regs; - irqstatus_t flag = irq_save(); - uint32_t cfg = PORT_PINCFG_INEN; - if (pull_up) { - cfg |= PORT_PINCFG_PULLEN; - if (pull_up > 0) - pg->OUTSET.reg = g.bit; - else - pg->OUTCLR.reg = g.bit; - } - set_pincfg(pg, g.bit, cfg); - pg->DIRCLR.reg = g.bit; - irq_restore(flag); -} - -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 deleted file mode 100644 index 5bf44454..00000000 --- a/src/samd21/gpio.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef __SAM3X8E_GPIO_H -#define __SAM3X8E_GPIO_H - -#include <stdint.h> - -struct gpio_out { - void *regs; - uint32_t bit; -}; -struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val); -void gpio_out_reset(struct gpio_out g, 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); -void gpio_in_reset(struct gpio_in g, int8_t pull_up); -uint8_t gpio_in_read(struct gpio_in g); - -struct gpio_pwm { - void *reg; -}; -struct gpio_pwm gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint8_t val); -void gpio_pwm_write(struct gpio_pwm g, uint8_t val); - -struct gpio_adc { - uint32_t chan; -}; -struct gpio_adc gpio_adc_setup(uint8_t pin); -uint32_t gpio_adc_sample(struct gpio_adc g); -uint16_t gpio_adc_read(struct gpio_adc g); -void gpio_adc_cancel_sample(struct gpio_adc g); - -struct spi_config { - uint32_t ctrla, baud; -}; -struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate); -void spi_prepare(struct spi_config config); -void spi_transfer(struct spi_config config, uint8_t receive_data - , uint8_t len, uint8_t *data); - -struct i2c_config { - uint8_t addr; -}; - -struct i2c_config i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr); -void i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write); -void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg - , uint8_t read_len, uint8_t *read); - -#endif // gpio.h diff --git a/src/samd21/hard_pwm.c b/src/samd21/hard_pwm.c deleted file mode 100644 index 7deecfb9..00000000 --- a/src/samd21/hard_pwm.c +++ /dev/null @@ -1,102 +0,0 @@ -// Hardware PWM support on samd21 -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "command.h" // shutdown -#include "gpio.h" // gpio_pwm_write -#include "internal.h" // GPIO -#include "samd21.h" // TCC0 -#include "sched.h" // sched_shutdown - -struct gpio_pwm_info { - uint32_t gpio; - Tcc *tcc; - uint32_t clock_id, power_id, channel; - char ptype; -}; - -static const struct gpio_pwm_info pwm_regs[] = { - { GPIO('A', 4), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 0, 'E' }, - { GPIO('A', 5), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 1, 'E' }, - { GPIO('A', 6), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 0, 'E' }, - { GPIO('A', 7), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 1, 'E' }, - { GPIO('A', 8), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 0, 'E' }, - { GPIO('A', 9), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 1, 'E' }, - { GPIO('A', 10), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 0, 'E' }, - { GPIO('A', 11), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 1, 'E' }, - { GPIO('A', 12), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 0, 'E' }, - { GPIO('A', 13), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 1, 'E' }, - { GPIO('A', 16), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 0, 'E' }, - { GPIO('A', 17), TCC2, TCC2_GCLK_ID, PM_APBCMASK_TCC2, 1, 'E' }, - { GPIO('A', 18), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 2, 'F' }, - { GPIO('A', 19), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 3, 'F' }, - { GPIO('A', 24), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 2, 'F' }, - { GPIO('A', 25), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 3, 'F' }, - { GPIO('A', 30), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 0, 'E' }, - { GPIO('A', 31), TCC1, TCC1_GCLK_ID, PM_APBCMASK_TCC1, 1, 'E' }, - { GPIO('B', 30), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 0, 'E' }, - { GPIO('B', 31), TCC0, TCC0_GCLK_ID, PM_APBCMASK_TCC0, 1, 'E' }, -}; - -#define MAX_PWM 255 - -DECL_CONSTANT(PWM_MAX, MAX_PWM); - -struct gpio_pwm -gpio_pwm_setup(uint8_t pin, uint32_t cycle_time, uint8_t val) -{ - // Find pin in pwm_regs table - const struct gpio_pwm_info *p = pwm_regs; - for (; ; p++) { - if (p >= &pwm_regs[ARRAY_SIZE(pwm_regs)]) - shutdown("Not a valid PWM pin"); - if (p->gpio == pin) - break; - } - - // Enable timer clock - enable_pclock(p->clock_id, p->power_id); - - // Map cycle_time to pwm clock divisor - uint32_t cs; - switch (cycle_time) { - case 0 ... (1+2) * MAX_PWM / 2 - 1: cs = 0; break; - case (1+2) * MAX_PWM / 2 ... (2+4) * MAX_PWM / 2 - 1: cs = 1; break; - case (2+4) * MAX_PWM / 2 ... (4+8) * MAX_PWM / 2 - 1: cs = 2; break; - case (4+8) * MAX_PWM / 2 ... (8+16) * MAX_PWM / 2 - 1: cs = 3; break; - case (8+16) * MAX_PWM / 2 ... (16+64) * MAX_PWM / 2 - 1: cs = 4; break; - case (16+64) * MAX_PWM / 2 ... (64+256) * MAX_PWM / 2 - 1: cs = 5; break; - case (64+256) * MAX_PWM / 2 ... (256+1024) * MAX_PWM / 2 - 1: cs = 6; break; - default: cs = 7; break; - } - uint32_t ctrla = TCC_CTRLA_ENABLE | TCC_CTRLA_PRESCALER(cs); - - // Enable timer - Tcc *tcc = p->tcc; - uint32_t old_ctrla = tcc->CTRLA.reg; - if (old_ctrla != ctrla) { - if (old_ctrla & TCC_CTRLA_ENABLE) - shutdown("PWM already programmed at different speed"); - tcc->CTRLA.reg = ctrla & ~TCC_CTRLA_ENABLE; - tcc->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; - tcc->PER.reg = MAX_PWM; - tcc->CTRLA.reg = ctrla; - } - - // Set initial value - struct gpio_pwm g = (struct gpio_pwm) { (void*)&tcc->CCB[p->channel].reg }; - gpio_pwm_write(g, val); - - // Route output to pin - gpio_peripheral(pin, p->ptype, 0); - - return g; -} - -void -gpio_pwm_write(struct gpio_pwm g, uint8_t val) -{ - *(volatile uint32_t*)g.reg = val; -} diff --git a/src/samd21/i2c.c b/src/samd21/i2c.c deleted file mode 100644 index 801c0e32..00000000 --- a/src/samd21/i2c.c +++ /dev/null @@ -1,114 +0,0 @@ -// i2c support on samd21 -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "internal.h" // enable_pclock -#include "command.h" // shutdown -#include "gpio.h" // i2c_setup -#include "samd21.h" // SERCOM3 -#include "sched.h" // sched_shutdown - -#define TIME_RISE 125ULL // 125 nanoseconds -#define I2C_FREQ 100000 - -static void -i2c_init(void) -{ - static int have_run_init; - if (have_run_init) - return; - have_run_init = 1; - - // Setup clock - enable_pclock(SERCOM3_GCLK_ID_CORE, PM_APBCMASK_SERCOM3); - - // Configure SDA, SCL pins - gpio_peripheral(GPIO('A', 22), 'C', 0); - gpio_peripheral(GPIO('A', 23), 'C', 0); - - // Configure i2c - SercomI2cm *si = &SERCOM3->I2CM; - si->CTRLA.reg = 0; - uint32_t areg = (SERCOM_I2CM_CTRLA_LOWTOUTEN - | SERCOM_I2CM_CTRLA_INACTOUT(3) - | SERCOM_I2CM_STATUS_SEXTTOUT - | SERCOM_I2CM_STATUS_MEXTTOUT - | SERCOM_I2CM_CTRLA_MODE_I2C_MASTER); - si->CTRLA.reg = areg; - uint32_t baud = (CONFIG_CLOCK_FREQ / I2C_FREQ - - 10 - CONFIG_CLOCK_FREQ*TIME_RISE/1000000000) / 2; - si->BAUD.reg = baud; - si->CTRLA.reg = areg | SERCOM_I2CM_CTRLA_ENABLE; - while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_ENABLE) - ; - - // Go into idle mode - si->STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1); - while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_SYSOP) - ; -} - -struct i2c_config -i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr) -{ - if (bus) - shutdown("Unsupported i2c bus"); - i2c_init(); - return (struct i2c_config){ .addr=addr<<1 }; -} - -static void -i2c_wait(SercomI2cm *si) -{ - for (;;) { - uint32_t intflag = si->INTFLAG.reg; - if (!(intflag & SERCOM_I2CM_INTFLAG_MB)) { - if (si->STATUS.reg & SERCOM_I2CM_STATUS_BUSERR) - shutdown("i2c buserror"); - continue; - } - if (intflag & SERCOM_I2CM_INTFLAG_ERROR) - shutdown("i2c error"); - break; - } -} - -static void -i2c_start(SercomI2cm *si, uint8_t addr) -{ - si->ADDR.reg = addr; - i2c_wait(si); -} - -static void -i2c_send_byte(SercomI2cm *si, uint8_t b) -{ - si->DATA.reg = b; - i2c_wait(si); -} - -static void -i2c_stop(SercomI2cm *si) -{ - si->CTRLB.reg = SERCOM_I2CM_CTRLB_CMD(3); -} - -void -i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write) -{ - SercomI2cm *si = &SERCOM3->I2CM; - i2c_start(si, config.addr); - while (write_len--) - i2c_send_byte(si, *write++); - i2c_stop(si); -} - -void -i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg - , uint8_t read_len, uint8_t *read) -{ - shutdown("i2c_read not supported on samd21"); -} diff --git a/src/samd21/internal.h b/src/samd21/internal.h deleted file mode 100644 index 7043007f..00000000 --- a/src/samd21/internal.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __SAMD21_INTERNAL_H -#define __SAMD21_INTERNAL_H -// Local definitions for samd21 code - -#include <stdint.h> // uint32_t - -#define GPIO(PORT, NUM) (((PORT)-'A') * 32 + (NUM)) -#define GPIO2PORT(PIN) ((PIN) / 32) -#define GPIO2BIT(PIN) (1<<((PIN) % 32)) - -void enable_pclock(uint32_t clock_id, uint32_t pmask); -void gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up); - -#endif // internal.h diff --git a/src/samd21/main.c b/src/samd21/main.c deleted file mode 100644 index 4687fc34..00000000 --- a/src/samd21/main.c +++ /dev/null @@ -1,52 +0,0 @@ -// Main starting point for SAMD21 boards -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "command.h" // DECL_CONSTANT -#include "samd21.h" // SystemInit -#include "sched.h" // sched_main - -DECL_CONSTANT(MCU, "samd21g"); - - -/**************************************************************** - * watchdog handler - ****************************************************************/ - -void -watchdog_reset(void) -{ - WDT->CLEAR.reg = 0xa5; -} -DECL_TASK(watchdog_reset); - -void -watchdog_init(void) -{ - WDT->CONFIG.reg = WDT_CONFIG_PER_16K; // 500ms timeout - WDT->CTRL.reg = WDT_CTRL_ENABLE; -} -DECL_INIT(watchdog_init); - - -/**************************************************************** - * misc functions - ****************************************************************/ - -void -command_reset(uint32_t *args) -{ - NVIC_SystemReset(); -} -DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset"); - -// Main entry point -int -main(void) -{ - SystemInit(); - sched_main(); - return 0; -} diff --git a/src/samd21/serial.c b/src/samd21/serial.c deleted file mode 100644 index 895ffb27..00000000 --- a/src/samd21/serial.c +++ /dev/null @@ -1,61 +0,0 @@ -// samd21 serial port -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_SERIAL_BAUD -#include "board/serial_irq.h" // serial_rx_data -#include "internal.h" // enable_pclock -#include "samd21.h" // SERCOM0 -#include "sched.h" // DECL_INIT - -void -serial_init(void) -{ - // Enable serial clock - enable_pclock(SERCOM0_GCLK_ID_CORE, PM_APBCMASK_SERCOM0); - // Enable pins - gpio_peripheral(GPIO('A', 10), 'C', 0); - gpio_peripheral(GPIO('A', 11), 'C', 0); - // Configure serial - SercomUsart *su = &SERCOM0->USART; - su->CTRLA.reg = 0; - uint32_t areg = (SERCOM_USART_CTRLA_MODE_USART_INT_CLK - | SERCOM_USART_CTRLA_DORD - | SERCOM_USART_CTRLA_SAMPR(1) - | SERCOM_USART_CTRLA_TXPO(1) - | SERCOM_USART_CTRLA_RXPO(3)); - su->CTRLA.reg = areg; - su->CTRLB.reg = SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN; - uint32_t baud8 = CONFIG_CLOCK_FREQ / (2 * CONFIG_SERIAL_BAUD); - su->BAUD.reg = (SERCOM_USART_BAUD_FRAC_BAUD(baud8 / 8) - | SERCOM_USART_BAUD_FRAC_FP(baud8 % 8)); - NVIC_SetPriority(SERCOM0_IRQn, 0); - NVIC_EnableIRQ(SERCOM0_IRQn); - su->INTENSET.reg = SERCOM_USART_INTENSET_RXC; - su->CTRLA.reg = areg | SERCOM_USART_CTRLA_ENABLE; -} -DECL_INIT(serial_init); - -void __visible -SERCOM0_Handler(void) -{ - uint32_t status = SERCOM0->USART.INTFLAG.reg; - if (status & SERCOM_USART_INTFLAG_RXC) - serial_rx_byte(SERCOM0->USART.DATA.reg); - if (status & SERCOM_USART_INTFLAG_DRE) { - uint8_t data; - int ret = serial_get_tx_byte(&data); - if (ret) - SERCOM0->USART.INTENCLR.reg = SERCOM_USART_INTENSET_DRE; - else - SERCOM0->USART.DATA.reg = data; - } -} - -void -serial_enable_tx_irq(void) -{ - SERCOM0->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE; -} diff --git a/src/samd21/spi.c b/src/samd21/spi.c deleted file mode 100644 index 12c7d680..00000000 --- a/src/samd21/spi.c +++ /dev/null @@ -1,92 +0,0 @@ -// spi support on samd21 -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "internal.h" // enable_pclock -#include "command.h" // shutdown -#include "gpio.h" // spi_setup -#include "samd21.h" // SERCOM4 -#include "sched.h" // sched_shutdown - -static void -spi_init(uint32_t ctrla, uint32_t baud) -{ - static int have_run_init; - if (have_run_init) - return; - have_run_init = 1; - - // Setup clock - enable_pclock(SERCOM4_GCLK_ID_CORE, PM_APBCMASK_SERCOM4); - - // Configure MISO, MOSI, SCK pins - gpio_peripheral(GPIO('A', 12), 'D', 0); - gpio_peripheral(GPIO('B', 10), 'D', 0); - gpio_peripheral(GPIO('B', 11), 'D', 0); - - // Configure spi - SercomSpi *ss = &SERCOM4->SPI; - ss->CTRLA.reg = 0; - ss->CTRLA.reg = ctrla & ~SERCOM_SPI_CTRLA_ENABLE; - ss->CTRLB.reg = SERCOM_SPI_CTRLB_RXEN; - ss->BAUD.reg = baud; - ss->CTRLA.reg = ctrla; -} - -struct spi_config -spi_setup(uint32_t bus, uint8_t mode, uint32_t rate) -{ - if (bus) - shutdown("Invalid spi bus"); - - uint32_t ctrla = (SERCOM_SPI_CTRLA_MODE_SPI_MASTER - | (mode << SERCOM_SPI_CTRLA_CPHA_Pos) - | SERCOM_SPI_CTRLA_DIPO(0) - | SERCOM_SPI_CTRLA_DOPO(1) - | SERCOM_SPI_CTRLA_ENABLE); - uint32_t baud = CONFIG_CLOCK_FREQ / (2 * rate) - 1; - spi_init(ctrla, baud); - return (struct spi_config){ .ctrla = ctrla, .baud = baud }; -} - -void -spi_prepare(struct spi_config config) -{ - uint32_t ctrla = config.ctrla, baud = config.baud; - SercomSpi *ss = &SERCOM4->SPI; - if (ctrla == ss->CTRLA.reg && baud == ss->BAUD.reg) - return; - ss->CTRLA.reg = ctrla & ~SERCOM_SPI_CTRLA_ENABLE; - ss->CTRLA.reg = ctrla & ~SERCOM_SPI_CTRLA_ENABLE; - ss->BAUD.reg = baud; - ss->CTRLA.reg = ctrla; -} - -void -spi_transfer(struct spi_config config, uint8_t receive_data - , uint8_t len, uint8_t *data) -{ - SercomSpi *ss = &SERCOM4->SPI; - if (receive_data) { - while (len--) { - ss->DATA.reg = *data; - // wait for receive register - while (!(ss->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) - ; - // get data - *data++ = ss->DATA.reg; - } - } else { - while (len--) { - ss->DATA.reg = *data++; - // wait for receive register - while (!(ss->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) - ; - // read data (to clear RXC) - ss->DATA.reg; - } - } -} diff --git a/src/samd21/timer.c b/src/samd21/timer.c deleted file mode 100644 index 882b4c10..00000000 --- a/src/samd21/timer.c +++ /dev/null @@ -1,66 +0,0 @@ -// SAMD21 timer interrupt scheduling -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "board/irq.h" // irq_disable -#include "board/misc.h" // timer_read_time -#include "board/timer_irq.h" // timer_dispatch_many -#include "internal.h" // enable_pclock -#include "samd21.h" // TC4 -#include "sched.h" // DECL_INIT - -// Set the next irq time -static void -timer_set(uint32_t value) -{ - TC4->COUNT32.CC[0].reg = value; - TC4->COUNT32.INTFLAG.reg = TC_INTFLAG_MC0; -} - -// Return the current time (in absolute clock ticks). -uint32_t -timer_read_time(void) -{ - return TC4->COUNT32.COUNT.reg; -} - -// Activate timer dispatch as soon as possible -void -timer_kick(void) -{ - timer_set(timer_read_time() + 50); -} - -void -timer_init(void) -{ - // Supply power and clock to the timer - enable_pclock(TC3_GCLK_ID, PM_APBCMASK_TC3); - enable_pclock(TC4_GCLK_ID, PM_APBCMASK_TC4); - - // Configure the timer - TcCount32 *tc = &TC4->COUNT32; - irqstatus_t flag = irq_save(); - tc->CTRLA.reg = 0; - tc->CTRLA.reg = TC_CTRLA_MODE_COUNT32; - NVIC_SetPriority(TC4_IRQn, 2); - NVIC_EnableIRQ(TC4_IRQn); - tc->INTENSET.reg = TC_INTENSET_MC0; - tc->COUNT.reg = 0; - timer_kick(); - tc->CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_ENABLE; - irq_restore(flag); -} -DECL_INIT(timer_init); - -// IRQ handler -void __visible __aligned(16) // aligning helps stabilize perf benchmarks -TC4_Handler(void) -{ - irq_disable(); - uint32_t next = timer_dispatch_many(); - timer_set(next); - irq_enable(); -} diff --git a/src/samd21/usbserial.c b/src/samd21/usbserial.c deleted file mode 100644 index 0864a4c5..00000000 --- a/src/samd21/usbserial.c +++ /dev/null @@ -1,246 +0,0 @@ -// Hardware interface to USB on samd21 -// -// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net> -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include <string.h> // memcpy -#include "autoconf.h" // CONFIG_FLASH_START -#include "board/io.h" // readl -#include "board/irq.h" // irq_disable -#include "board/usb_cdc.h" // usb_notify_ep0 -#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN -#include "internal.h" // enable_pclock -#include "samd21.h" // USB -#include "sched.h" // DECL_INIT - - -/**************************************************************** - * USB transfer memory - ****************************************************************/ - -static uint8_t __aligned(4) ep0out[USB_CDC_EP0_SIZE]; -static uint8_t __aligned(4) ep0in[USB_CDC_EP0_SIZE]; -static uint8_t __aligned(4) acmin[USB_CDC_EP_ACM_SIZE]; -static uint8_t __aligned(4) bulkout[USB_CDC_EP_BULK_OUT_SIZE]; -static uint8_t __aligned(4) bulkin[USB_CDC_EP_BULK_IN_SIZE]; - -static UsbDeviceDescriptor usb_desc[USB_CDC_EP_BULK_IN + 1] = { - [0] = { { - { - .ADDR.reg = (uint32_t)ep0out, - .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(ep0out) >> 4), - }, { - .ADDR.reg = (uint32_t)ep0in, - .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(ep0in) >> 4), - }, - } }, - [USB_CDC_EP_ACM] = { { - { - }, { - .ADDR.reg = (uint32_t)acmin, - .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(acmin) >> 4), - }, - } }, - [USB_CDC_EP_BULK_OUT] = { { - { - .ADDR.reg = (uint32_t)bulkout, - .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(bulkout) >> 4), - }, { - }, - } }, - [USB_CDC_EP_BULK_IN] = { { - { - }, { - .ADDR.reg = (uint32_t)bulkin, - .PCKSIZE.reg = USB_DEVICE_PCKSIZE_SIZE(sizeof(bulkin) >> 4), - }, - } }, -}; - - -/**************************************************************** - * Interface - ****************************************************************/ - -#define EP0 USB->DEVICE.DeviceEndpoint[0] -#define EP_ACM USB->DEVICE.DeviceEndpoint[USB_CDC_EP_ACM] -#define EP_BULKOUT USB->DEVICE.DeviceEndpoint[USB_CDC_EP_BULK_OUT] -#define EP_BULKIN USB->DEVICE.DeviceEndpoint[USB_CDC_EP_BULK_IN] - -static int_fast8_t -usb_write_packet(uint32_t ep, uint32_t bank, const void *data, uint_fast8_t len) -{ - // Check if there is room for this packet - UsbDeviceEndpoint *ude = &USB->DEVICE.DeviceEndpoint[ep]; - uint8_t sts = ude->EPSTATUS.reg; - uint8_t bkrdy = (bank ? USB_DEVICE_EPSTATUS_BK1RDY - : USB_DEVICE_EPSTATUS_BK0RDY); - if (sts & bkrdy) - return -1; - // Copy the packet to the given buffer - UsbDeviceDescBank *uddb = &usb_desc[ep].DeviceDescBank[bank]; - memcpy((void*)uddb->ADDR.reg, data, len); - // Inform the USB hardware of the available packet - uint32_t pcksize = uddb->PCKSIZE.reg; - uint32_t c = pcksize & ~USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk; - uddb->PCKSIZE.reg = c | USB_DEVICE_PCKSIZE_BYTE_COUNT(len); - ude->EPSTATUSSET.reg = bkrdy; - return len; -} - -static int_fast8_t -usb_read_packet(uint32_t ep, uint32_t bank, void *data, uint_fast8_t max_len) -{ - // Check if there is a packet ready - UsbDeviceEndpoint *ude = &USB->DEVICE.DeviceEndpoint[ep]; - uint8_t sts = ude->EPSTATUS.reg; - uint8_t bkrdy = (bank ? USB_DEVICE_EPSTATUS_BK1RDY - : USB_DEVICE_EPSTATUS_BK0RDY); - if (!(sts & bkrdy)) - return -1; - // Copy the packet to the given buffer - UsbDeviceDescBank *uddb = &usb_desc[ep].DeviceDescBank[bank]; - uint32_t pcksize = uddb->PCKSIZE.reg; - uint32_t c = pcksize & USB_DEVICE_PCKSIZE_BYTE_COUNT_Msk; - if (c > max_len) - c = max_len; - memcpy(data, (void*)uddb->ADDR.reg, c); - // Notify the USB hardware that the space is now available - ude->EPSTATUSCLR.reg = bkrdy; - return c; -} - -int_fast8_t -usb_read_bulk_out(void *data, uint_fast8_t max_len) -{ - return usb_read_packet(USB_CDC_EP_BULK_OUT, 0, data, max_len); -} - -int_fast8_t -usb_send_bulk_in(void *data, uint_fast8_t len) -{ - return usb_write_packet(USB_CDC_EP_BULK_IN, 1, data, len); -} - -int_fast8_t -usb_read_ep0(void *data, uint_fast8_t max_len) -{ - return usb_read_packet(0, 0, data, max_len); -} - -int_fast8_t -usb_read_ep0_setup(void *data, uint_fast8_t max_len) -{ - return usb_read_ep0(data, max_len); -} - -int_fast8_t -usb_send_ep0(const void *data, uint_fast8_t len) -{ - return usb_write_packet(0, 1, data, len); -} - -void -usb_stall_ep0(void) -{ - EP0.EPSTATUSSET.reg = USB_DEVICE_EPSTATUS_STALLRQ(3); -} - -static uint8_t set_address; - -void -usb_set_address(uint_fast8_t addr) -{ - writeb(&set_address, addr | USB_DEVICE_DADD_ADDEN); - usb_send_ep0(NULL, 0); -} - -void -usb_set_configure(void) -{ - EP_ACM.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); - - EP_BULKOUT.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(3); - EP_BULKOUT.EPINTENSET.reg = ( - USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1); - - EP_BULKIN.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(3); - EP_BULKIN.EPINTENSET.reg = ( - USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1); -} - -void -usb_request_bootloader(void) -{ - if (CONFIG_FLASH_START) { - // Arduino Zero bootloader hack - irq_disable(); - writel((void*)0x20007FFC, 0x07738135); - NVIC_SystemReset(); - } -} - -void -usbserial_init(void) -{ - // configure usb clock - enable_pclock(USB_GCLK_ID, 0); - // configure USBD+ and USBD- pins - gpio_peripheral(GPIO('A', 24), 'G', 0); - gpio_peripheral(GPIO('A', 25), 'G', 0); - uint16_t trim = (readl((void*)USB_FUSES_TRIM_ADDR) - & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos; - uint16_t transp = (readl((void*)USB_FUSES_TRANSP_ADDR) - & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos; - uint16_t transn = (readl((void*)USB_FUSES_TRANSN_ADDR) - & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos; - USB->DEVICE.PADCAL.reg = (USB_PADCAL_TRIM(trim) | USB_PADCAL_TRANSP(transp) - | USB_PADCAL_TRANSN(transn)); - // Enable USB in device mode - USB->DEVICE.CTRLA.reg = USB_CTRLA_ENABLE; - USB->DEVICE.DESCADD.reg = (uint32_t)usb_desc; - EP0.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(1) | USB_DEVICE_EPCFG_EPTYPE1(1); - EP_ACM.EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE1(4); - USB->DEVICE.CTRLB.reg = 0; - // enable irqs - USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_EORST; - NVIC_SetPriority(USB_IRQn, 1); - NVIC_EnableIRQ(USB_IRQn); -} -DECL_INIT(usbserial_init); - -void __visible -USB_Handler(void) -{ - uint8_t s = USB->DEVICE.INTFLAG.reg; - if (s & USB_DEVICE_INTFLAG_EORST) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; - // Enable endpoint 0 irqs - EP0.EPINTENSET.reg = ( - USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 - | USB_DEVICE_EPINTENSET_RXSTP); - } - - uint16_t ep = USB->DEVICE.EPINTSMRY.reg; - if (ep & (1<<0)) { - uint8_t sts = EP0.EPINTFLAG.reg; - EP0.EPINTFLAG.reg = sts; - if (set_address && sts & USB_DEVICE_EPINTFLAG_TRCPT1) { - // Apply address after last "in" message transmitted - USB->DEVICE.DADD.reg = set_address; - set_address = 0; - } - usb_notify_ep0(); - } - if (ep & (1<<USB_CDC_EP_BULK_OUT)) { - uint8_t sts = EP_BULKOUT.EPINTFLAG.reg; - EP_BULKOUT.EPINTFLAG.reg = sts; - usb_notify_bulk_out(); - } - if (ep & (1<<USB_CDC_EP_BULK_IN)) { - uint8_t sts = EP_BULKIN.EPINTFLAG.reg; - EP_BULKIN.EPINTFLAG.reg = sts; - usb_notify_bulk_in(); - } -} |