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.