diff --git a/klippy/pins.py b/klippy/pins.py index 6c82f0d1..0b6bc5ff 100644 --- a/klippy/pins.py +++ b/klippy/pins.py @@ -45,8 +45,8 @@ MCU_PINS = { "atmega32u4": port_pins(6), "atmega1280": port_pins(12), "atmega2560": port_pins(12), "sam3x8e": port_pins(4, 32), + "sam4s8c": port_pins(3, 32), "sam4e8e" : port_pins(5, 32), "samd21g": port_pins(2, 32), - "sam4e8e" : port_pins(5,32), "stm32f103": port_pins(5, 16), "lpc176x": lpc_pins(), "pru": beaglebone_pins(), diff --git a/src/sam3/Kconfig b/src/sam3/Kconfig index 1e79812a..e7085eaf 100644 --- a/src/sam3/Kconfig +++ b/src/sam3/Kconfig @@ -19,6 +19,8 @@ choice prompt "Processor model" config MACH_SAM3X8E bool "SAM3x8e (Arduino Due)" + config MACH_SAM4S8C + bool "SAM4s8c (Duet Maestro)" config MACH_SAM4E8E bool "SAM4e8e (Duet Wifi/Eth)" endchoice @@ -26,11 +28,13 @@ endchoice config MCU string default "sam3x8e" if MACH_SAM3X8E + default "sam4s8c" if MACH_SAM4S8C default "sam4e8e" if MACH_SAM4E8E config CLOCK_FREQ int default 42000000 if MACH_SAM3X8E # 84000000/2 + default 15000000 if MACH_SAM4S8C # 120000000/8 default 60000000 if MACH_SAM4E8E # 120000000/2 config SERIAL diff --git a/src/sam3/Makefile b/src/sam3/Makefile index 97503af4..30361ed8 100644 --- a/src/sam3/Makefile +++ b/src/sam3/Makefile @@ -5,29 +5,36 @@ CROSS_PREFIX=arm-none-eabi- dirs-y += src/sam3 src/generic dirs-$(CONFIG_MACH_SAM3X8E) += lib/sam3x/gcc/gcc +dirs-$(CONFIG_MACH_SAM4S8C) += lib/sam4s/gcc/gcc dirs-$(CONFIG_MACH_SAM4E8E) += lib/sam4e/gcc/gcc CFLAGS-$(CONFIG_MACH_SAM3X8E) += -mcpu=cortex-m3 -falign-loops=16 CFLAGS-$(CONFIG_MACH_SAM3X8E) += -Ilib/sam3x/include -D__SAM3X8E__ +CFLAGS-$(CONFIG_MACH_SAM4S8C) += -mcpu=cortex-m4 +CFLAGS-$(CONFIG_MACH_SAM4S8C) += -Ilib/sam4s/include -D__SAM4S8C__ 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 eflags-$(CONFIG_MACH_SAM3X8E) += -Llib/sam3x/gcc/gcc eflags-$(CONFIG_MACH_SAM3X8E) += -T lib/sam3x/gcc/gcc/sam3x8e_flash.ld +eflags-$(CONFIG_MACH_SAM4S8C) += -Llib/sam4s/gcc/gcc +eflags-$(CONFIG_MACH_SAM4S8C) += -T lib/sam4s/gcc/gcc/sam4s8c_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 sam3/gpio.c sam3/i2c.c sam3/spi.c +src-y += sam3/main.c sam3/gpio.c sam3/i2c.c sam3/spi.c src-y += generic/crc16_ccitt.c generic/alloc.c src-y += generic/armcm_irq.c generic/timer_irq.c src-$(CONFIG_SERIAL) += sam3/serial.c generic/serial_irq.c -src-$(CONFIG_MACH_SAM3X8E) += sam3/adc.c +src-$(CONFIG_MACH_SAM3X8E) += sam3/adc.c sam3/timer.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/sam4_cache.c +src-$(CONFIG_MACH_SAM4S8C) += sam3/adc.c sam3/sam4s_timer.c sam3/sam4s_sysinit.c +src-$(CONFIG_MACH_SAM4S8C) += ../lib/sam4s/gcc/gcc/startup_sam4s.c +src-$(CONFIG_MACH_SAM4E8E) += sam3/sam4e_afec.c sam3/timer.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 @@ -47,4 +54,4 @@ 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 -e -w $(OUT)klipper.bin -v -b - $(Q)lib/bossac/bin/bossac -p "$(FLASH_DEVICE)" -R > /dev/null 2>&1 || true + $(Q)lib/bossac/bin/bossac -p "$(FLASH_DEVICE)" -b -R > /dev/null 2>&1 || true diff --git a/src/sam3/adc.c b/src/sam3/adc.c index 0baf9118..425d60a9 100644 --- a/src/sam3/adc.c +++ b/src/sam3/adc.c @@ -13,10 +13,17 @@ #include "sched.h" // sched_shutdown static const uint8_t adc_pins[] = { +#if CONFIG_MACH_SAM3X8E GPIO('A', 2), GPIO('A', 3), GPIO('A', 4), GPIO('A', 6), GPIO('A', 22), GPIO('A', 23), GPIO('A', 24), GPIO('A', 16), GPIO('B', 12), GPIO('B', 13), GPIO('B', 17), GPIO('B', 18), GPIO('B', 19), GPIO('B', 20) +#elif CONFIG_MACH_SAM4S8C + GPIO('A', 17), GPIO('A', 18), GPIO('A', 19), GPIO('A', 20), + GPIO('B', 0), GPIO('B', 1), GPIO('B', 2), GPIO('B', 3), + GPIO('A', 21), GPIO('A', 22), GPIO('C', 13), GPIO('C', 15), + GPIO('C', 12), GPIO('C', 29), GPIO('C', 30) +#endif }; #define ADC_FREQ_MAX 20000000 diff --git a/src/sam3/gpio.c b/src/sam3/gpio.c index 065663f9..7e6a1dab 100644 --- a/src/sam3/gpio.c +++ b/src/sam3/gpio.c @@ -14,6 +14,8 @@ static Pio * const digital_regs[] = { #if CONFIG_MACH_SAM3X8E PIOA, PIOB, PIOC, PIOD +#elif CONFIG_MACH_SAM4S8C + PIOA, PIOB, PIOC #elif CONFIG_MACH_SAM4E8E PIOA, PIOB, PIOC, PIOD, PIOE #endif diff --git a/src/sam3/i2c.c b/src/sam3/i2c.c index 27a04738..910471fd 100644 --- a/src/sam3/i2c.c +++ b/src/sam3/i2c.c @@ -5,7 +5,6 @@ // // 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 @@ -18,7 +17,7 @@ #define TWI0_SDA_GPIO GPIO('A', 17) #define TWI1_SCL_GPIO GPIO('B', 13) #define TWI1_SDA_GPIO GPIO('B', 12) -#elif CONFIG_MACH_SAM4E8E +#elif CONFIG_MACH_SAM4S8C || CONFIG_MACH_SAM4E8E #define TWI0_SCL_GPIO GPIO('A', 4) #define TWI0_SDA_GPIO GPIO('A', 3) #define TWI1_SCL_GPIO GPIO('B', 5) @@ -48,7 +47,7 @@ i2c_init(Twi *p_twi, uint32_t rate) uint32_t chdiv = 0; uint32_t ckdiv = 0; - cldiv = CONFIG_CLOCK_FREQ / ((rate > 384000 ? 384000 : rate) * 2) - 4; + cldiv = SystemCoreClock / ((rate > 384000 ? 384000 : rate) * 4) - 4; while((cldiv > 255) && (ckdiv < 7)) { ckdiv++; @@ -56,7 +55,7 @@ i2c_init(Twi *p_twi, uint32_t rate) } if (rate > 348000) { - chdiv = CONFIG_CLOCK_FREQ / ((2 * rate - 384000) * 2) - 4; + chdiv = SystemCoreClock / ((2 * rate - 384000) * 4) - 4; while((chdiv > 255) && (ckdiv < 7)) { ckdiv++; chdiv /= 2; diff --git a/src/sam3/internal.h b/src/sam3/internal.h index e9457ed2..dd94a609 100644 --- a/src/sam3/internal.h +++ b/src/sam3/internal.h @@ -7,6 +7,8 @@ #if CONFIG_MACH_SAM3X8E #include "sam3x8e.h" +#elif CONFIG_MACH_SAM4S8C +#include "sam4s.h" #elif CONFIG_MACH_SAM4E8E #include "sam4e.h" #endif diff --git a/src/sam3/sam4s_sysinit.c b/src/sam3/sam4s_sysinit.c new file mode 100644 index 00000000..41a2dcfe --- /dev/null +++ b/src/sam3/sam4s_sysinit.c @@ -0,0 +1,65 @@ +// This code is from lib/sam4e/gcc/system_sam4e.c - it is unclear why +// it is not defined in the Atmel sam4s cmsis code. + +#include "internal.h" + +/* Clock Settings (120MHz) */ +#define SYS_BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8U)) +#define SYS_BOARD_PLLAR (CKGR_PLLAR_ONE \ + | CKGR_PLLAR_MULA(0x13U) \ + | CKGR_PLLAR_PLLACOUNT(0x3fU) \ + | CKGR_PLLAR_DIVA(0x1U)) +#define SYS_BOARD_MCKR (PMC_MCKR_PRES_CLK_2 | PMC_MCKR_CSS_PLLA_CLK) + +#define SYS_CKGR_MOR_KEY_VALUE CKGR_MOR_KEY(0x37) /* Key to unlock MOR register */ + +uint32_t SystemCoreClock = CHIP_FREQ_MAINCK_RC_4MHZ; + +void SystemInit( void ) +{ + /* Set FWS according to SYS_BOARD_MCKR configuration */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(5); + + /* Initialize main oscillator */ + if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) ) + { + PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE | SYS_BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN; + + while ( !(PMC->PMC_SR & PMC_SR_MOSCXTS) ) + { + } + } + + /* Switch to 3-20MHz Xtal oscillator */ + PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE | SYS_BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL; + + while ( !(PMC->PMC_SR & PMC_SR_MOSCSELS) ) + { + } + + PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; + + while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) ) + { + } + + /* Initialize PLLA */ + PMC->CKGR_PLLAR = SYS_BOARD_PLLAR; + while ( !(PMC->PMC_SR & PMC_SR_LOCKA) ) + { + } + + /* Switch to main clock */ + PMC->PMC_MCKR = (SYS_BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; + while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) ) + { + } + + /* Switch to PLLA */ + PMC->PMC_MCKR = SYS_BOARD_MCKR; + while ( !(PMC->PMC_SR & PMC_SR_MCKRDY) ) + { + } + + SystemCoreClock = CHIP_FREQ_CPU_MAX; +} diff --git a/src/sam3/sam4s_timer.c b/src/sam3/sam4s_timer.c new file mode 100644 index 00000000..a586dd64 --- /dev/null +++ b/src/sam3/sam4s_timer.c @@ -0,0 +1,118 @@ +// SAM4s 16bit timer interrupt scheduling +// +// Copyright (C) 2016-2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "board/io.h" // readl +#include "board/irq.h" // irq_disable +#include "board/misc.h" // timer_read_time +#include "board/timer_irq.h" // timer_dispatch_many +#include "command.h" // DECL_SHUTDOWN +#include "internal.h" // TC0 +#include "sched.h" // DECL_INIT + + +/**************************************************************** + * Low level timer code + ****************************************************************/ + +// Get the 16bit timer value +static uint32_t +timer_get(void) +{ + return TC0->TC_CHANNEL[0].TC_CV; +} + +// Set the next irq time +static void +timer_set(uint32_t value) +{ + TC0->TC_CHANNEL[0].TC_RA = value; +} + +// Activate timer dispatch as soon as possible +void +timer_kick(void) +{ + timer_set(timer_read_time() + 50); +} + + +/**************************************************************** + * 16bit hardware timer to 32bit conversion + ****************************************************************/ + +// High bits of timer (top 17 bits) +static uint32_t timer_high; + +// Return the current time (in absolute clock ticks). +uint32_t __always_inline +timer_read_time(void) +{ + uint32_t th = readl(&timer_high); + uint32_t cur = timer_get(); + // Combine timer_high (high 17 bits) and current time (low 16 + // bits) using method that handles rollovers correctly. + return (th ^ cur) + (th & 0x8000); +} + +// Update timer_high every 0x8000 clock ticks +static uint_fast8_t +timer_event(struct timer *t) +{ + timer_high += 0x8000; + t->waketime = timer_high + 0x8000; + return SF_RESCHEDULE; +} +static struct timer wrap_timer = { + .func = timer_event, + .waketime = 0x8000, +}; + +void +timer_reset(void) +{ + sched_add_timer(&wrap_timer); +} +DECL_SHUTDOWN(timer_reset); + + +/**************************************************************** + * Timer init + ****************************************************************/ + +void +timer_init(void) +{ + TcChannel *tc = &TC0->TC_CHANNEL[0]; + // Reset the timer + tc->TC_CCR = TC_CCR_CLKDIS; + tc->TC_IDR = 0xFFFFFFFF; + // Enable it + enable_pclock(ID_TC0); + tc->TC_CMR = TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK2; + tc->TC_IER = TC_IER_CPAS; + NVIC_SetPriority(TC0_IRQn, 1); + NVIC_EnableIRQ(TC0_IRQn); + timer_kick(); + timer_reset(); + tc->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; +} +DECL_INIT(timer_init); + + +/**************************************************************** + * Main timer dispatch irq handler + ****************************************************************/ + +// IRQ handler +void __visible __aligned(16) // aligning helps stabilize perf benchmarks +TC0_Handler(void) +{ + irq_disable(); + uint32_t next = timer_dispatch_many(); + timer_set(next); + TC0->TC_CHANNEL[0].TC_SR; // read to clear irq pending + irq_enable(); +} diff --git a/src/sam3/serial.c b/src/sam3/serial.c index b7df5680..c87539ad 100644 --- a/src/sam3/serial.c +++ b/src/sam3/serial.c @@ -16,6 +16,12 @@ 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_SAM4S8C +#define Serial_IRQ_Handler UART1_Handler +static Uart * const Port = UART1; +static const uint32_t Pmc_id = ID_UART1, Irq_id = UART1_IRQn; +static const uint32_t rx_pin = GPIO('B', 2); +static const uint32_t tx_pin = GPIO('B', 3); #elif CONFIG_MACH_SAM4E8E #define Serial_IRQ_Handler UART0_Handler static Uart * const Port = UART0; diff --git a/src/sam3/spi.c b/src/sam3/spi.c index 61b773e6..5f79a02c 100644 --- a/src/sam3/spi.c +++ b/src/sam3/spi.c @@ -28,6 +28,10 @@ static const struct spi_info spi_bus[] = { { USART0, ID_USART0, GPIO('A', 10), GPIO('A', 11), GPIO('A', 17), 'A', 'B'}, { USART1, ID_USART1, GPIO('A', 12), GPIO('A', 13), GPIO('A', 16), 'A', 'A'}, { USART2, ID_USART2, GPIO('B', 21), GPIO('B', 20), GPIO('B', 24), 'A', 'A'}, +#elif CONFIG_MACH_SAM4S8C + { SPI, ID_SPI, GPIO('A', 12), GPIO('A', 13), GPIO('A', 14), 'A', 'A' }, + { USART0, ID_USART0, GPIO('A', 5), GPIO('A', 6), GPIO('A', 2), 'A', 'B' }, + { USART1, ID_USART1, GPIO('A', 21), GPIO('A', 22), GPIO('A', 23), 'A', 'A'}, #elif CONFIG_MACH_SAM4E8E { USART0, ID_USART0, GPIO('B', 0), GPIO('B', 1), GPIO('B', 13), 'C', 'C' }, { USART1, ID_USART1, GPIO('A', 21), GPIO('A', 22), GPIO('A', 23), 'A', 'A'}, diff --git a/test/configs/sam4s8c.config b/test/configs/sam4s8c.config new file mode 100644 index 00000000..3b032bea --- /dev/null +++ b/test/configs/sam4s8c.config @@ -0,0 +1,3 @@ +# Base config file for Atmel SAM4S8C ARM processor +CONFIG_MACH_SAM3=y +CONFIG_MACH_SAM4S8C=y