diff --git a/.github/workflows/compile-all.yml b/.github/workflows/compile-all.yml
index 226a3b2d2d..ff89e15407 100644
--- a/.github/workflows/compile-all.yml
+++ b/.github/workflows/compile-all.yml
@@ -31,7 +31,7 @@ jobs:
name: avr-compile-all
path: test/all/log
- sam-compile-all:
+ sam-d0x-d1x-d2x-compile-all:
if: github.event.label.name == 'ci:hal'
runs-on: ubuntu-20.04
container:
@@ -47,9 +47,61 @@ jobs:
- name: Update lbuild
run: |
pip3 install --upgrade --upgrade-strategy=eager modm
- - name: Compile HAL for all SAM
+ - name: Compile HAL for SAMD0x, SAMD1x, SAMD2x
run: |
- (cd test/all && python3 run_all.py sam --quick-remaining)
+ (cd test/all && python3 run_all.py samd0 samd1 samd2 --quick-remaining)
+ - name: Upload log artifacts
+ if: always()
+ uses: actions/upload-artifact@v2
+ with:
+ name: sam-compile-all
+ path: test/all/log
+
+ sam-x5x-compile-all:
+ if: github.event.label.name == 'ci:hal'
+ runs-on: ubuntu-20.04
+ container:
+ image: ghcr.io/modm-ext/modm-build-cortex-m:2022-09-27
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v3
+ with:
+ submodules: 'recursive'
+ - name: Fix Git permission/ownership problem
+ run: |
+ git config --global --add safe.directory /__w/modm/modm
+ - name: Update lbuild
+ run: |
+ pip3 install --upgrade --upgrade-strategy=eager modm
+ - name: Compile HAL for SAMD5x, SAME5x, SAMG5x
+ run: |
+ (cd test/all && python3 run_all.py samd5 same5 samg5 --quick-remaining)
+ - name: Upload log artifacts
+ if: always()
+ uses: actions/upload-artifact@v2
+ with:
+ name: sam-compile-all
+ path: test/all/log
+
+ sam-x7x-compile-all:
+ if: github.event.label.name == 'ci:hal'
+ runs-on: ubuntu-20.04
+ container:
+ image: ghcr.io/modm-ext/modm-build-cortex-m:2022-09-27
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v3
+ with:
+ submodules: 'recursive'
+ - name: Fix Git permission/ownership problem
+ run: |
+ git config --global --add safe.directory /__w/modm/modm
+ - name: Update lbuild
+ run: |
+ pip3 install --upgrade --upgrade-strategy=eager modm
+ - name: Compile HAL for SAME7x, SAMS7x, SAMV7x
+ run: |
+ (cd test/all && python3 run_all.py same7 sams7 samv7 --quick-remaining)
- name: Upload log artifacts
if: always()
uses: actions/upload-artifact@v2
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index c476fff2c3..8bdb2c584b 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -92,15 +92,19 @@ jobs:
- name: Examples SAMD Devices
if: always()
run: |
- (cd examples && ../tools/scripts/examples_compile.py samd)
+ (cd examples && ../tools/scripts/examples_compile.py samd samd21_xplained_pro)
- name: Examples SAMG Devices
if: always()
run: |
(cd examples && ../tools/scripts/examples_compile.py samg55_xplained_pro)
+ - name: Examples SAME5x Devices
+ if: always()
+ run: |
+ (cd examples && ../tools/scripts/examples_compile.py same54_xplained_pro)
- name: Examples SAMV Devices
if: always()
run: |
- (cd examples && ../tools/scripts/examples_compile.py samv)
+ (cd examples && ../tools/scripts/examples_compile.py samv samv71_xplained_ultra)
- name: Examples RP20 Devices
if: always()
run: |
diff --git a/README.md b/README.md
index f12b1d9c64..d549a05b27 100644
--- a/README.md
+++ b/README.md
@@ -80,10 +80,10 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git
## Microcontrollers
-modm can create a HAL for 3304 devices of these vendors:
+modm can create a HAL for 3534 devices of these vendors:
- STMicroelectronics STM32: 2729 devices.
-- Microchip SAM: 186 devices.
+- Microchip SAM: 416 devices.
- Microchip AVR: 388 devices.
- Raspberry Pi: 1 device.
@@ -103,7 +103,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
|
STM32 |
-SAM |
+SAM |
RP |
AT |
@@ -121,9 +121,10 @@ Please [discover modm's peripheral drivers for your specific device][discover].
L1 |
L4 |
L5 |
-D21 |
-G55 |
-V70 |
+D1x D2x DAx |
+D5x E5x |
+E7x S7x V7x |
+G5x |
20 |
90 |
Mega |
@@ -144,8 +145,9 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
○ |
-✅ |
○ |
+○ |
+✅ |
✅ |
○ |
✅ |
@@ -166,8 +168,9 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
✕ |
-✕ |
○ |
+○ |
+✕ |
✕ |
○ |
○ |
@@ -188,8 +191,9 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
○ |
○ |
-✕ |
○ |
+○ |
+✕ |
✕ |
○ |
○ |
@@ -210,10 +214,11 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
○ |
-✕ |
+○ |
○ |
✕ |
✕ |
+✕ |
○ |
✕ |
@@ -232,8 +237,9 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
○ |
-✕ |
○ |
+○ |
+✕ |
✅ |
✕ |
✕ |
@@ -254,7 +260,8 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✕ |
✕ |
✕ |
-✕ |
+○ |
+○ |
✕ |
✕ |
✕ |
@@ -278,6 +285,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
○ |
○ |
+○ |
✅ |
✅ |
✅ |
@@ -300,6 +308,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✕ |
✕ |
○ |
+✕ |
○ |
✕ |
✕ |
@@ -326,6 +335,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
✅ |
+✅ |
I2C |
✅ |
@@ -344,6 +354,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
○ |
○ |
○ |
+○ |
✅ |
✅ |
✅ |
@@ -366,6 +377,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
○ |
○ |
○ |
+○ |
✕ |
✕ |
✕ |
@@ -386,8 +398,9 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
✕ |
-✕ |
○ |
+○ |
+✕ |
✕ |
✕ |
✕ |
@@ -408,8 +421,9 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
○ |
-✅ |
○ |
+○ |
+✅ |
✅ |
✅ |
✅ |
@@ -433,6 +447,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
✅ |
+✅ |
✕ |
✕ |
✕ |
@@ -452,9 +467,10 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
○ |
-✅ |
○ |
○ |
+✅ |
+○ |
○ |
○ |
○ |
@@ -475,7 +491,8 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
✅ |
✅ |
-○ |
+✅ |
+✅ |
✅ |
✅ |
✅ |
@@ -502,6 +519,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✕ |
✕ |
✕ |
+✕ |
USB |
✅ |
@@ -521,6 +539,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
✅ |
○ |
✅ |
+✅ |
✕ |
✕ |
✕ |
@@ -613,11 +632,15 @@ We have out-of-box support for many development boards including documentation.
Raspberry Pi Pico |
SAMD21-MINI |
+SAMD21-XPLAINED-PRO |
+SAME54-XPLAINED-PRO |
SAMG55-XPLAINED-PRO |
+
+SAMV71-XPLAINED-ULTRA |
Smart Response XE |
STM32-F4VE |
-
STM32F030-DEMO |
+
THINGPLUS-RP2040 |
diff --git a/examples/samd/interrupt/main.cpp b/examples/samd/interrupt/main.cpp
index 0e3a9aceb3..c35747a826 100644
--- a/examples/samd/interrupt/main.cpp
+++ b/examples/samd/interrupt/main.cpp
@@ -27,7 +27,7 @@ int
main()
{
Board::initialize();
- ExternalInterrupt::initialize();
+ ExternalInterrupt::initialize(Board::SystemClock::ClockGen32kHz);
ExtInt<3>::initialize(&isr);
ExtInt<3>::connect();
while (1)
diff --git a/examples/samd21_xplained_pro/blink/main.cpp b/examples/samd21_xplained_pro/blink/main.cpp
new file mode 100644
index 0000000000..90716c8993
--- /dev/null
+++ b/examples/samd21_xplained_pro/blink/main.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016-2017, Niklas Hauser
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+
+using namespace Board;
+
+int
+main()
+{
+ Board::initialize();
+
+ // Use the logging streams to print some messages.
+ // Change MODM_LOG_LEVEL above to enable or disable these messages
+ MODM_LOG_DEBUG << "debug" << modm::endl;
+ MODM_LOG_INFO << "info" << modm::endl;
+ MODM_LOG_WARNING << "warning" << modm::endl;
+ MODM_LOG_ERROR << "error" << modm::endl;
+
+ uint32_t counter(0);
+
+ while (true)
+ {
+ Led0::toggle();
+ modm::delay(Button::read() ? 500ms : 100ms);
+
+ MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/samd21_xplained_pro/blink/project.xml b/examples/samd21_xplained_pro/blink/project.xml
new file mode 100644
index 0000000000..2c9638f352
--- /dev/null
+++ b/examples/samd21_xplained_pro/blink/project.xml
@@ -0,0 +1,9 @@
+
+ modm:samd21-xplained-pro
+
+
+
+
+ modm:build:scons
+
+
diff --git a/examples/samd21_xplained_pro/usbserial/main.cpp b/examples/samd21_xplained_pro/usbserial/main.cpp
new file mode 100644
index 0000000000..2bf24ef589
--- /dev/null
+++ b/examples/samd21_xplained_pro/usbserial/main.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016-2017, Niklas Hauser
+ * Copyright (c) 2022, Christopher Durand
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+#include
+
+using namespace Board;
+
+modm::IODeviceWrapper usb_io_device;
+modm::IOStream usb_stream(usb_io_device);
+
+int
+main()
+{
+ Board::initialize();
+ Board::initializeUsbFs();
+
+ tusb_init();
+
+ usb_stream << "Hello from USB" << modm::endl;
+
+ uint32_t counter(0);
+
+ modm::PeriodicTimer timer{500ms};
+ while (true)
+ {
+ tud_task();
+ if (timer.execute()) {
+ Led0::toggle();
+ usb_stream << "loop: " << counter++ << modm::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/samd21_xplained_pro/usbserial/project.xml b/examples/samd21_xplained_pro/usbserial/project.xml
new file mode 100644
index 0000000000..8ab1e6a5a9
--- /dev/null
+++ b/examples/samd21_xplained_pro/usbserial/project.xml
@@ -0,0 +1,12 @@
+
+ modm:samd21-xplained-pro
+
+
+
+
+
+ modm:tinyusb
+ modm:build:scons
+ modm:processing:timer
+
+
diff --git a/examples/same54_xplained_pro/blink/main.cpp b/examples/same54_xplained_pro/blink/main.cpp
new file mode 100644
index 0000000000..90716c8993
--- /dev/null
+++ b/examples/same54_xplained_pro/blink/main.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016-2017, Niklas Hauser
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+
+using namespace Board;
+
+int
+main()
+{
+ Board::initialize();
+
+ // Use the logging streams to print some messages.
+ // Change MODM_LOG_LEVEL above to enable or disable these messages
+ MODM_LOG_DEBUG << "debug" << modm::endl;
+ MODM_LOG_INFO << "info" << modm::endl;
+ MODM_LOG_WARNING << "warning" << modm::endl;
+ MODM_LOG_ERROR << "error" << modm::endl;
+
+ uint32_t counter(0);
+
+ while (true)
+ {
+ Led0::toggle();
+ modm::delay(Button::read() ? 500ms : 100ms);
+
+ MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/same54_xplained_pro/blink/project.xml b/examples/same54_xplained_pro/blink/project.xml
new file mode 100644
index 0000000000..fa74596a8f
--- /dev/null
+++ b/examples/same54_xplained_pro/blink/project.xml
@@ -0,0 +1,10 @@
+
+ modm:same54-xplained-pro
+
+
+
+
+ modm:build:scons
+ modm:platform:uart:1
+
+
diff --git a/examples/same54_xplained_pro/usbserial/main.cpp b/examples/same54_xplained_pro/usbserial/main.cpp
new file mode 100644
index 0000000000..2bf24ef589
--- /dev/null
+++ b/examples/same54_xplained_pro/usbserial/main.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016-2017, Niklas Hauser
+ * Copyright (c) 2022, Christopher Durand
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+#include
+
+using namespace Board;
+
+modm::IODeviceWrapper usb_io_device;
+modm::IOStream usb_stream(usb_io_device);
+
+int
+main()
+{
+ Board::initialize();
+ Board::initializeUsbFs();
+
+ tusb_init();
+
+ usb_stream << "Hello from USB" << modm::endl;
+
+ uint32_t counter(0);
+
+ modm::PeriodicTimer timer{500ms};
+ while (true)
+ {
+ tud_task();
+ if (timer.execute()) {
+ Led0::toggle();
+ usb_stream << "loop: " << counter++ << modm::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/same54_xplained_pro/usbserial/project.xml b/examples/same54_xplained_pro/usbserial/project.xml
new file mode 100644
index 0000000000..a43ae490d0
--- /dev/null
+++ b/examples/same54_xplained_pro/usbserial/project.xml
@@ -0,0 +1,12 @@
+
+ modm:same54-xplained-pro
+
+
+
+
+
+ modm:tinyusb
+ modm:build:scons
+ modm:processing:timer
+
+
diff --git a/examples/samv71_xplained_ultra/blink/main.cpp b/examples/samv71_xplained_ultra/blink/main.cpp
new file mode 100644
index 0000000000..63d68f8de1
--- /dev/null
+++ b/examples/samv71_xplained_ultra/blink/main.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016-2017, Niklas Hauser
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+
+using namespace Board;
+
+int
+main()
+{
+ Board::initialize();
+
+ // Use the logging streams to print some messages.
+ // Change MODM_LOG_LEVEL above to enable or disable these messages
+ MODM_LOG_DEBUG << "debug" << modm::endl;
+ MODM_LOG_INFO << "info" << modm::endl;
+ MODM_LOG_WARNING << "warning" << modm::endl;
+ MODM_LOG_ERROR << "error" << modm::endl;
+
+ uint32_t counter(0);
+
+ while (true)
+ {
+ Led0::toggle();
+ Led1::toggle();
+ modm::delay(ButtonSW0::read() ? 500ms : 100ms);
+
+ MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/samv71_xplained_ultra/blink/project.xml b/examples/samv71_xplained_ultra/blink/project.xml
new file mode 100644
index 0000000000..44ac35294a
--- /dev/null
+++ b/examples/samv71_xplained_ultra/blink/project.xml
@@ -0,0 +1,9 @@
+
+ modm:samv71-xplained-ultra
+
+
+
+
+ modm:build:scons
+
+
diff --git a/ext/hathach/module.lb b/ext/hathach/module.lb
index 085eaf4bf0..f0273488c2 100644
--- a/ext/hathach/module.lb
+++ b/ext/hathach/module.lb
@@ -101,11 +101,12 @@ def build(env):
env.copy("tinyusb/src/portable/st/synopsys", "portable/st/synopsys/")
elif target.platform == "sam":
- if target.family == "g":
+ if target.family == "g5x":
tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAMG"
env.copy("tinyusb/src/portable/microchip/samg/", "portable/microchip/samg/")
else:
- tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAM{}{}".format(target.family.upper(), target.series.upper())
+ series = "e5x" if target.series.startswith("e5") else target.series
+ tusb_config["CFG_TUSB_MCU"] = "OPT_MCU_SAM{}".format(series.upper())
env.copy("tinyusb/src/portable/microchip/samd/", "portable/microchip/samd/")
elif target.platform == "rp":
@@ -179,8 +180,10 @@ def build(env):
if target.platform == "stm32":
irq_data = env.query(":platform:usb:irqs")
irqs = irq_data["port_irqs"][speed]
- elif target.platform == "sam" and target.family in ["g"]:
+ elif target.platform == "sam" and target.family in ["g5x"]:
irqs = ["UDP"]
+ elif target.platform == "sam" and target.family in ["d5x/e5x"]:
+ irqs = ["USB_OTHER", "USB_SOF_HSOF", "USB_TRCPT0", "USB_TRCPT1"]
elif target.platform == "rp" and target.family in ["20"]:
irqs = ["USBCTRL_IRQ"]
else:
diff --git a/ext/hathach/tusb_port.cpp.in b/ext/hathach/tusb_port.cpp.in
index 37f4554039..29006dfc79 100644
--- a/ext/hathach/tusb_port.cpp.in
+++ b/ext/hathach/tusb_port.cpp.in
@@ -66,7 +66,7 @@ tusb_get_device_serial(uint16_t *serial_str)
((uint32_t *) UID_BASE), ((uint32_t *) UID_BASE) + 1,
((uint32_t *) UID_BASE) + 2, ((uint32_t *) UID_BASE) + 3
%% elif target.platform in ["sam"]
- %% if "samd51" in target.string
+ %% if "samd51" in target.string or "same5" in target.string
(uint32_t *)0x008061FC, (uint32_t *)0x00806010,
(uint32_t *)0x00806014, (uint32_t *)0x00806018
%% else
diff --git a/ext/microchip/module.lb b/ext/microchip/module.lb
index a875db6af9..f5522900c3 100644
--- a/ext/microchip/module.lb
+++ b/ext/microchip/module.lb
@@ -23,16 +23,53 @@ def prepare(module, options):
return False
module.depends(":cmsis:core")
+
+ module.add_query(
+ EnvironmentQuery(name="clock-map", factory=clock_map))
+
return True
pp = {}
+
+def clock_map_gclk(env, header):
+ clock_pattern = re.compile(r"^#define\s+(?P(MCLK|PM))_(?P(AHB|APB[A-E]))MASK_(?P([A-Z0-9])+(_2X)?(_[A-Z]+)?)_Pos(\s+)(?P([0-9]+))")
+ peripheral_pattern = re.compile(r"^(?P[A-Za-z]+([0-9]+[A-Za-z]+)?(_2X)?(_[A-Z]+)?)(?P[0-9]?)$")
+ clock_map = {}
+ with open(header, "r") as clock_header:
+ for line in clock_header:
+ m = clock_pattern.match(line)
+ if m:
+ m2 = peripheral_pattern.match(m.group("per"))
+ (peripheral, instance) = (m2.group("name"), m2.group("instance"))
+ if (peripheral, instance) in clock_map:
+ clock_map[(peripheral, instance)].append((m.group("clk_per"), m.group("clk"), m.group("pos")))
+ else:
+ clock_map[(peripheral, instance)] = [(m.group("clk_per"), m.group("clk"), m.group("pos"))]
+ return clock_map
+
+def clock_map(env):
+ folder = Path(localpath(pp["folder"])) / "component"
+ clock_file = None
+ if (folder / "mclk.h").exists():
+ clock_file = folder / "mclk.h"
+ elif (folder / "mclk_100.h").exists():
+ clock_file = folder / "mclk_100.h"
+ elif (folder / "pm.h").exists():
+ clock_file = folder / "pm.h"
+ elif (folder / "pm_100.h").exists():
+ clock_file = folder / "pm_100.h"
+
+ if clock_file is not None:
+ return clock_map_gclk(env, clock_file)
+ return {}
+
def validate(env):
device = env[":target"]
# Some families use the variant in header defines, some do not (e.g. SAMG)
names = [
- "".join([device.identifier[f] for f in ["platform", "family", "series", "pin", "flash", "variant"]]),
- "".join([device.identifier[f] for f in ["platform", "family", "series", "pin", "flash"]]),
+ "".join([device.identifier[f] for f in ["platform", "series", "pin", "flash", "variant"]]),
+ "".join([device.identifier[f] for f in ["platform", "series", "pin", "flash"]]),
]
device_define = None
@@ -44,6 +81,10 @@ def validate(env):
for n in names:
define = "__{}__".format(n.upper())
if match is not None and define in match:
+ # In case of multiple matches the most specific header is selected.
+ # The one with the matching variant suffix will have the longest name.
+ if device_define is not None and len(device_define) > len(define):
+ continue
family_file = famfile.relative_to(localpath("."))
device_header = "{}.h".format(n)
device_define = define
diff --git a/ext/microchip/sam b/ext/microchip/sam
index 718fa0f98c..f903c3f55c 160000
--- a/ext/microchip/sam
+++ b/ext/microchip/sam
@@ -1 +1 @@
-Subproject commit 718fa0f98cbc7d35becddabc3612d73d03929cf3
+Subproject commit f903c3f55c1273ce1d121ee860e4fe7d2c6033bb
diff --git a/ext/modm-devices b/ext/modm-devices
index 05fca29f63..2714f2321f 160000
--- a/ext/modm-devices
+++ b/ext/modm-devices
@@ -1 +1 @@
-Subproject commit 05fca29f6398f847a99215ed0ab07d54f541cc3a
+Subproject commit 2714f2321f89bece09f0b339909ebe37e133858d
diff --git a/repo.lb b/repo.lb
index 570f35afce..87fc2b561c 100644
--- a/repo.lb
+++ b/repo.lb
@@ -86,7 +86,9 @@ class DevicesCache(dict):
"stm32h7",
"stm32l0", "stm32l1", "stm32l4", "stm32l5",
"at90", "attiny", "atmega",
- "samd21", "samg55", "samv70",
+ "samd21", "samg55",
+ "same70", "sams70", "samv70", "samv71",
+ "samd51", "same51", "same53", "same54",
"rp2040",
"hosted"]
device_file_names = [dfn for dfn in device_file_names if any(s in dfn for s in supported)]
diff --git a/src/modm/board/feather_m0/board.hpp b/src/modm/board/feather_m0/board.hpp
index 2b18fd3551..19860e77eb 100644
--- a/src/modm/board/feather_m0/board.hpp
+++ b/src/modm/board/feather_m0/board.hpp
@@ -2,6 +2,7 @@
* Copyright (c) 2016-2017, Sascha Schade
* Copyright (c) 2017-2018, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
+ * Copyright (c) 2022, Christopher Durand
*
* This file is part of the modm project.
*
@@ -60,42 +61,39 @@ using RadioCs = GpioA06;
// This is the red LED by the USB jack.
using Led = D13;
-/// samd21g18a running at 48MHz generated from the external 32.768 KHz crystal
+/// samd21g18a running at 48MHz generated from the external 32.768 kHz crystal
struct SystemClock
{
- static constexpr uint32_t Frequency = 48_MHz;
- static constexpr uint32_t Usb = 48_MHz;
- // static constexpr uint32_t Ahb = Frequency;
- // static constexpr uint32_t Apba = Frequency;
- // static constexpr uint32_t Apbb = Frequency;
- // static constexpr uint32_t Apbc = Frequency;
-
- // static constexpr uint32_t Adc = Apb2;
-
- // static constexpr uint32_t SercomSlow = Apb2;
- // static constexpr uint32_t Sercom0 = Apb2;
- // static constexpr uint32_t Sercom1 = Apb2;
- // static constexpr uint32_t Sercom2 = Apb2;
- // static constexpr uint32_t Sercom3 = Apb2;
- // static constexpr uint32_t Sercom4 = Apb2;
- // static constexpr uint32_t Sercom5 = Apb2;
-
- // static constexpr uint32_t Apb1Timer = Apb1 * 2;
- // static constexpr uint32_t Apb2Timer = Apb2 * 1;
- // static constexpr uint32_t Timer1 = Apb2Timer;
- // static constexpr uint32_t Timer2 = Apb1Timer;
- // static constexpr uint32_t Timer3 = Apb1Timer;
- // static constexpr uint32_t Timer4 = Apb1Timer;
+ static constexpr uint32_t Dfll48m = 48_MHz;
+ static constexpr uint32_t Xosc32k = 32768_Hz;
+
+ static constexpr uint32_t Frequency = Dfll48m;
+ static constexpr uint32_t Usb = Dfll48m;
+
+ static constexpr uint32_t Sercom0 = Frequency;
+ static constexpr uint32_t SercomSlow = Xosc32k;
+
+ static constexpr auto ClockGen32kHz = ClockGenerator::Generator2;
static bool inline
enable()
{
+ // Configure GCLK generator 2 with external 32k crystal source
+ GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms);
+ GenericClockController::enableGenerator();
+
+ // generate 48 MHz from 32768 Hz crystal reference
+ GenericClockController::connect(ClockGen32kHz);
+ GenericClockController::enableDfll48mClosedLoop();
+
GenericClockController::setFlashLatency();
- GenericClockController::initExternalCrystal();
- GenericClockController::initDFLL48MHz();
- GenericClockController::initOsc8MHz();
- GenericClockController::setSystemClock(ClockSource::DFLL48M);
+ GenericClockController::setSystemClock();
GenericClockController::updateCoreFrequency();
+
+ GenericClockController::connect(ClockGenerator::System);
+ GenericClockController::connect(ClockGen32kHz);
+
+ GenericClockController::connect(ClockGenerator::System);
return true;
}
};
diff --git a/src/modm/board/samd21_mini/board.hpp b/src/modm/board/samd21_mini/board.hpp
index 89e81f8fce..5ef27846eb 100644
--- a/src/modm/board/samd21_mini/board.hpp
+++ b/src/modm/board/samd21_mini/board.hpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2016-2017, Sascha Schade
* Copyright (c) 2017-2018, Niklas Hauser
+ * Copyright (c) 2022, Christopher Durand
*
* This file is part of the modm project.
*
@@ -25,39 +26,30 @@ using namespace modm::literals;
struct SystemClock
{
- static constexpr uint32_t Frequency = 48_MHz;
- // static constexpr uint32_t Ahb = Frequency;
- // static constexpr uint32_t Apba = Frequency;
- // static constexpr uint32_t Apbb = Frequency;
- // static constexpr uint32_t Apbc = Frequency;
-
- static constexpr uint32_t Usb = 48_MHz;
- // static constexpr uint32_t Adc = Apb2;
-
- // static constexpr uint32_t SercomSlow = Apb2;
- // static constexpr uint32_t Sercom0 = Apb2;
- // static constexpr uint32_t Sercom1 = Apb2;
- // static constexpr uint32_t Sercom2 = Apb2;
- // static constexpr uint32_t Sercom3 = Apb2;
- // static constexpr uint32_t Sercom4 = Apb2;
- // static constexpr uint32_t Sercom5 = Apb2;
-
- // static constexpr uint32_t Apb1Timer = Apb1 * 2;
- // static constexpr uint32_t Apb2Timer = Apb2 * 1;
- // static constexpr uint32_t Timer1 = Apb2Timer;
- // static constexpr uint32_t Timer2 = Apb1Timer;
- // static constexpr uint32_t Timer3 = Apb1Timer;
- // static constexpr uint32_t Timer4 = Apb1Timer;
+ static constexpr uint32_t Dfll48m = 48_MHz;
+ static constexpr uint32_t Xosc32k = 32768_Hz;
+
+ static constexpr uint32_t Frequency = Dfll48m;
+ static constexpr uint32_t Usb = Dfll48m;
+
+ static constexpr auto ClockGen32kHz = ClockGenerator::Generator2;
static bool inline
enable()
{
+ // Configure GCLK generator 2 with external 32k crystal source
+ GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms);
+ GenericClockController::enableGenerator();
+
+ // generate 48 MHz from 32768 Hz crystal reference
+ GenericClockController::connect(ClockGen32kHz);
+ GenericClockController::enableDfll48mClosedLoop();
+
GenericClockController::setFlashLatency();
- GenericClockController::initExternalCrystal();
- GenericClockController::initDFLL48MHz();
- GenericClockController::initOsc8MHz();
- GenericClockController::setSystemClock(ClockSource::DFLL48M);
+ GenericClockController::setSystemClock();
GenericClockController::updateCoreFrequency();
+
+ GenericClockController::connect(ClockGenerator::System);
return true;
}
};
@@ -103,10 +95,10 @@ initialize()
}
inline void
-initializeUsbFs(uint8_t priority=3)
+initializeUsbFs(uint8_t priority = 3)
{
- Usb::initialize(priority);
- Usb::connect();
+ modm::platform::Usb::initialize(priority);
+ modm::platform::Usb::connect();
}
/// @}
diff --git a/src/modm/board/samd21_xplained_pro/board.hpp b/src/modm/board/samd21_xplained_pro/board.hpp
new file mode 100644
index 0000000000..4b4ce82b84
--- /dev/null
+++ b/src/modm/board/samd21_xplained_pro/board.hpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022, Christopher Durand
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+#pragma once
+
+#include
+#include
+
+#define MODM_BOARD_HAS_LOGGER
+
+namespace Board
+{
+/// @ingroup modm_board_samd21_xplained_pro
+/// @{
+using namespace modm::literals;
+using namespace modm::platform;
+
+
+struct SystemClock
+{
+ static constexpr uint32_t Dfll48m = 48_MHz;
+ static constexpr uint32_t Xosc32k = 32768_Hz;
+
+ static constexpr uint32_t Frequency = Dfll48m;
+ static constexpr uint32_t Usb = Dfll48m;
+
+ static constexpr auto ClockGen32kHz = ClockGenerator::Generator2;
+
+ static constexpr uint32_t Sercom3 = Frequency;
+ static constexpr uint32_t SercomSlow = Xosc32k;
+
+ static bool inline
+ enable()
+ {
+ // Configure GCLK generator 2 with external 32k crystal source
+ GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms);
+ GenericClockController::enableGenerator();
+
+ // generate 48 MHz from 32768 Hz crystal reference
+ GenericClockController::connect(ClockGen32kHz);
+ GenericClockController::enableDfll48mClosedLoop();
+
+ GenericClockController::setFlashLatency();
+ GenericClockController::setSystemClock();
+ GenericClockController::updateCoreFrequency();
+
+ GenericClockController::connect(ClockGenerator::System);
+
+ GenericClockController::connect(ClockGenerator::System);
+ GenericClockController::connect(ClockGen32kHz);
+
+ return true;
+ }
+};
+
+using Led0 = GpioB30;
+using Button = GpioA15;
+
+// No SoftwareGpioPort yet for SAM
+struct Leds
+{
+ static constexpr std::size_t width{1};
+
+ static void setOutput()
+ {
+ Led0::setOutput();
+ }
+
+ static void write(uint32_t value)
+ {
+ Led0::set(value & 1);
+ }
+
+ static void toggle()
+ {
+ Led0::toggle();
+ }
+};
+
+struct Debug
+{
+ using Uart = Uart3;
+ using UartTx = GpioA22;
+ using UartRx = GpioA23;
+};
+
+using LoggerDevice = modm::IODeviceWrapper;
+
+inline void
+initialize()
+{
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+ Debug::Uart::initialize();
+ Debug::Uart::connect();
+
+ Led0::setOutput(modm::Gpio::Low);
+
+ Button::setInput(Button::InputType::PullUp);
+}
+
+inline void initializeUsbFs()
+{
+ modm::platform::Usb::initialize();
+ modm::platform::Usb::connect();
+}
+/// @}
+
+} // namespace Board
+
diff --git a/src/modm/board/samd21_xplained_pro/board.xml b/src/modm/board/samd21_xplained_pro/board.xml
new file mode 100644
index 0000000000..507a259706
--- /dev/null
+++ b/src/modm/board/samd21_xplained_pro/board.xml
@@ -0,0 +1,14 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+
+
+
+ modm:board:samd21-xplained-pro
+
+
diff --git a/src/modm/board/samd21_xplained_pro/module.lb b/src/modm/board/samd21_xplained_pro/module.lb
new file mode 100644
index 0000000000..359aebb225
--- /dev/null
+++ b/src/modm/board/samd21_xplained_pro/module.lb
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, Jeff McBride
+# Copyright (c) 2021-2022, Christopher Durand
+#
+# This file is part of the modm project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# -----------------------------------------------------------------------------
+
+def init(module):
+ module.name = ":board:samd21-xplained-pro"
+ module.description = "Microchip SAMD21 Xplained Pro"
+
+def prepare(module, options):
+ if not options[":target"].partname == "samd21j18a-au":
+ return False
+
+ module.depends(":debug", ":platform:gclk", ":platform:gpio", ":platform:core", ":platform:usb", ":platform:uart:3")
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/board"
+ env.substitutions = {
+ "with_logger": True,
+ "with_assert": env.has_module(":architecture:assert")
+ }
+ env.template("../board.cpp.in", "board.cpp")
+ env.copy('board.hpp')
+
+ env.outbasepath = "modm/openocd/modm/board/"
+ env.collect(":build:openocd.source", "board/atmel_samd21_xplained_pro.cfg");
diff --git a/src/modm/board/same54_xplained_pro/board.hpp b/src/modm/board/same54_xplained_pro/board.hpp
new file mode 100644
index 0000000000..a242acb4e8
--- /dev/null
+++ b/src/modm/board/same54_xplained_pro/board.hpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2021-2022, Christopher Durand
+ * Copyright (c) 2021, Jeff McBride
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+#pragma once
+
+#include
+#include
+
+#define MODM_BOARD_HAS_LOGGER
+
+namespace Board
+{
+/// @ingroup modm_board_same54_xplained_pro
+/// @{
+using namespace modm::literals;
+using namespace modm::platform;
+
+
+struct SystemClock
+{
+ static constexpr uint32_t Frequency = 120_MHz;
+
+ static constexpr uint32_t Clock48MHz = 48_MHz;
+ static constexpr auto Generator48MHz = ClockGenerator::Generator1;
+
+ static constexpr uint32_t Clock32k = 32768;
+ static constexpr auto Generator32k = ClockGenerator::Generator2;
+
+ static constexpr uint32_t Usb = Clock48MHz;
+
+ static constexpr uint32_t Sercom2 = Frequency;
+ static constexpr uint32_t SercomSlow = Clock32k;
+
+ static bool inline
+ enable()
+ {
+ GenericClockController::enableExternalCrystal<12_MHz>(Xosc::Xosc1);
+ GenericClockController::enableDpll, 120_MHz>();
+
+ GenericClockController::setFlashLatency();
+ GenericClockController::updateCoreFrequency();
+ GenericClockController::setSystemClock();
+
+ GenericClockController::enableExternalCrystal32k(Xosc32StartupTime::Start_500ms);
+ GenericClockController::enableGenerator();
+
+ // generate 48 MHz clock from external 32768 Hz crystal reference
+ GenericClockController::connect(Generator32k);
+ GenericClockController::enableDfll48mClosedLoop();
+
+ GenericClockController::enableGenerator();
+ GenericClockController::connect(Generator48MHz);
+
+ GenericClockController::connect(ClockGenerator::System);
+ GenericClockController::connect(Generator32k);
+
+ return true;
+ }
+};
+
+using Led0 = GpioC18;
+using Button = GpioB31;
+
+// No SoftwareGpioPort yet for SAM
+struct Leds
+{
+ static constexpr std::size_t width{1};
+
+ static void setOutput()
+ {
+ Led0::setOutput();
+ }
+
+ static void write(uint32_t value)
+ {
+ Led0::set(value & 1);
+ }
+};
+
+struct Debug
+{
+ using Uart = Uart2;
+ using UartTx = GpioB25;
+ using UartRx = GpioB24;
+};
+
+using LoggerDevice = modm::IODeviceWrapper;
+
+inline void
+initialize()
+{
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+ Debug::Uart::initialize();
+ Debug::Uart::connect();
+
+ Led0::setOutput(modm::Gpio::Low);
+
+ Button::setInput(InputType::PullUp);
+}
+
+inline void initializeUsbFs()
+{
+ modm::platform::Usb::initialize();
+ modm::platform::Usb::connect();
+}
+/// @}
+
+} // namespace Board
+
diff --git a/src/modm/board/same54_xplained_pro/board.xml b/src/modm/board/same54_xplained_pro/board.xml
new file mode 100644
index 0000000000..9f074a31ee
--- /dev/null
+++ b/src/modm/board/same54_xplained_pro/board.xml
@@ -0,0 +1,14 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+
+
+
+ modm:board:same54-xplained-pro
+
+
diff --git a/src/modm/board/same54_xplained_pro/module.lb b/src/modm/board/same54_xplained_pro/module.lb
new file mode 100644
index 0000000000..5bb733767c
--- /dev/null
+++ b/src/modm/board/same54_xplained_pro/module.lb
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, Jeff McBride
+# Copyright (c) 2021-2022, Christopher Durand
+#
+# This file is part of the modm project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# -----------------------------------------------------------------------------
+
+def init(module):
+ module.name = ":board:same54-xplained-pro"
+ module.description = "Microchip SAME54 Xplained Pro"
+
+def prepare(module, options):
+ if not options[":target"].partname == "same54p20a-au":
+ return False
+
+ module.depends(":debug", ":platform:gclk", ":platform:gpio", ":platform:core", ":platform:usb", ":platform:uart:2")
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/board"
+ env.substitutions = {
+ "with_logger": True,
+ "with_assert": env.has_module(":architecture:assert")
+ }
+ env.template("../board.cpp.in", "board.cpp")
+ env.copy('board.hpp')
+
+ env.outbasepath = "modm/openocd/modm/board/"
+ env.copy(repopath("tools/openocd/modm/atmel_same54_xplained_pro.cfg"), "atmel_same54_xplained_pro.cfg")
+ env.collect(":build:openocd.source", "modm/board/atmel_same54_xplained_pro.cfg")
diff --git a/src/modm/board/samg55_xplained_pro/board.hpp b/src/modm/board/samg55_xplained_pro/board.hpp
index 55be67fed6..1d9c0628e0 100644
--- a/src/modm/board/samg55_xplained_pro/board.hpp
+++ b/src/modm/board/samg55_xplained_pro/board.hpp
@@ -39,6 +39,8 @@ struct SystemClock
static constexpr uint32_t Pck6 = Mck;
static constexpr uint32_t Pck7 = Mck;
+ static constexpr uint32_t Usart7 = Mck;
+
static bool inline
enable()
{
@@ -62,7 +64,7 @@ struct SystemClock
using Led = GpioA6;
using Button = GpioA2;
-using DebugUart = Uart7;
+using DebugUart = Usart7;
using TxPin = GpioA28;
using RxPin = GpioA27;
diff --git a/src/modm/board/samg55_xplained_pro/module.lb b/src/modm/board/samg55_xplained_pro/module.lb
index b3302f866c..3aec8017fb 100644
--- a/src/modm/board/samg55_xplained_pro/module.lb
+++ b/src/modm/board/samg55_xplained_pro/module.lb
@@ -20,7 +20,7 @@ def prepare(module, options):
module.depends(
":platform:clockgen",
- ":platform:uart:7",
+ ":platform:usart:7",
":platform:gpio",
":platform:core",
":platform:usb",
@@ -31,4 +31,4 @@ def build(env):
env.outbasepath = "modm/src/modm/board"
env.copy('board.hpp')
- # TODO: openocd config?
\ No newline at end of file
+ # TODO: openocd config?
diff --git a/src/modm/board/samv71_xplained_ultra/board.hpp b/src/modm/board/samv71_xplained_ultra/board.hpp
new file mode 100644
index 0000000000..9ae9e57e10
--- /dev/null
+++ b/src/modm/board/samv71_xplained_ultra/board.hpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022, Christopher Durand
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+#pragma once
+
+#include
+#include
+#include
+
+#define MODM_BOARD_HAS_LOGGER
+
+namespace Board
+{
+/// @ingroup modm_board_samv71_xplained_ultra
+/// @{
+using namespace modm::literals;
+using namespace modm::platform;
+
+struct SystemClock
+{
+ // 300MHz system clock generated by PLLA from internal Rc 12MHz clock
+ static constexpr uint32_t PllAMult = 25;
+ static constexpr uint32_t Frequency = 300_MHz;
+ static constexpr uint32_t Mck = Frequency / 2; // 150 MHz max.
+ static constexpr uint32_t Usart1 = Mck;
+// static constexpr uint32_t Usb = 48_MHz;
+
+ static bool inline
+ enable()
+ {
+ ClockGen::setFlashLatency(); // Flash runs off MCK
+
+ ClockGen::enableMainInternal(MainInternalFreq::Rc12Mhz);
+ ClockGen::selectMainClockSource(MainClockSource::Internal);
+ ClockGen::enablePllA();
+ ClockGen::selectMasterClk();
+ ClockGen::updateCoreFrequency();
+
+ return true;
+ }
+};
+
+using Led0 = GpioA23;
+using Led1 = GpioC9;
+using ButtonSW0 = GpioA9;
+
+// No SoftwareGpioPort yet for SAM
+struct Leds
+{
+ static constexpr std::size_t width{2};
+
+ static void setOutput()
+ {
+ Led0::setOutput();
+ Led1::setOutput();
+ }
+
+ static void write(uint32_t value)
+ {
+ Led0::set(value & 1);
+ Led1::set(value & 2);
+ }
+};
+
+struct Debug
+{
+ using Uart = Usart1;
+ using UartTx = GpioB4;
+ using UartRx = GpioA21;
+};
+
+using LoggerDevice = modm::IODeviceWrapper;
+
+inline void
+initialize()
+{
+ // Turn off the watchdog
+ WDT->WDT_MR = WDT_MR_WDDIS_Msk;
+
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+ // Disable JTAG TDI function on debug UART TX pin
+ MATRIX->CCFG_SYSIO |= CCFG_SYSIO_SYSIO4;
+
+ Debug::Uart::initialize();
+ Debug::Uart::connect();
+
+ Leds::setOutput();
+ ButtonSW0::setInput(InputType::PullUp);
+}
+
+/*
+// TODO: usb
+inline void initializeUsbFs()
+{
+ //SystemClock::enableUsb();
+ //modm::platform::Usb::initialize();
+}
+*/
+/// @}
+
+} // namespace Board
+
diff --git a/src/modm/board/samv71_xplained_ultra/board.xml b/src/modm/board/samv71_xplained_ultra/board.xml
new file mode 100644
index 0000000000..b13402668a
--- /dev/null
+++ b/src/modm/board/samv71_xplained_ultra/board.xml
@@ -0,0 +1,14 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+
+
+
+ modm:board:samv71-xplained-ultra
+
+
diff --git a/src/modm/board/samv71_xplained_ultra/module.lb b/src/modm/board/samv71_xplained_ultra/module.lb
new file mode 100644
index 0000000000..1b08b54603
--- /dev/null
+++ b/src/modm/board/samv71_xplained_ultra/module.lb
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2021, Jeff McBride
+# Copyright (c) 2022, Christopher Durand
+#
+# This file is part of the modm project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# -----------------------------------------------------------------------------
+
+def init(module):
+ module.name = ":board:samv71-xplained-ultra"
+ module.description = "Microchip SAMV71 Xplained Ultra"
+
+def prepare(module, options):
+ if not options[":target"].partname == "samv71q21b-aab":
+ return False
+
+ module.depends(":debug", ":platform:clockgen", ":platform:gpio", ":platform:core", ":platform:usart:1") #, ":platform:usb")
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/board"
+ env.substitutions = {
+ "with_logger": True,
+ "with_assert": env.has_module(":architecture:assert")
+ }
+ env.template("../board.cpp.in", "board.cpp")
+ env.copy('board.hpp')
+ env.copy(repopath("tools/openocd/modm/atmel_samv71_xplained_ultra.cfg"), "atmel_samv71_xplained_ultra.cfg")
+ env.collect(":build:openocd.source", "modm/src/modm/board/atmel_samv71_xplained_ultra.cfg")
diff --git a/src/modm/platform/clock/sam/gclk.cpp.in b/src/modm/platform/clock/sam/gclk.cpp.in
index b2e3890a41..0b7e1759f0 100644
--- a/src/modm/platform/clock/sam/gclk.cpp.in
+++ b/src/modm/platform/clock/sam/gclk.cpp.in
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2020-2021, Niklas Hauser
* Copyright (c) 2020, Erik Henriksson
+ * Copyright (c) 2022, Christopher Durand
*
* This file is part of the modm project.
*
@@ -23,100 +24,53 @@ namespace modm::platform
constinit uint16_t modm_fastdata delay_fcpu_MHz(computeDelayMhz(GenericClockController::BootFrequency));
constinit uint16_t modm_fastdata delay_ns_per_loop(computeDelayNsPerLoop(GenericClockController::BootFrequency));
+%% if target.family == "d1x/d2x/dax"
bool
-GenericClockController::initOsc8MHz(uint32_t waitCycles)
+GenericClockController::configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCycles)
{
- SYSCTRL->OSC8M.bit.PRESC = 0x0;
+ SYSCTRL->OSC8M.bit.PRESC = static_cast(prescaler);
SYSCTRL->OSC8M.bit.ONDEMAND = true;
SYSCTRL->OSC8M.bit.RUNSTDBY = false;
SYSCTRL->OSC8M.bit.ENABLE = true;
while (!SYSCTRL->PCLKSR.bit.OSC8MRDY && --waitCycles);
return waitCycles;
}
+%% endif
+%% if target.family == "d1x/d2x/dax"
+/// Enable DFLL48M in open-loop mode
bool
-GenericClockController::initExternalCrystal(uint32_t waitCycles)
+GenericClockController::enableDfll48m(uint32_t waitCycles)
{
- // Enable external crystal.
- SYSCTRL->XOSC32K.reg =
- SYSCTRL_XOSC32K_STARTUP( 0x6u ) |
- SYSCTRL_XOSC32K_XTALEN |
- SYSCTRL_XOSC32K_RUNSTDBY |
- SYSCTRL_XOSC32K_EN32K;
- // separate call, as described in chapter 15.6.3
- SYSCTRL->XOSC32K.bit.ENABLE = 1;
- while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY and --waitCycles) ;
-
- // Write Generic Clock Generator configuration
- GCLK->GENCTRL.reg =
- GCLK_GENCTRL_ID(uint32_t(ClockGenerator::ExternalCrystal32K)) |
- GCLK_GENCTRL_SRC_XOSC32K |
- GCLK_GENCTRL_IDC |
- GCLK_GENCTRL_GENEN;
- // Wait for synchronization.
- while (GCLK->STATUS.bit.SYNCBUSY and --waitCycles) ;
-
- return waitCycles;
-}
-
-bool
-GenericClockController::initDFLL48MHz(uint32_t waitCycles)
-{
- // Put ExternalCrystal as source for the PLL
- GCLK->CLKCTRL.reg =
- GCLK_CLKCTRL_ID(uint32_t(ClockMux::DFLL48M)) |
- GCLK_CLKCTRL_GEN(uint32_t(ClockGenerator::ExternalCrystal32K)) |
- GCLK_CLKCTRL_CLKEN;
- // Wait for synchronization.
- while (GCLK->STATUS.bit.SYNCBUSY and --waitCycles) ;
-
- // Errata 1.2.1: Disable the OnDemand mode
+ // Errata 1.2.1: Disable OnDemand mode
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0;
- // Wait for synchronization.
- while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ;
+ // Wait for synchronization
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles;
- SYSCTRL->DFLLMUL.reg =
- SYSCTRL_DFLLMUL_CSTEP( 31 ) |
- SYSCTRL_DFLLMUL_FSTEP( 511 ) |
- SYSCTRL_DFLLMUL_MUL(48_MHz / 32'768_Hz);
- // Wait for synchronization.
- while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ;
+ // TODO: is returning the right thing to do?
+ if (waitCycles == 0)
+ return false;
+
+ // read calibration data from "NVM Software Calibration Area" (128 bits from address 0x806020)
+ // DFLL coarse value is in bits 63:58
+ const auto calibrationData = *reinterpret_cast(0x806020 + 4);
+ const auto dfllCoarseCalibration = (calibrationData >> (58 - 32)) & 0b11'1111;
+ SYSCTRL->DFLLVAL.reg = (dfllCoarseCalibration << SYSCTRL_DFLLVAL_COARSE_Pos)
+ | (512 << SYSCTRL_DFLLVAL_FINE_Pos);
// Write full configuration to DFLL control register
- SYSCTRL->DFLLCTRL.reg |=
- SYSCTRL_DFLLCTRL_MODE | // Enable the closed loop mode
+ SYSCTRL->DFLLCTRL.reg = (SYSCTRL->DFLLCTRL.reg |
SYSCTRL_DFLLCTRL_WAITLOCK | // No output until DFLL is locked.
- SYSCTRL_DFLLCTRL_QLDIS ; // Disable Quick lock
- // Wait for synchronization.
- while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ;
+ SYSCTRL_DFLLCTRL_QLDIS) // Disable quick lock
+ // Disable closed-loop and USB clock recovery mode
+ & ~(SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_USBCRM);
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY);
- // Enable the DFLL
SYSCTRL->DFLLCTRL.bit.ENABLE = true;
- // Wait for locks flags
- while (
- not (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) or
- not (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF));
- // Wait for synchronization.
- while (!SYSCTRL->PCLKSR.bit.DFLLRDY and --waitCycles) ;
-
- return waitCycles;
-}
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles;
-bool
-GenericClockController::setSystemClock(ClockSource source, uint32_t waitCycles)
-{
- GCLK->GENDIV.reg =
- GCLK_GENDIV_ID(uint32_t(ClockGenerator::System)) |
- GCLK_GENDIV_DIV(0u);
- GCLK->GENCTRL.reg =
- GCLK_GENCTRL_ID(uint32_t(ClockGenerator::System)) |
- GCLK_GENCTRL_SRC(uint32_t(source)) |
- GCLK_GENCTRL_IDC |
- GCLK_GENCTRL_GENEN;
- // Wait for synchronization.
- while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ;
-
- return waitCycles;
+ return waitCycles > 0;
}
+%% endif
}
diff --git a/src/modm/platform/clock/sam/gclk.hpp b/src/modm/platform/clock/sam/gclk.hpp
deleted file mode 100644
index 84d25abfa7..0000000000
--- a/src/modm/platform/clock/sam/gclk.hpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2019, Ethan Slattery
- * Copyright (c) 2020, Erik Henriksson
- *
- * This file is part of the modm project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-// ----------------------------------------------------------------------------
-
-#pragma once
-
-#include
-#include "../device.hpp"
-#include
-
-namespace modm::platform
-{
-/// @ingroup modm_platform_gclk
-/// @{
-
-enum class
-ClockSource : uint32_t
-{
- OSC8M = GCLK_GENCTRL_SRC_OSC8M_Val,
- DFLL48M = GCLK_GENCTRL_SRC_DFLL48M_Val
-};
-
-enum class
-ClockGenerator : uint32_t
-{
- System = 0,
- ExternalCrystal32K = 1,
- ULP32K = 2,
- Internal8M = 3,
-};
-
-enum class
-ClockPeripheral : uint32_t
-{
- Dfll48 = GCLK_CLKCTRL_ID_DFLL48_Val,
- Fdpll = GCLK_CLKCTRL_ID_FDPLL_Val,
- Fdpll32K = GCLK_CLKCTRL_ID_FDPLL32K_Val,
- Wdt = GCLK_CLKCTRL_ID_WDT_Val,
- Rtc = GCLK_CLKCTRL_ID_RTC_Val,
- Eic = GCLK_CLKCTRL_ID_EIC_Val,
- Usb = GCLK_CLKCTRL_ID_USB_Val,
- Evsys0 = GCLK_CLKCTRL_ID_EVSYS_0_Val,
- Evsys1 = GCLK_CLKCTRL_ID_EVSYS_1_Val,
- Evsys2 = GCLK_CLKCTRL_ID_EVSYS_2_Val,
- Evsys3 = GCLK_CLKCTRL_ID_EVSYS_3_Val,
- Evsys4 = GCLK_CLKCTRL_ID_EVSYS_4_Val,
- Evsys5 = GCLK_CLKCTRL_ID_EVSYS_5_Val,
- Evsys6 = GCLK_CLKCTRL_ID_EVSYS_6_Val,
- Evsys7 = GCLK_CLKCTRL_ID_EVSYS_7_Val,
- Evsys8 = GCLK_CLKCTRL_ID_EVSYS_8_Val,
- Evsys9 = GCLK_CLKCTRL_ID_EVSYS_9_Val,
- Evsys10 = GCLK_CLKCTRL_ID_EVSYS_10_Val,
- Evsys11 = GCLK_CLKCTRL_ID_EVSYS_11_Val,
- SercomXSlow = GCLK_CLKCTRL_ID_SERCOMX_SLOW_Val,
- Sercom0 = GCLK_CLKCTRL_ID_SERCOM0_CORE_Val,
- Sercom1 = GCLK_CLKCTRL_ID_SERCOM1_CORE_Val,
- Sercom2 = GCLK_CLKCTRL_ID_SERCOM2_CORE_Val,
- Sercom3 = GCLK_CLKCTRL_ID_SERCOM3_CORE_Val,
- Sercom4 = GCLK_CLKCTRL_ID_SERCOM4_CORE_Val,
- Sercom5 = GCLK_CLKCTRL_ID_SERCOM5_CORE_Val,
- Tcc0 = GCLK_CLKCTRL_ID_TCC0_TCC1_Val,
- Tcc1 = GCLK_CLKCTRL_ID_TCC0_TCC1_Val,
- Tcc2 = GCLK_CLKCTRL_ID_TCC2_TC3_Val,
- Tc3 = GCLK_CLKCTRL_ID_TCC2_TC3_Val,
- Tc4 = GCLK_CLKCTRL_ID_TC4_TC5_Val,
- Tc5 = GCLK_CLKCTRL_ID_TC4_TC5_Val,
- Tc6 = GCLK_CLKCTRL_ID_TC6_TC7_Val,
- Tc7 = GCLK_CLKCTRL_ID_TC6_TC7_Val,
- Adc = GCLK_CLKCTRL_ID_ADC_Val,
- AcDig = GCLK_CLKCTRL_ID_AC_DIG_Val,
- AcAna = GCLK_CLKCTRL_ID_AC_ANA_Val,
- Dac = GCLK_CLKCTRL_ID_DAC_Val,
- Ptc = GCLK_CLKCTRL_ID_PTC_Val,
- I2s0 = GCLK_CLKCTRL_ID_I2S_0_Val,
- I2s1 = GCLK_CLKCTRL_ID_I2S_1_Val
-};
-/// @}
-
-/**
- * Clock management
- *
- * \ingroup modm_platform_gclk
- */
-class GenericClockController
-{
-public:
- static constexpr uint32_t BootFrequency = 1'000'000;
-
- template< uint32_t Core_Hz>
- static uint32_t
- setFlashLatency();
-
- template< uint32_t Core_Hz >
- static void
- updateCoreFrequency();
-
- static bool
- initOsc8MHz(uint32_t waitCycles = 2048);
-
- static bool
- initExternalCrystal(uint32_t waitCycles = 2048);
-
- static bool
- initDFLL48MHz(uint32_t waitCycles = 2048);
-
- static bool
- setSystemClock(
- ClockSource source = ClockSource::OSC8M,
- uint32_t waitCycles = 2048);
-
- template< ClockPeripheral peripheral >
- static void
- connect(ClockGenerator clockGen);
-
-private:
-
- enum class
- ClockMux : uint32_t
- {
- DFLL48M = 0,
- };
-};
-
-}
-
-#include "gclk_impl.hpp"
diff --git a/src/modm/platform/clock/sam/gclk.hpp.in b/src/modm/platform/clock/sam/gclk.hpp.in
new file mode 100644
index 0000000000..397b0acc0e
--- /dev/null
+++ b/src/modm/platform/clock/sam/gclk.hpp.in
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2019, Ethan Slattery
+ * Copyright (c) 2020, Erik Henriksson
+ * Copyright (c) 2022, Christopher Durand
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#pragma once
+
+#include
+#include "../device.hpp"
+#include
+#include
+#include
+
+namespace modm::platform
+{
+/// @ingroup modm_platform_gclk
+/// @{
+
+enum class
+ClockSource : uint32_t
+{
+%% for source in clock_sources
+ {{ source.name }} = {{ source.value }}{% if not loop.last %},{% endif %}
+%% endfor
+};
+
+enum class
+ClockGenerator : uint32_t
+{
+ System = 0,
+ Main = 0,
+%% for i in range(0, generator_count)
+ Generator{{i}} = {{i}}{% if not loop.last %},{% endif %}
+%% endfor
+};
+
+struct GeneratorConfiguration
+{
+ ClockSource source{};
+
+ /**
+ * The clock will be divided by the selected divider.
+ * Normal integer division and division by 2^(N+1) is supported.
+ * The registers will be automatically configured in the appropriate mode
+ * for division by powers of 2.
+ *
+ * @warning Not all generator instances support the full 16 bit divider value range.
+ * This is currently not checked yet at compile-time. Only the maximum limits
+ * are verified.
+ */
+ uint32_t divider = 1;
+
+ bool gpioOutputEnabled = false;
+};
+
+enum class
+ClockPeripheral : uint32_t
+{
+%% for clock in peripheral_clocks
+%% set instance=clock.get("instance", "")
+%% set name=clock.get("name", "")
+%% if clock["peripheral"] in ["sysctrl", "oscctrl"]
+%% set peripheral=""
+%% else
+%% set peripheral=clock["peripheral"]
+%% endif
+%% if clock["peripheral"] == "sercom" and name == "core"
+%% set name=""
+%% endif
+%% set id=peripheral.capitalize() + instance + name.capitalize()
+ {{ id }} = {{clock["value"]}}{% if not loop.last %},{% endif %}
+%% endfor
+};
+
+%% if has_dpll
+
+struct DpllSource
+{
+ enum class DpllReference
+ {
+ // values correspond to REFCLOCK field in DPLLCTRLB
+%% if target.family == "d5x/e5x"
+ Gclk = 0,
+ Xosc32 = 1,
+ Xosc0 = 2,
+ Xosc1 = 3
+%% elif target.family == "d1x/d2x/dax"
+ Xosc32 = 0,
+ Xosc = 1,
+ Gclk = 2
+%% endif
+ };
+
+ DpllReference reference{};
+ frequency_t frequency{};
+
+ constexpr bool isXoscSource() const
+ {
+%% if target.family == "d5x/e5x"
+ return (reference == DpllReference::Xosc0)
+ || (reference == DpllReference::Xosc1);
+%% elif target.family == "d1x/d2x/dax"
+ return reference == DpllReference::Xosc;
+%% endif
+ }
+};
+
+template
+constexpr DpllSource GclkSource = DpllSource{DpllSource::DpllReference::Gclk, freq};
+
+template
+constexpr DpllSource Xosc32Source = DpllSource{DpllSource::DpllReference::Xosc32, freq};
+
+%% if target.family == "d5x/e5x"
+template
+constexpr DpllSource Xosc0Source = DpllSource{DpllSource::DpllReference::Xosc0, freq};
+
+template
+constexpr DpllSource Xosc1Source = DpllSource{DpllSource::DpllReference::Xosc1, freq};
+%% elif target.family == "d1x/d2x/dax"
+template
+constexpr DpllSource XoscSource = DpllSource{DpllSource::DpllReference::Xosc, freq};
+%% endif
+
+struct DpllConfig
+{
+%% if target.family == "d5x/e5x"
+ static constexpr uint16_t MultiplierFractionalBits{5};
+ static constexpr uint16_t MultiplierIntegerBits{13};
+ static constexpr unsigned MaxReference{kHz(3200)};
+ static constexpr unsigned MinOutput{MHz(96)};
+ static constexpr unsigned MaxOutput{MHz(200)};
+%% elif target.family == "d1x/d2x/dax"
+ static constexpr uint16_t MultiplierFractionalBits{4};
+ static constexpr uint16_t MultiplierIntegerBits{12};
+ static constexpr unsigned MaxReference{MHz(2)};
+ static constexpr unsigned MinOutput{MHz(48)};
+ static constexpr unsigned MaxOutput{MHz(96)};
+%% endif
+ static constexpr unsigned MinReference{kHz(32)};
+ // divider operation: f_out = f_in / (2 * (DIV + 1))
+ static constexpr uint16_t XoscDividerBits{11};
+
+ uint16_t integerMultiplier{};
+ uint16_t fractionalMultiplier{};
+ uint16_t xoscDivider{};
+};
+
+%% if target.family == "d5x/e5x"
+enum class DpllInstance
+{
+ Dpll0 = 0,
+ Dpll1 = 1
+};
+%% endif
+%% endif
+
+%% if target.family == "d5x/e5x"
+enum class Xosc
+{
+ Xosc0 = 0,
+ Xosc1 = 1
+};
+%% endif
+
+enum class XoscStartupTime
+{
+ Start_31us = 0x0u,
+ Start_61us = 0x1u,
+ Start_122us = 0x2u,
+ Start_244us = 0x3u,
+ Start_488us = 0x4u,
+ Start_977us = 0x5u,
+ Start_1953us = 0x6u,
+ Start_3906us = 0x7u,
+ Start_7813us = 0x8u,
+ Start_15625us = 0x9u,
+ Start_31250us = 0xAu,
+ Start_61250us = 0xBu,
+ Start_125000us = 0xCu,
+ Start_250000us = 0xDu,
+ Start_500000us = 0xEu,
+ Start_1000000us = 0xFu
+};
+
+enum class Xosc32StartupTime
+{
+%% if target.family == "d1x/d2x/dax"
+ Start_132us = 0x0u,
+ Start_1ms = 0x1u,
+ Start_63ms = 0x2u,
+ Start_125ms = 0x3u,
+ Start_500ms = 0x4u,
+ Start_1000ms = 0x5u,
+ Start_2000ms = 0x6u,
+ Start_4000ms = 0x7u
+%% else
+ Start_63ms = 0x0u,
+ Start_125ms = 0x1u,
+ Start_500ms = 0x2u,
+ Start_1000ms = 0x3u,
+ Start_2000ms = 0x4u,
+ Start_4000ms = 0x5u,
+ Start_8000ms = 0x6u
+%% endif
+};
+
+%% if target.family == "d1x/d2x/dax"
+ enum class Osc8mPrescaler
+ {
+ Prescaler1 = 0x0,
+ Prescaler2 = 0x1,
+ Prescaler4 = 0x2,
+ Prescaler8 = 0x3
+ };
+%% endif
+
+/// @}
+
+/**
+ * Clock management
+ *
+ * @ingroup modm_platform_gclk
+ */
+class GenericClockController
+{
+public:
+ static constexpr uint32_t BootFrequency = {{ boot_frequency }};
+
+ template< uint32_t Core_Hz, uint16_t Vdd_mV=3300 >
+ static uint32_t
+ setFlashLatency();
+
+ template< uint32_t Core_Hz >
+ static void
+ updateCoreFrequency();
+
+%% if target.family == "d1x/d2x/dax"
+ /// Configure frequency of the internal oscillator
+ static bool
+ configureOsc8m(Osc8mPrescaler prescaler, uint32_t waitCycles = 10'000);
+
+ /// Enable DFLL48M in open-loop mode
+ static bool
+ enableDfll48m(uint32_t waitCycles = 10'000);
+%% endif
+
+ /// Enable DFLL48M in closed-loop mode
+ /// @warning The reference clock on GCLK channel 0 must be available prior to calling this function
+ template
+ static bool
+ enableDfll48mClosedLoop(uint32_t waitCycles = 10'000);
+
+ /// Enable PLL with automatically computed coefficients
+ /// If the specified tolerance is exceeded, compilation will fail.
+ template
+ static bool
+%% if target.family == "d5x/e5x"
+ enableDpll(DpllInstance instance = DpllInstance::Dpll0);
+%% else
+ enableDpll();
+%% endif
+
+ /// Enable PLL with manual configuration
+ template
+ static bool
+%% if target.family == "d5x/e5x"
+ enableDpll(DpllInstance instance = DpllInstance::Dpll0);
+%% else
+ enableDpll();
+%% endif
+
+ static inline void
+%% if target.family == "d5x/e5x"
+ disableDpll(DpllInstance instance = DpllInstance::Dpll0);
+%% else
+ disableDpll();
+%% endif
+
+ template
+ static bool
+%% if target.family == "d5x/e5x"
+ enableExternalCrystal(Xosc clock, uint32_t waitCycles = (1000u << unsigned(startupTime)));
+%% else
+ enableExternalCrystal(uint32_t waitCycles = (1000u << unsigned(startupTime)));
+%% endif
+
+ static inline bool
+%% if target.family == "d5x/e5x"
+ enableExternalClock(Xosc clock, uint32_t waitCycles = 10'000);
+%% else
+ enableExternalClock(uint32_t waitCycles = 10'000);
+%% endif
+
+ static inline bool
+ enableExternalCrystal32k(Xosc32StartupTime time);
+
+ static inline bool
+ enableExternalClock32k();
+
+ template
+ static void
+ connect(ClockGenerator clockGen);
+
+ template
+ static void
+ enableGenerator();
+
+ template
+ static void
+ enableGenerator();
+
+ template
+ static void
+ disableGenerator();
+
+ /**
+ * Convenience function to configure "Main" clock generator source
+ * with a divider of 1.
+ *
+ * Equivalent to:
+ * @code
+ * const auto config = GeneratorConfiguration{ .source = SOURCE, .divider = 1 };
+ * GenericClockController::enableGenerator();
+ * @endcode
+ */
+ template
+ static bool
+ setSystemClock();
+
+private:
+ static inline void
+ sync();
+
+ static inline void
+ sync(ClockGenerator clockGen);
+};
+
+#if defined(__DOXYGEN__)
+/// Peripheral AHB/APB bus clock control
+/// @ingroup modm_platform_gclk
+template
+struct PeripheralClock
+{
+ /// Enable peripheral clock
+ static void enable();
+ /// Disable peripheral clock
+ static void disable();
+};
+#else
+template
+struct PeripheralClock;
+#endif
+
+}
+
+#include "gclk_impl.hpp"
diff --git a/src/modm/platform/clock/sam/gclk_impl.hpp.in b/src/modm/platform/clock/sam/gclk_impl.hpp.in
index 32485f9bbc..6a2a198802 100644
--- a/src/modm/platform/clock/sam/gclk_impl.hpp.in
+++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in
@@ -2,6 +2,7 @@
* Copyright (c) 2019, Ethan Slattery
* Copyright (c) 2020, Erik Henriksson
* Copyright (c) 2021, Niklas Hauser
+ * Copyright (c) 2022, Christopher Durand
*
* This file is part of the modm project.
*
@@ -12,12 +13,41 @@
// ----------------------------------------------------------------------------
#include
-#include
+#include
+#include
+#include
+#include
namespace modm::platform
{
extern "C" uint32_t SystemCoreClock;
+%% for peripheral, clocks in clock_map.items()
+template<>
+%% set name=peripheral[0]
+%% set instance=peripheral[1]
+%% if instance
+struct PeripheralClock>
+%% else
+struct PeripheralClock
+%% endif
+{
+ static inline void enable()
+ {
+%% for clock in clocks
+ {{clock[0]}}->{{clock[1]}}MASK.reg |= (1u << {{clock[2]}});
+%% endfor
+ }
+
+ static inline void disable()
+ {
+%% for clock in clocks
+ {{clock[0]}}->{{clock[1]}}MASK.reg &= ~(1u << {{clock[2]}});
+%% endfor
+ }
+};
+%% endfor
+
template< uint32_t Core_Hz >
void
GenericClockController::updateCoreFrequency()
@@ -27,28 +57,577 @@ GenericClockController::updateCoreFrequency()
delay_ns_per_loop = computeDelayNsPerLoop(Core_Hz);
}
-template< uint32_t Core_Hz >
+template< uint32_t Core_Hz, uint16_t Vdd_mV=3300 >
uint32_t
GenericClockController::setFlashLatency()
{
+%% if target.family == "d5x/e5x":
+{% raw %}
+ // TODO: move to device files
+ constexpr std::array, 6> waitStates0{{
+ {22_MHz, 0}, { 44_MHz, 1}, { 67_MHz, 2},
+ {89_MHz, 3}, {111_MHz, 4}, {120_MHz, 5}
+ }};
+ constexpr std::array, 6> waitStates1{{
+ { 24_MHz, 0}, { 51_MHz, 1}, { 77_MHz, 2},
+ {101_MHz, 3}, {119_MHz, 4}, {120_MHz, 5}
+ }};
+{% endraw %}
+ constexpr auto waitStates = (Vdd_mV >= 2700) ? waitStates1 : waitStates0;
+ constexpr auto rws = std::lower_bound(std::begin(waitStates), std::end(waitStates), Core_Hz,
+ [](auto w1, auto w2) {
+ return w1.first < w2;
+ })->second;
+ NVMCTRL->CTRLA.bit.RWS = rws;
+ NVMCTRL->CTRLA.bit.AUTOWS = 0;
+%% else
// See table 41.11 (NVM Characteristics) in the datasheet
if constexpr (Core_Hz > 24_MHz) {
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val;
} else {
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_SINGLE_Val;
}
+%% endif
return Core_Hz;
}
+template
+bool
+GenericClockController::enableDfll48mClosedLoop(uint32_t waitCycles)
+{
+ static_assert(reference > 732_Hz, "DFLL48 reference frequency must be larger than 732 Hz");
+ static_assert(reference < 43_kHz, "DFLL48 reference frequency must be less than 33 kHz");
+ constexpr auto multiplier = uint16_t(std::round(48_MHz / double(reference)));
+
+%% if target.family == "d1x/d2x/dax"
+ // Errata 1.2.1: Disable OnDemand mode
+ SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0;
+ // Wait for synchronization
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles;
+
+ // TODO: is returning the right thing to do?
+ if (waitCycles == 0)
+ return false;
+
+ // read DFLL coarse value calibration from "NVM Software Calibration Area" (0x806020, 128 bits)
+ // DFLL coarse calibration value is in bits 63:58
+ const auto calibrationData = *reinterpret_cast(0x806020 + 4);
+ const auto dfllCoarseCalibration = (calibrationData >> (58 - 32)) & 0b11'1111;
+ SYSCTRL->DFLLVAL.reg = (dfllCoarseCalibration << SYSCTRL_DFLLVAL_COARSE_Pos);
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY);
+
+ // Skip coarse lock phase with DFLLVAL.COARSE pre-programmed (17.6.7.1.2 in datasheet)
+ SYSCTRL->DFLLCTRL.bit.BPLCKC = 1;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY);
+
+ // Set multiplier and adjustment step sizes
+ // TODO: evaluate step size values
+ SYSCTRL->DFLLMUL.reg =
+ SYSCTRL_DFLLMUL_CSTEP(8) |
+ SYSCTRL_DFLLMUL_FSTEP(8) |
+ SYSCTRL_DFLLMUL_MUL(multiplier);
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY);
+
+ // Write full configuration to DFLL control register
+ SYSCTRL->DFLLCTRL.reg = (SYSCTRL->DFLLCTRL.reg |
+ SYSCTRL_DFLLCTRL_MODE | // Enable closed-loop mode
+ SYSCTRL_DFLLCTRL_WAITLOCK | // No output until DFLL is locked.
+ SYSCTRL_DFLLCTRL_QLDIS) // Disable quick lock
+ // Disable USB clock recovery mode
+ & ~(SYSCTRL_DFLLCTRL_USBCRM);
+
+ SYSCTRL->DFLLCTRL.bit.ENABLE = true;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY && waitCycles > 0) --waitCycles;
+ // wait for PLL lock
+ while (!SYSCTRL->PCLKSR.bit.DFLLLCKC && waitCycles > 0) --waitCycles;
+ while (!SYSCTRL->PCLKSR.bit.DFLLLCKF && waitCycles > 0) --waitCycles;
+%% else
+ // Set multiplier and adjustment step sizes
+ // TODO: evaluate step size values
+ OSCCTRL->DFLLMUL.reg =
+ OSCCTRL_DFLLMUL_CSTEP(8) |
+ OSCCTRL_DFLLMUL_FSTEP(8) |
+ OSCCTRL_DFLLMUL_MUL(multiplier);
+ while (OSCCTRL->DFLLSYNC.bit.DFLLMUL);
+
+ OSCCTRL->DFLLCTRLB.reg =
+ OSCCTRL_DFLLCTRLB_MODE | // Enable closed-loop mode
+ OSCCTRL_DFLLCTRLB_QLDIS; // Disable quick lock
+ while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB);
+
+ OSCCTRL->DFLLCTRLA.bit.ONDEMAND = 0;
+ OSCCTRL->DFLLCTRLA.bit.ENABLE = 1;
+ while (OSCCTRL->DFLLSYNC.bit.ENABLE);
+
+ // wait for PLL lock
+ while (!OSCCTRL->STATUS.bit.DFLLLCKC && waitCycles > 0) --waitCycles;
+ while (!OSCCTRL->STATUS.bit.DFLLLCKF && waitCycles > 0) --waitCycles;
+ while (!OSCCTRL->STATUS.bit.DFLLRDY && waitCycles > 0) --waitCycles;
+%% endif
+
+ return waitCycles > 0;
+}
+
+%% if target.family == "d1x/d2x/dax"
template< ClockPeripheral peripheral >
void
GenericClockController::connect(ClockGenerator clockGen)
{
+ GCLK->CLKCTRL.bit.ID = uint8_t(peripheral);
+ GCLK->CLKCTRL.bit.CLKEN = 0;
+ while (GCLK->CLKCTRL.bit.CLKEN);
+
GCLK->CLKCTRL.reg =
GCLK_CLKCTRL_CLKEN |
GCLK_CLKCTRL_GEN(uint32_t(clockGen)) |
- GCLK_CLKCTRL_ID(uint32_t(peripheral));
+ GCLK_CLKCTRL_ID(uint8_t(peripheral));
+ sync();
+}
+
+void
+GenericClockController::sync()
+{
+ while (GCLK->STATUS.bit.SYNCBUSY);
+}
+
+void
+GenericClockController::sync(ClockGenerator)
+{
+ sync();
+}
+
+%% elif target.family == "d5x/e5x"
+void
+GenericClockController::sync()
+{
+ constexpr auto mask = GCLK_SYNCBUSY_GENCTRL_Msk | GCLK_SYNCBUSY_SWRST;
+ while (GCLK->SYNCBUSY.reg & mask);
+}
+
+void
+GenericClockController::sync(ClockGenerator clockGen)
+{
+ const auto bit = static_cast(clockGen) << GCLK_SYNCBUSY_GENCTRL_Pos;
+ while (GCLK->SYNCBUSY.reg & bit);
+}
+
+template< ClockPeripheral peripheral >
+void
+GenericClockController::connect(ClockGenerator clockGen)
+{
+ auto& reg = GCLK->PCHCTRL[static_cast(peripheral)].reg;
+ reg = 0;
+ while (reg != 0);
+ reg = GCLK_PCHCTRL_CHEN | (static_cast(clockGen) << GCLK_PCHCTRL_GEN_Pos);
+ sync(clockGen);
+}
+%% endif
+
+template
+bool
+%% if target.family == "d5x/e5x"
+GenericClockController::enableExternalCrystal(Xosc clock, uint32_t waitCycles)
+%% else
+GenericClockController::enableExternalCrystal(uint32_t waitCycles)
+%% endif
+{
+%% if target.family == "d5x/e5x"
+%% set reg="OSCCTRL->XOSCCTRL[int(clock)]"
+%% set prefix="OSCCTRL_XOSCCTRL"
+%% set status="OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_XOSCRDY0 << int(clock))"
+ PeripheralClock::enable();
+%% elif target.family == "d1x/d2x/dax"
+%% set reg="SYSCTRL->XOSC"
+%% set prefix="SYSCTRL_XOSC"
+%% set status="SYSCTRL->PCLKSR.bit.XOSCRDY"
+ PeripheralClock::enable();
+%% endif
+ {{reg}}.bit.STARTUP = uint32_t(startupTime);
+ {{reg}}.bit.XTALEN = 1;
+ // Automatic gain control can only be enabled when the crystal is running
+%% if target.family == "d5x/e5x"
+ {{reg}}.bit.ENALC = 0;
+ if constexpr (frequency <= 8'000'000) {
+ {{reg}}.bit.IMULT = 0x3;
+ {{reg}}.bit.IPTAT = 0x2;
+ } else if constexpr (frequency <= 16'000'000) {
+ {{reg}}.bit.IMULT = 0x4;
+ {{reg}}.bit.IPTAT = 0x3;
+ } else if constexpr (frequency <= 24'000'000) {
+ {{reg}}.bit.IMULT = 0x5;
+ {{reg}}.bit.IPTAT = 0x3;
+ } else {
+ {{reg}}.bit.IMULT = 0x6;
+ {{reg}}.bit.IPTAT = 0x3;
+ }
+%% else
+ {{reg}}.bit.AMPGC = 0;
+ if constexpr (frequency <= 2'000'000) {
+ {{reg}}.bit.GAIN = 0x0;
+ } else if constexpr (frequency <= 4'000'000) {
+ {{reg}}.bit.GAIN = 0x1;
+ } else if constexpr (frequency <= 8'000'000) {
+ {{reg}}.bit.GAIN = 0x2;
+ } else if constexpr (frequency <= 16'000'000) {
+ {{reg}}.bit.GAIN = 0x3;
+ } else {
+ {{reg}}.bit.GAIN = 0x4;
+ }
+%% endif
+
+ // force oscillator start even if no clock sink is using it yet
+ {{reg}}.bit.ONDEMAND = 0;
+
+ {{reg}}.bit.ENABLE = 1;
+ while(!({{status}}) && --waitCycles);
+ // Enable automatic gain control on success
+%% if target.family == "d5x/e5x"
+ {{reg}}.bit.ENALC = waitCycles > 0;
+%% else
+ {{reg}}.bit.AMPGC = waitCycles > 0;
+%% endif
+ return waitCycles;
+}
+
+bool
+%% if target.family == "d5x/e5x"
+GenericClockController::enableExternalClock(Xosc clock, uint32_t waitCycles)
+%% else
+GenericClockController::enableExternalClock(uint32_t waitCycles)
+%% endif
+{
+%% if target.family == "d5x/e5x"
+%% set reg="OSCCTRL->XOSCCTRL[int(clock)]"
+%% set status="OSCCTRL->STATUS.reg & (OSCCTRL_STATUS_XOSCRDY0 << int(clock))"
+ PeripheralClock::enable();
+%% elif target.family == "d1x/d2x/dax"
+%% set reg="SYSCTRL->XOSC"
+%% set status="SYSCTRL->PCLKSR.bit.XOSCRDY"
+ PeripheralClock::enable();
+%% endif
+ // force oscillator start even if no clock sink is using it yet
+ {{reg}}.bit.ONDEMAND = 0;
+
+ {{reg}}.bit.STARTUP = 0;
+ {{reg}}.bit.XTALEN = 0;
+ {{reg}}.bit.ENABLE = 1;
+ while(!({{status}}) && --waitCycles);
+ return waitCycles;
+}
+
+bool
+GenericClockController::enableExternalCrystal32k(Xosc32StartupTime time)
+{
+%% if target.family == "d1x/d2x/dax"
+%% set reg="SYSCTRL->XOSC32K"
+%% set status="SYSCTRL->PCLKSR.bit.XOSC32KRDY"
+ PeripheralClock::enable();
+%% else
+%% set reg="OSC32KCTRL->XOSC32K"
+%% set status="OSC32KCTRL->STATUS.bit.XOSC32KRDY"
+ PeripheralClock::enable();
+%% endif
+ // force oscillator start even if no clock sink is using it yet
+ {{reg}}.bit.ONDEMAND = 0;
+%% if target.family == "d1x/d2x/dax"
+ // disable non-functional automatic gain control, see errata 1.1.1
+ {{reg}}.bit.AAMPEN = 0;
+%% endif
+ {{reg}}.bit.EN1K = 1;
+ {{reg}}.bit.EN32K = 1;
+ {{reg}}.bit.RUNSTDBY = 1;
+ {{reg}}.bit.XTALEN = 1;
+ {{reg}}.bit.STARTUP = static_cast(time);
+ {{reg}}.bit.ENABLE = 1;
+ while(!({{status}}));
+ return true;
+}
+
+bool
+GenericClockController::enableExternalClock32k()
+{
+%% if target.family == "d1x/d2x/dax"
+%% set reg="SYSCTRL->XOSC32K"
+%% set status="SYSCTRL->PCLKSR.bit.XOSC32KRDY"
+ PeripheralClock::enable();
+%% else
+%% set reg="OSC32KCTRL->XOSC32K"
+%% set status="OSC32KCTRL->STATUS.bit.XOSC32KRDY"
+ PeripheralClock::enable();
+%% endif
+ // force oscillator start even if no clock sink is using it yet
+ {{reg}}.bit.ONDEMAND = 0;
+
+ {{reg}}.bit.EN1K = 1;
+ {{reg}}.bit.EN32K = 1;
+ {{reg}}.bit.RUNSTDBY = 1;
+ {{reg}}.bit.XTALEN = 0;
+ {{reg}}.bit.STARTUP = 0;
+ {{reg}}.bit.ENABLE = 1;
+ while(!({{status}}));
+ return true;
+}
+
+%% if has_dpll
+
+/// @cond
+namespace detail
+{
+
+struct DpllConfigCalculation : DpllConfig
+{
+ double bestOutputFrequency{};
+};
+
+consteval DpllConfigCalculation
+findDpllConfig(double inputClock, double target, bool fractional)
+{
+ uint32_t maxMultiplier = (1u << DpllConfig::MultiplierIntegerBits);
+ if (fractional) {
+ maxMultiplier = (1u << (DpllConfig::MultiplierIntegerBits + DpllConfig::MultiplierFractionalBits));
+ target *= (1 << DpllConfig::MultiplierFractionalBits);
+ }
+ // f_pll = f_reference * (1 + N_int + N_frac/(2^frac_bits))
+ const auto idealMultiplier = (target / inputClock) - 1;
+ const uint32_t multplier = std::min(maxMultiplier, std::round(idealMultiplier));
+ if (fractional) {
+ const auto output = inputClock * (multplier + 1) / (1u << DpllConfig::MultiplierFractionalBits);
+ return DpllConfigCalculation {
+ {.integerMultiplier = uint16_t(multplier >> DpllConfig::MultiplierFractionalBits),
+ .fractionalMultiplier = uint16_t(multplier & ((1u << DpllConfig::MultiplierFractionalBits) - 1)),
+ .xoscDivider = 0},
+ output
+ };
+ } else {
+ const auto output = inputClock * (multplier + 1);
+ return DpllConfigCalculation {
+ {.integerMultiplier = uint16_t(multplier),
+ .fractionalMultiplier = 0,
+ .xoscDivider = 0},
+ output
+ };
+ }
}
+consteval DpllConfigCalculation
+calculateDpllConfigXosc(double xoscClock, double target, bool fractional)
+{
+ DpllConfigCalculation bestConfig;
+ bestConfig.bestOutputFrequency = std::numeric_limits::max();
+ auto minError = std::numeric_limits::max();
+
+ for (uint32_t div = 0; div < (1u << DpllConfig::XoscDividerBits); ++div) {
+ // Xosc divider divides by / (2*(div + 1))
+ const double reference = xoscClock / (2*(div + 1));
+ if (reference < DpllConfig::MinReference || reference > DpllConfig::MaxReference) continue;
+ auto result = findDpllConfig(reference, target, fractional);
+ const auto output = result.bestOutputFrequency;
+ result.xoscDivider = div;
+ const double error = std::abs(target - output);
+ if (error < minError && output >= DpllConfig::MinOutput && output <= DpllConfig::MaxOutput) {
+ bestConfig = result;
+ minError = error;
+ }
+ }
+ return bestConfig;
}
+consteval DpllConfigCalculation
+findDpllConfigXosc(double xoscClock, double target, uint16_t tolerance_ppm [[maybe_unused]])
+{
+ return calculateDpllConfigXosc(xoscClock, target, false);
+
+ // TODO: fractional mode is disabled for now, it was causing an unstable PLL for some parameters
+ // it can still be used with manually specified coefficients
+
+ // For reducing PLL jitter first try to find a suitable configuration in PLL integer mode.
+ // In case no solution is found fractional mode is used.
+ /*DpllConfigCalculation bestConfig{calculateDpllConfigXosc(xoscClock, target, false)};
+ const auto output = bestConfig.bestOutputFrequency;
+ const double error = std::abs(target - output);
+
+ // treat errors below tolerance as exact match
+ if ((error / target) < (tolerance_ppm * double(1e-6))) {
+ return bestConfig;
+ }
+
+ return calculateDpllConfigXosc(xoscClock, target, true);*/
+}
+
+}
+/// @endcond
+
+template
+bool
+%% if target.family == "d5x/e5x"
+GenericClockController::enableDpll(DpllInstance instance)
+%% else
+GenericClockController::enableDpll()
+%% endif
+{
+ constexpr auto config = [&]() {
+ if constexpr (source.isXoscSource()) {
+ return detail::findDpllConfigXosc(source.frequency, output, tolerance_ppm);
+ } else {
+ const auto resultInt = detail::findDpllConfig(source.frequency, output, false);
+ // TODO: fractional mode is disabled for now, because of PLL instability issues
+ //if (std::abs((resultInt.bestOutputFrequency / output) - 1) < (tolerance_ppm* double(1e-6))) {
+ return resultInt;
+ //}
+ //return detail::findDpllConfig(source.frequency, output, true);
+ }
+ }();
+
+ static_assert(std::abs((config.bestOutputFrequency / output) - 1) <= tolerance_ppm, "DPLL clock tolerance exceeded");
+%% if target.family == "d5x/e5x"
+ return enableDpll