Added required changes outside of TARGET_Cypress tree:

1. In drivers/Timer.cpp make sure that hardware timer is initialized outside of critical section.
   This is because on PSoC 6 hardware resources are shared between both cores
   and we have to make sure that the other core is not already using a particular resource.
   This mechanism is based on interprocessor communication taht cannot be handled iside of
   critical section.
2. Added support for post-binary hook function for PSoC 6 targets, so the hex image for M0+ CPU core
   can be merged with M4 core image for the final image.
3. Added possibility to use hook function from exportes, so the M0+ hex image could be included
   in the generated project.
4. Included hex images in the build dependency list, so the update of image is catched by the
   build process.
pull/8491/head
Leszek Rusinowicz 2018-10-22 14:10:10 +02:00
parent f906aac096
commit 9b1db83eaa
12 changed files with 386 additions and 13 deletions

View File

@ -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());

View File

@ -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
}
}
}

View File

@ -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"
}
}
}
}

View File

@ -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

View File

@ -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:

View File

@ -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):

View File

@ -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):

View File

@ -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
}
}

View File

@ -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

167
tools/targets/PSOC6.py Normal file
View File

@ -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)

View File

@ -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

View File

@ -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