diff --git a/drivers/Timer.cpp b/drivers/Timer.cpp index 5a6d7df9e4..c73dd6f10f 100644 --- a/drivers/Timer.cpp +++ b/drivers/Timer.cpp @@ -23,11 +23,13 @@ namespace mbed { Timer::Timer() : _running(), _start(), _time(), _ticker_data(get_us_ticker_data()), _lock_deepsleep(true) { + (void)ticker_read_us(_ticker_data); // Make sure h/w timer is initialized in non-critical context. reset(); } Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker_data(data), _lock_deepsleep(true) { + (void)ticker_read_us(_ticker_data); // Make sure h/w timer is initialized in non-critical context. reset(); #if DEVICE_LPTICKER _lock_deepsleep = (data != get_lp_ticker_data()); diff --git a/features/storage/nvstore/mbed_lib.json b/features/storage/nvstore/mbed_lib.json index d13cdbd4b2..a7f72acad0 100644 --- a/features/storage/nvstore/mbed_lib.json +++ b/features/storage/nvstore/mbed_lib.json @@ -27,5 +27,19 @@ "macro_name": "NVSTORE_AREA_2_SIZE", "help": "Area 2 size" } + }, + "target_overrides": { + "FUTURE_SEQUANA": { + "area_1_address": "0x100F8000", + "area_1_size": 16384, + "area_2_address": "0x100FC000", + "area_2_size": 16384 + }, + "FUTURE_SEQUANA_M0": { + "area_1_address": "0x10078000", + "area_1_size": 16384, + "area_2_address": "0x1007C000", + "area_2_size": 16384 + } } } diff --git a/targets/targets.json b/targets/targets.json index fabe6f0dc3..a2d235a741 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -4533,5 +4533,82 @@ "detect_code": ["7016"], "release_versions": ["5"], "bootloader_supported": true + }, + "MCU_PSOC6": { + "inherits": ["Target"], + "default_toolchain": "GCC_ARM", + "supported_toolchains": ["GCC_ARM", "IAR", "ARM"], + "core": "Cortex-M4F", + "OUTPUT_EXT": "hex", + "device_has": ["USTICKER", "INTERRUPTIN", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "PORTIN", "PORTOUT", "PORTINOUT", "RTC", "PWMOUT", "ANALOGIN", "ANALOGOUT", "I2C", "I2C_ASYNCH", "SPI", "SPI_ASYNCH", "STDIO_MESSAGES", "LPTICKER", "SLEEP", "FLASH" ], + "release_versions": ["5"], + "extra_labels": ["Cypress", "PSOC6"] + }, + "MCU_PSOC6_M0": { + "inherits": ["MCU_PSOC6"], + "core": "Cortex-M0+", + "macros": ["MCU_PSOC6_M0"] + }, + "MCU_PSOC6_M4": { + "inherits": ["MCU_PSOC6"], + "macros": ["MCU_PSOC6_M4"] + }, + "FUTURE_SEQUANA_M0": { + "inherits": ["MCU_PSOC6_M0"], + "supported_form_factors": ["ARDUINO"], + "device_name": "CY8C6347BZI-BLD53M0+", + "extra_labels_add": ["CY8C63XX", "FUTURE_SEQUANA"], + "macros_add": ["CY8C6347BZI_BLD53"], + "detect_code": ["6000"], + "post_binary_hook": { + "function": "PSOC6Code.complete" + }, + "config": { + "system-clock": { + "help": "Desired frequency of main clock (Hz)", + "value": "100000000UL", + "macro_name": "CY_CLK_HFCLK0_FREQ_HZ" + }, + "peri-clock": { + "help": "Desired frequency of peripheral clock (Hz)", + "value": "50000000UL", + "macro_name": "CY_CLK_PERICLK_FREQ_HZ" + }, + "m0-clock": { + "help": "Desired frequency of M0+ core clock (Hz)", + "value": "50000000UL", + "macro_name": "CY_CLK_SLOWCLK_FREQ_HZ" + } + } + }, + "FUTURE_SEQUANA": { + "inherits": ["MCU_PSOC6_M4"], + "sub_target": "FUTURE_SEQUANA_M0", + "supported_form_factors": ["ARDUINO"], + "device_name": "CY8C6347BZI-BLD53M4", + "extra_labels_add": ["CY8C63XX", "CORDIO"], + "macros_add": ["CY8C6347BZI_BLD53"], + "detect_code": ["6000"], + "m0_core_img": "psoc63_m0_default_1.01.hex", + "post_binary_hook": { + "function": "PSOC6Code.complete" + }, + "config": { + "system-clock": { + "help": "Desired frequency of main clock (Hz)", + "value": "100000000UL", + "macro_name": "CY_CLK_HFCLK0_FREQ_HZ" + }, + "peri-clock": { + "help": "Desired frequency of peripheral clock (Hz)", + "value": "50000000UL", + "macro_name": "CY_CLK_PERICLK_FREQ_HZ" + }, + "m0-clock": { + "help": "Desired frequency of M0+ core clock (Hz)", + "value": "50000000UL", + "macro_name": "CY_CLK_SLOWCLK_FREQ_HZ" + } + } } } diff --git a/tools/export/__init__.py b/tools/export/__init__.py index 26654c16f4..1c7e7cb005 100644 --- a/tools/export/__init__.py +++ b/tools/export/__init__.py @@ -24,6 +24,8 @@ from os import makedirs, walk import copy from shutil import rmtree, copyfile import zipfile +import inspect +from inspect import getmro from ..resources import Resources, FileType, FileRef from ..config import ALLOWED_FEATURES @@ -129,6 +131,62 @@ def mcu_ide_matrix(verbose_html=False): return result +def get_target_exporter(target, toolchain): + """Locate target-specyfic exporter function. + Positional Arguments: + target - the target object for inspection + toolchain - the toolchain object for inspection + """ + # If there's no hook, simply return + target_obj = toolchain.config.target + try: + hook_data = target_obj.post_binary_hook + except AttributeError: + return None + # A hook was found. The hook's name is in the format + # "classname.functionname" + temp = hook_data["export_function"].split(".") + if len(temp) != 2: + raise HookError( + ("Invalid format for hook '%s' in target '%s'" + % (hook_data["export_function"], target_obj.name)) + + " (must be 'class_name.function_name')") + class_name, function_name = temp + # "class_name" must refer to a class in tools/targets module, so check if the + # class exists + from .. import targets + from targets import HookError + mdata = dict([(m[0], m[1]) for m in + inspect.getmembers(sys.modules[targets.__name__])]) + + if class_name not in mdata or \ + not inspect.isclass(mdata[class_name]): + print (mdata) + raise HookError( + ("Class '%s' required by '%s' in target '%s'" + % (class_name, hook_data["export_function"], target_obj.name)) + + " not found in targets.py") + # "function_name" must refer to a static function inside class + # "class_name" + cls = mdata[class_name] + if (not hasattr(cls, function_name)) or \ + (not inspect.isfunction(getattr(cls, function_name))): + raise HookError( + ("Static function '%s' " % function_name) + + ("required by '%s' " % hook_data["export_function"]) + + ("in target '%s' " % target_obj.name) + + ("not found in class '%s'" % class_name)) + # Check if the hook specification also has toolchain restrictions + toolchain_restrictions = set(hook_data.get("toolchains", [])) + toolchain_labels = set(c.__name__ for c in getmro(toolchain.__class__)) + if toolchain_restrictions and \ + not toolchain_labels.intersection(toolchain_restrictions): + return None + # Finally, get the requested function + print("Found function '%s' in class '%s'."% (function_name, class_name)) + return getattr(cls, function_name) + + def get_exporter_toolchain(ide): """ Return the exporter class and the toolchain string as a tuple @@ -158,6 +216,9 @@ def generate_project_files(resources, export_path, target, name, toolchain, ide, exporter_cls, _ = get_exporter_toolchain(ide) exporter = exporter_cls(target, export_path, name, toolchain, extra_symbols=macros, resources=resources) + # Locate target-specyfic exporter if specified. + exporter.TARGET_EXPORTER = get_target_exporter(target, toolchain) + exporter.generate() files = exporter.generated_files return files, exporter diff --git a/tools/export/codeblocks/__init__.py b/tools/export/codeblocks/__init__.py index 31841355be..93c64c9ec3 100644 --- a/tools/export/codeblocks/__init__.py +++ b/tools/export/codeblocks/__init__.py @@ -35,7 +35,8 @@ class CodeBlocks(GccArm): PREPROCESS_ASM = False POST_BINARY_WHITELIST = set([ - "NCS36510TargetCode.ncs36510_addfib" + "NCS36510TargetCode.ncs36510_addfib", + "PSOC6Code.complete" ]) @staticmethod @@ -132,7 +133,9 @@ class CodeBlocks(GccArm): 'NRF51_DK_LEGACY': 'board/nordic_nrf51_dk.cfg', 'NRF51_DK_BOOT': 'board/nordic_nrf51_dk.cfg', 'NRF51_DK_OTA': 'board/nordic_nrf51_dk.cfg', - 'NRF51_DK': 'board/nordic_nrf51_dk.cfg' + 'NRF51_DK': 'board/nordic_nrf51_dk.cfg', + 'FUTURE_SEQUANA': 'board/cy8ckit_062_ble.cfg', + 'FUTURE_SEQUANA_M0': 'board/cy8ckit_062_ble.cfg' } if self.target in openocd_board: @@ -162,7 +165,7 @@ class CodeBlocks(GccArm): if ignorefiles: with open(self.gen_file_dest('.mbedignore'), 'a') as f: for fi in ignorefiles: - f.write("%s\n" % fi) + f.write("%s\n" % fi) # finally, generate the project file super(CodeBlocks, self).generate() diff --git a/tools/export/exporters.py b/tools/export/exporters.py index 61e91f48a0..054945d142 100644 --- a/tools/export/exporters.py +++ b/tools/export/exporters.py @@ -53,7 +53,7 @@ class Exporter(object): TARGETS = set() TOOLCHAIN = None CLEAN_FILES = ("GettingStarted.html",) - + TARGET_EXPORTER = None def __init__(self, target, export_dir, project_name, toolchain, extra_symbols=None, resources=None): diff --git a/tools/export/gnuarmeclipse/__init__.py b/tools/export/gnuarmeclipse/__init__.py index bb94d4200f..f458f71719 100644 --- a/tools/export/gnuarmeclipse/__init__.py +++ b/tools/export/gnuarmeclipse/__init__.py @@ -16,7 +16,7 @@ limitations under the License. Title: GNU ARM Eclipse (http://gnuarmeclipse.github.io) exporter. -Description: Creates a managed build project that can be imported by +Description: Creates a managed build project that can be imported by the GNU ARM Eclipse plug-ins. Author: Liviu Ionescu @@ -64,7 +64,8 @@ POST_BINARY_WHITELIST = set([ "TEENSY3_1Code.binary_hook", "MCU_NRF51Code.binary_hook", "LPCTargetCode.lpc_patch", - "LPC4088Code.binary_hook" + "LPC4088Code.binary_hook", + "PSOC6Code.complete" ]) class GNUARMEclipse(Exporter): @@ -249,9 +250,9 @@ class GNUARMEclipse(Exporter): Headless build an Eclipse project. The following steps are performed: - - a temporary workspace is created, + - a temporary workspace is created, - the project is imported, - - a clean build of all configurations is performed and + - a clean build of all configurations is performed and - the temporary workspace is removed. The build results are in the Debug & Release folders. @@ -354,7 +355,7 @@ class GNUARMEclipse(Exporter): The steps are: - get the list of source folders, as dirname(source_file) - compute the top folders (subfolders of the project folder) - - iterate all subfolders and add them to a tree, with all + - iterate all subfolders and add them to a tree, with all nodes markes as 'not used' - iterate the source folders and mark them as 'used' in the tree, including all intermediate nodes @@ -401,8 +402,8 @@ class GNUARMEclipse(Exporter): Once identified, the options are removed from the command lines. - The options that were not identified are options that do not - have CDT equivalents and will be passed in the 'Other options' + The options that were not identified are options that do not + have CDT equivalents and will be passed in the 'Other options' categories. Although this process does not have a very complicated logic, diff --git a/tools/export/iar/iar_definitions.json b/tools/export/iar/iar_definitions.json index b391b5b04b..4be71315c7 100644 --- a/tools/export/iar/iar_definitions.json +++ b/tools/export/iar/iar_definitions.json @@ -320,5 +320,20 @@ }, "STM32L432KC": { "OGChipSelectEditMenu": "STM32L432KC\tST STM32L432KC" + }, + "CY8C6347BZI-BLD53M0+": { + "OGChipSelectEditMenu": "CY8C6347BZI-BLD53M0+\tCypress CY8C6347BZI-BLD53M0+", + "CoreVariant": 35, + "GFPUCoreSlave": 35, + "GBECoreSlave": 35, + "GFPUCoreSlave2": 35 + }, + "CY8C6347BZI-BLD53M4": { + "OGChipSelectEditMenu": "CY8C6347BZI-BLD53M4\tCypress CY8C6347BZI-BLD53M4", + "CoreVariant": 39, + "GFPUCoreSlave": 39, + "GBECoreSlave": 39, + "FPU2": 6, + "GFPUCoreSlave2": 39 } } diff --git a/tools/export/makefile/__init__.py b/tools/export/makefile/__init__.py index e812e2be49..6696487f5d 100644 --- a/tools/export/makefile/__init__.py +++ b/tools/export/makefile/__init__.py @@ -54,7 +54,8 @@ class Makefile(Exporter): "MCU_NRF51Code.binary_hook", "TEENSY3_1Code.binary_hook", "LPCTargetCode.lpc_patch", - "LPC4088Code.binary_hook" + "LPC4088Code.binary_hook", + "PSOC6Code.complete" ]) @classmethod @@ -145,6 +146,12 @@ class Makefile(Exporter): new_asm_flags.append(flag) ctx['asm_flags'] = new_asm_flags + # If there is a target-specific exporter function, call it now. + if self.TARGET_EXPORTER: + print ("Calling target exporter...") + self.TARGET_EXPORTER(self, ctx) + + # Generate makefiles. for templatefile in \ ['makefile/%s_%s.tmpl' % (self.TEMPLATE, self.target.lower())] + \ @@ -154,6 +161,7 @@ class Makefile(Exporter): ['makefile/%s.tmpl' % self.TEMPLATE]: try: self.gen_file(templatefile, ctx, 'Makefile') + print("Generated Makefile from %s"%templatefile) break except TemplateNotFound: pass diff --git a/tools/targets/PSOC6.py b/tools/targets/PSOC6.py new file mode 100644 index 0000000000..4f8de3effa --- /dev/null +++ b/tools/targets/PSOC6.py @@ -0,0 +1,167 @@ +# +# Copyright (c) 2017-2018 Future Electronics +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import os +import platform +import subprocess +import errno +from array import array +from distutils.spawn import find_executable +from shutil import copyfile +from intelhex import IntelHex +from intelhex.compat import asbytes + +from ..config import ConfigException + + +class HookError(Exception): + def __init__(self, msg): + self.msg = msg + def __str__(self): + return self.msg + + +# Patch Cypress hex file: +# - update checksum +# - update metadata +# - align regions to page (256 bytes) boundary +def patch(message_func, ihex, hexf, align=256): + #calculate checksum + checksum = 0 + for start, end in ihex.segments(): + if start >= 0x090000000: + continue + segment = ihex.tobinarray(start = start, end = end) + checksum += sum(segment) + + lowchecksum = checksum & 0x0FFFF + message_func("Calculated checksum for %s is 0x%04x" % (hexf, checksum)) + + # update checksum + checksum_bytes = array('B', asbytes('\0'*2)) + checksum_bytes[0] = lowchecksum >> 8 + checksum_bytes[1] = lowchecksum & 0xFF + ihex.frombytes(checksum_bytes, offset=0x90300000) + + # update metadata + sig_bytes = ihex.tobinarray(start=0x90500002, size=4) + signature = (sig_bytes[0] << 24) | (sig_bytes[1] << 16) | (sig_bytes[2] << 8) | sig_bytes[3] + sigcheck = checksum + signature + sigcheck_bytes = array('B', asbytes('\0'*4)) + sigcheck_bytes[0] = (sigcheck >> 24) & 0xff + sigcheck_bytes[1] = (sigcheck >> 16) & 0xff + sigcheck_bytes[2] = (sigcheck >> 8) & 0xff + sigcheck_bytes[3] = sigcheck & 0xFF + ihex.frombytes(sigcheck_bytes, offset=0x90500008) + + # align flash segments + align_mask = align - 1 + alignments = IntelHex() + for start, end in ihex.segments(): + if start >= 0x090000000: + continue + aligned_start = start & ~align_mask + if start != aligned_start: + message_func("Aligning start from 0x%x to 0x%x" % (start, aligned_start)) + alignments.frombytes(ihex.tobinarray(aligned_start, start - 1), aligned_start) + aligned_end = end & ~align_mask + if end != aligned_end: + aligned_end += align + message_func("Aligning end from 0x%x to 0x%x" % (end, aligned_end)) + alignments.frombytes(ihex.tobinarray(end, aligned_end - 1), end) + ihex.merge(alignments) + +def merge_images(hexf0, hexf1=None): + ihex = IntelHex() + ihex.padding = 0x00 + ihex.loadfile(hexf0, "hex") + if hexf1 is not None: + # get chip ID from metadata and compare + ihex1 = IntelHex(hexf1) + type0 = ihex.tobinarray(start=0x90500002, size=4) + type1 = ihex1.tobinarray(start=0x90500002, size=4) + if type0 != type1: + raise HookError( + "Incompatible processor type: %s in '%s' and 0x%s in '%s'" + % (hexf0, type0, hexf1, type1)) + ihex.merge(ihex1, 'ignore') + return ihex + +def complete_func(message_func, elf0, hexf0, hexf1=None, dest=None): + message_func("Postprocessing %s -> %s" % (elf0, hexf0)) + ihex = merge_images(hexf0, hexf1) + patch(message_func, ihex, hexf0) + ihex.write_hex_file(dest if dest else hexf0, write_start_addr=False, byte_count=64) + +def check_matching_features(image_features, target_features): + for feature in image_features: + if not (feature in target_features): + return False + return True + +# Find Cortex M0 boot image proper for the application image. +def find_cm0_images(toolchain, resources, elf, hexf): + # Scan to find the actual paths of m0 image + # First check if user-compiled image exists. + params, _ = toolchain.config.get_config_data() + dual_core_enabled = params['target.sub-target-build-enable'].value + if dual_core_enabled: + if "BLE" in toolchain.target.features: + raise ConfigException("Feature 'BLE' not compatible with dual core configuration.") + m0target = toolchain.target.sub_target + m4target = toolchain.target.name + m0hexf = hexf.replace(m4target, m0target) + if not os.path.isfile(m0hexf): + raise ConfigException("Matching M0 core hex image not found.") + else: + # Try default image. + m0hexf = None + m0_images = toolchain.target.M0_CORE_IMAGE + # convert into a list if needed + if not isinstance(m0_images, list): + m0_images = [m0_images] + + # find an image with matching features + try: + target_features = toolchain.target.features + except AttributeError: + target_features = [] + pass + + for image in m0_images: + features = image['features'] + if check_matching_features(image['features'], target_features): + for hexf in resources.hex_files: + if hexf.find(image['name']) != -1: + m0hexf = hexf + break + if m0hexf: + break + + if m0hexf: + toolchain.notify.info("M0 core image file found %s." % os.path.basename(m0hexf)) + else: + toolchain.notify.debug("M0 core hex image file not found. Aborting.") + raise ConfigException("Matching M0 core hex image not found.") + + m0elf = m0hexf.replace(".hex", ".elf") + return m0elf, m0hexf + + +def complete(toolchain, elf0, hexf0, hexf1=None): + complete_func(toolchain.notify.debug, elf0, hexf0, hexf1) + + diff --git a/tools/targets/__init__.py b/tools/targets/__init__.py index af1ac67fd4..8c67a906a0 100644 --- a/tools/targets/__init__.py +++ b/tools/targets/__init__.py @@ -557,6 +557,30 @@ class RTL8195ACode: def binary_hook(t_self, resources, elf, binf): from tools.targets.REALTEK_RTL8195AM import rtl8195a_elf2bin rtl8195a_elf2bin(t_self, elf, binf) + +class PSOC6Code: + @staticmethod + def complete(t_self, resources, elf, binf): + from tools.targets.PSOC6 import complete as psoc6_complete + if hasattr(t_self.target, "sub_target"): + # Completing main image involves merging M0 image. + from tools.targets.PSOC6 import find_cm0_images + _, m0hexf = find_cm0_images(t_self, resources, elf, binf) + psoc6_complete(t_self, elf, binf, m0hexf) + else: + psoc6_complete(t_self, elf, binf) + + @staticmethod + def export_function(exporter, ctx): + if exporter.NAME in ['Make-GCC-ARM', 'Eclipse-GCC-ARM']: + from tools.targets.PSOC6 import find_cm0_images + elf = ctx['name']+'.elf' + hexf = ctx['name']+'.hex' + _, m0_hexf = find_cm0_images(exporter.toolchain, exporter.resources, elf, hexf) + print ("Adding hex image: %s"% m0_hexf) + ctx['hex_files'] = [m0_hexf] + + ################################################################################ # Instantiate all public targets diff --git a/tools/toolchains/__init__.py b/tools/toolchains/__init__.py index c32d48aada..5c973538a2 100644 --- a/tools/toolchains/__init__.py +++ b/tools/toolchains/__init__.py @@ -630,7 +630,8 @@ class mbedToolchain: lib_dirs = r.get_file_paths(FileType.LIB_DIR) libraries = [l for l in r.get_file_paths(FileType.LIB) if l.endswith(self.LIBRARY_EXT)] - dependencies = objects + libraries + [linker_script] + config_file + hex_files = r.get_file_paths(FileType.HEX) + dependencies = objects + libraries + [linker_script] + config_file + hex_files dependencies.append(join(self.build_dir, self.PROFILE_FILE_NAME + "-ld")) if self.need_update(elf, dependencies): needed_update = True