From 94c86d6c6ce85143d47b79f7cc2680c6b0ee6889 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Wed, 26 Dec 2018 16:50:44 -0500 Subject: sam3: Merge sam4e8e support into sam3 code Most of the peripherals on the sam4e8e are similar to the ones on the sam3x8e mcu. Merge the code together and use just one code directory. Signed-off-by: Kevin O'Connor --- src/Kconfig | 7 +- src/sam3/Kconfig | 23 +++++- src/sam3/Makefile | 35 +++++--- src/sam3/adc.c | 11 ++- src/sam3/gpio.c | 21 +++-- src/sam3/gpio.h | 13 ++- src/sam3/i2c.c | 180 +++++++++++++++++++++++++++++++++++++++++ src/sam3/internal.h | 9 ++- src/sam3/main.c | 8 +- src/sam3/sam4_cache.c | 16 ++++ src/sam3/sam4e_afec.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++ src/sam3/sam4e_spi.c | 124 ++++++++++++++++++++++++++++ src/sam3/serial.c | 55 ++++++++----- src/sam3/spi.c | 3 +- src/sam3/timer.c | 6 +- src/sam4e8e/Kconfig | 30 ------- src/sam4e8e/Makefile | 41 ---------- src/sam4e8e/afec.c | 206 ----------------------------------------------- src/sam4e8e/gpio.c | 173 --------------------------------------- src/sam4e8e/gpio.h | 57 ------------- src/sam4e8e/i2c.c | 180 ----------------------------------------- src/sam4e8e/internal.h | 13 --- src/sam4e8e/main.c | 48 ----------- src/sam4e8e/sam4_cache.c | 16 ---- src/sam4e8e/serial.c | 56 ------------- src/sam4e8e/spi.c | 124 ---------------------------- src/sam4e8e/timer.c | 67 --------------- 27 files changed, 651 insertions(+), 1077 deletions(-) create mode 100644 src/sam3/i2c.c create mode 100644 src/sam3/sam4_cache.c create mode 100644 src/sam3/sam4e_afec.c create mode 100644 src/sam3/sam4e_spi.c delete mode 100644 src/sam4e8e/Kconfig delete mode 100644 src/sam4e8e/Makefile delete mode 100644 src/sam4e8e/afec.c delete mode 100644 src/sam4e8e/gpio.c delete mode 100644 src/sam4e8e/gpio.h delete mode 100644 src/sam4e8e/i2c.c delete mode 100644 src/sam4e8e/internal.h delete mode 100644 src/sam4e8e/main.c delete mode 100644 src/sam4e8e/sam4_cache.c delete mode 100644 src/sam4e8e/serial.c delete mode 100644 src/sam4e8e/spi.c delete mode 100644 src/sam4e8e/timer.c (limited to 'src') diff --git a/src/Kconfig b/src/Kconfig index 69768a4e..e94ff5b2 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -6,12 +6,10 @@ choice prompt "Micro-controller Architecture" config MACH_AVR bool "Atmega AVR" - config MACH_SAM3X8E - bool "SAM3x8e (Arduino Due)" + config MACH_SAM3 + bool "SAM3/SAM4 (Due and Duet)" config MACH_SAMD21 bool "SAMD21 (Arduino Zero)" - config MACH_SAM4E8E - bool "SAM4e8e (Duet Wifi/Eth)" config MACH_LPC176X bool "LPC176x (Smoothieboard)" config MACH_STM32F1 @@ -27,7 +25,6 @@ endchoice source "src/avr/Kconfig" source "src/sam3/Kconfig" source "src/samd21/Kconfig" -source "src/sam4e8e/Kconfig" source "src/lpc176x/Kconfig" source "src/stm32f1/Kconfig" source "src/pru/Kconfig" diff --git a/src/sam3/Kconfig b/src/sam3/Kconfig index 03bdac8a..f87b84fa 100644 --- a/src/sam3/Kconfig +++ b/src/sam3/Kconfig @@ -1,12 +1,13 @@ -# Kconfig settings for SAM3 processors +# Kconfig settings for SAM3/SAM4 processors -if MACH_SAM3X8E +if MACH_SAM3 -config SAM_SELECT +config SAM3_SELECT bool default y select HAVE_GPIO select HAVE_GPIO_ADC + select HAVE_GPIO_I2C if MACH_SAM4E8E select HAVE_GPIO_SPI select HAVE_GPIO_BITBANGING @@ -14,9 +15,23 @@ config BOARD_DIRECTORY string default "sam3" +choice + prompt "Processor model" + config MACH_SAM3X8E + bool "SAM3x8e (Arduino Due)" + config MACH_SAM4E8E + bool "SAM4e8e (Duet Wifi/Eth)" +endchoice + +config MCU + string + default "sam3x8e" if MACH_SAM3X8E + default "sam4e8e" if MACH_SAM4E8E + config CLOCK_FREQ int - default 42000000 # 84000000/2 + default 42000000 if MACH_SAM3X8E # 84000000/2 + default 60000000 if MACH_SAM4E8E # 120000000/2 config SERIAL bool diff --git a/src/sam3/Makefile b/src/sam3/Makefile index 98809cdd..c49fab5d 100644 --- a/src/sam3/Makefile +++ b/src/sam3/Makefile @@ -1,33 +1,42 @@ -# Additional SAM3 build rules +# Additional SAM3/SAM4 build rules # Setup the toolchain CROSS_PREFIX=arm-none-eabi- dirs-y += src/sam3 src/generic -dirs-y += lib/sam3x/gcc/gcc +dirs-$(CONFIG_MACH_SAM3X8E) += lib/sam3x/gcc/gcc +dirs-$(CONFIG_MACH_SAM4E8E) += lib/sam4e/gcc/gcc -CFLAGS += -mthumb -mcpu=cortex-m3 -falign-loops=16 -CFLAGS += -Ilib/sam3x/include -Ilib/cmsis-core -CFLAGS += -D__SAM3X8E__ +CFLAGS-$(CONFIG_MACH_SAM3X8E) += -mcpu=cortex-m3 -falign-loops=16 +CFLAGS-$(CONFIG_MACH_SAM3X8E) += -Ilib/sam3x/include -D__SAM3X8E__ +CFLAGS-$(CONFIG_MACH_SAM4E8E) += -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard +CFLAGS-$(CONFIG_MACH_SAM4E8E) += -Ilib/sam4e/include -D__SAM4E8E__ +CFLAGS += -mthumb $(CFLAGS-y) -Ilib/cmsis-core -CFLAGS_klipper.elf += -Llib/sam3x/gcc/gcc -CFLAGS_klipper.elf += -T lib/sam3x/gcc/gcc/sam3x8e_flash.ld -CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs +eflags-$(CONFIG_MACH_SAM3X8E) += -Llib/sam3x/gcc/gcc +eflags-$(CONFIG_MACH_SAM3X8E) += -T lib/sam3x/gcc/gcc/sam3x8e_flash.ld +eflags-$(CONFIG_MACH_SAM4E8E) += -Llib/sam4e/gcc/gcc +eflags-$(CONFIG_MACH_SAM4E8E) += -T lib/sam4e/gcc/gcc/sam4e8e_flash.ld +CFLAGS_klipper.elf += $(eflags-y) --specs=nano.specs --specs=nosys.specs # Add source files -src-y += sam3/main.c sam3/timer.c -src-y += sam3/gpio.c sam3/adc.c sam3/spi.c +src-y += sam3/main.c sam3/timer.c sam3/gpio.c src-y += generic/crc16_ccitt.c generic/alloc.c src-y += generic/armcm_irq.c generic/timer_irq.c -src-y += ../lib/sam3x/gcc/system_sam3xa.c -src-y += ../lib/sam3x/gcc/gcc/startup_sam3xa.c src-$(CONFIG_SERIAL) += sam3/serial.c generic/serial_irq.c +src-$(CONFIG_MACH_SAM3X8E) += sam3/adc.c sam3/spi.c +src-$(CONFIG_MACH_SAM3X8E) += ../lib/sam3x/gcc/system_sam3xa.c +src-$(CONFIG_MACH_SAM3X8E) += ../lib/sam3x/gcc/gcc/startup_sam3xa.c +src-$(CONFIG_MACH_SAM4E8E) += sam3/sam4e_afec.c sam3/sam4e_spi.c +src-$(CONFIG_MACH_SAM4E8E) += sam3/i2c.c sam3/sam4_cache.c +src-$(CONFIG_MACH_SAM4E8E) += ../lib/sam4e/gcc/system_sam4e.c +src-$(CONFIG_MACH_SAM4E8E) += ../lib/sam4e/gcc/gcc/startup_sam4e.c # Build the additional hex output file target-y += $(OUT)klipper.bin $(OUT)klipper.bin: $(OUT)klipper.elf - @echo " Creating hex file $@" + @echo " Creating bin file $@" $(Q)$(OBJCOPY) -O binary $< $@ # Flash rules diff --git a/src/sam3/adc.c b/src/sam3/adc.c index 4a4d2cf0..b9c5fb12 100644 --- a/src/sam3/adc.c +++ b/src/sam3/adc.c @@ -10,7 +10,6 @@ #include "compiler.h" // ARRAY_SIZE #include "gpio.h" // gpio_adc_setup #include "internal.h" // GPIO -#include "sam3x8e.h" // ADC #include "sched.h" // sched_shutdown static const uint8_t adc_pins[] = { @@ -43,7 +42,7 @@ gpio_adc_setup(uint8_t pin) | ADC_MR_STARTUP_SUT768 | ADC_MR_TRANSFER(1)); } - return (struct gpio_adc){ .bit = 1 << chan }; + return (struct gpio_adc){ .chan = 1 << chan }; } // Try to sample a value. Returns zero if sample ready, otherwise @@ -55,11 +54,11 @@ gpio_adc_sample(struct gpio_adc g) uint32_t chsr = ADC->ADC_CHSR & 0xffff; if (!chsr) { // Start sample - ADC->ADC_CHER = g.bit; + ADC->ADC_CHER = g.chan; ADC->ADC_CR = ADC_CR_START; goto need_delay; } - if (chsr != g.bit) + if (chsr != g.chan) // Sampling in progress on another channel goto need_delay; if (!(ADC->ADC_ISR & ADC_ISR_DRDY)) @@ -75,7 +74,7 @@ need_delay: uint16_t gpio_adc_read(struct gpio_adc g) { - ADC->ADC_CHDR = g.bit; + ADC->ADC_CHDR = g.chan; return ADC->ADC_LCDR; } @@ -84,7 +83,7 @@ void gpio_adc_cancel_sample(struct gpio_adc g) { irqstatus_t flag = irq_save(); - if ((ADC->ADC_CHSR & 0xffff) == g.bit) + if ((ADC->ADC_CHSR & 0xffff) == g.chan) gpio_adc_read(g); irq_restore(flag); } diff --git a/src/sam3/gpio.c b/src/sam3/gpio.c index f48c5f0d..a0dfa0a4 100644 --- a/src/sam3/gpio.c +++ b/src/sam3/gpio.c @@ -1,4 +1,4 @@ -// GPIO functions on sam3x8e +// GPIO functions on sam3/sam4 // // Copyright (C) 2016-2018 Kevin O'Connor // @@ -9,11 +9,14 @@ #include "compiler.h" // ARRAY_SIZE #include "gpio.h" // gpio_out_setup #include "internal.h" // gpio_peripheral -#include "sam3x8e.h" // Pio #include "sched.h" // sched_shutdown static Pio * const digital_regs[] = { +#if CONFIG_MACH_SAM3X8E PIOA, PIOB, PIOC, PIOD +#elif CONFIG_MACH_SAM4E8E + PIOA, PIOB, PIOC, PIOD, PIOE +#endif }; @@ -24,12 +27,16 @@ static Pio * const digital_regs[] = { void gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up) { - uint32_t bank = GPIO2PORT(gpio), bit = GPIO2BIT(gpio); + uint32_t bank = GPIO2PORT(gpio), bit = GPIO2BIT(gpio), pt = ptype - 'A'; Pio *regs = digital_regs[bank]; - if (ptype == 'A') - regs->PIO_ABSR &= ~bit; - else - regs->PIO_ABSR |= bit; + +#if CONFIG_MACH_SAM3X8E + regs->PIO_ABSR = (regs->PIO_ABSR & ~bit) | (pt & 0x01 ? bit : 0); +#else + regs->PIO_ABCDSR[0] = (regs->PIO_ABCDSR[0] & ~bit) | (pt & 0x01 ? bit : 0); + regs->PIO_ABCDSR[1] = (regs->PIO_ABCDSR[1] & ~bit) | (pt & 0x02 ? bit : 0); +#endif + if (pull_up > 0) regs->PIO_PUER = bit; else diff --git a/src/sam3/gpio.h b/src/sam3/gpio.h index 1c412d8d..26a05aff 100644 --- a/src/sam3/gpio.h +++ b/src/sam3/gpio.h @@ -22,7 +22,7 @@ void gpio_in_reset(struct gpio_in g, int8_t pull_up); uint8_t gpio_in_read(struct gpio_in g); struct gpio_adc { - uint32_t bit; + uint32_t chan; }; struct gpio_adc gpio_adc_setup(uint8_t pin); uint32_t gpio_adc_sample(struct gpio_adc g); @@ -30,6 +30,7 @@ uint16_t gpio_adc_read(struct gpio_adc g); void gpio_adc_cancel_sample(struct gpio_adc g); struct spi_config { + void *sspi; uint32_t cfg; }; struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate); @@ -37,4 +38,14 @@ 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 { + void *twi; + 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/sam3/i2c.c b/src/sam3/i2c.c new file mode 100644 index 00000000..caf05f0a --- /dev/null +++ b/src/sam3/i2c.c @@ -0,0 +1,180 @@ +// SAM4 I2C Port +// +// Copyright (C) 2018 Florian Heilmann +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_FREQ +#include "board/misc.h" // timer_from_us +#include "command.h" // shutdown +#include "gpio.h" // i2c_setup +#include "internal.h" // gpio_peripheral +#include "sam4e.h" // TWI0 +#include "sched.h" // sched_shutdown + +// I2C pin definitions +#define TWI0_SCL_GPIO GPIO('A', 4) +#define TWI0_SCL_PERIPH 'A' + +#define TWI0_SDA_GPIO GPIO('A', 3) +#define TWI0_SDA_PERIPH 'A' + +#define TWI1_SCL_GPIO GPIO('B', 5) +#define TWI1_SCL_PERIPH 'A' + +#define TWI1_SDA_GPIO GPIO('B', 4) +#define TWI1_SDA_PERIPH 'A' + +void +i2c_init(Twi *p_twi, uint32_t rate) +{ + uint32_t twi_id = (p_twi == TWI0) ? ID_TWI0 : ID_TWI1; + if ((PMC->PMC_PCSR0 & (1u << twi_id)) == 0) { + PMC->PMC_PCER0 = 1 << twi_id; + } + if (p_twi == TWI0) { + gpio_peripheral(TWI0_SCL_GPIO, TWI0_SCL_PERIPH, 0); + gpio_peripheral(TWI0_SDA_GPIO, TWI0_SDA_PERIPH, 0); + } else { + gpio_peripheral(TWI1_SCL_GPIO, TWI1_SCL_PERIPH, 0); + gpio_peripheral(TWI1_SDA_GPIO, TWI1_SDA_PERIPH, 0); + } + p_twi->TWI_IDR = 0xFFFFFFFF; + (void)p_twi->TWI_SR; + p_twi->TWI_CR = TWI_CR_SWRST; + (void)p_twi->TWI_RHR; + p_twi->TWI_CR = TWI_CR_MSDIS; + p_twi->TWI_CR = TWI_CR_SVDIS; + p_twi->TWI_CR = TWI_CR_MSEN; + + uint32_t cldiv = 0; + uint32_t chdiv = 0; + uint32_t ckdiv = 0; + + cldiv = CONFIG_CLOCK_FREQ / ((rate > 384000 ? 384000 : rate) * 2) - 4; + + while((cldiv > 255) && (ckdiv < 7)) { + ckdiv++; + cldiv /= 2; + } + + if (rate > 348000) { + chdiv = CONFIG_CLOCK_FREQ / ((2 * rate - 384000) * 2) - 4; + while((chdiv > 255) && (ckdiv < 7)) { + ckdiv++; + chdiv /= 2; + } + } else { + chdiv = cldiv; + } + p_twi->TWI_CWGR = TWI_CWGR_CLDIV(cldiv) | \ + TWI_CWGR_CHDIV(chdiv) | \ + TWI_CWGR_CKDIV(ckdiv); +} + +uint32_t +addr_to_u32(uint8_t addr_len, uint8_t *addr) +{ + uint32_t address = addr[0]; + if (addr_len > 1) { + address <<= 8; + address |= addr[1]; + } + if (addr_len > 2) { + address <<= 8; + address |= addr[2]; + } + if (addr_len > 3) { + shutdown("Addresses larger than 3 bytes are not supported"); + } + return address; +} + +struct i2c_config +i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr) +{ + if ((bus > 1) | (rate > 400000)) + shutdown("Invalid i2c_setup parameters!"); + Twi *p_twi = (bus == 0) ? TWI0 : TWI1; + i2c_init(p_twi, rate); + return (struct i2c_config){ .twi=p_twi, .addr=addr}; +} + +void +i2c_write(struct i2c_config config, + uint8_t write_len, uint8_t *write) +{ + Twi *p_twi = config.twi; + uint32_t status; + uint32_t bytes_to_send = write_len; + p_twi->TWI_MMR = TWI_MMR_DADR(config.addr); + for(;;) { + status = p_twi->TWI_SR; + if (status & TWI_SR_NACK) + shutdown("I2C NACK error encountered!"); + if (!(status & TWI_SR_TXRDY)) + continue; + if (!bytes_to_send) + break; + p_twi->TWI_THR = *write++; + bytes_to_send--; + } + p_twi->TWI_CR = TWI_CR_STOP; + while(!(p_twi->TWI_SR& TWI_SR_TXCOMP)) { + } +} + +static void +i2c_wait(Twi* p_twi, uint32_t bit, uint32_t timeout) +{ + for (;;) { + uint32_t flags = p_twi->TWI_SR; + if (flags & bit) + break; + if (!timer_is_before(timer_read_time(), timeout)) + shutdown("I2C timeout occured"); + } +} + +void +i2c_read(struct i2c_config config, + uint8_t reg_len, uint8_t *reg, + uint8_t read_len, uint8_t *read) +{ + Twi *p_twi = config.twi; + uint32_t status; + uint32_t bytes_to_send=read_len; + uint8_t stop = 0; + p_twi->TWI_MMR = 0; + p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(config.addr) | + ((reg_len << TWI_MMR_IADRSZ_Pos) & + TWI_MMR_IADRSZ_Msk); + p_twi->TWI_IADR = 0; + p_twi->TWI_IADR = addr_to_u32(reg_len, reg); + if (bytes_to_send == 1) { + p_twi->TWI_CR = TWI_CR_START | TWI_CR_STOP; + stop = 1; + } else { + p_twi->TWI_CR = TWI_CR_START; + stop = 0; + } + while (bytes_to_send > 0) { + status = p_twi->TWI_SR; + if (status & TWI_SR_NACK) { + shutdown("I2C NACK error encountered!"); + } + if (bytes_to_send == 1 && !stop) { + p_twi->TWI_CR = TWI_CR_STOP; + stop = 1; + } + i2c_wait(p_twi, TWI_SR_RXRDY, timer_read_time() + timer_from_us(5000)); + if (!(status & TWI_SR_RXRDY)) { + continue; + } + *read++ = p_twi->TWI_RHR; + bytes_to_send--; + } + while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {} + (void)p_twi->TWI_SR; +} diff --git a/src/sam3/internal.h b/src/sam3/internal.h index 8246d7a4..d90dda0b 100644 --- a/src/sam3/internal.h +++ b/src/sam3/internal.h @@ -1,8 +1,15 @@ #ifndef __SAM3_INTERNAL_H #define __SAM3_INTERNAL_H -// Local definitions for sam3 code +// Local definitions for sam3/sam4 code #include // uint32_t +#include "autoconf.h" // CONFIG_MACH_SAM3X8E + +#if CONFIG_MACH_SAM3X8E +#include "sam3x8e.h" +#elif CONFIG_MACH_SAM4E8E +#include "sam4e.h" +#endif #define GPIO(PORT, NUM) (((PORT)-'A') * 32 + (NUM)) #define GPIO2PORT(PIN) ((PIN) / 32) diff --git a/src/sam3/main.c b/src/sam3/main.c index dd8445ac..3908fddb 100644 --- a/src/sam3/main.c +++ b/src/sam3/main.c @@ -1,14 +1,14 @@ -// Main starting point for SAM3x8e boards. +// Main starting point for SAM3/SAM4 boards // -// Copyright (C) 2016,2017 Kevin O'Connor +// Copyright (C) 2016-2018 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. #include "command.h" // DECL_CONSTANT -#include "sam3x8e.h" // WDT +#include "internal.h" // WDT #include "sched.h" // sched_main -DECL_CONSTANT(MCU, "sam3x8e"); +DECL_CONSTANT(MCU, CONFIG_MCU); /**************************************************************** diff --git a/src/sam3/sam4_cache.c b/src/sam3/sam4_cache.c new file mode 100644 index 00000000..75459660 --- /dev/null +++ b/src/sam3/sam4_cache.c @@ -0,0 +1,16 @@ +// SAM4 cache enable +// +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "sam4e.h" // CMCC +#include "sched.h" // DECL_INIT + +void +sam4_cache_init(void) +{ + if (!(CMCC->CMCC_SR & CMCC_SR_CSTS)) + CMCC->CMCC_CTRL = CMCC_CTRL_CEN; +} +DECL_INIT(sam4_cache_init); diff --git a/src/sam3/sam4e_afec.c b/src/sam3/sam4e_afec.c new file mode 100644 index 00000000..69205c50 --- /dev/null +++ b/src/sam3/sam4e_afec.c @@ -0,0 +1,206 @@ +// SAM4e8e Analog Front-End Converter (AFEC) support +// +// Copyright (C) 2018 Florian Heilmann +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_FREQ +#include "command.h" // shutdown +#include "gpio.h" // gpio_adc_setup +#include "internal.h" // GPIO +#include "sam4e.h" // AFEC0 +#include "sched.h" // sched_shutdown + +static const uint8_t afec_pins[] = { + //remove first channel, since it offsets the channel number: GPIO('A', 8), + GPIO('A', 17), GPIO('A', 18), GPIO('A', 19), + GPIO('A', 20), GPIO('B', 0), GPIO('B', 1), GPIO('C', 13), + GPIO('C', 15), GPIO('C', 12), GPIO('C', 29), GPIO('C', 30), + GPIO('C', 31), GPIO('C', 26), GPIO('C', 27), GPIO('C',0), + // AFEC1 + GPIO('B', 2), GPIO('B', 3), GPIO('A', 21), GPIO('A', 22), + GPIO('C', 1), GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), +}; + +#define AFEC1_START 15 // The first 15 pins are on afec0 + +static inline struct gpio_adc +pin_to_gpio_adc(uint8_t pin) +{ + int chan; + for (chan=0; ; chan++) { + if (chan >= ARRAY_SIZE(afec_pins)) + shutdown("Not a valid ADC pin"); + if (afec_pins[chan] == pin) { + break; + } + } + return (struct gpio_adc){ .chan=chan }; +} + +static inline Afec * +gpio_adc_to_afec(struct gpio_adc g) +{ + return (g.chan >= AFEC1_START ? AFEC1 : AFEC0); +} + +static inline uint32_t +gpio_adc_to_afec_chan(struct gpio_adc g) +{ + return (g.chan >= AFEC1_START ? g.chan - AFEC1_START : g.chan); +} + +#define ADC_FREQ_MAX 6000000UL +DECL_CONSTANT(ADC_MAX, 4095); + +static int +init_afec(Afec* afec) { + + // Enable PMC + if (afec == AFEC0) + PMC->PMC_PCER0 = 1 << ID_AFEC0; + else + PMC->PMC_PCER0 = 1 << ID_AFEC1; + + // If busy, return busy + if ((afec->AFE_ISR & AFE_ISR_DRDY) == AFE_ISR_DRDY) { + return -1; + } + + // Reset + afec->AFE_CR = AFE_CR_SWRST; + + // Configure afec + afec->AFE_MR = AFE_MR_ANACH_ALLOWED | \ + AFE_MR_PRESCAL (SystemCoreClock / (2 * ADC_FREQ_MAX) -1) | \ + AFE_MR_SETTLING_AST3 | \ + AFE_MR_TRACKTIM(2) | \ + AFE_MR_TRANSFER(1) | \ + AFE_MR_STARTUP_SUT64; + afec->AFE_EMR = AFE_EMR_TAG | \ + AFE_EMR_RES_NO_AVERAGE | \ + AFE_EMR_STM; + afec->AFE_ACR = AFE_ACR_IBCTL(1); + + // Disable interrupts + afec->AFE_IDR = 0xDF00803F; + + // Disable SW triggering + uint32_t mr = afec->AFE_MR; + + mr &= ~(AFE_MR_TRGSEL_Msk | AFE_MR_TRGEN | AFE_MR_FREERUN_ON); + mr |= AFE_MR_TRGEN_DIS; + afec->AFE_MR = mr; + + return 0; +} + +void +gpio_afec_init(void) { + + while(init_afec(AFEC0) != 0) { + (void)(AFEC0->AFE_LCDR & AFE_LCDR_LDATA_Msk); + } + while(init_afec(AFEC1) != 0) { + (void)(AFEC1->AFE_LCDR & AFE_LCDR_LDATA_Msk); + } + +} +DECL_INIT(gpio_afec_init); + +struct gpio_adc +gpio_adc_setup(uint8_t pin) +{ + struct gpio_adc adc_pin = pin_to_gpio_adc(pin); + Afec *afec = gpio_adc_to_afec(adc_pin); + uint32_t afec_chan = gpio_adc_to_afec_chan(adc_pin); + + //config channel + uint32_t reg = afec->AFE_DIFFR; + reg &= ~(1u << afec_chan); + afec->AFE_DIFFR = reg; + reg = afec->AFE_CGR; + reg &= ~(0x03u << (2 * afec_chan)); + reg |= 1 << (2 * afec_chan); + afec->AFE_CGR = reg; + + // Configure channel + // afec_ch_get_config_defaults(&ch_cfg); + // afec_ch_set_config(afec, afec_chan, &ch_cfg); + // Remove default internal offset from channel + // See Atmel Appnote AT03078 Section 1.5 + afec->AFE_CSELR = afec_chan; + afec->AFE_COCR = (0x800 & AFE_COCR_AOFF_Msk); + + // Enable and calibrate Channel + afec->AFE_CHER = 1 << afec_chan; + + reg = afec->AFE_CHSR; + afec->AFE_CDOR = reg; + afec->AFE_CR = AFE_CR_AUTOCAL; + + return adc_pin; +} + +enum { AFE_DUMMY=0xff }; +uint8_t active_channel = AFE_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) +{ + Afec *afec = gpio_adc_to_afec(g); + uint32_t afec_chan = gpio_adc_to_afec_chan(g); + if (active_channel == g.chan) { + if ((afec->AFE_ISR & AFE_ISR_DRDY) + && (afec->AFE_ISR & (1 << afec_chan))) { + // Sample now ready + return 0; + } else { + // Busy + goto need_delay; + } + } else if (active_channel != AFE_DUMMY) { + goto need_delay; + } + + afec->AFE_CHDR = 0x803F; // Disable all channels + afec->AFE_CHER = 1 << afec_chan; + + active_channel = g.chan; + + for (uint32_t chan = 0; chan < 16; ++chan) + { + if ((afec->AFE_ISR & (1 << chan)) != 0) + { + afec->AFE_CSELR = chan; + (void)(afec->AFE_CDR); + } + } + afec->AFE_CR = AFE_CR_START; + +need_delay: + return ADC_FREQ_MAX * 10000ULL / CONFIG_CLOCK_FREQ; // about 400 mcu clock cycles or 40 afec cycles +} + +// Read a value; use only after gpio_adc_sample() returns zero +uint16_t +gpio_adc_read(struct gpio_adc g) +{ + Afec *afec = gpio_adc_to_afec(g); + uint32_t afec_chan = gpio_adc_to_afec_chan(g); + active_channel = AFE_DUMMY; + afec->AFE_CSELR = afec_chan; + return afec->AFE_CDR; +} + +// Cancel a sample that may have been started with gpio_adc_sample() +void +gpio_adc_cancel_sample(struct gpio_adc g) +{ + if (active_channel == g.chan) { + active_channel = AFE_DUMMY; + } +} diff --git a/src/sam3/sam4e_spi.c b/src/sam3/sam4e_spi.c new file mode 100644 index 00000000..0fa9d3ca --- /dev/null +++ b/src/sam3/sam4e_spi.c @@ -0,0 +1,124 @@ +// SAM4e8e SPI port +// +// Copyright (C) 2018 Florian Heilmann +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_FREQ +#include "command.h" // shutdown +#include "gpio.h" // spi_setup +#include "internal.h" // gpio_peripheral +#include "sam4e.h" // USART0 +#include "sched.h" // sched_shutdown + +#define SSPI_USART0 0 +#define SSPI_USART1 1 +#define SSPI_SPI 2 + +struct spi_config +spi_setup(uint32_t bus, uint8_t mode, uint32_t rate) +{ + Usart *p_usart = USART0; + if (bus > 2) { + shutdown("Invalid spi_setup parameters"); + } + + if (bus == SSPI_USART0) { + // DUET_USART0_SCK as per dc42 CoreNG + gpio_peripheral(GPIO('B', 13), 'C', 0); + // DUET_USART0_MOSI as per dc42 CoreNG + gpio_peripheral(GPIO('B', 1), 'C', 0); + // DUET_USART0_MISO as per dc42 CoreNG + gpio_peripheral(GPIO('B', 0), 'C', 1); + + if ((PMC->PMC_PCSR0 & (1u << ID_USART0)) == 0) { + PMC->PMC_PCER0 = 1 << ID_USART0; + } + p_usart = USART0; + } else if (bus == SSPI_USART1) { + // DUET_USART1_SCK as per dc42 CoreNG + gpio_peripheral(GPIO('A', 23), 'A', 0); + // DUET_USART1_MOSI as per dc42 CoreNG + gpio_peripheral(GPIO('A', 22), 'A', 0); + // DUET_USART1_MISO as per dc42 CoreNG + gpio_peripheral(GPIO('A', 21), 'A', 1); + + if ((PMC->PMC_PCSR0 & (1u << ID_USART1)) == 0) { + PMC->PMC_PCER0 = 1 << ID_USART1; + } + p_usart = USART1; + } + + if (bus < 2) { + p_usart->US_MR = 0; + p_usart->US_RTOR = 0; + p_usart->US_TTGR = 0; + + p_usart->US_CR = US_CR_RSTTX | US_CR_RSTRX | US_CR_TXDIS | US_CR_RXDIS; + + uint32_t br = (CONFIG_CLOCK_FREQ + rate / 2) / rate; + p_usart-> US_BRGR = br << US_BRGR_CD_Pos; + + uint32_t reg = US_MR_CHRL_8_BIT | + US_MR_USART_MODE_SPI_MASTER | + US_MR_CLKO | + US_MR_CHMODE_NORMAL; + switch (mode) { + case 0: + reg |= US_MR_CPHA; + reg &= ~US_MR_CPOL; + break; + case 1: + reg &= ~US_MR_CPHA; + reg &= ~US_MR_CPOL; + break; + case 2: + reg |= US_MR_CPHA; + reg |= US_MR_CPOL; + break; + case 3: + reg &= ~US_MR_CPHA; + reg |= US_MR_CPOL; + break; + } + + p_usart->US_MR |= reg; + p_usart->US_CR = US_CR_RXEN | US_CR_TXEN; + return (struct spi_config){ .sspi=p_usart, .cfg=p_usart->US_MR }; + } + + // True SPI implementation still ToDo + return (struct spi_config){ .sspi = 0, .cfg=0}; +} + +void +spi_transfer(struct spi_config config, uint8_t receive_data + , uint8_t len, uint8_t *data) +{ + if ((config.sspi == USART0) || (config.sspi == USART1)) { + Usart *p_usart = config.sspi; + if (receive_data) { + for (uint32_t i = 0; i < len; ++i) { + uint32_t co = (uint32_t)*data & 0x000000FF; + while(!(p_usart->US_CSR & US_CSR_TXRDY)) {} + p_usart->US_THR = US_THR_TXCHR(co); + uint32_t ci = 0; + while(!(p_usart->US_CSR & US_CSR_RXRDY)) {} + ci = p_usart->US_RHR & US_RHR_RXCHR_Msk; + *data++ = (uint8_t)ci; + } + } else { + for (uint32_t i = 0; i < len; ++i) { + uint32_t co = (uint32_t)*data & 0x000000FF; + while(!(p_usart->US_CSR & US_CSR_TXRDY)) {} + p_usart->US_THR = US_THR_TXCHR(co); + while(!(p_usart->US_CSR & US_CSR_RXRDY)) {} + (void)(p_usart->US_RHR & US_RHR_RXCHR_Msk); + (void)*data++; + } + } + } +} + +void +spi_prepare(struct spi_config config) {} diff --git a/src/sam3/serial.c b/src/sam3/serial.c index 1fe55751..e0249448 100644 --- a/src/sam3/serial.c +++ b/src/sam3/serial.c @@ -1,4 +1,4 @@ -// sam3x8e serial port +// sam3/sam4 serial port // // Copyright (C) 2016-2018 Kevin O'Connor // @@ -7,50 +7,65 @@ #include "autoconf.h" // CONFIG_SERIAL_BAUD #include "board/serial_irq.h" // serial_rx_data #include "internal.h" // gpio_peripheral -#include "sam3x8e.h" // UART #include "sched.h" // DECL_INIT +// Serial port pins +#if CONFIG_MACH_SAM3X8E +#define Serial_IRQ_Handler UART_Handler +static Uart * const Port = UART; +static const uint32_t Pmc_id = ID_UART, Irq_id = UART_IRQn; +static const uint32_t rx_pin = GPIO('A', 8); +static const uint32_t tx_pin = GPIO('A', 9); +#elif CONFIG_MACH_SAM4E8E +#define Serial_IRQ_Handler UART0_Handler +static Uart * const Port = UART0; +static const uint32_t Pmc_id = ID_UART0, Irq_id = UART0_IRQn; +static const uint32_t rx_pin = GPIO('A', 9); +static const uint32_t tx_pin = GPIO('A', 10); +#endif + void serial_init(void) { - gpio_peripheral(GPIO('A', 8), 'A', 1); - gpio_peripheral(GPIO('A', 9), 'A', 0); + gpio_peripheral(rx_pin, 'A', 1); + gpio_peripheral(tx_pin, 'A', 0); // Reset uart - PMC->PMC_PCER0 = 1 << ID_UART; - UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; - UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; - UART->UART_IDR = 0xFFFFFFFF; + PMC->PMC_PCER0 = 1 << Pmc_id; + Port->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; + Port->UART_CR = (UART_CR_RSTRX | UART_CR_RSTTX + | UART_CR_RXDIS | UART_CR_TXDIS); + Port->UART_IDR = 0xFFFFFFFF; // Enable uart - UART->UART_MR = (US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO + Port->UART_MR = (US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO | UART_MR_CHMODE_NORMAL); - UART->UART_BRGR = SystemCoreClock / (16 * CONFIG_SERIAL_BAUD); - UART->UART_IER = UART_IER_RXRDY; - NVIC_EnableIRQ(UART_IRQn); - NVIC_SetPriority(UART_IRQn, 0); - UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN; + Port->UART_BRGR = SystemCoreClock / (16 * CONFIG_SERIAL_BAUD); + Port->UART_IER = UART_IER_RXRDY; + NVIC_EnableIRQ(Irq_id); + NVIC_SetPriority(Irq_id, 0); + Port->UART_CR = UART_CR_RXEN | UART_CR_TXEN; } DECL_INIT(serial_init); void __visible -UART_Handler(void) +Serial_IRQ_Handler(void) { - uint32_t status = UART->UART_SR; + uint32_t status = Port->UART_SR; if (status & UART_SR_RXRDY) - serial_rx_byte(UART->UART_RHR); + serial_rx_byte(Port->UART_RHR); if (status & UART_SR_TXRDY) { uint8_t data; int ret = serial_get_tx_byte(&data); if (ret) - UART->UART_IDR = UART_IDR_TXRDY; + Port->UART_IDR = UART_IDR_TXRDY; else - UART->UART_THR = data; + Port->UART_THR = data; } } void serial_enable_tx_irq(void) { - UART->UART_IER = UART_IDR_TXRDY; + Port->UART_IER = UART_IDR_TXRDY; } diff --git a/src/sam3/spi.c b/src/sam3/spi.c index 91b28e34..b6b832e5 100644 --- a/src/sam3/spi.c +++ b/src/sam3/spi.c @@ -1,10 +1,9 @@ -// SPI transmissions on sam3x8e +// SPI transmissions on sam3 // // Copyright (C) 2018 Petri Honkala // // This file may be distributed under the terms of the GNU GPLv3 license. -#include // REGPTR #include "command.h" // shutdown #include "gpio.h" // spi_setup #include "internal.h" // gpio_peripheral diff --git a/src/sam3/timer.c b/src/sam3/timer.c index f7698c65..d5bc8c6a 100644 --- a/src/sam3/timer.c +++ b/src/sam3/timer.c @@ -1,6 +1,6 @@ -// SAM3x8e timer interrupt scheduling +// SAM3/SAM4 timer interrupt scheduling // -// Copyright (C) 2016,2017 Kevin O'Connor +// Copyright (C) 2016-2018 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. @@ -8,7 +8,7 @@ #include "board/misc.h" // timer_read_time #include "board/timer_irq.h" // timer_dispatch_many #include "command.h" // DECL_SHUTDOWN -#include "sam3x8e.h" // TC0 +#include "internal.h" // TC0 #include "sched.h" // DECL_INIT // Set the next irq time diff --git a/src/sam4e8e/Kconfig b/src/sam4e8e/Kconfig deleted file mode 100644 index 72e21857..00000000 --- a/src/sam4e8e/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# Kconfig settings for SAM4e8e processors - -if MACH_SAM4E8E - -config SAM_SELECT - bool - default y - select HAVE_GPIO - select HAVE_GPIO_I2C - select HAVE_GPIO_ADC - select HAVE_GPIO_SPI - select HAVE_GPIO_BITBANGING - -config BOARD_DIRECTORY - string - default "sam4e8e" - -config CLOCK_FREQ - int - default 60000000 # 120000000/2 - -config SERIAL - bool - default y -config SERIAL_BAUD - depends on SERIAL - int "Baud rate for serial port" - default 250000 - -endif diff --git a/src/sam4e8e/Makefile b/src/sam4e8e/Makefile deleted file mode 100644 index a80741bf..00000000 --- a/src/sam4e8e/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# Additional sam4e8e build rules - -# Setup the toolchain -CROSS_PREFIX=arm-none-eabi- -dirs-y += src/sam4e8e src/generic - -CFLAGS += -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -CFLAGS += -D__SAM4E8E__ - -CFLAGS_klipper.elf += -L lib/sam4e/gcc/gcc -CFLAGS_klipper.elf += -T lib/sam4e/gcc/gcc/sam4e8e_flash.ld -CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs - -dirs-y += lib/sam4e/gcc lib/sam4e/gcc/gcc -CFLAGS += -Ilib/sam4e/include -Ilib/cmsis-core -src-y += ../lib/sam4e/gcc/system_sam4e.c ../lib/sam4e/gcc/gcc/startup_sam4e.c - -src-$(CONFIG_HAVE_GPIO_SPI) += sam4e8e/spi.c -src-$(CONFIG_HAVE_GPIO_I2C) += sam4e8e/i2c.c -src-$(CONFIG_SERIAL) += sam4e8e/serial.c generic/serial_irq.c -src-$(CONFIG_HAVE_GPIO) += sam4e8e/gpio.c sam4e8e/afec.c -src-y += generic/crc16_ccitt.c generic/alloc.c -src-y += generic/armcm_irq.c generic/timer_irq.c -src-y += sam4e8e/main.c sam4e8e/sam4_cache.c sam4e8e/timer.c - -# Build the additional hex output file -target-y += $(OUT)klipper.bin - -$(OUT)klipper.bin: $(OUT)klipper.elf - @echo " Creating bin file $@" - $(Q)$(OBJCOPY) -O binary $< $@ - -# 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)" -e -w $(OUT)klipper.bin -v -b -R diff --git a/src/sam4e8e/afec.c b/src/sam4e8e/afec.c deleted file mode 100644 index 69205c50..00000000 --- a/src/sam4e8e/afec.c +++ /dev/null @@ -1,206 +0,0 @@ -// SAM4e8e Analog Front-End Converter (AFEC) support -// -// Copyright (C) 2018 Florian Heilmann -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "command.h" // shutdown -#include "gpio.h" // gpio_adc_setup -#include "internal.h" // GPIO -#include "sam4e.h" // AFEC0 -#include "sched.h" // sched_shutdown - -static const uint8_t afec_pins[] = { - //remove first channel, since it offsets the channel number: GPIO('A', 8), - GPIO('A', 17), GPIO('A', 18), GPIO('A', 19), - GPIO('A', 20), GPIO('B', 0), GPIO('B', 1), GPIO('C', 13), - GPIO('C', 15), GPIO('C', 12), GPIO('C', 29), GPIO('C', 30), - GPIO('C', 31), GPIO('C', 26), GPIO('C', 27), GPIO('C',0), - // AFEC1 - GPIO('B', 2), GPIO('B', 3), GPIO('A', 21), GPIO('A', 22), - GPIO('C', 1), GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), -}; - -#define AFEC1_START 15 // The first 15 pins are on afec0 - -static inline struct gpio_adc -pin_to_gpio_adc(uint8_t pin) -{ - int chan; - for (chan=0; ; chan++) { - if (chan >= ARRAY_SIZE(afec_pins)) - shutdown("Not a valid ADC pin"); - if (afec_pins[chan] == pin) { - break; - } - } - return (struct gpio_adc){ .chan=chan }; -} - -static inline Afec * -gpio_adc_to_afec(struct gpio_adc g) -{ - return (g.chan >= AFEC1_START ? AFEC1 : AFEC0); -} - -static inline uint32_t -gpio_adc_to_afec_chan(struct gpio_adc g) -{ - return (g.chan >= AFEC1_START ? g.chan - AFEC1_START : g.chan); -} - -#define ADC_FREQ_MAX 6000000UL -DECL_CONSTANT(ADC_MAX, 4095); - -static int -init_afec(Afec* afec) { - - // Enable PMC - if (afec == AFEC0) - PMC->PMC_PCER0 = 1 << ID_AFEC0; - else - PMC->PMC_PCER0 = 1 << ID_AFEC1; - - // If busy, return busy - if ((afec->AFE_ISR & AFE_ISR_DRDY) == AFE_ISR_DRDY) { - return -1; - } - - // Reset - afec->AFE_CR = AFE_CR_SWRST; - - // Configure afec - afec->AFE_MR = AFE_MR_ANACH_ALLOWED | \ - AFE_MR_PRESCAL (SystemCoreClock / (2 * ADC_FREQ_MAX) -1) | \ - AFE_MR_SETTLING_AST3 | \ - AFE_MR_TRACKTIM(2) | \ - AFE_MR_TRANSFER(1) | \ - AFE_MR_STARTUP_SUT64; - afec->AFE_EMR = AFE_EMR_TAG | \ - AFE_EMR_RES_NO_AVERAGE | \ - AFE_EMR_STM; - afec->AFE_ACR = AFE_ACR_IBCTL(1); - - // Disable interrupts - afec->AFE_IDR = 0xDF00803F; - - // Disable SW triggering - uint32_t mr = afec->AFE_MR; - - mr &= ~(AFE_MR_TRGSEL_Msk | AFE_MR_TRGEN | AFE_MR_FREERUN_ON); - mr |= AFE_MR_TRGEN_DIS; - afec->AFE_MR = mr; - - return 0; -} - -void -gpio_afec_init(void) { - - while(init_afec(AFEC0) != 0) { - (void)(AFEC0->AFE_LCDR & AFE_LCDR_LDATA_Msk); - } - while(init_afec(AFEC1) != 0) { - (void)(AFEC1->AFE_LCDR & AFE_LCDR_LDATA_Msk); - } - -} -DECL_INIT(gpio_afec_init); - -struct gpio_adc -gpio_adc_setup(uint8_t pin) -{ - struct gpio_adc adc_pin = pin_to_gpio_adc(pin); - Afec *afec = gpio_adc_to_afec(adc_pin); - uint32_t afec_chan = gpio_adc_to_afec_chan(adc_pin); - - //config channel - uint32_t reg = afec->AFE_DIFFR; - reg &= ~(1u << afec_chan); - afec->AFE_DIFFR = reg; - reg = afec->AFE_CGR; - reg &= ~(0x03u << (2 * afec_chan)); - reg |= 1 << (2 * afec_chan); - afec->AFE_CGR = reg; - - // Configure channel - // afec_ch_get_config_defaults(&ch_cfg); - // afec_ch_set_config(afec, afec_chan, &ch_cfg); - // Remove default internal offset from channel - // See Atmel Appnote AT03078 Section 1.5 - afec->AFE_CSELR = afec_chan; - afec->AFE_COCR = (0x800 & AFE_COCR_AOFF_Msk); - - // Enable and calibrate Channel - afec->AFE_CHER = 1 << afec_chan; - - reg = afec->AFE_CHSR; - afec->AFE_CDOR = reg; - afec->AFE_CR = AFE_CR_AUTOCAL; - - return adc_pin; -} - -enum { AFE_DUMMY=0xff }; -uint8_t active_channel = AFE_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) -{ - Afec *afec = gpio_adc_to_afec(g); - uint32_t afec_chan = gpio_adc_to_afec_chan(g); - if (active_channel == g.chan) { - if ((afec->AFE_ISR & AFE_ISR_DRDY) - && (afec->AFE_ISR & (1 << afec_chan))) { - // Sample now ready - return 0; - } else { - // Busy - goto need_delay; - } - } else if (active_channel != AFE_DUMMY) { - goto need_delay; - } - - afec->AFE_CHDR = 0x803F; // Disable all channels - afec->AFE_CHER = 1 << afec_chan; - - active_channel = g.chan; - - for (uint32_t chan = 0; chan < 16; ++chan) - { - if ((afec->AFE_ISR & (1 << chan)) != 0) - { - afec->AFE_CSELR = chan; - (void)(afec->AFE_CDR); - } - } - afec->AFE_CR = AFE_CR_START; - -need_delay: - return ADC_FREQ_MAX * 10000ULL / CONFIG_CLOCK_FREQ; // about 400 mcu clock cycles or 40 afec cycles -} - -// Read a value; use only after gpio_adc_sample() returns zero -uint16_t -gpio_adc_read(struct gpio_adc g) -{ - Afec *afec = gpio_adc_to_afec(g); - uint32_t afec_chan = gpio_adc_to_afec_chan(g); - active_channel = AFE_DUMMY; - afec->AFE_CSELR = afec_chan; - return afec->AFE_CDR; -} - -// Cancel a sample that may have been started with gpio_adc_sample() -void -gpio_adc_cancel_sample(struct gpio_adc g) -{ - if (active_channel == g.chan) { - active_channel = AFE_DUMMY; - } -} diff --git a/src/sam4e8e/gpio.c b/src/sam4e8e/gpio.c deleted file mode 100644 index 3e2c9796..00000000 --- a/src/sam4e8e/gpio.c +++ /dev/null @@ -1,173 +0,0 @@ -// SAM4e8e GPIO port -// -// Copyright (C) 2018 Florian Heilmann -// -// 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 "sam4e.h" // Pio -#include "sched.h" // sched_shutdown - -static Pio * const digital_regs[] = { - PIOA, PIOB, PIOC, PIOD, PIOE -}; - - -/**************************************************************** - * Pin multiplexing - ****************************************************************/ - -void -gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up) -{ - uint32_t bank = GPIO2PORT(gpio), bit = GPIO2BIT(gpio); - Pio *regs = digital_regs[bank]; - regs ->PIO_IDR = bit; - - // Enable peripheral for pin - uint32_t sr; - - switch (ptype) { - case 'A': - sr = regs->PIO_ABCDSR[0]; - regs->PIO_ABCDSR[0] &= (~bit & sr); - sr = regs->PIO_ABCDSR[1]; - regs->PIO_ABCDSR[1] &= (~bit & sr); - break; - case 'B': - sr = regs->PIO_ABCDSR[0]; - regs->PIO_ABCDSR[0] = (bit | sr); - sr = regs->PIO_ABCDSR[1]; - regs->PIO_ABCDSR[1] &= (~bit & sr); - break; - case 'C': - sr = regs->PIO_ABCDSR[0]; - regs->PIO_ABCDSR[0] &= (~bit & sr); - sr = regs->PIO_ABCDSR[1]; - regs->PIO_ABCDSR[1] = (bit | sr); - break; - case 'D': - sr = regs->PIO_ABCDSR[0]; - regs->PIO_ABCDSR[0] = (bit | sr); - sr = regs->PIO_ABCDSR[1]; - regs->PIO_ABCDSR[1] = (bit | sr); - break; - } - - // Disable pin in IO controller - regs->PIO_PDR = bit; - - // Set pullup - if (pull_up > 0) { - regs->PIO_PUER = bit; - } else { - regs->PIO_PUDR = bit; - } -} - - -/**************************************************************** - * General Purpose Input Output (GPIO) pins - ****************************************************************/ - -struct gpio_out -gpio_out_setup(uint8_t pin, uint8_t val) -{ - if (GPIO2PORT(pin) >= ARRAY_SIZE(digital_regs)) - goto fail; - uint32_t port = GPIO2PORT(pin); - Pio *regs = digital_regs[port]; - uint32_t bank_id = ID_PIOA + port; - if ((PMC->PMC_PCSR0 & (1u << bank_id)) == 0) { - PMC->PMC_PCER0 = 1 << bank_id; - } - struct gpio_out g = { .regs=regs, .bit=GPIO2BIT(pin) }; - gpio_out_reset(g, val); - return g; -fail: - shutdown("Not an output pin"); -} - -void -gpio_out_reset(struct gpio_out g, uint8_t val) -{ - Pio *regs = g.regs; - irqstatus_t flag = irq_save(); - if (val) - regs->PIO_SODR = g.bit; - else - regs->PIO_CODR = g.bit; - regs->PIO_OER = g.bit; - regs->PIO_OWER = g.bit; - regs->PIO_PER = g.bit; - regs->PIO_PUDR = g.bit; - irq_restore(flag); -} - -void -gpio_out_toggle_noirq(struct gpio_out g) -{ - Pio *regs = g.regs; - regs->PIO_ODSR ^= g.bit; -} - -void -gpio_out_toggle(struct gpio_out g) -{ - irqstatus_t flag = irq_save(); - gpio_out_toggle_noirq(g); - irq_restore(flag); -} - -void -gpio_out_write(struct gpio_out g, uint8_t val) -{ - Pio *regs = g.regs; - if (val) - regs->PIO_SODR = g.bit; - else - regs->PIO_CODR = g.bit; -} - -struct gpio_in -gpio_in_setup(uint8_t pin, int8_t pull_up) -{ - if (GPIO2PORT(pin) >= ARRAY_SIZE(digital_regs)) - goto fail; - uint32_t port = GPIO2PORT(pin); - Pio *regs = digital_regs[port]; - uint32_t bank_id = ID_PIOA + port; - if ((PMC->PMC_PCSR0 & (1u << bank_id)) == 0) { - PMC->PMC_PCER0 = 1 << bank_id; - } - struct gpio_in g = { .regs=regs, .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) -{ - Pio *regs = g.regs; - irqstatus_t flag = irq_save(); - regs->PIO_IDR = g.bit; - if (pull_up) - regs->PIO_PUER = g.bit; - else - regs->PIO_PUDR = g.bit; - regs->PIO_ODR = g.bit; - regs->PIO_PER = g.bit; - irq_restore(flag); -} - -uint8_t -gpio_in_read(struct gpio_in g) -{ - Pio *regs = g.regs; - return !!(regs->PIO_PDSR & g.bit); -} diff --git a/src/sam4e8e/gpio.h b/src/sam4e8e/gpio.h deleted file mode 100644 index a32a59a7..00000000 --- a/src/sam4e8e/gpio.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef __SAM4E8E_GPIO_H -#define __SAM4E8E_GPIO_H - -#include - -struct gpio_out { - uint8_t pin; - 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 { - uint8_t pin; - 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_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 { - void *sspi; - uint32_t cfg; -}; -struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate); -void spi_transfer(struct spi_config config, uint8_t receive_data - , uint8_t len, uint8_t *data); -void spi_prepare(struct spi_config config); - -struct i2c_config { - void *twi; - 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/sam4e8e/i2c.c b/src/sam4e8e/i2c.c deleted file mode 100644 index caf05f0a..00000000 --- a/src/sam4e8e/i2c.c +++ /dev/null @@ -1,180 +0,0 @@ -// SAM4 I2C Port -// -// Copyright (C) 2018 Florian Heilmann -// Copyright (C) 2018 Kevin O'Connor -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "board/misc.h" // timer_from_us -#include "command.h" // shutdown -#include "gpio.h" // i2c_setup -#include "internal.h" // gpio_peripheral -#include "sam4e.h" // TWI0 -#include "sched.h" // sched_shutdown - -// I2C pin definitions -#define TWI0_SCL_GPIO GPIO('A', 4) -#define TWI0_SCL_PERIPH 'A' - -#define TWI0_SDA_GPIO GPIO('A', 3) -#define TWI0_SDA_PERIPH 'A' - -#define TWI1_SCL_GPIO GPIO('B', 5) -#define TWI1_SCL_PERIPH 'A' - -#define TWI1_SDA_GPIO GPIO('B', 4) -#define TWI1_SDA_PERIPH 'A' - -void -i2c_init(Twi *p_twi, uint32_t rate) -{ - uint32_t twi_id = (p_twi == TWI0) ? ID_TWI0 : ID_TWI1; - if ((PMC->PMC_PCSR0 & (1u << twi_id)) == 0) { - PMC->PMC_PCER0 = 1 << twi_id; - } - if (p_twi == TWI0) { - gpio_peripheral(TWI0_SCL_GPIO, TWI0_SCL_PERIPH, 0); - gpio_peripheral(TWI0_SDA_GPIO, TWI0_SDA_PERIPH, 0); - } else { - gpio_peripheral(TWI1_SCL_GPIO, TWI1_SCL_PERIPH, 0); - gpio_peripheral(TWI1_SDA_GPIO, TWI1_SDA_PERIPH, 0); - } - p_twi->TWI_IDR = 0xFFFFFFFF; - (void)p_twi->TWI_SR; - p_twi->TWI_CR = TWI_CR_SWRST; - (void)p_twi->TWI_RHR; - p_twi->TWI_CR = TWI_CR_MSDIS; - p_twi->TWI_CR = TWI_CR_SVDIS; - p_twi->TWI_CR = TWI_CR_MSEN; - - uint32_t cldiv = 0; - uint32_t chdiv = 0; - uint32_t ckdiv = 0; - - cldiv = CONFIG_CLOCK_FREQ / ((rate > 384000 ? 384000 : rate) * 2) - 4; - - while((cldiv > 255) && (ckdiv < 7)) { - ckdiv++; - cldiv /= 2; - } - - if (rate > 348000) { - chdiv = CONFIG_CLOCK_FREQ / ((2 * rate - 384000) * 2) - 4; - while((chdiv > 255) && (ckdiv < 7)) { - ckdiv++; - chdiv /= 2; - } - } else { - chdiv = cldiv; - } - p_twi->TWI_CWGR = TWI_CWGR_CLDIV(cldiv) | \ - TWI_CWGR_CHDIV(chdiv) | \ - TWI_CWGR_CKDIV(ckdiv); -} - -uint32_t -addr_to_u32(uint8_t addr_len, uint8_t *addr) -{ - uint32_t address = addr[0]; - if (addr_len > 1) { - address <<= 8; - address |= addr[1]; - } - if (addr_len > 2) { - address <<= 8; - address |= addr[2]; - } - if (addr_len > 3) { - shutdown("Addresses larger than 3 bytes are not supported"); - } - return address; -} - -struct i2c_config -i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr) -{ - if ((bus > 1) | (rate > 400000)) - shutdown("Invalid i2c_setup parameters!"); - Twi *p_twi = (bus == 0) ? TWI0 : TWI1; - i2c_init(p_twi, rate); - return (struct i2c_config){ .twi=p_twi, .addr=addr}; -} - -void -i2c_write(struct i2c_config config, - uint8_t write_len, uint8_t *write) -{ - Twi *p_twi = config.twi; - uint32_t status; - uint32_t bytes_to_send = write_len; - p_twi->TWI_MMR = TWI_MMR_DADR(config.addr); - for(;;) { - status = p_twi->TWI_SR; - if (status & TWI_SR_NACK) - shutdown("I2C NACK error encountered!"); - if (!(status & TWI_SR_TXRDY)) - continue; - if (!bytes_to_send) - break; - p_twi->TWI_THR = *write++; - bytes_to_send--; - } - p_twi->TWI_CR = TWI_CR_STOP; - while(!(p_twi->TWI_SR& TWI_SR_TXCOMP)) { - } -} - -static void -i2c_wait(Twi* p_twi, uint32_t bit, uint32_t timeout) -{ - for (;;) { - uint32_t flags = p_twi->TWI_SR; - if (flags & bit) - break; - if (!timer_is_before(timer_read_time(), timeout)) - shutdown("I2C timeout occured"); - } -} - -void -i2c_read(struct i2c_config config, - uint8_t reg_len, uint8_t *reg, - uint8_t read_len, uint8_t *read) -{ - Twi *p_twi = config.twi; - uint32_t status; - uint32_t bytes_to_send=read_len; - uint8_t stop = 0; - p_twi->TWI_MMR = 0; - p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(config.addr) | - ((reg_len << TWI_MMR_IADRSZ_Pos) & - TWI_MMR_IADRSZ_Msk); - p_twi->TWI_IADR = 0; - p_twi->TWI_IADR = addr_to_u32(reg_len, reg); - if (bytes_to_send == 1) { - p_twi->TWI_CR = TWI_CR_START | TWI_CR_STOP; - stop = 1; - } else { - p_twi->TWI_CR = TWI_CR_START; - stop = 0; - } - while (bytes_to_send > 0) { - status = p_twi->TWI_SR; - if (status & TWI_SR_NACK) { - shutdown("I2C NACK error encountered!"); - } - if (bytes_to_send == 1 && !stop) { - p_twi->TWI_CR = TWI_CR_STOP; - stop = 1; - } - i2c_wait(p_twi, TWI_SR_RXRDY, timer_read_time() + timer_from_us(5000)); - if (!(status & TWI_SR_RXRDY)) { - continue; - } - *read++ = p_twi->TWI_RHR; - bytes_to_send--; - } - while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {} - (void)p_twi->TWI_SR; -} diff --git a/src/sam4e8e/internal.h b/src/sam4e8e/internal.h deleted file mode 100644 index cf0e0f81..00000000 --- a/src/sam4e8e/internal.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __SAM4_INTERNAL_H -#define __SAM4_INTERNAL_H -// Local definitions for sam4 code - -#include // uint32_t - -#define GPIO(PORT, NUM) (((PORT)-'A') * 32 + (NUM)) -#define GPIO2PORT(PIN) ((PIN) / 32) -#define GPIO2BIT(PIN) (1<<((PIN) % 32)) - -void gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up); - -#endif // internal.h diff --git a/src/sam4e8e/main.c b/src/sam4e8e/main.c deleted file mode 100644 index f3666075..00000000 --- a/src/sam4e8e/main.c +++ /dev/null @@ -1,48 +0,0 @@ -// SAM4e8e port main entry -// -// Copyright (C) 2018 Florian Heilmann -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -// CMSIS -#include "sam4e.h" - -// Klipper -#include "command.h" // DECL_CONSTANT -#include "sched.h" // sched_main - -DECL_CONSTANT(MCU, "sam4e8e"); - -#define WDT_PASSWORD 0xA5000000 -#define WDT_SLOW_CLOCK_DIV 128 - -void -watchdog_reset(void) -{ - WDT->WDT_CR = WDT_PASSWORD | WDT_CR_WDRSTT; -} -DECL_TASK(watchdog_reset); - -void -watchdog_init(void) -{ - uint32_t timeout = 500000 / (WDT_SLOW_CLOCK_DIV * 1000000 / 32768UL); - WDT->WDT_MR = WDT_MR_WDRSTEN | WDT_MR_WDV(timeout) | WDT_MR_WDD(timeout); -} -DECL_INIT(watchdog_init); - -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/sam4e8e/sam4_cache.c b/src/sam4e8e/sam4_cache.c deleted file mode 100644 index 75459660..00000000 --- a/src/sam4e8e/sam4_cache.c +++ /dev/null @@ -1,16 +0,0 @@ -// SAM4 cache enable -// -// Copyright (C) 2018 Kevin O'Connor -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "sam4e.h" // CMCC -#include "sched.h" // DECL_INIT - -void -sam4_cache_init(void) -{ - if (!(CMCC->CMCC_SR & CMCC_SR_CSTS)) - CMCC->CMCC_CTRL = CMCC_CTRL_CEN; -} -DECL_INIT(sam4_cache_init); diff --git a/src/sam4e8e/serial.c b/src/sam4e8e/serial.c deleted file mode 100644 index c75623bc..00000000 --- a/src/sam4e8e/serial.c +++ /dev/null @@ -1,56 +0,0 @@ -// SAM4e8e serial port -// -// Copyright (C) 2018 Florian Heilmann -// -// 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" // gpio_peripheral -#include "sam4e.h" // UART0 -#include "sched.h" // DECL_INIT - -void -serial_init(void) -{ - gpio_peripheral(GPIO('A', 9), 'A', 1); - gpio_peripheral(GPIO('A', 10), 'A', 0); - - // Reset uart - PMC->PMC_PCER0 = 1 << ID_UART0; - UART0->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; - UART0->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; - UART0->UART_IDR = 0xFFFFFFFF; - - // Enable uart - UART0->UART_MR = (US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO - | UART_MR_CHMODE_NORMAL); - UART0->UART_BRGR = SystemCoreClock / (16 * CONFIG_SERIAL_BAUD); - UART0->UART_IER = UART_IER_RXRDY; - NVIC_EnableIRQ(UART0_IRQn); - NVIC_SetPriority(UART0_IRQn, 0); - UART0->UART_CR = UART_CR_RXEN | UART_CR_TXEN; -} -DECL_INIT(serial_init); - -void __visible -UART0_Handler(void) -{ - uint32_t status = UART0->UART_SR; - if (status & UART_SR_RXRDY) - serial_rx_byte(UART0->UART_RHR); - if (status & UART_SR_TXRDY) { - uint8_t data; - int ret = serial_get_tx_byte(&data); - if (ret) - UART0->UART_IDR = UART_IDR_TXRDY; - else - UART0->UART_THR = data; - } -} - -void -serial_enable_tx_irq(void) -{ - UART0->UART_IER = UART_IDR_TXRDY; -} diff --git a/src/sam4e8e/spi.c b/src/sam4e8e/spi.c deleted file mode 100644 index 0fa9d3ca..00000000 --- a/src/sam4e8e/spi.c +++ /dev/null @@ -1,124 +0,0 @@ -// SAM4e8e SPI port -// -// Copyright (C) 2018 Florian Heilmann -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "command.h" // shutdown -#include "gpio.h" // spi_setup -#include "internal.h" // gpio_peripheral -#include "sam4e.h" // USART0 -#include "sched.h" // sched_shutdown - -#define SSPI_USART0 0 -#define SSPI_USART1 1 -#define SSPI_SPI 2 - -struct spi_config -spi_setup(uint32_t bus, uint8_t mode, uint32_t rate) -{ - Usart *p_usart = USART0; - if (bus > 2) { - shutdown("Invalid spi_setup parameters"); - } - - if (bus == SSPI_USART0) { - // DUET_USART0_SCK as per dc42 CoreNG - gpio_peripheral(GPIO('B', 13), 'C', 0); - // DUET_USART0_MOSI as per dc42 CoreNG - gpio_peripheral(GPIO('B', 1), 'C', 0); - // DUET_USART0_MISO as per dc42 CoreNG - gpio_peripheral(GPIO('B', 0), 'C', 1); - - if ((PMC->PMC_PCSR0 & (1u << ID_USART0)) == 0) { - PMC->PMC_PCER0 = 1 << ID_USART0; - } - p_usart = USART0; - } else if (bus == SSPI_USART1) { - // DUET_USART1_SCK as per dc42 CoreNG - gpio_peripheral(GPIO('A', 23), 'A', 0); - // DUET_USART1_MOSI as per dc42 CoreNG - gpio_peripheral(GPIO('A', 22), 'A', 0); - // DUET_USART1_MISO as per dc42 CoreNG - gpio_peripheral(GPIO('A', 21), 'A', 1); - - if ((PMC->PMC_PCSR0 & (1u << ID_USART1)) == 0) { - PMC->PMC_PCER0 = 1 << ID_USART1; - } - p_usart = USART1; - } - - if (bus < 2) { - p_usart->US_MR = 0; - p_usart->US_RTOR = 0; - p_usart->US_TTGR = 0; - - p_usart->US_CR = US_CR_RSTTX | US_CR_RSTRX | US_CR_TXDIS | US_CR_RXDIS; - - uint32_t br = (CONFIG_CLOCK_FREQ + rate / 2) / rate; - p_usart-> US_BRGR = br << US_BRGR_CD_Pos; - - uint32_t reg = US_MR_CHRL_8_BIT | - US_MR_USART_MODE_SPI_MASTER | - US_MR_CLKO | - US_MR_CHMODE_NORMAL; - switch (mode) { - case 0: - reg |= US_MR_CPHA; - reg &= ~US_MR_CPOL; - break; - case 1: - reg &= ~US_MR_CPHA; - reg &= ~US_MR_CPOL; - break; - case 2: - reg |= US_MR_CPHA; - reg |= US_MR_CPOL; - break; - case 3: - reg &= ~US_MR_CPHA; - reg |= US_MR_CPOL; - break; - } - - p_usart->US_MR |= reg; - p_usart->US_CR = US_CR_RXEN | US_CR_TXEN; - return (struct spi_config){ .sspi=p_usart, .cfg=p_usart->US_MR }; - } - - // True SPI implementation still ToDo - return (struct spi_config){ .sspi = 0, .cfg=0}; -} - -void -spi_transfer(struct spi_config config, uint8_t receive_data - , uint8_t len, uint8_t *data) -{ - if ((config.sspi == USART0) || (config.sspi == USART1)) { - Usart *p_usart = config.sspi; - if (receive_data) { - for (uint32_t i = 0; i < len; ++i) { - uint32_t co = (uint32_t)*data & 0x000000FF; - while(!(p_usart->US_CSR & US_CSR_TXRDY)) {} - p_usart->US_THR = US_THR_TXCHR(co); - uint32_t ci = 0; - while(!(p_usart->US_CSR & US_CSR_RXRDY)) {} - ci = p_usart->US_RHR & US_RHR_RXCHR_Msk; - *data++ = (uint8_t)ci; - } - } else { - for (uint32_t i = 0; i < len; ++i) { - uint32_t co = (uint32_t)*data & 0x000000FF; - while(!(p_usart->US_CSR & US_CSR_TXRDY)) {} - p_usart->US_THR = US_THR_TXCHR(co); - while(!(p_usart->US_CSR & US_CSR_RXRDY)) {} - (void)(p_usart->US_RHR & US_RHR_RXCHR_Msk); - (void)*data++; - } - } - } -} - -void -spi_prepare(struct spi_config config) {} diff --git a/src/sam4e8e/timer.c b/src/sam4e8e/timer.c deleted file mode 100644 index 8115ea8a..00000000 --- a/src/sam4e8e/timer.c +++ /dev/null @@ -1,67 +0,0 @@ -// SAM4e8e timer port -// -// Copyright (C) 2018 Florian Heilmann -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -// CMSIS -#include "sam4e.h" -// Klipper -#include "board/irq.h" // irq_disable -#include "board/misc.h" // timer_read_time -#include "board/timer_irq.h" // timer_dispatch_many -#include "sched.h" // DECL_INIT - -// Set the next irq time -static void -timer_set(uint32_t value) -{ - TC0->TC_CHANNEL[0].TC_RA = value; -} - -// Return the current time (in absolute clock ticks). -uint32_t -timer_read_time(void) -{ - return TC0->TC_CHANNEL[0].TC_CV; -} - -// Activate timer dispatch as soon as possible -void -timer_kick(void) -{ - timer_set(timer_read_time() + 50); - TC0->TC_CHANNEL[0].TC_SR; -} - -void -timer_init(void) -{ - if ((PMC->PMC_PCSR0 & (1u << ID_TC0)) == 0) { - PMC->PMC_PCER0 = 1 << ID_TC0; - } - TcChannel *tc_channel = &TC0->TC_CHANNEL[0]; - tc_channel->TC_CCR = TC_CCR_CLKDIS; - tc_channel->TC_IDR = 0xFFFFFFFF; - tc_channel->TC_SR; - tc_channel->TC_CMR = TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1; - tc_channel->TC_IER = TC_IER_CPAS; - NVIC_SetPriority(TC0_IRQn, 1); - NVIC_EnableIRQ(TC0_IRQn); - timer_kick(); - tc_channel->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; -} -DECL_INIT(timer_init); - -// IRQ handler -void __visible __aligned(16) // aligning helps stabilize perf benchmarks -TC0_Handler(void) -{ - irq_disable(); - uint32_t status = TC0->TC_CHANNEL[0].TC_SR; - if (likely(status & TC_SR_CPAS)) { - uint32_t next = timer_dispatch_many(); - timer_set(next); - } - irq_enable(); -} -- cgit v1.2.3-70-g09d2