From f9cc15e4f3298c1c37eda8169ed8f966a7dfd824 Mon Sep 17 00:00:00 2001 From: dylad Date: Sat, 8 Feb 2025 13:15:19 +0100 Subject: [PATCH 1/4] cpu/sam4s: introduce initial support Signed-off-by: dylad --- cpu/sam4s/Kconfig | 27 ++++++++ cpu/sam4s/Makefile | 10 +++ cpu/sam4s/Makefile.dep | 1 + cpu/sam4s/Makefile.features | 6 ++ cpu/sam4s/Makefile.include | 8 +++ cpu/sam4s/cpu.c | 107 +++++++++++++++++++++++++++++ cpu/sam4s/doc.txt | 9 +++ cpu/sam4s/include/periph_cpu.h | 35 ++++++++++ cpu/sam4s/periph/Makefile | 1 + cpu/sam4s/vectors.c | 106 ++++++++++++++++++++++++++++ features.yaml | 4 ++ makefiles/features_existing.inc.mk | 1 + 12 files changed, 315 insertions(+) create mode 100644 cpu/sam4s/Kconfig create mode 100644 cpu/sam4s/Makefile create mode 100644 cpu/sam4s/Makefile.dep create mode 100644 cpu/sam4s/Makefile.features create mode 100644 cpu/sam4s/Makefile.include create mode 100644 cpu/sam4s/cpu.c create mode 100644 cpu/sam4s/doc.txt create mode 100644 cpu/sam4s/include/periph_cpu.h create mode 100644 cpu/sam4s/periph/Makefile create mode 100644 cpu/sam4s/vectors.c diff --git a/cpu/sam4s/Kconfig b/cpu/sam4s/Kconfig new file mode 100644 index 0000000000..d1adc8d5c5 --- /dev/null +++ b/cpu/sam4s/Kconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2025 Mesotic SAS +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. +# + +config CPU_FAM_SAM4S + bool + select CPU_CORE_CORTEX_M4 + +## CPU Models +config CPU_MODEL_SAM4SD32C + bool + select CPU_FAM_SAM4S + +## Common CPU symbols +config CPU_FAM + default "sam4s" if CPU_FAM_SAM4S + +config CPU_MODEL + default "sam4sd32c" if CPU_MODEL_SAM4SD32C + +config CPU + default "sam4s" if CPU_FAM_SAM4s + +source "$(RIOTCPU)/cortexm_common/Kconfig" diff --git a/cpu/sam4s/Makefile b/cpu/sam4s/Makefile new file mode 100644 index 0000000000..7907dbac97 --- /dev/null +++ b/cpu/sam4s/Makefile @@ -0,0 +1,10 @@ +# define the module that is build +MODULE = cpu + +# add a list of subdirectories, that should also be build +DIRS = periph $(RIOTCPU)/cortexm_common $(RIOTCPU)/sam_common + +# (file triggers compiler bug. see #5775) +SRC_NOLTO += vectors.c + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/sam4s/Makefile.dep b/cpu/sam4s/Makefile.dep new file mode 100644 index 0000000000..652f3ba1ae --- /dev/null +++ b/cpu/sam4s/Makefile.dep @@ -0,0 +1 @@ +include $(RIOTCPU)/sam_common/Makefile.dep diff --git a/cpu/sam4s/Makefile.features b/cpu/sam4s/Makefile.features new file mode 100644 index 0000000000..31ed1ccaa4 --- /dev/null +++ b/cpu/sam4s/Makefile.features @@ -0,0 +1,6 @@ +CPU_CORE = cortex-m4 +CPU_FAM = sam4s + +FEATURES_PROVIDED += cortexm_mpu + +include $(RIOTCPU)/cortexm_common/Makefile.features diff --git a/cpu/sam4s/Makefile.include b/cpu/sam4s/Makefile.include new file mode 100644 index 0000000000..ed685102d0 --- /dev/null +++ b/cpu/sam4s/Makefile.include @@ -0,0 +1,8 @@ +ROM_START_ADDR ?= 0x400000 +RAM_START_ADDR ?= 0x20000000 + +ROM_LEN ?= 0x200000 +RAM_LEN ?= 0x28000 + +include $(RIOTCPU)/sam_common/Makefile.include +include $(RIOTMAKE)/arch/cortexm.inc.mk diff --git a/cpu/sam4s/cpu.c b/cpu/sam4s/cpu.c new file mode 100644 index 0000000000..49973d3eee --- /dev/null +++ b/cpu/sam4s/cpu.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_sam4s + * @{ + * + * @file + * @brief Implementation of the CPU initialization + * + * @author Dylan Laduranty + * @} + */ + +#include "cpu.h" +#include "board.h" +#include "kernel_init.h" +#include "periph_conf.h" +#include "periph/init.h" +#include "stdio_base.h" + +#define XTAL_STARTUP (8U) +#define PLL_CNT (64U) + +#if ((CLOCK_PLL_MUL < 7) || (CLOCK_PLL_MUL > 62)) +#error "CLOCK_PLL_MUL has an incorrect value" +#endif + +/** + * @brief Initialize the CPU, set IRQ priorities + */ +void cpu_init(void) +{ + /* SAM4s MCUs requires WPKEY for enabling peripheral */ + PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD; + + /* disable the watchdog timer */ + WDT->WDT_MR |= WDT_MR_WDDIS; + + /* initialize the Cortex-M core */ + cortexm_init(); + + /* setup the flash wait states */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(CLOCK_FWS); + EFC1->EEFC_FMR = EEFC_FMR_FWS(CLOCK_FWS); + + /* enable the Cortex-M Cache Controller */ + CMCC->CMCC_CTRL |= CMCC_CTRL_CEN; + + /* unlock write protect register for PMC module */ + PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD; + + /* activate the external crystal */ + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD + | CKGR_MOR_MOSCXTST(XTAL_STARTUP) + | CKGR_MOR_MOSCXTEN + | CKGR_MOR_MOSCRCEN; + + /* wait for crystal to be stable */ + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) {} + + /* select crystal to clock the main clock */ + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD + | CKGR_MOR_MOSCXTST(XTAL_STARTUP) + | CKGR_MOR_MOSCXTEN + | CKGR_MOR_MOSCRCEN + | CKGR_MOR_MOSCSEL; + + /* wait for main oscillator selection to be complete */ + while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) {} + + /* setup PLLA */ + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE + | CKGR_PLLAR_PLLACOUNT(PLL_CNT) + | CKGR_PLLAR_MULA(CLOCK_PLL_MUL) + | CKGR_PLLAR_DIVA(CLOCK_PLL_DIV); + + /* wait for PLL to lock */ + while (!(PMC->PMC_SR & PMC_SR_LOCKA)) {} + + /* before switching to PLLA, we need to switch to main clock */ + PMC->PMC_MCKR = PMC_MCKR_CSS_MAIN_CLK; + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} + + /* use PLLA as main clock source */ + PMC->PMC_MCKR = PMC_MCKR_CSS_PLLA_CLK; + /* wait for master clock to be ready */ + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {} + + /* setup the SCLK: switch to external oscillator if applicable */ +#if CLOCK_SCLK_XTAL + /* enable external oscillator */ + SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; + while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST)) {} +#endif + + /* initialize stdio prior to periph_init() to allow use of DEBUG() there */ + early_init(); + + /* trigger static peripheral initialization */ + periph_init(); +} diff --git a/cpu/sam4s/doc.txt b/cpu/sam4s/doc.txt new file mode 100644 index 0000000000..1507ff1889 --- /dev/null +++ b/cpu/sam4s/doc.txt @@ -0,0 +1,9 @@ +/** + * @defgroup cpu_sam4s Atmel SAM4S + * @ingroup cpu + * @brief Atmel SAM4S Cortex-M4 MCU specific implementation. + * + * This module contains Atmel SAM4S specific code and definition. + * + * @see cpu_sam_common + */ diff --git a/cpu/sam4s/include/periph_cpu.h b/cpu/sam4s/include/periph_cpu.h new file mode 100644 index 0000000000..2731f9b90c --- /dev/null +++ b/cpu/sam4s/include/periph_cpu.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2025 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_sam4s + * @{ + * + * @file + * @brief CPU specific definitions for internal peripheral handling + * + * @author Dylan Laduranty + * + */ + +#ifndef PERIPH_CPU_H +#define PERIPH_CPU_H + +#include "periph_cpu_common.h" +#include "macros/units.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CPU_H */ +/** @} */ diff --git a/cpu/sam4s/periph/Makefile b/cpu/sam4s/periph/Makefile new file mode 100644 index 0000000000..a36df249ac --- /dev/null +++ b/cpu/sam4s/periph/Makefile @@ -0,0 +1 @@ +include $(RIOTMAKE)/periph.mk diff --git a/cpu/sam4s/vectors.c b/cpu/sam4s/vectors.c new file mode 100644 index 0000000000..9381f9ae09 --- /dev/null +++ b/cpu/sam4s/vectors.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2025 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_sam4s + * @{ + * + * @file + * @brief Startup code and interrupt vector definition + * + * @author Dylan Laduranty + * + * @} + */ + +#include +#include "vectors_cortexm.h" + +/* define a local dummy handler as it needs to be in the same compilation unit + * as the alias definition */ +void dummy_handler(void) { + dummy_handler_default(); +} + +/* Cortex-M common interrupt vectors */ +WEAK_DEFAULT void isr_svc(void); +WEAK_DEFAULT void isr_pendsv(void); +WEAK_DEFAULT void isr_systick(void); +/* SAM4S specific interrupt vector */ +WEAK_DEFAULT void isr_supc(void); +WEAK_DEFAULT void isr_rstc(void); +WEAK_DEFAULT void isr_rtc(void); +WEAK_DEFAULT void isr_rtt(void); +WEAK_DEFAULT void isr_wdt(void); +WEAK_DEFAULT void isr_pmc(void); +WEAK_DEFAULT void isr_eefc0(void); +WEAK_DEFAULT void isr_eefc1(void); +WEAK_DEFAULT void isr_uart0(void); +WEAK_DEFAULT void isr_uart1(void); +WEAK_DEFAULT void isr_smc(void); +WEAK_DEFAULT void isr_pioa(void); +WEAK_DEFAULT void isr_piob(void); +WEAK_DEFAULT void isr_pioc(void); +WEAK_DEFAULT void isr_usart0(void); +WEAK_DEFAULT void isr_usart1(void); +WEAK_DEFAULT void isr_hsmci(void); +WEAK_DEFAULT void isr_twi0(void); +WEAK_DEFAULT void isr_twi1(void); +WEAK_DEFAULT void isr_spi(void); +WEAK_DEFAULT void isr_ssc(void); +WEAK_DEFAULT void isr_tc0(void); +WEAK_DEFAULT void isr_tc1(void); +WEAK_DEFAULT void isr_tc2(void); +WEAK_DEFAULT void isr_tc3(void); +WEAK_DEFAULT void isr_tc4(void); +WEAK_DEFAULT void isr_tc5(void); +WEAK_DEFAULT void isr_adc(void); +WEAK_DEFAULT void isr_dacc(void); +WEAK_DEFAULT void isr_pwm(void); +WEAK_DEFAULT void isr_crccu(void); +WEAK_DEFAULT void isr_acc(void); +WEAK_DEFAULT void isr_udp(void); + +/* CPU specific interrupt vector table */ +ISR_VECTOR(1) const isr_t vector_cpu[CPU_IRQ_NUMOF] = { + isr_supc, /* 0 Supply Controller */ + isr_rstc, /* 1 Reset Controller */ + isr_rtc, /* 2 Real Time Clock */ + isr_rtt, /* 3 Real Timer Timer */ + isr_wdt, /* 4 Watchdog Timer */ + isr_pmc, /* 5 Power Management Controller */ + isr_eefc0, /* 6 Enhanced Embedded Flash Controller 0 */ + isr_eefc1, /* 7 Enhanced Embedded Flash Controller 1 */ + isr_uart0, /* 8 Universal Asynchronous Receiver Transceiver 0 */ + isr_uart1, /* 9 Universal Asynchronous Receiver Transceiver 1 */ + isr_smc, /* 10 Static Memory Controller */ + isr_pioa, /* 11 GPIO port A */ + isr_piob, /* 12 GPIO port B */ + isr_pioc, /* 13 GPIO port C */ + isr_usart0, /* 14 USART0 */ + isr_usart1, /* 15 USART1 */ + (0UL), /* Reserved */ + (0UL), /* Reserved */ + isr_hsmci, /* 18 Multimedia Card Interface */ + isr_twi0, /* 19 Two-wire Interface 0 */ + isr_twi1, /* 20 Two-wire Interface 1 */ + isr_spi, /* 21 Serial Peripheral Interface */ + isr_ssc, /* 22 Synchronous Serial Controller */ + isr_tc0, /* 23 Timer Counter 0 */ + isr_tc1, /* 24 Timer Counter 1 */ + isr_tc2, /* 25 Timer Counter 2 */ + isr_tc3, /* 26 Timer Counter 3 */ + isr_tc4, /* 27 Timer Counter 4 */ + isr_tc5, /* 28 Timer Counter 5 */ + isr_adc, /* 29 Analog/Digital Converter */ + isr_dacc, /* 30 Digital/Analog Converter Controller */ + isr_pwm, /* 31 Pulse Width Modulation */ + isr_crccu, /* 32 CRC Calculation Unit */ + isr_acc, /* 33 Analog Comparator Controller */ + isr_udp, /* 34 USB Device Port */ +}; diff --git a/features.yaml b/features.yaml index ca514dbb3f..da2a35f8db 100644 --- a/features.yaml +++ b/features.yaml @@ -246,6 +246,10 @@ groups: features: - name: cpu_sam3 help: The MCU has an Atmel/Microchip SAM 3 CPU + - title: SAM4S Grouping + features: + - name: cpu_sam4s + help: The MCU has an Atmel/Microchip SAM 4S CPU - title: GigaDevice Semiconductor Inc Grouping features: diff --git a/makefiles/features_existing.inc.mk b/makefiles/features_existing.inc.mk index 4aecbb5984..ef36b97f32 100644 --- a/makefiles/features_existing.inc.mk +++ b/makefiles/features_existing.inc.mk @@ -87,6 +87,7 @@ FEATURES_EXISTING := \ cpu_qn908x \ cpu_rpx0xx \ cpu_sam3 \ + cpu_sam4s \ cpu_samd21 \ cpu_samd5x \ cpu_saml1x \ From 6b74c45a9b1ddea0605bb1bf874f1e52e75b4262 Mon Sep 17 00:00:00 2001 From: dylad Date: Sat, 8 Feb 2025 13:23:21 +0100 Subject: [PATCH 2/4] cpu/sam3: miscellaneous cleanup Signed-off-by: dylad --- cpu/sam3/Makefile.include | 6 ++++++ cpu/sam_common/Makefile.include | 6 ------ cpu/sam_common/include/vendor/sam.h | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cpu/sam3/Makefile.include b/cpu/sam3/Makefile.include index 24f75984d7..96f297ea32 100644 --- a/cpu/sam3/Makefile.include +++ b/cpu/sam3/Makefile.include @@ -1,2 +1,8 @@ +ROM_START_ADDR ?= 0x80000 +RAM_START_ADDR ?= 0x20070000 + +ROM_LEN ?= 0x80000 +RAM_LEN ?= 0x18000 + include $(RIOTCPU)/sam_common/Makefile.include include $(RIOTMAKE)/arch/cortexm.inc.mk diff --git a/cpu/sam_common/Makefile.include b/cpu/sam_common/Makefile.include index 103ee94dd7..45cebbbd3f 100644 --- a/cpu/sam_common/Makefile.include +++ b/cpu/sam_common/Makefile.include @@ -4,12 +4,6 @@ CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM)) # this CPU implementation doesn't use CMSIS initialization CFLAGS += -DDONT_USE_CMSIS_INIT -ROM_START_ADDR ?= 0x80000 -RAM_START_ADDR ?= 0x20070000 - -ROM_LEN ?= 0x80000 -RAM_LEN ?= 0x18000 - LINKER_SCRIPT ?= cortexm.ld INCLUDES += -I$(RIOTCPU)/sam_common/include diff --git a/cpu/sam_common/include/vendor/sam.h b/cpu/sam_common/include/vendor/sam.h index 5aabd57cd9..933345ef26 100644 --- a/cpu/sam_common/include/vendor/sam.h +++ b/cpu/sam_common/include/vendor/sam.h @@ -23,13 +23,6 @@ extern "C" { #endif -#if defined(CPU_FAM_SAM3) && !defined(PERIPH_COUNT_IRQn) -/** - * @brief Number of periphical IRQs for SAM3 CPUs - */ -#define PERIPH_COUNT_IRQn (45U) -#endif - #if defined(CPU_MODEL_SAM3A4C) #include "vendor/sam3x/include/sam3a4c.h" #elif defined(CPU_MODEL_SAM3A8C) @@ -82,6 +75,13 @@ extern "C" { #error "Unsupported Atmel SAM variant." #endif +#if defined(CPU_FAM_SAM3) && !defined(PERIPH_COUNT_IRQn) +/** + * @brief Number of periphical IRQs for SAM3 CPUs + */ +#define PERIPH_COUNT_IRQn (45U) +#endif + #ifdef __cplusplus } #endif From 8cfc42b5623f10038ff1ee5665bffcd7e5d9cedf Mon Sep 17 00:00:00 2001 From: dylad Date: Sat, 8 Feb 2025 13:42:12 +0100 Subject: [PATCH 3/4] cpu/sam_common: move some SAM3 drivers to common folder This commit allows to share GPIO, Timers and UARTs driver across SAM3/SAM4s MCUs as they relies on the same IPs Signed-off-by: dylad --- cpu/sam3/Makefile.dep | 2 +- cpu/sam3/include/periph_cpu.h | 101 +--------------- cpu/sam_common/Makefile | 2 + cpu/sam_common/Makefile.dep | 4 + cpu/sam_common/include/periph_cpu_common.h | 134 +++++++++++++++++++++ cpu/sam_common/periph/Makefile | 3 + cpu/{sam3 => sam_common}/periph/gpio.c | 27 ++++- cpu/{sam3 => sam_common}/periph/timer.c | 7 +- cpu/{sam3 => sam_common}/periph/uart.c | 2 +- 9 files changed, 177 insertions(+), 105 deletions(-) create mode 100644 cpu/sam_common/Makefile.dep create mode 100644 cpu/sam_common/include/periph_cpu_common.h create mode 100644 cpu/sam_common/periph/Makefile rename cpu/{sam3 => sam_common}/periph/gpio.c (92%) rename cpu/{sam3 => sam_common}/periph/timer.c (96%) rename cpu/{sam3 => sam_common}/periph/uart.c (98%) diff --git a/cpu/sam3/Makefile.dep b/cpu/sam3/Makefile.dep index 849cc8d116..652f3ba1ae 100644 --- a/cpu/sam3/Makefile.dep +++ b/cpu/sam3/Makefile.dep @@ -1 +1 @@ -include $(RIOTCPU)/cortexm_common/Makefile.dep +include $(RIOTCPU)/sam_common/Makefile.dep diff --git a/cpu/sam3/include/periph_cpu.h b/cpu/sam3/include/periph_cpu.h index 973460a4be..73493f4860 100644 --- a/cpu/sam3/include/periph_cpu.h +++ b/cpu/sam3/include/periph_cpu.h @@ -22,21 +22,12 @@ #ifndef PERIPH_CPU_H #define PERIPH_CPU_H -#include "cpu.h" +#include "periph_cpu_common.h" #ifdef __cplusplus extern "C" { #endif -#ifndef DOXYGEN -#define HAVE_GPIO_T -typedef uint32_t gpio_t; - -#define GPIO_UNDEF (0xffffffff) - -#define GPIO_PIN(x, y) (((uint32_t)PIOA + (x << 9)) | y) -#endif /* DOXYGEN */ - /** * @name Declare needed generic SPI functions * @{ @@ -52,21 +43,6 @@ typedef uint32_t gpio_t; */ #define CPUID_LEN (16U) -/** - * @brief All SAM3 timers are 32-bit wide - */ -#define TIMER_MAX_VAL (0xffffffff) - -/** - * @brief We use one channel for each defined timer - * - * While the peripheral provides three channels, the current interrupt - * flag handling leads to a race condition where calling timer_clear() on one - * channel can disable a pending flag for other channels. - * Until resolved, limit the peripheral to only one channel. - */ -#define TIMER_CHANNEL_NUMOF (1) - /** * @name RTT configuration * @{ @@ -77,16 +53,6 @@ typedef uint32_t gpio_t; #define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ /** @} */ -/** - * @brief Generate GPIO mode bitfields - * - * We use 3 bit to determine the pin functions: - * - bit 0: in/out - * - bit 1: PU enable - * - bit 2: OD enable - */ -#define GPIO_MODE(io, pu, od) (io | (pu << 1) | (od << 2)) - /** * @name ADC configuration, valid for all boards using this CPU * @@ -109,43 +75,6 @@ typedef uint32_t gpio_t; */ #define DAC_NUMOF (2U) -#ifndef DOXYGEN -#define HAVE_GPIO_MODE_T -typedef enum { - GPIO_IN = GPIO_MODE(0, 0, 0), /**< IN */ - GPIO_IN_PD = 0xf, /**< not supported by HW */ - GPIO_IN_PU = GPIO_MODE(0, 1, 0), /**< IN with pull-up */ - GPIO_OUT = GPIO_MODE(1, 0, 0), /**< OUT (push-pull) */ - GPIO_OD = GPIO_MODE(1, 0, 1), /**< OD */ - GPIO_OD_PU = GPIO_MODE(1, 1, 1), /**< OD with pull-up */ -} gpio_mode_t; - -#define HAVE_GPIO_FLANK_T -typedef enum { - GPIO_RISING = 1, /**< emit interrupt on rising flank */ - GPIO_FALLING = 2, /**< emit interrupt on falling flank */ - GPIO_BOTH = 3 /**< emit interrupt on both flanks */ -} gpio_flank_t; -#endif /* ndef DOXYGEN */ - -/** - * @brief Available ports on the SAM3X8E - */ -enum { - PA = 0, /**< port A */ - PB = 1, /**< port B */ - PC = 2, /**< port C */ - PD = 3, /**< port D */ -}; - -/** - * @brief GPIO mux configuration - */ -typedef enum { - GPIO_MUX_A = 0, /**< alternate function A */ - GPIO_MUX_B = 1, /**< alternate function B */ -} gpio_mux_t; - #ifndef DOXYGEN /** * @brief Override default SPI modes @@ -192,26 +121,6 @@ typedef enum { /** @} */ #endif /* ndef DOXYGEN */ -/** - * @brief Timer configuration data - */ -typedef struct { - Tc *dev; /**< timer device */ - uint8_t id_ch0; /**< ID of the timer's first channel */ -} timer_conf_t; - -/** - * @brief UART configuration data - */ -typedef struct { - Uart *dev; /**< U(S)ART device used */ - gpio_t rx_pin; /**< RX pin */ - gpio_t tx_pin; /**< TX pin */ - gpio_mux_t mux; /**< MUX used for pins */ - uint8_t pmc_id; /**< bit in the PMC register of the device*/ - uint8_t irqn; /**< interrupt number of the device */ -} uart_conf_t; - /** * @brief PWM channel configuration data */ @@ -232,14 +141,6 @@ typedef struct { gpio_mux_t mux; /**< pin MUX setting */ } spi_conf_t; -/** - * @brief Configure the given GPIO pin to be used with the given MUX setting - * - * @param[in] pin GPIO pin to configure - * @param[in] mux MUX setting to use - */ -void gpio_init_mux(gpio_t pin, gpio_mux_t mux); - #ifdef __cplusplus } #endif diff --git a/cpu/sam_common/Makefile b/cpu/sam_common/Makefile index 48422e909a..e09377cd1e 100644 --- a/cpu/sam_common/Makefile +++ b/cpu/sam_common/Makefile @@ -1 +1,3 @@ +DIRS = periph + include $(RIOTBASE)/Makefile.base diff --git a/cpu/sam_common/Makefile.dep b/cpu/sam_common/Makefile.dep new file mode 100644 index 0000000000..e276cf2145 --- /dev/null +++ b/cpu/sam_common/Makefile.dep @@ -0,0 +1,4 @@ +# include sam common periph drivers +USEMODULE += sam_common_periph + +include $(RIOTCPU)/cortexm_common/Makefile.dep diff --git a/cpu/sam_common/include/periph_cpu_common.h b/cpu/sam_common/include/periph_cpu_common.h new file mode 100644 index 0000000000..688f2c9c96 --- /dev/null +++ b/cpu/sam_common/include/periph_cpu_common.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2025 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_sam_common + * @brief Common CPU specific definitions for all SAM3/SAM4x based CPUs + * @{ + * + * @file + * @brief Common CPU specific definitions for all SAM3/SAM4x based CPUs + * + * @author Dylan Laduranty + */ + +#ifndef PERIPH_CPU_COMMON_H +#define PERIPH_CPU_COMMON_H + +#include "cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN +#define HAVE_GPIO_T +typedef uint32_t gpio_t; + +#define GPIO_UNDEF (0xffffffff) + +#define GPIO_PIN(x, y) (((uint32_t)PIOA + (x << 9)) | y) +#endif /* DOXYGEN */ + +/** + * @brief We use one channel for each defined timer + * + * While the peripheral provides three channels, the current interrupt + * flag handling leads to a race condition where calling timer_clear() on one + * channel can disable a pending flag for other channels. + * Until resolved, limit the peripheral to only one channel. + */ +#define TIMER_CHANNEL_NUMOF (1) + +/** + * @brief Generate GPIO mode bitfields + * + * We use 3 bit to determine the pin functions: + * - bit 0: in/out + * - bit 1: PU enable + * - bit 2: OD enable + */ +#define GPIO_MODE(io, pu, od) (io | (pu << 1) | (od << 2)) + +#ifndef DOXYGEN +#define HAVE_GPIO_MODE_T +typedef enum { + GPIO_IN = GPIO_MODE(0, 0, 0), /**< IN */ + GPIO_IN_PD = 0xf, /**< not supported by HW */ + GPIO_IN_PU = GPIO_MODE(0, 1, 0), /**< IN with pull-up */ + GPIO_OUT = GPIO_MODE(1, 0, 0), /**< OUT (push-pull) */ + GPIO_OD = GPIO_MODE(1, 0, 1), /**< OD */ + GPIO_OD_PU = GPIO_MODE(1, 1, 1), /**< OD with pull-up */ +} gpio_mode_t; + +#define HAVE_GPIO_FLANK_T +typedef enum { + GPIO_RISING = 1, /**< emit interrupt on rising flank */ + GPIO_FALLING = 2, /**< emit interrupt on falling flank */ + GPIO_BOTH = 3 /**< emit interrupt on both flanks */ +} gpio_flank_t; +#endif /* ndef DOXYGEN */ + +/** + * @brief GPIO mux configuration + */ +typedef enum { + GPIO_MUX_A = 0, /**< alternate function A */ + GPIO_MUX_B = 1, /**< alternate function B */ +#ifdef CPU_FAM_SAM4S + GPIO_MUX_C = 2, /**< alternate function C */ + GPIO_MUX_D = 3, /**< alternate function D */ +#endif +} gpio_mux_t; + +/** + * @brief Available ports on the SAM3/SAM4S based MCUs + */ +enum { + PA = 0, /**< port A */ + PB = 1, /**< port B */ + PC = 2, /**< port C */ +#ifdef CPU_FAM_SAM3 + PD = 3, /**< port D */ +#endif +}; + +/** + * @brief Configure the given GPIO pin to be used with the given MUX setting + * + * @param[in] pin GPIO pin to configure + * @param[in] mux MUX setting to use + */ +void gpio_init_mux(gpio_t pin, gpio_mux_t mux); + +/** + * @brief Timer configuration data + */ +typedef struct { + Tc *dev; /**< timer device */ + uint8_t id_ch0; /**< ID of the timer's first channel */ +} timer_conf_t; + +/** + * @brief UART configuration data + */ +typedef struct { + Uart *dev; /**< U(S)ART device used */ + gpio_t rx_pin; /**< RX pin */ + gpio_t tx_pin; /**< TX pin */ + gpio_mux_t mux; /**< MUX used for pins */ + uint8_t pmc_id; /**< bit in the PMC register of the device*/ + uint8_t irqn; /**< interrupt number of the device */ +} uart_conf_t; + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CPU_COMMON_H */ +/** @} */ diff --git a/cpu/sam_common/periph/Makefile b/cpu/sam_common/periph/Makefile new file mode 100644 index 0000000000..0e09bae91d --- /dev/null +++ b/cpu/sam_common/periph/Makefile @@ -0,0 +1,3 @@ +MODULE = sam_common_periph + +include $(RIOTMAKE)/periph.mk diff --git a/cpu/sam3/periph/gpio.c b/cpu/sam_common/periph/gpio.c similarity index 92% rename from cpu/sam3/periph/gpio.c rename to cpu/sam_common/periph/gpio.c index b55179cbca..e69aafce1f 100644 --- a/cpu/sam3/periph/gpio.c +++ b/cpu/sam_common/periph/gpio.c @@ -9,7 +9,7 @@ */ /** - * @ingroup cpu_sam3 + * @ingroup cpu_sam_common * @ingroup drivers_periph_gpio * @{ * @@ -134,9 +134,14 @@ static inline int _port_num(gpio_t pin) */ static bool _port_valid(Pio *port) { - if (port == PIOA || port == PIOB || port == PIOC || port == PIOD) { + if (port == PIOA || port == PIOB || port == PIOC) { return true; } +#ifdef PIOD + if (port == PIOD) { + return true; + } +#endif return false; } @@ -162,6 +167,11 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) /* power on the corresponding port */ PMC->PMC_PCER0 = (1 << (port_num + 11)); + /* SAM4s MCUs requires WPKEY for enabling peripheral */ +#ifdef PIO_WPMR_WPKEY_PASSWD + port->PIO_WPMR = PIO_WPMR_WPKEY_PASSWD; +#endif + /* disable interrupt and clear context (to be safe) */ port->PIO_IDR = (1 << pin_num); #ifdef MODULE_PERIPH_GPIO_IRQ @@ -203,8 +213,19 @@ void gpio_init_mux(gpio_t pin, gpio_mux_t mux) /* give peripheral control over the pin */ _port(pin)->PIO_PDR = (1 << _pin_num(pin)); /* and configure the MUX */ +#ifdef PIO_ABCDSR_P0 + _port(pin)->PIO_ABCDSR[0] &= ~(1 << _pin_num(pin)); + _port(pin)->PIO_ABCDSR[1] &= ~(1 << _pin_num(pin)); + if (mux & 0x2) { + _port(pin)->PIO_ABCDSR[1] |= 1 << _pin_num(pin); + } + if (mux & 0x1) { + _port(pin)->PIO_ABCDSR[0] |= 1 << _pin_num(pin); + } +#else _port(pin)->PIO_ABSR &= ~(1 << _pin_num(pin)); _port(pin)->PIO_ABSR |= (mux << _pin_num(pin)); +#endif } void gpio_set(gpio_t pin) @@ -338,8 +359,10 @@ void isr_pioc(void) isr_handler(PIOC, PC); } +#ifdef PIOD void isr_piod(void) { isr_handler(PIOD, PD); } +#endif #endif /* MODULE_PERIPH_GPIO_IRQ */ diff --git a/cpu/sam3/periph/timer.c b/cpu/sam_common/periph/timer.c similarity index 96% rename from cpu/sam3/periph/timer.c rename to cpu/sam_common/periph/timer.c index 721b6f879f..8012fe3b4c 100644 --- a/cpu/sam3/periph/timer.c +++ b/cpu/sam_common/periph/timer.c @@ -7,7 +7,7 @@ */ /** - * @ingroup cpu_sam3 + * @ingroup cpu_sam_common * @ingroup drivers_periph_timer * @{ * @@ -82,6 +82,11 @@ int timer_init(tim_t tim, uint32_t freq, timer_cb_t cb, void *arg) return -1; } + /* SAM4s requires this WPKEY for enabling peripheral access */ +#ifdef TC_WPMR_WPKEY_PASSWD + dev(tim)->TC_WPMR = TC_WPMR_WPKEY_PASSWD; +#endif + /* enable the device clock */ clk_en(tim); diff --git a/cpu/sam3/periph/uart.c b/cpu/sam_common/periph/uart.c similarity index 98% rename from cpu/sam3/periph/uart.c rename to cpu/sam_common/periph/uart.c index 8cb8723ed0..eb9e53409f 100644 --- a/cpu/sam3/periph/uart.c +++ b/cpu/sam_common/periph/uart.c @@ -7,7 +7,7 @@ */ /** - * @ingroup cpu_sam3 + * @ingroup cpu_sam_common * @ingroup drivers_periph_uart * @{ * From 363fb755de3e11d52f330c0adaf15b2ce283b6c1 Mon Sep 17 00:00:00 2001 From: dylad Date: Sat, 8 Feb 2025 13:15:46 +0100 Subject: [PATCH 4/4] boards/sam4s-xpro: introduce initial board support Signed-off-by: dylad --- boards/sam4s-xpro/Makefile | 3 + boards/sam4s-xpro/Makefile.features | 7 ++ boards/sam4s-xpro/Makefile.include | 6 ++ boards/sam4s-xpro/dist/openocd.cfg | 2 + boards/sam4s-xpro/doc.txt | 48 +++++++++++++ boards/sam4s-xpro/include/board.h | 62 ++++++++++++++++ boards/sam4s-xpro/include/periph_conf.h | 94 +++++++++++++++++++++++++ 7 files changed, 222 insertions(+) create mode 100644 boards/sam4s-xpro/Makefile create mode 100644 boards/sam4s-xpro/Makefile.features create mode 100644 boards/sam4s-xpro/Makefile.include create mode 100644 boards/sam4s-xpro/dist/openocd.cfg create mode 100644 boards/sam4s-xpro/doc.txt create mode 100644 boards/sam4s-xpro/include/board.h create mode 100644 boards/sam4s-xpro/include/periph_conf.h diff --git a/boards/sam4s-xpro/Makefile b/boards/sam4s-xpro/Makefile new file mode 100644 index 0000000000..f8fcbb53a0 --- /dev/null +++ b/boards/sam4s-xpro/Makefile @@ -0,0 +1,3 @@ +MODULE = board + +include $(RIOTBASE)/Makefile.base diff --git a/boards/sam4s-xpro/Makefile.features b/boards/sam4s-xpro/Makefile.features new file mode 100644 index 0000000000..4607825d90 --- /dev/null +++ b/boards/sam4s-xpro/Makefile.features @@ -0,0 +1,7 @@ +CPU = sam4s +CPU_MODEL = sam4sd32c + +# Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_gpio periph_gpio_irq +FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_uart diff --git a/boards/sam4s-xpro/Makefile.include b/boards/sam4s-xpro/Makefile.include new file mode 100644 index 0000000000..2b8dbd97fa --- /dev/null +++ b/boards/sam4s-xpro/Makefile.include @@ -0,0 +1,6 @@ +# export this module and its includes +INCLUDES += -I$(RIOTBOARD)/sam4s-xpro/include + +# setup flasher (using openOCD) +PROGRAMMER ?= openocd +PROGRAMMERS_SUPPORTED += openocd edbg diff --git a/boards/sam4s-xpro/dist/openocd.cfg b/boards/sam4s-xpro/dist/openocd.cfg new file mode 100644 index 0000000000..c1b0e1f9a2 --- /dev/null +++ b/boards/sam4s-xpro/dist/openocd.cfg @@ -0,0 +1,2 @@ +source [find board/atmel_sam4s_xplained_pro.cfg] +$_TARGETNAME configure -rtos auto diff --git a/boards/sam4s-xpro/doc.txt b/boards/sam4s-xpro/doc.txt new file mode 100644 index 0000000000..46dae32405 --- /dev/null +++ b/boards/sam4s-xpro/doc.txt @@ -0,0 +1,48 @@ +/** +@defgroup boards_sam4s-xpro ATSAM4S Xplained Pro board +@ingroup boards +@brief Support for the ATSAM4S Xplained Pro board + +## Overview + +The `ATSAM4S Xplained Pro` is an evaluation board by Microchip (formerly Atmel) +featuring a SAM4SD32 (Cortex-M4) SoC running up to 120 MHz. This MCU comes with +160Kb of RAM and 2048Kb of flash memory. + +## Hardware + +![sam4s-xpro image](https://www.microchip.com/content/dam/mchp/mrt-dam/devtools/1801-atsam4s-xpro.jpg) + + +### MCU +| MCU | ATSAM4SD32C | +|:------------- |:--------------------- | +| Family | ARM Cortex-M4 | +| Vendor | Microchip | +| RAM | 160Kb | +| Flash | 2048Kb | +| Frequency | up to 120MHz | +| FPU | no | +| Timers | 2 three channels (16-bit) | +| ADCs | 1x 12-bit (16 channels) | +| UARTs | 2 UARTs (+ 2 USARTs shared with SPIs) | +| SPIs | 2 shared with USARTs | +| I2Cs | 2 | +| Datasheet | [Datasheet](https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/Atmel-11100-32-bitCortex-M4-Microcontroller-SAM4S_Datasheet.pdf) | +| Board Manual | [Board Manual](https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/UserGuides/Atmel-42075-SAM4S-Xplained-Pro_User-Guide.pdf)| + +### User Interface + +1 User button and 1 LED: + +| Device | PIN | +|:------ |:--- | +| LED0 | PC23 | +| SW0 (button) | PA02 | + +### Flashing options +By default, openOCD is used for both flashing and debugging. +EDBG programmer is also available with: +`PROGRAMMER=edbg BOARD=sam4s-xpro make -C tests/leds flash` + + */ diff --git a/boards/sam4s-xpro/include/board.h b/boards/sam4s-xpro/include/board.h new file mode 100644 index 0000000000..03876978dd --- /dev/null +++ b/boards/sam4s-xpro/include/board.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2025 Mesotic SAS + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup boards_sam4s-xpro + * @{ + * + * @file + * @brief Board specific definitions for the Microchip SAM 4S Xplained Pro + * board + * + * @author Dylan Laduranty + */ + +#ifndef BOARD_H +#define BOARD_H + +#include "cpu.h" +#include "periph_conf.h" +#include "periph_cpu.h" +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name ztimer configuration + * @{ + */ +#define CONFIG_ZTIMER_USEC_WIDTH (16) +/** @} */ + +/** + * @name LED pin definitions and handlers + * @{ + */ +#define LED0_PIN GPIO_PIN(PC, 23) + +#define LED0_ON (PIOC->PIO_CODR = PIO_PC23) +#define LED0_OFF (PIOC->PIO_SODR = PIO_PC23) +#define LED0_TOGGLE ((PIOC->PIO_ODSR & PIO_PC23) ? LED0_ON : LED0_OFF) +/** @} */ + +/** + * @name SW0 (Button) pin definitions + * @{ + */ +#define BTN0_PIN GPIO_PIN(PA, 2) +#define BTN0_MODE GPIO_IN_PU +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H */ +/** @} */ diff --git a/boards/sam4s-xpro/include/periph_conf.h b/boards/sam4s-xpro/include/periph_conf.h new file mode 100644 index 0000000000..6946fca7b1 --- /dev/null +++ b/boards/sam4s-xpro/include/periph_conf.h @@ -0,0 +1,94 @@ + /* + * Copyright (C) 2025 Mesotic SAS + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup boards_sam4s-xpro + * @{ + * + * @file + * @brief Peripheral MCU configuration for SAM4S Xplained pro + * + * @author Dylan Laduranty + */ + +#ifndef PERIPH_CONF_H +#define PERIPH_CONF_H + +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Clock configuration + * @{ + */ +/* targeted system core clock */ +#define CLOCK_CORECLOCK MHZ(120) +/* external oscillator clock */ +#define CLOCK_EXT_OSC MHZ(12) +/* define PLL configuration + * + * The values must fulfill this equation: + * CORECLOCK = (EXT_OCS / PLL_DIV) * (PLL_MUL + 1) + */ +#define CLOCK_PLL_MUL (9) +#define CLOCK_PLL_DIV (1) + +/* number of wait states before flash read and write operations */ +#define CLOCK_FWS (5) /* 5 is safe for 120 MHz */ +/** @} */ + +/** + * @brief Enable external oscillator for driving the slow clock + */ +#define CLOCK_SCLK_XTAL (1) + +/** + * @name Timer peripheral configuration + * @{ + */ +static const timer_conf_t timer_config[] = { + { .dev = TC0, .id_ch0 = ID_TC0 }, + { .dev = TC1, .id_ch0 = ID_TC3 } +}; + +#define TIMER_0_ISR isr_tc0 +#define TIMER_1_ISR isr_tc3 + +#define TIMER_NUMOF ARRAY_SIZE(timer_config) +/** @} */ + +/** + * @name UART configuration + * @{ + */ +static const uart_conf_t uart_config[] = { + { + .dev = (Uart *)UART1, + .rx_pin = GPIO_PIN(PB, 2), + .tx_pin = GPIO_PIN(PB, 3), + .mux = GPIO_MUX_A, + .pmc_id = ID_UART1, + .irqn = UART1_IRQn + } +}; + +/* define interrupt vectors */ +#define UART_0_ISR isr_uart1 + +#define UART_NUMOF ARRAY_SIZE(uart_config) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CONF_H */ +/** @} */