sam3: Add support for sam4s8c chips

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-12-26 20:31:23 -05:00
parent 519f2cff41
commit 75ad16ea1a
12 changed files with 226 additions and 9 deletions

View File

@ -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(),

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

65
src/sam3/sam4s_sysinit.c Normal file
View File

@ -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;
}

118
src/sam3/sam4s_timer.c Normal file
View File

@ -0,0 +1,118 @@
// SAM4s 16bit timer interrupt scheduling
//
// Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
//
// 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();
}

View File

@ -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;

View File

@ -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'},

View File

@ -0,0 +1,3 @@
# Base config file for Atmel SAM4S8C ARM processor
CONFIG_MACH_SAM3=y
CONFIG_MACH_SAM4S8C=y