diff --git a/README.md b/README.md
index 36980e32..557134ec 100644
--- a/README.md
+++ b/README.md
@@ -46,4 +46,99 @@ information, assuming GNAT is installed in ~/install/gnat, run the following:
```
gprbuild -P ~/install/gnat/arm-eabi/lib/gnat/ravenscar-sfp-stm32f4/ravenscar-build.gpr -XBUILD=Debug
+```
+
+## customizing runtimes
+
+Some targets are configurable and allow certain parts of the runtime to be customized during generation.
+For example, with a custom system clock configuration.
+
+The configuration for such runtimes are defined in a JSON file in the following format:
+
+```json
+{
+ "base_target": "",
+ "board_name": "",
+ "board_params": {
+ "param1": 123,
+ "param2": "example",
+ "param3": True
+ }
+}
+```
+
+* `base_target` is the name of the target that will be customized. This can be any runtime
+supported by bb-runtimes, but note that not all targets can be customized. Targets that are
+not customizable will ignore the contents of `board_params`.
+
+* `board_name` sets the name of the generated runtime.
+
+* `board_params` sets the board parameters to use when generating the runtime.
+The set of available board parameters depends on the chosen `base_target`. See the following
+sub-sections of this README for a list of available parameters for each target.
+
+All board parameters are optional. Board parameters that are not defined will use their default value.
+Unrecognized board parameters are ignored.
+
+To generate a runtime with the custom configuration, pass the name of the JSON file to build_rts.py:
+
+```
+./build_rts.py --output=temp --build my-board.json ...
+```
+
+**Note:** The file name *must* end in `.json`
+
+The available board parameters for each customizable `base_target` are described in the following sub-sections:
+
+### stm32f0xx board parameters
+
+These are the board parameters for stm32f0xx `base_target`s:
+
+**Note:** The `base_target` is the full STM32 device name, e.g. "stm32f072rb", or "stm32f030r8".
+
+| Parameter | Type | Default Value | Description |
+|:------------------:|:-----:|:-------------:|:-------------------------------------------------|
+| `sysclk_frequency` | `int` | 48000000 | Configures the target SYSCLK (and CPU) frequency (in Hz). |
+| `hse_frequency` | `int` | 8000000 | Specifies the frequency (in Hz) of the board's HSE oscillator. Valid range is 4 MHz - 32 MHz. |
+| `clock_source` | `str` | "HSI" | Configures the source oscillator used to generate SYSCLK. Valid values are "HSE", "HSI", and "HSI48". |
+| `hse_bypass` | `bool` | False | Enables or disables the HSE bypass (see the STM32F0xx Reference Manual). |
+| `lsi_enabled` | `bool` | True | Enables or disables the LSI oscillator at startup. |
+| `apb_prescaler` | `int` | 1 | Configures the APB prescaler. Valid values are: 1, 2, 4, 8, 16. |
+
+Here is an example configuration to generate a runtime for the Nucleo-F072RB board from ST (no external HSE oscillator fitted):
+
+```json
+{
+ "base_target": "stm32f072rb",
+ "board_name": "nucleo-f072rb",
+ "board_params": {
+ "sysclk_frequency": 48000000,
+ "clock_source": "HSI"
+ }
+}
+```
+
+### nRF52 board parameters
+
+These are the board parameters for the nrf52832 and nrf52840 `base_target`s:
+
+| Parameter | Type | Default Value | Description |
+|:-----------:|:------:|:-------------:|:-------------------------------------------------|
+| `use_hfxo` | `bool` | False | Selects whether the high-frequency external oscillator (HFXO) is enabled at startup. When False the internal oscillator is used by default. |
+| `lfclk_src` | `str` | "Xtal" | Selects the clock source used for the low-frequency (32 kHz) clock that drives the RTC peripherals. Valid values are: "Xtal", "Rc", and "Synth" |
+| `use_swo_trace` | `bool` | True | Set to True to configure the SWO trace pins to enable debugging. When False,the SWO pins are not configured. |
+| `use_reset_pin` | `bool` | True | Set to True to configure pin P0.18 as the reset pin. When False, the reset pin is not configured. |
+| `alarm_rtc_periph` | `str` | "RTC0" | Selects which RTC peripheral is used to implement the clock for Ravenscar delays (Ada.Real_Time). Valid values are: "RTC0", "RTC1", "RTC2" |
+
+Here is an example configuration to generate a runtime that enables the HFXO at startup, and uses RTC1 for Ravenscar delays:
+
+```json
+{
+ "base_target": "nrf52840",
+ "board_name": "my-board",
+ "board_params": {
+ "use_hfxo": True,
+ "alarm_rtc_periph": "RTC1"
+ }
+}
```
\ No newline at end of file
diff --git a/arm/cortexm.py b/arm/cortexm.py
index 7a8b2dce..91c4fa0b 100644
--- a/arm/cortexm.py
+++ b/arm/cortexm.py
@@ -403,55 +403,6 @@ class Stm32F0(CortexM0CommonArchSupport):
'vb': 16,
}
- # Board parameters (for s-bbmcpa.ads) when HSE is used.
- # For now these are hard-coded. These could be calculated
- # from a configurable HSE clock frequency in a future
- # improvement.
- board_parameters_hse = {
- 'STM32_Main_Clock_Frequency': '48_000_000',
- 'STM32_HSE_Clock_Frequency': '8_000_000',
- 'STM32_HSE_Bypass': 'False',
- 'STM32_LSI_Enabled': 'True',
- 'STM32_PLL_Src': 'System.STM32.PLL_SRC_HSE_PREDIV',
- 'STM32_SYSCLK_Src': 'System.STM32.SYSCLK_SRC_PLL',
- 'STM32_PREDIV': '1',
- 'STM32_PLLMUL_Value': '6',
- 'STM32_AHB_PRE': 'System.STM32.AHBPRE_DIV1',
- 'STM32_APB_PRE': 'System.STM32.APBPRE_DIV1'
- }
-
- # Board parameters (for s-bbmcpa.ads) when HSI is used.
- # These parameters are suitable for the clock tree in
- # F04x, F07x, and F09x devices.
- board_parameters_hsi = {
- 'STM32_Main_Clock_Frequency': '48_000_000',
- 'STM32_HSE_Clock_Frequency': '8_000_000',
- 'STM32_HSE_Bypass': 'False',
- 'STM32_LSI_Enabled': 'True',
- 'STM32_PLL_Src': 'System.STM32.PLL_SRC_HSI_PREDIV',
- 'STM32_SYSCLK_Src': 'System.STM32.SYSCLK_SRC_PLL',
- 'STM32_PREDIV': '1',
- 'STM32_PLLMUL_Value': '6',
- 'STM32_AHB_PRE': 'System.STM32.AHBPRE_DIV1',
- 'STM32_APB_PRE': 'System.STM32.APBPRE_DIV1'
- }
-
- # Board parameters (for s-bbmcpa.ads) when HSI is used.
- # These parameters are suitable for the clock tree in
- # F03x and F05x devices (fixed /2 divider on HSI).
- board_parameters_hsi2 = {
- 'STM32_Main_Clock_Frequency': '48_000_000',
- 'STM32_HSE_Clock_Frequency': '8_000_000',
- 'STM32_HSE_Bypass': 'False',
- 'STM32_LSI_Enabled': 'True',
- 'STM32_PLL_Src': 'System.STM32.PLL_SRC_HSI_2',
- 'STM32_SYSCLK_Src': 'System.STM32.SYSCLK_SRC_PLL',
- 'STM32_PREDIV': '1',
- 'STM32_PLLMUL_Value': '12',
- 'STM32_AHB_PRE': 'System.STM32.AHBPRE_DIV1',
- 'STM32_APB_PRE': 'System.STM32.APBPRE_DIV1'
- }
-
@property
def name(self):
return self.board
@@ -464,23 +415,20 @@ def use_semihosting_io(self):
def loaders(self):
return ('ROM', 'RAM')
- def __init__(self, board):
+ def __init__(self, board_name, base_target, board_params):
super(Stm32F0, self).__init__()
- # Determine MCU features from board name (e.g. 'stm32f071rb-hse')
- # The -hse or -hsi suffix specifies which clock source to
- # use for the runtime (either HSE or HSI)
- m = re.match(r'.*f0([34579])([0128])([cefgkrv])([468bc])-(hsi|hse)',
- board)
+ # Determine MCU features from target name (e.g. 'stm32f071rb')
+ m = re.match(r'.*f0([34579])([0128])([cefgkrv])([468bc])',
+ base_target)
if m is None:
- raise RuntimeError("Unknown STM32F0 target: " + board)
+ raise RuntimeError("Unknown STM32F0 target: " + base_target)
sub_family_major = m.group(1)
sub_family_minor = m.group(2)
package = m.group(3)
user_code_memory_size = m.group(4)
- clock_source = m.group(5)
- self.board = board
+ self.board = board_name
# Determine RAM size from sub-family, package, and user code mem. size
if sub_family_major == '3':
@@ -529,33 +477,151 @@ def __init__(self, board):
'/svd/i-stm32-rcc.ads').format(sub_family_minor))
# Configure MCU parameters based on family.
- if sub_family_major in '479':
- self.add_template_config_value('STM32_Simple_Clock_Tree', 'False')
- else:
- self.add_template_config_value('STM32_Simple_Clock_Tree', 'True')
-
- # Configure board parameters based on chosen clock source (HSE or HSI)
- # and the device family.
- if clock_source == 'hse':
- for key, value in self.board_parameters_hse.items():
- self.add_template_config_value(key, value)
-
- elif sub_family_major in '479':
- # STM32F04x/STM32F07x/STM32F09x can use HSI directly
- # as PLL input.
- for key, value in self.board_parameters_hsi.items():
- self.add_template_config_value(key, value)
-
- else:
- # STM32F03x/STM32F05x are forced to HSI/2 as PLL input.
- for key, value in self.board_parameters_hsi2.items():
- self.add_template_config_value(key, value)
+ simple_clock_tree = (sub_family_major in '35')
+ self.add_template_config_value('STM32_Simple_Clock_Tree',
+ str(simple_clock_tree))
+
+ # Determine clock configuration from provided board_parameters.
+ clock_configs = self._configure_clocks(board_params,
+ simple_clock_tree)
+ for key, value in clock_configs.items():
+ self.add_template_config_value(key, value)
# Choose interrupt names based on family
self.add_gnarl_sources(
('arm/stm32/stm32f0xx/stm32f0x{}/'
'svd/a-intnam.ads').format(sub_family_minor))
+ def _configure_clocks(self, board_params, simple_clock_tree):
+ sysclk_freq = board_params.get('sysclk_frequency', 48000000)
+ hse_freq = board_params.get('hse_frequency', 8000000)
+ clock_source = board_params.get('clock_source', 'HSI')
+ hse_bypass = bool(board_params.get('hse_bypass', False))
+ lsi_enabled = bool(board_params.get('lsi_enabled', True))
+ apb_prescaler = board_params.get('apb_prescaler', 1)
+
+ assert clock_source in ['HSI', 'HSE', 'HSI48'], \
+ 'Invalid clock_source: {}'.format(clock_source)
+
+ if simple_clock_tree:
+ assert clock_source != 'HSI48', \
+ 'HSI48 is not available for STM32f03x and STM32F05x devices'
+
+ assert apb_prescaler in [1, 2, 4, 8, 16], \
+ 'Invalid apb_prescaler: {}'.format(apb_prescaler)
+
+ assert hse_freq in range(4000000, 32000001), \
+ 'Invalid hse_frequency: {} (must be 4-32 MHz)'.format(hse_freq)
+
+ hsi_freq = 8000000
+ pllin_freq = None # Don't use PLL unless needed below
+ pllsrc = 'HSI_2' # Default, might be overriden below
+
+ # Determine SYSCLK source from the configured clock_source and
+ # target sysclk_frequency.
+ #
+ # Note that the PLL is only used to generate SYSCLK if the
+ # target SYSCLK frequency is not exactly equal to the frequency
+ # of the clock source. Otherwise, the PLL is not used to save power.
+
+ if clock_source == 'HSE':
+ # Only enable PLL if needed to attain target SYSCLK frequency.
+ if sysclk_freq == hse_freq:
+ sysclk_src = 'HSE'
+ else:
+ sysclk_src = 'PLL'
+ pllsrc = 'HSE_PREDIV'
+ pllin_freq = hse_freq
+
+ elif clock_source == 'HSI':
+ if sysclk_freq == hsi_freq:
+ sysclk_src = 'HSI'
+
+ else:
+ sysclk_src = 'PLL'
+ if simple_clock_tree:
+ # Fixed /2 divider on F03x and F05x devices
+ pllsrc = 'HSI_2'
+ pllin_freq = hsi_freq / 2
+ else:
+ pllsrc = 'HSI_PREDIV'
+ pllin_freq = hsi_freq
+
+ elif clock_source == 'HSI48':
+ sysclk_src = 'HSI48'
+ assert sysclk_freq == 48000000, \
+ 'sysclk_frequency must be 48000000 ' \
+ 'when clock_source is HSI48'
+
+ if pllin_freq is None:
+ # PLL not needed. Set defaults
+ prediv = 1
+ pllmul = 2 # minimum allowed value
+ else:
+ # PLL needed to obtain target main clock frequency.
+ # Brute force all possible PREDIV and PLLMUL values to find the
+ # configuration that generates the target frequency.
+ pll_configs = []
+
+ for prediv in range(1, 17):
+ # PREDIV not available on simple clock tree devices
+ if pllsrc != 'HSI_2' or prediv == 1:
+ for pllmul in range(2, 17):
+ pllout_freq = int((pllin_freq / prediv) * pllmul)
+
+ # Only accept configurations that result in the
+ # target SYSCLK speed.
+ #
+ # Also ensure the PLL output frequency is in the
+ # range 16-48 MHz.
+ if pllout_freq == sysclk_freq and \
+ pllout_freq >= 16000000 and \
+ pllout_freq <= 48000000:
+ pll_configs.append({
+ 'PREDIV': 1,
+ 'PLLMUL': pllmul,
+ 'PLLOUT_FREQ': pllout_freq
+ })
+
+ # Check that there is at least one configuration that generates
+ # the requested clock speed. This fails if there is no possible
+ # PLL configuration that can generate the requested frequency.
+ assert len(pll_configs) > 0, \
+ 'Cannot generate requested sysclk_frequency of ' + \
+ '{} Hz '.format(sysclk_freq) + \
+ 'from the requested clock_source ({})'.format(clock_source)
+
+ # Use first valid PLL configuration found.
+ cfg = pll_configs[0]
+ prediv = cfg['PREDIV']
+ pllmul = cfg['PLLMUL']
+ pllout_freq = cfg['PLLOUT_FREQ']
+
+ # Choose configuration value for STM32_APB_PRE
+ if apb_prescaler == 1:
+ stm32_apb_pre = 'System.STM32.APBPRE_DIV1'
+ else:
+ stm32_apb_pre = '(Enabled => True, Value => System.STM32.DIV{})' \
+ .format(apb_prescaler)
+
+ # AHB_PRE is fixed to 1 in the current implementation, since
+ # the implementation of System.BB.Parameters assumes that the
+ # processor frequency (Clock_Frequency) is equal to
+ # Main_Clock_Frequency, which is set to SYSCLK.
+
+ return {
+ 'STM32_Main_Clock_Frequency': str(sysclk_freq),
+ 'STM32_HSE_Clock_Frequency': str(hse_freq),
+ 'STM32_HSE_Bypass': str(hse_bypass),
+ 'STM32_LSI_Enabled': str(lsi_enabled),
+ 'STM32_PLL_Src': 'System.STM32.PLL_SRC_' + pllsrc,
+ 'STM32_SYSCLK_Src': 'System.STM32.SYSCLK_SRC_' + sysclk_src,
+ 'STM32_PREDIV': str(prediv),
+ 'STM32_PLLMUL_Value': str(pllmul),
+ 'STM32_AHB_PRE': 'System.STM32.AHBPRE_DIV1',
+ 'STM32_APB_PRE': stm32_apb_pre
+ }
+
class CortexM1CommonArchSupport(ArmV6MTarget):
@property
@@ -691,7 +757,7 @@ def __init__(self):
class NRF52(ArmV7MTarget):
@property
def name(self):
- return 'nRF52'
+ return self.board
@property
def parent(self):
@@ -721,9 +787,11 @@ def compiler_switches(self):
return ('-mlittle-endian', '-mthumb', '-mhard-float',
'-mfpu=fpv4-sp-d16', '-mcpu=cortex-m4')
- def __init__(self):
+ def __init__(self, board_name, board_params):
super(NRF52, self).__init__()
+ self.board = board_name
+
self.add_linker_script('arm/nordic/nrf52/common-ROM.ld', loader='ROM')
self.add_linker_script('arm/nordic/nrf52/memory-map_%s.ld' % self.name,
'memory-map.ld')
@@ -736,9 +804,53 @@ def __init__(self):
self.add_gnarl_sources(
'src/s-bbpara__nrf52.ads',
- 'src/s-bbbosu__nrf52.adb',
+ 'src/s-bbbosu__nrf52.adb.tmpl',
'src/s-bcpcst__pendsv.adb')
+ use_hfxo = board_params.get('use_hfxo', False)
+ lfclk_src = board_params.get('use_hfxo', 'Xtal')
+ use_swo_trace = board_params.get('use_swo_trace', True)
+ use_reset_pin = board_params.get('use_reset_pin', True)
+ alarm_rtc_periph = board_params.get('alarm_rtc_periph', 'RTC0')
+
+ assert type(use_hfxo) == bool, "use_hfxo must be of type bool"
+
+ assert type(use_swo_trace) == bool, \
+ "use_swo_trace must be of type bool"
+
+ assert type(use_reset_pin) == bool, \
+ "use_reset_pin must be of type bool"
+
+ assert lfclk_src in ["Xtal", "Rc", "Synth"], \
+ "Invalid value for lfclk_src." \
+ "Valid values are: 'Xtal', 'Rc', 'Synth'"
+
+ assert alarm_rtc_periph in ["RTC0", "RTC1", "RTC2"], \
+ "Invalid value for alarm_rtc_periph." \
+ "Valid values are: 'RTC0', 'RTC1', 'RTC2'"
+
+ self.add_template_config_value("NRF52_Use_HFXO",
+ str(use_hfxo))
+ self.add_template_config_value("NRF52_LFCLK_Src",
+ lfclk_src)
+ self.add_template_config_value("NRF52_Use_SWO_Trace",
+ str(use_swo_trace))
+ self.add_template_config_value("NRF52_Use_Reset_Pin",
+ str(use_reset_pin))
+ self.add_template_config_value("NRF52_Alarm_RTC_Periph",
+ str(alarm_rtc_periph))
+
+ # s-bbbosu.adb cannot depend on Ada.Interrupt.Names to get the
+ # selected RTC peripheral's Interrupt_ID, so it is passed in
+ # as a template parameter.
+ alarm_interrupt_ids = {
+ "RTC0": "11",
+ "RTC1": "17",
+ "RTC2": "36"
+ }
+ self.add_template_config_value("NRF52_Alarm_Interrupt_ID",
+ alarm_interrupt_ids[alarm_rtc_periph])
+
class NRF52840(NRF52):
@property
@@ -749,12 +861,12 @@ def name(self):
def use_semihosting_io(self):
return True
- def __init__(self):
- super(NRF52840, self).__init__()
+ def __init__(self, board_name, board_params):
+ super(NRF52840, self).__init__(board_name, board_params)
self.add_gnat_sources(
'arm/nordic/nrf52/nrf52840/s-bbbopa.ads',
- 'arm/nordic/nrf52/nrf52840/setup_board.adb',
+ 'arm/nordic/nrf52/nrf52840/setup_board.adb.tmpl',
'arm/nordic/nrf52/nrf52840/svd/i-nrf52.ads',
'arm/nordic/nrf52/nrf52840/svd/i-nrf52-ccm.ads',
'arm/nordic/nrf52/nrf52840/svd/i-nrf52-clock.ads',
@@ -778,12 +890,12 @@ def name(self):
def use_semihosting_io(self):
return True
- def __init__(self):
- super(NRF52832, self).__init__()
+ def __init__(self, board_name, board_params):
+ super(NRF52832, self).__init__(board_name, board_params)
self.add_gnat_sources(
'arm/nordic/nrf52/nrf52832/s-bbbopa.ads',
- 'arm/nordic/nrf52/nrf52832/setup_board.adb',
+ 'arm/nordic/nrf52/nrf52832/setup_board.adb.tmpl',
'arm/nordic/nrf52/nrf52832/svd/i-nrf52.ads',
'arm/nordic/nrf52/nrf52832/svd/i-nrf52-clock.ads',
'arm/nordic/nrf52/nrf52832/svd/i-nrf52-ficr.ads',
diff --git a/arm/nordic/nrf52/nrf52832/setup_board.adb b/arm/nordic/nrf52/nrf52832/setup_board.adb.tmpl
similarity index 98%
rename from arm/nordic/nrf52/nrf52832/setup_board.adb
rename to arm/nordic/nrf52/nrf52832/setup_board.adb.tmpl
index 6b177067..b9b516eb 100644
--- a/arm/nordic/nrf52/nrf52832/setup_board.adb
+++ b/arm/nordic/nrf52/nrf52832/setup_board.adb.tmpl
@@ -56,21 +56,21 @@ procedure Setup_Board is
-- Board Configuration --
---------------------------
- Use_HFXO : constant Boolean := False;
+ Use_HFXO : constant Boolean := "${NRF52_Use_HFXO}";
-- Set to True to use the high-frequency external oscillator (HFXO).
-- When False, the on-chip oscillator is used.
-- The HFXO can also be turned on and off later by the main program.
- LFCLK_Source : constant LFCLKSRC_SRC_Field := Xtal;
+ LFCLK_Source : constant LFCLKSRC_SRC_Field := "${NRF52_LFCLK_Src}";
-- Selects the source for the LFCLK.
-- Xtal selects the external 32.768 kHz crystal (LFXO).
-- Rc selects the internal 32.768 kHz RC oscillator.
-- Synth selects the LFCLK synthesized from the 16 MHz HFCLK.
- Use_SWO_Trace : constant Boolean := True;
+ Use_SWO_Trace : constant Boolean := "${NRF52_Use_SWO_Trace}";
-- Set to True to enable the SWO trace pins.
- Use_Reset_Pin : constant Boolean := True;
+ Use_Reset_Pin : constant Boolean := "${NRF52_Use_Reset_Pin}";
-- When True, P0.18 will be configured as the reset pin.
--------------------------
diff --git a/arm/nordic/nrf52/nrf52840/setup_board.adb b/arm/nordic/nrf52/nrf52840/setup_board.adb.tmpl
similarity index 97%
rename from arm/nordic/nrf52/nrf52840/setup_board.adb
rename to arm/nordic/nrf52/nrf52840/setup_board.adb.tmpl
index d376554c..57acaa51 100644
--- a/arm/nordic/nrf52/nrf52840/setup_board.adb
+++ b/arm/nordic/nrf52/nrf52840/setup_board.adb.tmpl
@@ -56,21 +56,21 @@ procedure Setup_Board is
-- Board Configuration --
---------------------------
- Use_HFXO : constant Boolean := False;
+ Use_HFXO : constant Boolean := "${NRF52_Use_HFXO}";
-- Set to True to use the high-frequency external oscillator (HFXO).
-- When False, the on-chip oscillator is used.
-- The HFXO can also be turned on and off later by the main program.
- LFCLK_Source : constant LFCLKSRC_SRC_Field := Xtal;
+ LFCLK_Source : constant LFCLKSRC_SRC_Field := "${NRF52_LFCLK_Src}";
-- Selects the source for the LFCLK.
-- Xtal selects the external 32.768 kHz crystal (LFXO).
-- Rc selects the internal 32.768 kHz RC oscillator.
-- Synth selects the LFCLK synthesized from the 16 MHz HFCLK.
- Use_SWO_Trace : constant Boolean := True;
+ Use_SWO_Trace : constant Boolean := "${NRF52_Use_SWO_Trace}";
-- Set to True to enable the SWO trace pins.
- Use_Reset_Pin : constant Boolean := True;
+ Use_Reset_Pin : constant Boolean := "${NRF52_Use_Reset_Pin}";
-- When True, P0.18 will be configured as the reset pin.
LFRC_Used : constant Boolean := LFCLK_Source = Rc;
diff --git a/build_rts.py b/build_rts.py
index baac8a1a..e3b68847 100755
--- a/build_rts.py
+++ b/build_rts.py
@@ -45,12 +45,13 @@
from native import X86Native, X8664Native
import argparse
+import json
import os
import subprocess
import sys
-def build_configs(target):
+def build_configs(target, board_name, board_params={}):
# PikeOS
if target == 'arm-pikeos':
t = ArmPikeOS()
@@ -77,7 +78,7 @@ def build_configs(target):
elif target.startswith('smartfusion2'):
t = SmartFusion2()
elif target.startswith('stm32f0'):
- t = Stm32F0(target)
+ t = Stm32F0(board_name, target, board_params)
elif target.startswith('stm32'):
t = Stm32(target)
elif target == 'feather_stm32f405':
@@ -102,9 +103,9 @@ def build_configs(target):
elif target == 'microbit':
t = Microbit()
elif target == 'nrf52840':
- t = NRF52840()
+ t = NRF52840(board_name, board_params)
elif target == 'nrf52832':
- t = NRF52832()
+ t = NRF52832(board_name, board_params)
elif target == "microsemi-m1":
t = MicrosemiM1()
elif target == 'cortex-m0':
@@ -180,6 +181,15 @@ def build_configs(target):
return t
+def build_custom_configs(json_file):
+ with open(json_file, 'r') as fp:
+ cnt = fp.read()
+ cnt = json.loads(cnt)
+ return build_configs(target=cnt['base_target'],
+ board_name=cnt['board_name'],
+ board_params=cnt.get('board_params', {}))
+
+
def main():
parser = argparse.ArgumentParser()
@@ -222,7 +232,10 @@ def main():
boards = []
for arg in args.target:
- board = build_configs(arg)
+ if arg.endswith('.json'):
+ board = build_custom_configs(arg)
+ else:
+ board = build_configs(arg, arg)
boards.append(board)
dest = os.path.abspath(args.output)
diff --git a/install.py b/install.py
index 3bd708b9..876c36e6 100755
--- a/install.py
+++ b/install.py
@@ -26,7 +26,7 @@ def usage():
'stm32f469disco',
'stm32f746disco', 'stm32756geval', 'stm32f769disco',
'samg55', 'sam4s', 'samv71', 'openmv2', 'rpi2',
- 'feather_stm32f405', 'stm32f051r8-hsi', 'nrf52832',
+ 'feather_stm32f405', 'stm32f051r8', 'nrf52832',
'nrf52840', 'cortex-m0', 'cortex-m0p',
'cortex-m1', 'cortex-m3', 'cortex-m4', 'cortex-m4f',
'cortex-m7f', 'cortex-m7df'
diff --git a/src/s-bbbosu__nrf52.adb b/src/s-bbbosu__nrf52.adb.tmpl
similarity index 92%
rename from src/s-bbbosu__nrf52.adb
rename to src/s-bbbosu__nrf52.adb.tmpl
index cdb7e556..b0ca34d6 100644
--- a/src/s-bbbosu__nrf52.adb
+++ b/src/s-bbbosu__nrf52.adb.tmpl
@@ -56,14 +56,14 @@ package body System.BB.Board_Support is
pragma Volatile (Alarm_Time);
pragma Export (C, Alarm_Time, "__gnat_alarm_time");
- Alarm_Interrupt_ID : constant Interrupt_ID := 11; -- RTC0 IRQ
+ Alarm_Interrupt_ID : constant Interrupt_ID := "${NRF52_Alarm_Interrupt_ID}";
-------------------
- -- RTC0 Handling --
+ -- RTC Handling --
-------------------
- -- RTC0 is used as the clock source, which we use to implement
- -- "tick-less" alarm handling.
+ -- An RTC peripheral is used as the clock source, which we use to
+ -- implement "tick-less" alarm handling.
--
-- The RTC is a 24-bit timer running at 32.768 kHz, resulting in a period
-- of 512 seconds (2**24 / 32_768).
@@ -71,13 +71,15 @@ package body System.BB.Board_Support is
-- We use the COMPARE feature of the RTC to provide accurate alarms.
-- We achieve this by updating CC[0] each time Set_Alarm is called so
-- that the alarm is triggered exactly at the alarm time. This results in
- -- an alarm accuracy of 30.518 µs.
+ -- an alarm accuracy of 30.518 us.
--
-- Note that the underlying 24-bit RTC runs at a frequency of 32.768 kHz,
-- but Timer_Interval is scaled up that, at 65.536 kHz ticks (or higher,
-- depending on RTC_Tick_Scaling_Factor) to ensure that
-- Ada.Real_Time.Time_Unit meets the requirements in Ada RM D.8/30
+ Alarm_RTC : RTC_Peripheral renames "${NRF52_Alarm_RTC_Periph}"_Periph;
+
----------------------------------------------
-- New Vectored Interrupt Controller (NVIC) --
----------------------------------------------
@@ -138,12 +140,12 @@ package body System.BB.Board_Support is
-- Timer --
- -- The 32.768 kHz RTC0 peripheral is used as the clock source on this
+ -- The 32.768 kHz RTC peripheral is used as the clock source on this
-- board. This is used instead of the SysTick timer because the "wfi"
-- instruction (used for entering the CPU sleep mode to save power)
-- powers down the entire CPU, *including* the SysTick.
-- Since we still want to use "wfi" to save power whilst keeping task
- -- delays alive, we instead use the RTC0 peripheral.
+ -- delays alive, we instead use the RTC peripheral.
-- Start LFCLK
-- We assume that the LFCLK source (Xtal, Rc, or Synth) has already been
@@ -160,22 +162,22 @@ package body System.BB.Board_Support is
others => <>);
-- Ensure RTC is stopped.
- RTC0_Periph.TASKS_STOP := (TASKS_STOP => 1, others => <>);
+ Alarm_RTC.TASKS_STOP := (TASKS_STOP => 1, others => <>);
-- Set to 0 before setting TASKS_CLEAR to prevent triggering a COMPARE
-- event.
- RTC0_Periph.CC (0).COMPARE := 0;
+ Alarm_RTC.CC (0).COMPARE := 0;
-- Clear RTC
- RTC0_Periph.TASKS_CLEAR := (TASKS_CLEAR => 1, others => <>);
+ Alarm_RTC.TASKS_CLEAR := (TASKS_CLEAR => 1, others => <>);
-- Run at 32.768 kHz
- RTC0_Periph.PRESCALER.PRESCALER := 0;
+ Alarm_RTC.PRESCALER.PRESCALER := 0;
-- Enable CC[0] interrupt only; TICK and OVRFLW aren't needed.
- RTC0_Periph.INTENSET.TICK := Intenset_Tick_Field_Reset;
- RTC0_Periph.INTENSET.OVRFLW := Intenset_Ovrflw_Field_Reset;
- RTC0_Periph.INTENSET.COMPARE := (As_Array => False, -- Use COMPARE0
+ Alarm_RTC.INTENSET.TICK := Intenset_Tick_Field_Reset;
+ Alarm_RTC.INTENSET.OVRFLW := Intenset_Ovrflw_Field_Reset;
+ Alarm_RTC.INTENSET.COMPARE := (As_Array => False, -- Use COMPARE0
Val => 2#0001#);
Time.Set_Alarm (Max_Timer_Interval);
@@ -224,7 +226,7 @@ package body System.BB.Board_Support is
-- Double the value of the COUNTER register since the RTC runs at
-- 32.768 kHz, but our Timer_Interval values are in scaled up units
-- (e.g. 65.536 kHz if RTC_Tick_Scaling_Factor is 2)
- Res := Timer_Interval (RTC0_Periph.COUNTER.COUNTER);
+ Res := Timer_Interval (Alarm_RTC.COUNTER.COUNTER);
Res := Res * BBOPA.RTC_Tick_Scaling_Factor;
-- Restore interrupt mask
@@ -245,7 +247,7 @@ package body System.BB.Board_Support is
-- Only clear the COMPARE event; don't clear OVRFLW here since we
-- read (and clear) that event in Read_Clock to return the correct
-- time when an overflow occurs.
- RTC0_Periph.EVENTS_COMPARE (0) := (EVENTS_COMPARE => 0, others => <>);
+ Alarm_RTC.EVENTS_COMPARE (0) := (EVENTS_COMPARE => 0, others => <>);
end Clear_Alarm_Interrupt;
---------------
@@ -273,9 +275,9 @@ package body System.BB.Board_Support is
RTC_Ticks := UInt24'Max (RTC_Ticks, 2);
-- Set an interrupt to trigger after the requested number of ticks.
- RTC_Counter := RTC0_Periph.COUNTER.COUNTER;
+ RTC_Counter := Alarm_RTC.COUNTER.COUNTER;
CC0_Value := RTC_Counter + RTC_Ticks;
- RTC0_Periph.CC (0).COMPARE := CC0_Value;
+ Alarm_RTC.CC (0).COMPARE := CC0_Value;
-- Note that the RTC might have ticked between reading COUNTER and
-- setting CC[0], which may break the guarantee that CC[0] is always
@@ -288,7 +290,7 @@ package body System.BB.Board_Support is
-- This might result in an extra unecessary interrupt just before
-- the alarm time, but ensures the alarm time is not missed.
- RTC_Counter := RTC0_Periph.COUNTER.COUNTER;
+ RTC_Counter := Alarm_RTC.COUNTER.COUNTER;
RTC_Ticks_Until_Alarm := CC0_Value - RTC_Counter;
if RTC_Ticks_Until_Alarm < 2
@@ -296,7 +298,7 @@ package body System.BB.Board_Support is
or RTC_Ticks_Until_Alarm > RTC_Ticks
then
CC0_Value := RTC_Counter + RTC_Ticks;
- RTC0_Periph.CC (0).COMPARE := CC0_Value;
+ Alarm_RTC.CC (0).COMPARE := CC0_Value;
Trigger_Interrupt (Alarm_Interrupt_ID);
end if;
@@ -318,7 +320,7 @@ package body System.BB.Board_Support is
Time.Clear_Alarm_Interrupt;
-- Now that the interrupt handler is attached, we can start the timer
- RTC0_Periph.TASKS_START := (TASKS_START => 1, others => <>);
+ Alarm_RTC.TASKS_START := (TASKS_START => 1, others => <>);
end Install_Alarm_Handler;
end Time;
diff --git a/support/files_holder.py b/support/files_holder.py
index 2aca35d9..0dbca8dc 100644
--- a/support/files_holder.py
+++ b/support/files_holder.py
@@ -189,7 +189,16 @@ def add_source(self, dir, src):
SRC is the full name of the file to copy"""
base = os.path.basename(src)
# A file could have `.` in its name. (eg: pikeos4.2-cert-app.c)
- _, ext = base.rsplit('.', 1)
+ #
+ # Template files have a .tmpl extension, which needs to be kept.
+ # Example:
+ # s-textio__myboard.adb.tmpl should aliased as s-myboard.adb.tmpl
+ # The .tmpl extension is kept for now as it is removed later in
+ # the installation process.
+ if base.endswith('.tmpl'):
+ _, ext, _ = base.rsplit('.', 2)
+ else:
+ _, ext = base.rsplit('.', 1)
# Check if the basename of the source file contains two consecutive
# underscores. This is by naming convention a file variant whose
# variant part needs to be removed before installation.