Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for NRF arm processors #410

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions .circleci/config.yml
Expand Up @@ -140,6 +140,20 @@ jobs:
command: |
(cd examples && ../tools/scripts/examples_compile.py avr arduino_uno)

nrf-examples:
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: Examples NRF Series
command: |
(cd examples && ../tools/scripts/examples_compile.py nrf)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CircleCI gives us 4x parallelism that's why we should keep the examples running in four jobs, so that they fail quicker => faster iteration. I recommend that you rename the stm32-examples job to cortex-m-examples and add the NRF series there.

avr-compile-all:
docker:
- image: modm/modm-build:latest
Expand Down Expand Up @@ -424,6 +438,10 @@ workflows:
filters:
branches:
ignore: /^develop.*/
- nrf-examples:
filters:
branches:
ignore: /^develop.*/
- stm32-examples:
filters:
branches:
Expand Down
5 changes: 4 additions & 1 deletion .gitmodules
@@ -1,9 +1,12 @@
[submodule "ext/st/stm32"]
path = ext/st/stm32
url = https://github.com/modm-io/cmsis-header-stm32.git
[submodule "ext/nordic/nrf"]
path = ext/nordic/nrf
url = https://github.com/elli89/cmsis-header-nrf.git
[submodule "ext/modm-devices"]
path = ext/modm-devices
url = https://github.com/modm-io/modm-devices.git
url = https://github.com/elli89/modm-devices.git
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've looked at this repo, it looks manually copied? Where from? I'm seeing a lot of linker script and so many header files it would be nice to have the some folders that structure this just a little bit (at least by family?). Preferrably automated via update.py similiar to the other cmsis-header repos to simplify maintenance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, never mind, I just looked at the top-level nrf.h file and it looks like it is not meant to be split apart by family. Let's keep this in mind as a future goal, currently this copies all family files, which is unfortunate.

[submodule "ext/dlr/scons-build-tools"]
path = ext/dlr/scons-build-tools
url = https://github.com/modm-io/scons-build-tools.git
Expand Down
31 changes: 31 additions & 0 deletions examples/nrf/blink/main.cpp
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2010-2011, Fabian Greif
* Copyright (c) 2013-2014, 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 <modm/platform.hpp>

using namespace modm::platform;

typedef GpioOutputP0_22 Led;

int
main()
{
Led::setOutput();

while (true)
{
Led::toggle();

modm::delay_ms(1000);
}
}

14 changes: 14 additions & 0 deletions examples/nrf/blink/project.xml
@@ -0,0 +1,14 @@
<library>
<options>
<option name="modm:target">nrf52840-xxaa</option>
<option name="modm:build:build.path">../../../../build/nrf/blink</option>
</options>
<modules>
<module>modm:architecture:delay</module>
<module>modm:platform:core</module>
<module>modm:platform:clock</module>
<module>modm:platform:hfclk</module>
<module>modm:platform:gpio</module>
<module>modm:build:scons</module>
</modules>
</library>
2 changes: 1 addition & 1 deletion ext/modm-devices
29 changes: 29 additions & 0 deletions ext/nordic/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 <stdint.h>
// Defines for example the modm_always_inline macro
#include <modm/architecture/utils.hpp>

// Include external device headers:
%% for header in headers
#include <{{ header }}>
%% endfor

#endif // MODM_DEVICE_HPP
70 changes: 70 additions & 0 deletions ext/nordic/module.lb
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2019, Niklas Hauser
# Copyright (c) 2020, Hannes Ellinger
#
# 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"] != "nrf":
return False

module.depends(":cmsis:core")
return True

pp = {}
def validate(env):
device = env[":target"]
device_name = device.identifier.string.split("-")[0]

define = "{}".format(device_name.upper())
family_file = None
famfile = Path(localpath("nrf/nrf.h"))
content = famfile.read_text(encoding="utf-8", errors="replace")
match = re.findall(r"defined \((?P<define>_?.*)\)", content)
for m in match:
if define in m:
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(device_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/cmsis/device")

env.outbasepath = "modm/ext/cmsis/device"
files = [pp["device_header"], "system_"+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")
1 change: 1 addition & 0 deletions ext/nordic/nrf
Submodule nrf added at 5972dc
1 change: 1 addition & 0 deletions repo.lb
Expand Up @@ -85,6 +85,7 @@ class DevicesCache(dict):
"stm32g0", "stm32g4",
"stm32l1", "stm32l4",
"at90", "attiny", "atmega",
"nrf",
"hosted"]
device_file_names = [dfn for dfn in device_file_names if any(s in dfn for s in supported)]

Expand Down
20 changes: 20 additions & 0 deletions src/modm/platform/clock/nrf/hfclk.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 "hfclk.hpp"

namespace modm::platform
{
uint16_t modm_fastdata delay_fcpu_MHz(64);
uint16_t modm_fastdata delay_ns_per_loop({{ loops * 1000 / 64 }});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core runs at 64MHz right after boot? This should be set to the default clock frequency which is probably much less than 64MHz.

}
35 changes: 35 additions & 0 deletions src/modm/platform/clock/nrf/hfclk.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 <stdint.h>
#include "../device.hpp"

namespace modm::platform
{

/**
* Clock management
*
* \ingroup modm_platform_hfclk
*/
class HighFrequencyClockController
{
public:
template< uint32_t Core_Hz >
void
updateCoreFrequency();
};

}

#include "hfclk_impl.hpp"
30 changes: 30 additions & 0 deletions src/modm/platform/clock/nrf/hfclk_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 <cmath>

namespace modm::platform
{
/// @cond
extern uint16_t delay_fcpu_MHz;
extern uint16_t delay_ns_per_loop;
/// @endcond

template< uint32_t Core_Hz >
void
HighFrequencyClockController::updateCoreFrequency()
{
delay_fcpu_MHz = Core_Hz / 64'000'000;
delay_ns_per_loop = ::round({{loops}}000.f / (Core_Hz / 64'000'000));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

divide by 1MHz.

}

}

40 changes: 40 additions & 0 deletions src/modm/platform/clock/nrf/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:hfclk"
module.description = "High Frequency Clock Controller (HFCLK)"

def prepare(module, options):
if not options[":target"].has_driver("clock", ["nrf51", "nrf52"]):
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("hfclk.hpp")
env.template("hfclk.cpp.in")
env.template("hfclk_impl.hpp.in")
50 changes: 50 additions & 0 deletions src/modm/platform/core/nrf/linkerscript/nrf.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() }}
}