From af2eb29f68d86a5c6cbb5fe192cb88b1d53fcc59 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 27 Apr 2020 15:47:17 +0200 Subject: [PATCH 01/11] [ext] Enable SAMD devices and update submodules --- .gitmodules | 3 +++ README.md | 4 +++- ext/microchip/sam | 1 + repo.lb | 1 + tools/scripts/docs_modm_io_generator.py | 5 ++++- tools/scripts/synchronize_docs.py | 2 ++ 6 files changed, 14 insertions(+), 2 deletions(-) create mode 160000 ext/microchip/sam diff --git a/.gitmodules b/.gitmodules index d604e01df7..4693242c2b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "ext/adamgreen/crashcatcher"] path = ext/adamgreen/crashcatcher url = https://github.com/modm-ext/CrashCatcher-partial.git +[submodule "ext/microchip/sam"] + path = ext/microchip/sam + url = https://github.com/modm-io/cmsis-header-sam.git diff --git a/README.md b/README.md index 5d31921f71..86638dc604 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,8 @@ git clone --recurse-submodules https://github.com/modm-io/modm.git ## Targets -modm can generate code for 530 AVR and 1959 +modm can generate code for 530 AVR, +163 SAM and 1959 STM32 devices, however, there are different levels of support and testing.
@@ -81,6 +82,7 @@ STM32 devices, however, there are different levels of support and testing. | STM32F2 | ★★★★ | STM32F3 | ★★★★★ | STM32F4 | ★★★★★ | | STM32F7 | ★★★★ | STM32L1 | ★★★★ | STM32L4 | ★★★★ | | STM32L4+ | ★★★★ | STM32G0 | ★★★★ | STM32G4 | ★★★★ | +| SAMD21 | ★ | | | | |
diff --git a/ext/microchip/sam b/ext/microchip/sam new file mode 160000 index 0000000000..9f08123fc9 --- /dev/null +++ b/ext/microchip/sam @@ -0,0 +1 @@ +Subproject commit 9f08123fc9c504cfe99928fb8f125e149c815e80 diff --git a/repo.lb b/repo.lb index db99cf8aa3..4810f89dfd 100644 --- a/repo.lb +++ b/repo.lb @@ -85,6 +85,7 @@ class DevicesCache(dict): "stm32g0", "stm32g4", "stm32l1", "stm32l4", "at90", "attiny", "atmega", + "samd21", "hosted"] device_file_names = [dfn for dfn in device_file_names if any(s in dfn for s in supported)] diff --git a/tools/scripts/docs_modm_io_generator.py b/tools/scripts/docs_modm_io_generator.py index 3b8545cc9e..7a186f5e5e 100755 --- a/tools/scripts/docs_modm_io_generator.py +++ b/tools/scripts/docs_modm_io_generator.py @@ -59,6 +59,9 @@ def get_targets(): elif target.platform == "hosted": short_id.naming_schema = "{platform}" + elif target.platform == "sam": + short_id.naming_schema = "{platform}{family}{series}" + short_id.set("platform", target.platform) # invalidate caches minimal_targets[short_id.string].append(target) @@ -93,7 +96,7 @@ def main(): # test list device_list = ["hosted-linux", "atmega328p-au", "stm32f103c8t6", "stm32g474cet6"] elif args.test2: - device_list = ["hosted-linux", "atmega328p-pu", "stm32f103zgt7", "stm32g474vet7"] + device_list = ["hosted-linux", "atmega328p-pu", "stm32f103zgt7", "stm32g474vet7", "samd21g18a-uu"] else: device_list = get_targets() diff --git a/tools/scripts/synchronize_docs.py b/tools/scripts/synchronize_docs.py index 7106ec1044..29e8efb066 100755 --- a/tools/scripts/synchronize_docs.py +++ b/tools/scripts/synchronize_docs.py @@ -124,6 +124,7 @@ def get_lbuild(root, target=None): targets -= ignored_devices avr_count = len([t for t in targets if t.startswith("at")]) stm_count = len([t for t in targets if t.startswith("stm32")]) +sam_count = len([t for t in targets if t.startswith("sam")]) # get the author count from authors import author_handles @@ -141,6 +142,7 @@ def get_lbuild(root, target=None): readme = readme_path.read_text() readme = replace(readme, "authorcount", author_count - 7) readme = replace(readme, "avrcount", avr_count) +readme = replace(readme, "samcount", sam_count) readme = replace(readme, "stmcount", stm_count) readme = replace(readme, "bsptable", bsp_table) readme = replace(readme, "drivertable", driver_table) From 5367b04438c413e8d4d77f17fda7aa39e9283230 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Wed, 24 Apr 2019 02:27:36 +0200 Subject: [PATCH 02/11] [ext] Add :cmsis:device module for SAM devices --- ext/microchip/device.hpp.in | 29 +++++++++++++++ ext/microchip/module.lb | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 ext/microchip/device.hpp.in create mode 100644 ext/microchip/module.lb diff --git a/ext/microchip/device.hpp.in b/ext/microchip/device.hpp.in new file mode 100644 index 0000000000..5106855867 --- /dev/null +++ b/ext/microchip/device.hpp.in @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 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/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_DEVICE_HPP +#define MODM_DEVICE_HPP + +#define DONT_USE_CMSIS_INIT 1 +%% for define in defines +#define {{ define }} 1 +%% endfor + +#include +// Defines for example the modm_always_inline macro +#include + +// Include external device headers: +%% for header in headers +#include <{{ header }}> +%% endfor + +#endif // MODM_DEVICE_HPP diff --git a/ext/microchip/module.lb b/ext/microchip/module.lb new file mode 100644 index 0000000000..026f0a9cf9 --- /dev/null +++ b/ext/microchip/module.lb @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2019, 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/. +# ----------------------------------------------------------------------------- + +import re +from pathlib import Path + +# ----------------------------------------------------------------------------- +def init(module): + module.name = ":cmsis:device" + +def prepare(module, options): + device = options[":target"] + if device.identifier["platform"] != "sam": + return False + + module.depends(":cmsis:core") + return True + +pp = {} +def validate(env): + device = env[":target"] + name = device.partname.split("-")[0] + + + define = "__{}__".format(name.upper()) + family_file = None + for famfile in Path(localpath("sam")).glob("**/sam.h"): + content = famfile.read_text(encoding="utf-8", errors="replace") + match = re.findall(r"defined\((?P__SAM.*?__)\)", content) + if match is not None and define in match: + family_file = famfile.relative_to(localpath(".")) + + if family_file is None: + raise ValidateException("No device define found for '{}'!".format(device.partname)) + + family_folder = family_file.parent + device_header = "{}.h".format(name) + + global pp + pp = { + "define": define, + "folder": family_folder, + "device_header": device_header, + } + +def build(env): + global pp + env.collect(":build:path.include", "modm/ext") + env.collect(":build:path.include", "modm/ext/cmsis/device") + + env.outbasepath = "modm/ext/cmsis/device" + files = ["sam.h", "component-version.h", "pio", "instance", "component", pp["device_header"]] + for file in files: + env.copy(localpath(pp["folder"], file), file) + + env.substitutions = { + "headers": [pp["device_header"]], + "defines": [pp["define"]], + } + env.outbasepath = "modm/src/modm/platform" + env.template("device.hpp.in") From 9081d7a507d792cce6f824036ada150b65b744a5 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sun, 26 Apr 2020 20:40:28 +0200 Subject: [PATCH 03/11] [build] Add BOSSA tool for SAM programming --- docs/src/guide/installation.md | 4 + tools/build_script_generator/module.lb | 7 ++ tools/build_script_generator/scons/module.lb | 5 ++ .../scons/resources/SConscript.in | 10 ++- .../scons/resources/build_target.py.in | 17 +++- .../scons/site_tools/avrdude.py | 2 +- .../scons/site_tools/bossac.py | 44 ++++++++++ tools/modm_tools/bossac.py | 81 +++++++++++++++++++ 8 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 tools/build_script_generator/scons/site_tools/bossac.py create mode 100644 tools/modm_tools/bossac.py diff --git a/docs/src/guide/installation.md b/docs/src/guide/installation.md index b66c58be6f..aa75820db1 100644 --- a/docs/src/guide/installation.md +++ b/docs/src/guide/installation.md @@ -49,6 +49,10 @@ well: brew install arm-gcc-bin brew install openocd --HEAD +To program Microchip SAM devices via the bootloader, install the `bossac` tool: + + brew cask install bossa + We recommend the use of a graphical frontend for GDB called [gdbgui][]: pip3 install gdbgui diff --git a/tools/build_script_generator/module.lb b/tools/build_script_generator/module.lb index c722247900..db780748a8 100644 --- a/tools/build_script_generator/module.lb +++ b/tools/build_script_generator/module.lb @@ -117,6 +117,11 @@ def prepare(module, options): PathCollector(name="path.openocd", description="Search path for OpenOCD configuration files")) + if platform == "sam": + module.add_collector( + StringCollector(name="bossac.options", + description="Additional BOSSAc options")) + elif platform in ["avr"]: module.add_collector( StringCollector(name="default.avrdude.programmer", @@ -171,6 +176,8 @@ def build(env): if is_cortex_m: tools.update({"bmp", "openocd", "crashdebug", "gdb", "backend", "log", "build_id", "size"}) + if platform in ["sam"]: + tools.update({"bossac"}) elif platform in ["avr"]: tools.update({"avrdude"}) diff --git a/tools/build_script_generator/scons/module.lb b/tools/build_script_generator/scons/module.lb index c0486ea4a5..a98038aeb3 100644 --- a/tools/build_script_generator/scons/module.lb +++ b/tools/build_script_generator/scons/module.lb @@ -104,6 +104,8 @@ def build(env): if device["core"].startswith("cortex-m"): tools.update({"compiler_arm_none_eabi_gcc", "size", "log_itm", "artifact", "openocd", "openocd_remote", "bmp", "crashdebug", "dfu"}) + if device["platform"] in ["sam"]: + tools.update({"bossac"}) elif device["core"].startswith("avr"): tools.update({"compiler_avr_gcc", "size", "avrdude"}) else: # hosted @@ -185,6 +187,9 @@ def post_build(env): }) if subs["platform"] == "avr": subs.update(env.query("::avrdude_options")) + if subs["platform"] == "sam": + subs.update({"bossac_offset": env.get(":platform:cortex-m:linkerscript.flash_offset", None), + "bossac_options": " ".join(env.collector_values(":build:bossac.options"))}) # Set these substitutions for all templates env.substitutions = subs diff --git a/tools/build_script_generator/scons/resources/SConscript.in b/tools/build_script_generator/scons/resources/SConscript.in index 77d3000de9..03f930d1c6 100644 --- a/tools/build_script_generator/scons/resources/SConscript.in +++ b/tools/build_script_generator/scons/resources/SConscript.in @@ -108,13 +108,21 @@ env["CONFIG_AVRDUDE_PORT"] = "{{ avrdude_port }}" %% if avrdude_options env["CONFIG_AVRDUDE_OPTIONS"] = "{{ avrdude_options }}" %% endif -%% if avrdude_baudrate > 0 +%% if avrdude_baudrate env["CONFIG_AVRDUDE_BAUDRATE"] = "{{ avrdude_baudrate }}" %% endif %% elif core.startswith("cortex-m") env.Append(MODM_OPENOCD_CONFIGFILES="$BASEPATH/openocd.cfg") env.Append(MODM_OPENOCD_GDBINIT="$BASEPATH/openocd_gdbinit") env.Append(MODM_GDBINIT="$BASEPATH/gdbinit") +%% if platform == "sam" +%% if bossac_offset +env.Append(MODM_BOSSAC_OFFSET={{ bossac_offset }}) +%% endif +%% if bossac_options +env.Append(MODM_BOSSAC_OPTIONS="{{ bossac_options }}") +%% endif +%% endif %% endif # XPCC generator tool path diff --git a/tools/build_script_generator/scons/resources/build_target.py.in b/tools/build_script_generator/scons/resources/build_target.py.in index 30d673b10d..6d302224d7 100644 --- a/tools/build_script_generator/scons/resources/build_target.py.in +++ b/tools/build_script_generator/scons/resources/build_target.py.in @@ -40,23 +40,32 @@ def build_target(env, sources): env.Alias("artifact", env.CacheArtifact(program)) %% set artifact = ', "artifact"' if upload_with_artifact else '' - env.Alias("program", [env.ProgramOpenOcd(program){{ artifact }}]) + env.Alias("program-openocd", [env.ProgramOpenOcd(program){{ artifact }}]) env.Alias("program-remote", [env.ProgramGdbRemote(program){{ artifact }}]) env.Alias("program-bmp", [env.ProgramBMP(program){{ artifact }}]) env.Alias('program-dfu', [env.ProgramDFU(env.Bin(program)){{ artifact }}]) + %% if platform in ["sam"] + env.Alias("program-bossac", [env.ProgramBossac(env.Bin(program)){{ artifact }}]) + %% endif - env.Alias("debug", env.DebugOpenOcd(program)) + env.Alias("debug-openocd", env.DebugOpenOcd(program)) env.Alias("debug-remote", env.DebugGdbRemote(program)) env.Alias("debug-bmp", env.DebugBMP(program)) env.Alias("debug-coredump", env.DebugCoredump(program)) - env.Alias("reset", env.ResetOpenOcd()) + env.Alias("reset-openocd", env.ResetOpenOcd()) env.Alias("reset-bmp", env.ResetBMP()) env.Alias("reset-remote", env.ResetGdbRemote()) + # Default to OpenOCD + env.Alias("program", "program-openocd") + env.Alias("reset", "reset-openocd") + env.Alias("debug", "debug-openocd") + %% elif core.startswith("avr") - env.Alias("program", env.ProgramAvrdude(program)) + env.Alias("program-avrdude", env.ProgramAvrdude(program)) env.Alias("program-fuses", env.ProgramAvrdudeFuses(program)) + env.Alias("program", "program-avrdude") %% endif env.Alias("all", ["build", "size"]) diff --git a/tools/build_script_generator/scons/site_tools/avrdude.py b/tools/build_script_generator/scons/site_tools/avrdude.py index a480be0406..ef76f3fd2e 100644 --- a/tools/build_script_generator/scons/site_tools/avrdude.py +++ b/tools/build_script_generator/scons/site_tools/avrdude.py @@ -24,7 +24,7 @@ def call_avrdude(env, source, fuses=None): fuses=fuses) # ----------------------------------------------------------------------------- -def avrdude_flash(env, source, alias="avrdude_program"): +def avrdude_flash(env, source, alias="avrdude_flash"): def call_program(target, source, env): call_avrdude(env, source[0]) diff --git a/tools/build_script_generator/scons/site_tools/bossac.py b/tools/build_script_generator/scons/site_tools/bossac.py new file mode 100644 index 0000000000..8ec99b25e9 --- /dev/null +++ b/tools/build_script_generator/scons/site_tools/bossac.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2018, 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/. +# ----------------------------------------------------------------------------- + +import platform +from SCons.Script import * +from modm_tools import bossac + +# ----------------------------------------------------------------------------- +def bossac_program(env, source, alias="bossac_program"): + def call_program(target, source, env): + offset = env.get("MODM_BOSSAC_OFFSET", 0) + if offset < 0x1000: # Is 4kB the smallest SAM-BA bootloader? + raise ValueError("Refusing to overwrite bootloader!\n" + " Hint: Set `:platform:cortex-m:linkerscript.flash_offset` to bootloader size!") + else: + bossac.program(source=source[0], offset=offset, + port=ARGUMENTS.get("port", "auto"), + options=env.get("MODM_BOSSAC_OPTIONS")) + + action = Action(call_program, cmdstr="$PROGRAM_BOSSAC_STR") + return env.AlwaysBuild(env.Alias(alias, source, action)) + +# ----------------------------------------------------------------------------- +def generate(env, **kw): + # build messages + if ARGUMENTS.get("verbose") != "1": + env["PROGRAM_BOSSAC_STR"] = \ + "{0}.-------------- {1}$SOURCE\n" \ + "{0}'----BOSSAc---> {2}$CONFIG_DEVICE_NAME{3}" \ + .format("\033[;0;32m", "\033[;0;33m", "\033[;1;33m", "\033[;0;0m") + + env.AddMethod(bossac_program, "ProgramBossac") + +def exists(env): + return env.Detect("bossac") diff --git a/tools/modm_tools/bossac.py b/tools/modm_tools/bossac.py new file mode 100644 index 0000000000..2b22e67a11 --- /dev/null +++ b/tools/modm_tools/bossac.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2020, 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/. +# ----------------------------------------------------------------------------- + +""" +### BOSSA + +This tool simply wraps the `bossac` command line tool to guess the serial port. + +```sh +python3 modm/modm_tools/bossac.py -p auto --offset=0x2000 -e \\ + path/to/project.bin +``` + +(\* *only SAM targets*) +""" + +import os +import subprocess +if __name__ == "__main__": + import sys + sys.path.append(os.path.dirname(os.path.dirname(__file__))) + +from modm_tools import utils +from elftools.elf.elffile import ELFFile, NoteSection + +# ----------------------------------------------------------------------------- +def program(source, offset=None, port=None, erase=False, options=None): + command = ["bossac", "-b", "-R"] + + # Attempt to find a serial port automatically + if port == "auto": + port = utils.guess_serial_port("bossac") + + if port is not None: + command.append("--port={}".format(port)) + + if offset is not None: + command.append("--offset={}".format(offset)) + + if erase: + command.append("-e") + + command.extend(utils.listify(options)) + command.extend(["-v", "-w", str(source)]) + + command = " ".join(command) + # print(command) + subprocess.call(command, cwd=os.getcwd(), shell=True) + + +# ----------------------------------------------------------------------------- +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description='Program ELF file via BOSSA') + parser.add_argument( + dest="source", + metavar="BIN") + parser.add_argument( + "-p", + dest="port", + default="auto") + parser.add_argument( + "--offset", + dest="offset") + parser.add_argument( + "-e", + dest="erase", + default=False) + + args = parser.parse_args() + program(args.source, offset=args.offset, port=args.port, erase=args.erase) From 4327990368150dcc6564797cbc6c027ce53d22c2 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sun, 5 Jul 2020 16:57:43 +0200 Subject: [PATCH 04/11] [test] Use Cortex-M runner for unit tests --- test/module.lb | 5 +++-- test/runner/{stm32.cpp => cortex-m.cpp} | 0 2 files changed, 3 insertions(+), 2 deletions(-) rename test/runner/{stm32.cpp => cortex-m.cpp} (100%) diff --git a/test/module.lb b/test/module.lb index f444a99eb2..865bb72787 100644 --- a/test/module.lb +++ b/test/module.lb @@ -22,6 +22,7 @@ def prepare(module, options): def build(env): env.collect("modm:build:path.include", "modm-test/src") + core = env[":target"].get_driver("core")["type"] + core = next(t for t in ("avr", "cortex-m", "hosted") if core.startswith(t)) env.outbasepath = "." - env.copy("runner/{}.cpp".format(env[":target"].identifier.platform), - "main.cpp") + env.copy("runner/{}.cpp".format(core), "main.cpp") diff --git a/test/runner/stm32.cpp b/test/runner/cortex-m.cpp similarity index 100% rename from test/runner/stm32.cpp rename to test/runner/cortex-m.cpp From 304f43c1c0acc7d490401371bf3cf2b337aa78c8 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 6 May 2019 03:48:56 +0200 Subject: [PATCH 05/11] [core] Add ATSAM port --- .../core/sam/linkerscript/sam_ram.ld.in | 50 +++++++++++++++++ src/modm/platform/core/sam/module.lb | 39 ++++++++++++++ .../platform/core/sam/startup_platform.c.in | 53 +++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 src/modm/platform/core/sam/linkerscript/sam_ram.ld.in create mode 100644 src/modm/platform/core/sam/module.lb create mode 100644 src/modm/platform/core/sam/startup_platform.c.in diff --git a/src/modm/platform/core/sam/linkerscript/sam_ram.ld.in b/src/modm/platform/core/sam/linkerscript/sam_ram.ld.in new file mode 100644 index 0000000000..8b1c33a64e --- /dev/null +++ b/src/modm/platform/core/sam/linkerscript/sam_ram.ld.in @@ -0,0 +1,50 @@ +%% import "../../cortex/linker.macros" as linker with context +{{ linker.copyright() }} + +{{ linker.prefix() }} + +%% if vector_table_location == "ram" +/* Round up the number of vector table entries to the nearest power-of-two and multiply by 8. */ +VECTOR_TABLE_ALIGNMENT = (1 << LOG2CEIL({{ number_of_interrupts + 16 }})) * 8; +/* compute the vector table offset from start of RAM */ +VECTOR_TABLE_OFFSET = ALIGN(TOTAL_STACK_SIZE, VECTOR_TABLE_ALIGNMENT); +%% else +VECTOR_TABLE_OFFSET = TOTAL_STACK_SIZE; +%% endif + +SECTIONS +{ +{{ linker.section_rom_start("FLASH") }} + +{{ linker.section_vector_rom("FLASH") }} + +{{ linker.section_stack("RAM", "VECTOR_TABLE_OFFSET - TOTAL_STACK_SIZE") }} + +{{ linker.section_vector_ram("RAM") }} + +{{ linker.section_rom("FLASH") }} + +{{ linker.section("FLASH", "fastcode") }} + +{{ linker.section_ram("RAM", "FLASH") }} + +{{ linker.section("RAM AT >FLASH", "fastdata") }} + +{{ linker.section_heap("RAM", "heap1") }} + +{{ linkerscript_sections | indent(first=True) }} + + /* TABLES! TABLES! ALL THE TABLES YOU COULD EVER WANT! TABLES! */ +{{ linker.section_table_zero("FLASH") }} + +{{ linker.section_table_copy("FLASH") }} + +{{ linker.section_table_extern("FLASH") }} + +%% set heap_table = [{"name": "heap1", "prop": "0x000f"}] +{{ linker.section_table_heap("FLASH", heap_table) }} + +{{ linker.section_rom_end("FLASH") }} + +{{ linker.section_debug() }} +} diff --git a/src/modm/platform/core/sam/module.lb b/src/modm/platform/core/sam/module.lb new file mode 100644 index 0000000000..e19ea01ecf --- /dev/null +++ b/src/modm/platform/core/sam/module.lb @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2019, Ethan Slattery +# +# 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 = ":platform:core" + module.description = """ +# Microchip SAM core module + +Provides SAM specific linkerscripts and startup code. +""" + +def prepare(module, options): + if options[":target"].identifier.platform != "sam": + return False + + module.depends(":platform:cortex-m") + return True + + +def build(env): + env.substitutions = {"target": env[":target"].identifier} + env.outbasepath = "modm/src/modm/platform/core" + # startup helper code + env.template("startup_platform.c.in") + + +def post_build(env): + env.substitutions = env.query("::cortex-m:linkerscript") + env.outbasepath = "modm/link" + env.template("linkerscript/sam_ram.ld.in", "linkerscript.ld") diff --git a/src/modm/platform/core/sam/startup_platform.c.in b/src/modm/platform/core/sam/startup_platform.c.in new file mode 100644 index 0000000000..6bd7663bfb --- /dev/null +++ b/src/modm/platform/core/sam/startup_platform.c.in @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019, Ethan Slattery + * + * 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 "../device.hpp" + +/** + * This code should _only_ enable internal memories and nothing else. + * Since this is the first code executed after a reset, you do not + * have access to _any_ data stored in RAM, since it has not yet been + * initialized. + * In the worst case you won't even have access to the stack, if the + * memory containing the stack is not physically enabled yet. + * In that case, consider using inline assembly to manage stack access + * manually, until the memory is enabled. + */ +void +__modm_initialize_platform(void) +{ +%% if target.family == "d" +%% if target.series == "21" + + // Overwriting the default value of the NVMCTRL.CTRLB.MANW bit (errata reference 13134) + NVMCTRL->CTRLB.bit.MANW = 1; + + // Change default QOS values to have the best performance and correct USB behaviour + SBMATRIX->SFR[SBMATRIX_SLAVE_HMCRAMC0].reg = 2; + +#ifdef USB + USB->DEVICE.QOSCTRL.bit.CQOS = 2; + USB->DEVICE.QOSCTRL.bit.DQOS = 2; +#endif + + DMAC->QOSCTRL.bit.DQOS = 2; + DMAC->QOSCTRL.bit.FQOS = 2; + DMAC->QOSCTRL.bit.WRBQOS = 2; + +%% elif target.series == "21" +%% endif + +%% elif target.family == "l" +%% if target.series == "21" +%% endif +%% endif + +} From 8f8590538eec17b5b2e3c0262067efbbf9d87a4d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 6 May 2019 05:00:28 +0200 Subject: [PATCH 06/11] [clock] Port ATSAM GCLK peripheral --- src/modm/platform/clock/sam/gclk.cpp.in | 20 ++++++++++ src/modm/platform/clock/sam/gclk.hpp | 35 +++++++++++++++++ src/modm/platform/clock/sam/gclk_impl.hpp.in | 30 +++++++++++++++ src/modm/platform/clock/sam/module.lb | 40 ++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 src/modm/platform/clock/sam/gclk.cpp.in create mode 100644 src/modm/platform/clock/sam/gclk.hpp create mode 100644 src/modm/platform/clock/sam/gclk_impl.hpp.in create mode 100644 src/modm/platform/clock/sam/module.lb diff --git a/src/modm/platform/clock/sam/gclk.cpp.in b/src/modm/platform/clock/sam/gclk.cpp.in new file mode 100644 index 0000000000..c53ba5b92d --- /dev/null +++ b/src/modm/platform/clock/sam/gclk.cpp.in @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2013-2014, Kevin Läufer + * Copyright (c) 2014-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 "../device.hpp" +#include "gclk.hpp" + +namespace modm::platform +{ +uint16_t modm_fastdata delay_fcpu_MHz(1); +uint16_t modm_fastdata delay_ns_per_loop({{ loops * 1000 }}); +} diff --git a/src/modm/platform/clock/sam/gclk.hpp b/src/modm/platform/clock/sam/gclk.hpp new file mode 100644 index 0000000000..82e57430bb --- /dev/null +++ b/src/modm/platform/clock/sam/gclk.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019, Ethan Slattery + * + * 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" + +namespace modm::platform +{ + +/** + * Clock management + * + * \ingroup modm_platform_gclk + */ +class GenericClockController +{ +public: + template< uint32_t Core_Hz > + void + updateCoreFrequency(); +}; + +} + +#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 new file mode 100644 index 0000000000..d1cfc9dc00 --- /dev/null +++ b/src/modm/platform/clock/sam/gclk_impl.hpp.in @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019, Ethan Slattery + * + * 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 + +namespace modm::platform +{ +/// @cond +extern uint16_t delay_fcpu_MHz; +extern uint16_t delay_ns_per_loop; +/// @endcond + +template< uint32_t Core_Hz > +void +GenericClockController::updateCoreFrequency() +{ + delay_fcpu_MHz = Core_Hz / 1'000'000; + delay_ns_per_loop = ::round({{loops}}000.f / (Core_Hz / 1'000'000)); +} + +} + diff --git a/src/modm/platform/clock/sam/module.lb b/src/modm/platform/clock/sam/module.lb new file mode 100644 index 0000000000..a4d1fadf54 --- /dev/null +++ b/src/modm/platform/clock/sam/module.lb @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016-2018, Niklas Hauser +# Copyright (c) 2017, Fabian Greif +# +# 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 = ":platform:gclk" + module.description = "Generic Clock Controller (GCLK)" + +def prepare(module, options): + if not options[":target"].has_driver("gclk:sam"): + return False + + module.depends(":cmsis:device") + return True + +def build(env): + device = env[":target"] + core = device.get_driver("core")["type"] + + if "m0" in core: + loops = 4 + elif "m7" in core: + loops = 1 + else: + loops = 3 + + env.substitutions = {"loops": loops} + env.outbasepath = "modm/src/modm/platform/clock" + env.copy("gclk.hpp") + env.template("gclk.cpp.in") + env.template("gclk_impl.hpp.in") From 411150e394d785842e168016257db49748491176 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 27 Apr 2020 00:04:49 +0200 Subject: [PATCH 07/11] [gpio] Implement GPIO driver for SAMD --- src/modm/platform/gpio/common/inverted.hpp | 2 +- src/modm/platform/gpio/sam/base.hpp.in | 103 ++++++++++++ src/modm/platform/gpio/sam/module.lb | 75 +++++++++ src/modm/platform/gpio/sam/peripherals.hpp.in | 23 +++ src/modm/platform/gpio/sam/pin.hpp.in | 112 +++++++++++++ src/modm/platform/gpio/sam/set.hpp.in | 148 ++++++++++++++++++ src/modm/platform/gpio/sam/unused.hpp.in | 81 ++++++++++ 7 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 src/modm/platform/gpio/sam/base.hpp.in create mode 100644 src/modm/platform/gpio/sam/module.lb create mode 100644 src/modm/platform/gpio/sam/peripherals.hpp.in create mode 100644 src/modm/platform/gpio/sam/pin.hpp.in create mode 100644 src/modm/platform/gpio/sam/set.hpp.in create mode 100644 src/modm/platform/gpio/sam/unused.hpp.in diff --git a/src/modm/platform/gpio/common/inverted.hpp b/src/modm/platform/gpio/common/inverted.hpp index 96fb642356..3bcf0dfbde 100644 --- a/src/modm/platform/gpio/common/inverted.hpp +++ b/src/modm/platform/gpio/common/inverted.hpp @@ -44,7 +44,7 @@ class GpioInverted : public Pin using Input = GpioInverted; using IO = GpioInverted; using Type = typename Pin::Type; - static constexpr bool isInverted = Pin::isInverted ^ true; + static constexpr bool isInverted = not Pin::isInverted; public: using Pin::setOutput; diff --git a/src/modm/platform/gpio/sam/base.hpp.in b/src/modm/platform/gpio/sam/base.hpp.in new file mode 100644 index 0000000000..a2873316fd --- /dev/null +++ b/src/modm/platform/gpio/sam/base.hpp.in @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020, 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include "../device.hpp" +#include +#include +#include + +namespace modm::platform +{ + +/// @ingroup modm_platform_gpio +struct Gpio +{ + enum class + InputType + { + Floating = 0x0, ///< floating on input + PullUp = 0x1, ///< pull-up on input + PullDown = 0x2, ///< pull-down on input + }; + + enum class + OutputType + { + PushPull = 0x0, ///< push-pull on output + OpenDrain = 0x1, ///< open-drain on output + }; + + enum class + OutputSpeed + { + Low = 0, + Medium = 0x1, + High = 0x2, + VeryHigh = 0x3, ///< 30 pF (80 MHz Output max speed on 15 pF) + MHz2 = Low, + MHz25 = Medium, + MHz50 = High, + MHz100 = VeryHigh, + }; + + enum class + InputTrigger + { + RisingEdge, + FallingEdge, + BothEdges, + }; + + /// The Port a Gpio Pin is connected to. + enum class + Port + { +%% for port in ports + {{ port | upper }} = {{ port | modm.ord }}, +%% endfor + }; + + /// @cond + enum class + Signal + { + BitBang, + }; + /// @endcond + +protected: + /// @cond + /// I/O Direction Mode values for this specific pin. + enum class + Mode + { + Input = 0x0, + Output = 0x1, + AlternateFunction = 0x2, + Analog = 0x3, + Mask = 0x3, + }; + + static constexpr uint32_t + i(Mode mode) { return uint32_t(mode); } + // Enum Class To Integer helper functions. + static constexpr uint32_t + i(InputType pull) { return uint32_t(pull); } + static constexpr uint32_t + i(OutputType out) { return uint32_t(out); } + static constexpr uint32_t + i(OutputSpeed speed) { return uint32_t(speed); } + /// @endcond +}; + +} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/module.lb b/src/modm/platform/gpio/sam/module.lb new file mode 100644 index 0000000000..70c53fa480 --- /dev/null +++ b/src/modm/platform/gpio/sam/module.lb @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016-2018, Niklas Hauser +# Copyright (c) 2017, Fabian Greif +# +# 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/. +# ----------------------------------------------------------------------------- + +import copy +from collections import defaultdict, OrderedDict + +def port_ranges(gpios): + ports = {p: (32, 0) for p in set(p["port"] for p in gpios)} + for gpio in gpios: + pin = int(gpio["pin"]) + pmin, pmax = ports[gpio["port"]] + ports[gpio["port"]] = (min(pin, pmin), max(pin, pmax)) + + ports = [{"name": k.upper(), "start": v[0], "width": v[1] - v[0] + 1} for k,v in ports.items()] + ports.sort(key=lambda p: p["name"]) + return ports + +bprops = {} + +# ----------------------------------------------------------------------------- +def init(module): + module.name = ":platform:gpio" + module.description = "General Purpose I/O (GPIO)" + +def prepare(module, options): + device = options[":target"] + if not device.has_driver("gpio:sam*"): + return False + + module.depends( + ":architecture:gpio", + ":cmsis:device", + ":math:utils") + return True + +def build(env): + device = env[":target"] + driver = device.get_driver("gpio") + bprops["ranges"] = port_ranges(driver["gpio"]) + bprops["ports"] = OrderedDict([(k, i) for i, k in enumerate([p["name"] for p in bprops["ranges"]])]) + + properties = {"target": device.identifier} + properties.update(bprops) + + env.substitutions = properties + env.outbasepath = "modm/src/modm/platform/gpio" + + for gpio in driver["gpio"]: + po, pi = gpio["port"], gpio["pin"] + properties["gpio"] = gpio + env.template("pin.hpp.in", "gpio_{}{}.hpp".format(po.upper(), pi)) + + # env.template("port.hpp.in") + # env.template("software_port.hpp.in") + env.template("set.hpp.in") + env.template("base.hpp.in") + env.template("unused.hpp.in") + + env.copy("../common/inverted.hpp", "inverted.hpp") + env.copy("../common/connector.hpp", "connector.hpp") + env.template("../common/connector_detail.hpp.in", "connector_detail.hpp") + + # FIXME: Move to modm:platform:core! + env.outbasepath = "modm/src/modm/platform/core" + env.template("peripherals.hpp.in") diff --git a/src/modm/platform/gpio/sam/peripherals.hpp.in b/src/modm/platform/gpio/sam/peripherals.hpp.in new file mode 100644 index 0000000000..f87f1b776f --- /dev/null +++ b/src/modm/platform/gpio/sam/peripherals.hpp.in @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019, 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +namespace modm::platform +{ + +enum class +Peripheral +{ + BitBang, +}; + +} diff --git a/src/modm/platform/gpio/sam/pin.hpp.in b/src/modm/platform/gpio/sam/pin.hpp.in new file mode 100644 index 0000000000..44e38a0644 --- /dev/null +++ b/src/modm/platform/gpio/sam/pin.hpp.in @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2017-2018, 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/. + */ +// ---------------------------------------------------------------------------- + +%% set port = gpio.port | upper +%% set reg = "GPIO" ~ port +%% set pin = gpio.pin +%% set pnr = gpio.port | modm.ord + +#pragma once + +#include "../device.hpp" +#include "base.hpp" +#include "set.hpp" + +namespace modm::platform +{ + +/// @cond +class Gpio{{ port ~ pin }}; +using GpioOutput{{ port ~ pin }} = Gpio{{ port ~ pin }}; +using GpioInput{{ port ~ pin }} = Gpio{{ port ~ pin }}; +/// @endcond + +/// IO class for Pin {{port ~ pin}} +/// @ingroup modm_platform_gpio +class Gpio{{ port ~ pin }} : public Gpio, public ::modm::GpioIO +{ + template + friend class GpioSet; + using PinSet = GpioSet; + friend class Adc; + friend class Adc1; friend class Adc2; + friend class Adc3; friend class Adc4; +public: + using Output = Gpio{{ port ~ pin }}; + using Input = Gpio{{ port ~ pin }}; + using IO = Gpio{{ port ~ pin }}; + using Type = Gpio{{ port ~ pin }}; + static constexpr bool isInverted = false; + static constexpr Port port = Port::{{port}}; ///< Port name + static constexpr uint8_t pin = {{pin|int}}; ///< Pin number + +protected: + /// Bitmask for registers that contain a 1bit value for every pin. + static constexpr uint32_t mask = 1ul << pin; + /// Bitmask for registers that contain a 2bit value for every pin. + // static constexpr uint32_t mask2 = 0x3 << (pin * 2); + /// Port Number. + static constexpr uint8_t port_nr = uint8_t(port); + /// Alternate Function register id. 0 for pin 0-7. 1 for pin 8-15. + // static constexpr uint8_t af_id = pin / 8; + /// Alternate Function offset. + // static constexpr uint8_t af_offset = (pin * 4) % 32; + /// Alternate Function register mask. + // static constexpr uint32_t af_mask = 0xf << af_offset; + +public: + /// @cond + inline static void setAlternateFunction(uint8_t) { + // {{reg}}->AFR[af_id] = ({{reg}}->AFR[af_id] & ~af_mask) | ((af & 0xf) << af_offset); + // {{reg}}->MODER = ({{reg}}->MODER & ~mask2) | (i(Mode::AlternateFunction) << (pin * 2)); + } + + /// Enable Analog Mode which is needed to use this pin as an ADC input. + inline static void setAnalogInput() { PinSet::setAnalogInput(); } + /// @endcond + +public: + // GpioOutput + // start documentation inherited + inline static void setOutput() { PinSet::setOutput(); } + inline static void setOutput(bool status) { PinSet::setOutput(status); } + inline static void set() { PinSet::set(); } + inline static void set(bool status) { PinSet::set(status); } + inline static void reset() { PinSet::reset(); } + inline static void toggle() { + if (isSet()) { reset(); } + else { set(); } + } + inline static bool isSet() { return (REG_PORT_OUT{{pnr}} & mask); } + // stop documentation inherited + inline static void configure(OutputType type, OutputSpeed speed = OutputSpeed::MHz50) { PinSet::configure(type, speed); } + inline static void setOutput(OutputType type, OutputSpeed speed = OutputSpeed::MHz50) { PinSet::setOutput(type, speed); } + // GpioInput + // start documentation inherited + inline static void setInput() { PinSet::setInput(); } + inline static bool read() { return (REG_PORT_IN{{pnr}} & mask); } + // end documentation inherited + inline static void configure(InputType type) { PinSet::configure(type); } + inline static void setInput(InputType type) { PinSet::setInput(type); } + // GpioIO + // start documentation inherited + inline static Direction getDirection() { + if (REG_PORT_DIR{{pnr}} & mask) + return Direction::In; + return Direction::Out; + } + // end documentation inherited + inline static void disconnect() { + setInput(InputType::Floating); + } +}; + +} // namespace modm::platform diff --git a/src/modm/platform/gpio/sam/set.hpp.in b/src/modm/platform/gpio/sam/set.hpp.in new file mode 100644 index 0000000000..bc1d89bab7 --- /dev/null +++ b/src/modm/platform/gpio/sam/set.hpp.in @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018, 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/. + */ +// ---------------------------------------------------------------------------- + +#ifndef MODM_STM32_GPIO_SET_HPP +#define MODM_STM32_GPIO_SET_HPP + +#include "../device.hpp" +#include "base.hpp" + +namespace modm +{ + +namespace platform +{ + +/// @ingroup modm_platform_gpio +template< class... Gpios > +class GpioSet : public Gpio +{ +protected: + static constexpr uint32_t inverteds[{{ ports | length }}] = { +%% for port in ports + (((Gpios::port == Port::{{port}} and Gpios::isInverted) ? Gpios::mask : 0) | ...), +%% endfor + }; + static constexpr uint32_t inverted(uint8_t id) { return inverteds[id]; } + + static constexpr uint32_t masks[{{ ports | length }}] = { +%% for port in ports + (((Gpios::port == Port::{{port}}) ? Gpios::mask : 0) | ...), +%% endfor + }; + static constexpr uint32_t mask(uint8_t id) { return masks[id]; } + static constexpr uint8_t numberOfPorts() { + uint8_t r{0}; + for (const auto &m: masks) r += (m) ? 1 : 0; + return r; + } +public: + static constexpr uint8_t width = sizeof...(Gpios); + static constexpr uint8_t number_of_ports = numberOfPorts(); +public: + static void setOutput() + { + %% for port, id in ports.items() + if constexpr (mask({{id}})) REG_PORT_DIRSET{{id}} = mask({{id}}); + %% endfor + } + + static void setOutput(bool status) + { + set(status); + setOutput(); + } + + static void setOutput(OutputType type, OutputSpeed speed = OutputSpeed::MHz50) + { + configure(type, speed); + setOutput(); + } + + static void configure(OutputType , OutputSpeed = OutputSpeed::MHz50) + { + %% for port, id in ports.items() + if constexpr (mask({{id}})) { + // GPIO{{port}}->OSPEEDR = (GPIO{{port}}->OSPEEDR & ~mask2({{id}})) | (i(speed) * mask2({{id}}, 0b01)); + // GPIO{{port}}->OTYPER = (GPIO{{port}}->OTYPER & ~mask({{id}})) | (i(type) ? mask({{id}}) : 0); + } + %% endfor + } + + static void setInput() + { + %% for port, id in ports.items() + if constexpr (mask({{id}})) { + REG_PORT_DIRCLR{{id}} = mask({{id}}); + } + %% endfor + } + + static void setInput(InputType type) + { + configure(type); + setInput(); + } + + static void setAnalogInput() + { + %% for port, id in ports.items() + // if constexpr (mask({{id}})) GPIO{{port}}->MODER |= mask2({{id}}, i(Mode::Analog)); + %% endfor + } + + static void configure(InputType) + { + %% for port, id in ports.items() + if constexpr (mask({{id}})) { + // GPIO{{port}}->PUPDR = (GPIO{{port}}->PUPDR & ~mask2({{id}})) | (i(type) * mask2({{id}}, 0b01)); + } + %% endfor + } + + static void set() + { +%% for port, id in ports.items() + if constexpr (mask({{id}})) REG_PORT_OUTSET{{id}} = mask({{id}}); +%% endfor + } + + static void set(bool status) + { + if (status) set(); + else reset(); + } + + static void reset() + { +%% for port, id in ports.items() + if constexpr (mask({{id}})) REG_PORT_OUTCLR{{id}} = mask({{id}}); +%% endfor + } + + static void toggle() + { +%% for port, id in ports.items() + if constexpr (mask({{id}})) REG_PORT_OUTTGL{{id}} = mask({{id}}); +%% endfor + } + + static void disconnect() + { + // (Gpios::disconnect(), ...); + } +}; + +} // namespace platform + +} // namespace modm + +#endif // MODM_STM32_GPIO_SET_HPP diff --git a/src/modm/platform/gpio/sam/unused.hpp.in b/src/modm/platform/gpio/sam/unused.hpp.in new file mode 100644 index 0000000000..1be9a4d1af --- /dev/null +++ b/src/modm/platform/gpio/sam/unused.hpp.in @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020, 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include "base.hpp" +#include + +namespace modm::platform +{ + +/** + * @author Niklas Hauser + * @ingroup modm_platform_gpio + */ +class GpioUnused : public Gpio, public ::modm::GpioIO +{ +public: + using Output = GpioUnused; + using Input = GpioUnused; + using IO = GpioUnused; + using Type = GpioUnused; + static constexpr bool isInverted = false; + static constexpr Port port = Port(-1); + static constexpr uint8_t pin = uint8_t(-1); + static constexpr uint32_t mask = 0; + +protected: + /// @cond + static void setAlternateFunction(uint8_t) {} + static void setAnalogInput() {} + /// @endcond + +public: + // GpioOutput + // start documentation inherited + static void setOutput() {} + static void setOutput(bool) {} + static void set() {} + static void set(bool) {} + static void reset() {} + static void toggle() {} + static bool isSet() { return false; } + // stop documentation inherited + static void configure(OutputType, OutputSpeed = OutputSpeed::MHz50) {} + static void setOutput(OutputType, OutputSpeed = OutputSpeed::MHz50) {} + + // GpioInput + // start documentation inherited + static void setInput() {} + static bool read() { return false; } + // end documentation inherited + static void configure(InputType) {} + static void setInput(InputType) {} + // External Interrupts + static void enableExternalInterrupt() {} + static void disableExternalInterrupt() {} + static void enableExternalInterruptVector(const uint32_t) {} + static void disableExternalInterruptVector() {} + static void setInputTrigger(const InputTrigger) {} + static bool getExternalInterruptFlag() { return false; } + /// Reset the interrupt flag in the interrupt routine. + static void acknowledgeExternalInterruptFlag() {} + + // GpioIO + // start documentation inherited + static Direction getDirection() { return Direction::Special; } + // end documentation inherited + static void lock() {} + static void disconnect() {} +}; + +} // namespace modm::platform From 1dd5c4a615d7ba6d4458b6009cd4ea7c579dbf7d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 6 May 2019 03:49:11 +0200 Subject: [PATCH 08/11] [board] Add Feather-M0 and SAMD21-MINI board --- README.md | 12 ++-- src/modm/board/feather_m0/board.hpp | 81 +++++++++++++++++++++++++++ src/modm/board/feather_m0/board.xml | 14 +++++ src/modm/board/feather_m0/module.lb | 43 ++++++++++++++ src/modm/board/samd21_mini/board.hpp | 84 ++++++++++++++++++++++++++++ src/modm/board/samd21_mini/board.xml | 15 +++++ src/modm/board/samd21_mini/module.lb | 43 ++++++++++++++ 7 files changed, 287 insertions(+), 5 deletions(-) create mode 100644 src/modm/board/feather_m0/board.hpp create mode 100644 src/modm/board/feather_m0/board.xml create mode 100644 src/modm/board/feather_m0/module.lb create mode 100644 src/modm/board/samd21_mini/board.hpp create mode 100644 src/modm/board/samd21_mini/board.xml create mode 100644 src/modm/board/samd21_mini/module.lb diff --git a/README.md b/README.md index 86638dc604..c4eca83206 100644 --- a/README.md +++ b/README.md @@ -132,31 +132,33 @@ documentation. DISCO-L152RC DISCO-L476VG +FEATHER-M0 MEGA-2560-PRO MINI-F401 MINI-F411 -NUCLEO-F031K6 +NUCLEO-F031K6 NUCLEO-F042K6 NUCLEO-F103RB NUCLEO-F303K8 -NUCLEO-F303RE +NUCLEO-F303RE NUCLEO-F401RE NUCLEO-F411RE NUCLEO-F429ZI -NUCLEO-F446RE +NUCLEO-F446RE NUCLEO-F746ZG NUCLEO-G071RB NUCLEO-G474RE -NUCLEO-L152RE +NUCLEO-L152RE NUCLEO-L432KC NUCLEO-L476RG OLIMEXINO-STM32 -STM32F030F4P6-DEMO +SAMD21-MINI +STM32F030F4P6-DEMO diff --git a/src/modm/board/feather_m0/board.hpp b/src/modm/board/feather_m0/board.hpp new file mode 100644 index 0000000000..277da20516 --- /dev/null +++ b/src/modm/board/feather_m0/board.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016-2017, Sascha Schade + * Copyright (c) 2017-2018, 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include + +using namespace modm::platform; + + +/// @ingroup modm_board_feather_m0 +namespace Board +{ + using namespace modm::literals; + +/// 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 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 bool inline + enable() + { + // GenericClockController::enableExternalCrystal(Frequency); + + // switch system clock to PLL output + // GenericClockController::enableSystemClock(ClockControl::SystemClockSource::Pll); + + // update frequencies for busy-wait delay functions + // GenericClockController::updateCoreFrequency(); + + return true; + } +}; + +// User LED (inverted, because connected to 3V3) +// using LedRed = GpioOutputA17; +// using Leds = SoftwareGpioPort< LedRed >; + +// using Button = GpioUnused; + +inline void +initialize() +{ + SystemClock::enable(); + SysTickTimer::initialize(); + + // LedGreen::setOutput(modm::Gpio::Low); +} + +} // Board namespace diff --git a/src/modm/board/feather_m0/board.xml b/src/modm/board/feather_m0/board.xml new file mode 100644 index 0000000000..c816c6f149 --- /dev/null +++ b/src/modm/board/feather_m0/board.xml @@ -0,0 +1,14 @@ + + + + ../../../../repo.lb + + + + + + + + modm:board:feather-m0 + + diff --git a/src/modm/board/feather_m0/module.lb b/src/modm/board/feather_m0/module.lb new file mode 100644 index 0000000000..ad1fa5d59c --- /dev/null +++ b/src/modm/board/feather_m0/module.lb @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016-2018, Niklas Hauser +# Copyright (c) 2017, Fabian Greif +# +# 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:feather-m0" + module.description = """\ +# Adafruit Feather-M0 + +At the Feather M0's heart is an ATSAMD21G18 ARM Cortex M0 processor, +clocked at 48 MHz and at 3.3V logic, the same one used in the new Arduino Zero. +This chip has a whopping 256K of FLASH (8x more than the Atmega328 or 32u4) +and 32K of RAM (16x as much)! This chip comes with built in USB so it has +USB-to-Serial program & debug capability built in with no need for an FTDI-like chip. + +https://www.adafruit.com/product/2772 +""" + +def prepare(module, options): + if not options[":target"].partname.startswith("samd21g18a"): + return False + + module.depends(":platform:gclk", ":platform:core", ":platform:clock") + return True + +def build(env): + env.outbasepath = "modm/src/modm/board" + # env.substitutions = {"board_has_logger": False} + # env.template("../board.cpp.in", "board.cpp") + env.copy('.') + + # env.outbasepath = "modm/openocd/modm/board/" + # env.copy(repopath("tools/openocd/modm/stm32f103_blue_pill.cfg"), "stm32f103_blue_pill.cfg") + # env.collect(":build:openocd.source", "modm/board/stm32f103_blue_pill.cfg"); diff --git a/src/modm/board/samd21_mini/board.hpp b/src/modm/board/samd21_mini/board.hpp new file mode 100644 index 0000000000..901662728d --- /dev/null +++ b/src/modm/board/samd21_mini/board.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016-2017, Sascha Schade + * Copyright (c) 2017-2018, 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/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include + +using namespace modm::platform; + + +/// @ingroup modm_board_samd21_mini +namespace Board +{ +using namespace modm::literals; + +struct SystemClock +{ + static constexpr uint32_t Frequency = 1_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 bool inline + enable() + { + // GenericClockController::enableExternalCrystal(Frequency); + + // switch system clock to PLL output + // GenericClockController::enableSystemClock(ClockControl::SystemClockSource::Pll); + + // update frequencies for busy-wait delay functions + // GenericClockController::updateCoreFrequency(); + + return true; + } +}; + +// User LED (inverted, because connected to 3V3) +using LedD13 = GpioInverted; +using LedTx = GpioInverted; +using LedRx = GpioInverted; +// using Leds = SoftwareGpioPort< LedRed >; + +using Button = GpioUnused; + +inline void +initialize() +{ + SystemClock::enable(); + SysTickTimer::initialize(); + + LedTx::setOutput(modm::Gpio::Low); + LedRx::setOutput(modm::Gpio::Low); +} + +} // Board namespace diff --git a/src/modm/board/samd21_mini/board.xml b/src/modm/board/samd21_mini/board.xml new file mode 100644 index 0000000000..d57567cf23 --- /dev/null +++ b/src/modm/board/samd21_mini/board.xml @@ -0,0 +1,15 @@ + + + + ../../../../repo.lb + + + + + + + + + modm:board:samd21-mini + + diff --git a/src/modm/board/samd21_mini/module.lb b/src/modm/board/samd21_mini/module.lb new file mode 100644 index 0000000000..f6d243640c --- /dev/null +++ b/src/modm/board/samd21_mini/module.lb @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016-2018, Niklas Hauser +# Copyright (c) 2017, Fabian Greif +# +# 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-mini" + module.description = """ +# RobotDyn SAMD21 M0 MINI + +The SAMD21 MINI board is a small breakout board for the ATSAMD21G18 ARM +Cortex-M0 processor, clocked at 48 MHz and at 3.3V logic. + +See: https://robotdyn.com/samd21-m0-mini.html + +It can be bought for little cost from well known Chinese online stores. +""" + +def prepare(module, options): + if not options[":target"].partname.startswith("samd21g18a"): + return False + + module.depends(":platform:gclk", ":platform:core", ":platform:clock", + ":platform:gpio") + return True + +def build(env): + env.outbasepath = "modm/src/modm/board" + # env.substitutions = {"board_has_logger": False} + # env.template("../board.cpp.in", "board.cpp") + env.copy('.') + + # env.outbasepath = "modm/openocd/modm/board/" + # env.copy(repopath("tools/openocd/modm/stm32f103_blue_pill.cfg"), "stm32f103_blue_pill.cfg") + # env.collect(":build:openocd.source", "modm/board/stm32f103_blue_pill.cfg"); From 6dbeb59e436f95a387772cfe8bc8311b5f706aa4 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 27 Apr 2020 15:35:46 +0200 Subject: [PATCH 09/11] [examples] Add SAMD21 examples --- .circleci/config.yml | 4 ++++ examples/samd/blink/main.cpp | 35 +++++++++++++++++++++++++++++++++ examples/samd/blink/project.xml | 9 +++++++++ 3 files changed, 48 insertions(+) create mode 100644 examples/samd/blink/main.cpp create mode 100644 examples/samd/blink/project.xml diff --git a/.circleci/config.yml b/.circleci/config.yml index 25330c979a..9b1792df30 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,6 +51,10 @@ jobs: name: Generic Examples command: | (cd examples && ../tools/scripts/examples_compile.py generic) + - run: + name: Examples SAM Devices + command: | + (cd examples && ../tools/scripts/examples_compile.py samd) - run: name: Execute Python Scripts command: | diff --git a/examples/samd/blink/main.cpp b/examples/samd/blink/main.cpp new file mode 100644 index 0000000000..7472a0a5ec --- /dev/null +++ b/examples/samd/blink/main.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019, Ethan Slattery + * + * 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; +using namespace std::chrono_literals; + +int +main() +{ + Board::initialize(); + LedRx::set(); + + while (1) + { + LedTx::toggle(); + LedRx::toggle(); + modm::delay(500ms); + +#ifdef MODM_BOARD_HAS_LOGGER + static uint32_t counter(0); + MODM_LOG_INFO << "Loop counter: " << (counter++) << modm::endl; +#endif + } + + return 0; +} diff --git a/examples/samd/blink/project.xml b/examples/samd/blink/project.xml new file mode 100644 index 0000000000..0c80983a8b --- /dev/null +++ b/examples/samd/blink/project.xml @@ -0,0 +1,9 @@ + + modm:samd21-mini + + + + + modm:build:scons + + From 6c4a8d655f45bfefb498e4a3d8bfad7a2c597ac2 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 27 Apr 2020 23:00:07 +0200 Subject: [PATCH 10/11] [ci] Add SAMD devices to CI --- .circleci/config.yml | 24 ++++++++++++++++++++++++ test/all/{stm32.cpp => cortex-m.cpp} | 0 test/all/{stm32.xml => cortex-m.xml} | 0 test/all/ignored.txt | 5 +++++ test/all/run_all.py | 6 +++--- 5 files changed, 32 insertions(+), 3 deletions(-) rename test/all/{stm32.cpp => cortex-m.cpp} (100%) rename test/all/{stm32.xml => cortex-m.xml} (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9b1792df30..5bfd6c3a3a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -161,6 +161,23 @@ jobs: path: test/all/log destination: log + samd-compile-all: + docker: + - image: modm/modm-build:latest + steps: + - checkout + - run: + name: Checkout code and update modm tools + command: | + (git submodule sync && git submodule update --init --jobs 8) & pip3 install --upgrade --upgrade-strategy=eager modm & wait + - run: + name: Compile HAL for all SAMD + command: | + (cd test/all && python3 run_all.py samd) + - store_artifacts: + path: test/all/log + destination: log + stm32f0-compile-all: docker: - image: modm/modm-build:latest @@ -441,6 +458,12 @@ workflows: filters: branches: ignore: /^develop.*/ + - samd-compile-all: + requires: + - unittests-linux-generic + filters: + branches: + ignore: /^develop.*/ - stm32f0-compile-all: requires: - unittests-linux-generic @@ -518,6 +541,7 @@ workflows: ignore: /^develop.*/ requires: - avr-compile-all + - samd-compile-all - stm32f0-compile-all - stm32f1-compile-all - stm32f2-compile-all diff --git a/test/all/stm32.cpp b/test/all/cortex-m.cpp similarity index 100% rename from test/all/stm32.cpp rename to test/all/cortex-m.cpp diff --git a/test/all/stm32.xml b/test/all/cortex-m.xml similarity index 100% rename from test/all/stm32.xml rename to test/all/cortex-m.xml diff --git a/test/all/ignored.txt b/test/all/ignored.txt index 44ac365e5a..7a0b65ef99 100644 --- a/test/all/ignored.txt +++ b/test/all/ignored.txt @@ -98,3 +98,8 @@ stm32l151qch6 stm32l151zct6 stm32l152qch6 stm32l152zct6 +# FIXME: Missing cmsis-header for these ones +samd21e15c-uf +samd21e15c-uu +samd21e16c-uf +samd21e16c-uu diff --git a/test/all/run_all.py b/test/all/run_all.py index 54a695b781..31e9841da8 100644 --- a/test/all/run_all.py +++ b/test/all/run_all.py @@ -84,9 +84,9 @@ def run(self): if self.device.startswith("at"): lbuild_command = ["-c", "avr.xml"] shutil.copyfile("avr.cpp", os.path.join(tempdir, "main.cpp")) - elif self.device.startswith("stm32"): - lbuild_command = ["-c", "stm32.xml", "-D:::main_stack_size=512"] - shutil.copyfile("stm32.cpp", os.path.join(tempdir, "main.cpp")) + else: + lbuild_command = ["-c", "cortex-m.xml", "-D:::main_stack_size=512"] + shutil.copyfile("cortex-m.cpp", os.path.join(tempdir, "main.cpp")) if self.cache_dir: lbuild_command.append("-D:::cache_dir={}".format(self.cache_dir)) From 2f125fdc7af41c6484c1a03fb9bbd7fd4fe5c57d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sun, 5 Jul 2020 18:38:06 +0200 Subject: [PATCH 11/11] [scons] Use GCC-10 on hosted-darwin targets --- .../cmake/cmake_scripts/configure-gcc.cmake.in | 7 +++---- tools/build_script_generator/scons/resources/SConscript.in | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/build_script_generator/cmake/cmake_scripts/configure-gcc.cmake.in b/tools/build_script_generator/cmake/cmake_scripts/configure-gcc.cmake.in index 564ff4a78a..23224fbb26 100644 --- a/tools/build_script_generator/cmake/cmake_scripts/configure-gcc.cmake.in +++ b/tools/build_script_generator/cmake/cmake_scripts/configure-gcc.cmake.in @@ -30,10 +30,9 @@ if(WIN32) %% if platform == "hosted" elseif(APPLE) # Using homebrew gcc on macOS - find_program(GCC_VERSION NAMES "gcc-9" "gcc-8" "gcc-7") - string(LENGTH ${GCC_VERSION} GCC_VERSION_LENGTH) - math(EXPR GCC_VERSION_LENGTH "${GCC_VERSION_LENGTH}-2") - string(SUBSTRING ${GCC_VERSION} ${GCC_VERSION_LENGTH} -1 GCC_VERSION) + find_program(GCC_VERSION NAMES "gcc-10" "gcc-9" "gcc-8" "gcc-7") + string(REGEX MATCH "gcc-[0-9]+" GCC_VERSION ${GCC_VERSION}) + string(SUBSTRING ${GCC_VERSION} 3 -1 GCC_VERSION) set(TOOL_EXECUTABLE_SUFFIX "${GCC_VERSION}") %% endif else() diff --git a/tools/build_script_generator/scons/resources/SConscript.in b/tools/build_script_generator/scons/resources/SConscript.in index 03f930d1c6..f6d29755cc 100644 --- a/tools/build_script_generator/scons/resources/SConscript.in +++ b/tools/build_script_generator/scons/resources/SConscript.in @@ -17,7 +17,7 @@ env["BUILDPATH"] = join(env["CONFIG_BUILD_BASE"], profile) env["BASEPATH"] = abspath(".") %% if family == "darwin" # Using homebrew gcc on macOS instead of clang -env["COMPILERSUFFIX"] = env.Detect(["gcc-9", "gcc-8", "gcc-7"])[3:] +env["COMPILERSUFFIX"] = env.Detect(["gcc-10", "gcc-9", "gcc-8", "gcc-7"])[3:] %% endif %% endif