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

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

@ -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 <ilg@livius.net>
@ -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,

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