Skip to content

Commit

Permalink
Merge pull request #690 from flit/bugfix/lpc55s69
Browse files Browse the repository at this point in the history
LPC55S69 flash programming bug fixes.
  • Loading branch information
flit authored Jun 19, 2019
2 parents 0965f7f + 30111a8 commit 96c125e
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 4 deletions.
Binary file added binaries/lpcxpresso55s69.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion pyocd/board/board_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(self, name, target, binary):
"0233": BoardInfo( "FRDM-KE16Z", "mke16z64vlf4", None, ),
"0234": BoardInfo( "Rapid-IoT-KW41Z", "kw41z4", "l1_kw41z4.bin", ),
"0235": BoardInfo( "LPC54018IoTModule", "lpc54018jet180", None, ),
"0236": BoardInfo( "LPCXpresso55S69", "lpc55s69", None, ),
"0236": BoardInfo( "LPCXpresso55S69", "lpc55s69", "lpcxpresso55s69.bin", ),
"0240": BoardInfo( "FRDM-K64F", "k64f", "l1_k64f.bin", ),
"0245": BoardInfo( "IBMEthernetKit", "k64f", "l1_k64f.bin" ),
"0250": BoardInfo( "FRDM-KW24D512", "kw24d5", "l1_kw24d5.bin" ),
Expand Down
7 changes: 7 additions & 0 deletions pyocd/core/coresight_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ def select_core(self, num):
@property
def aps(self):
return self.dp.aps

@property
def supported_security_states(self):
return self.selected_core.supported_security_states

@property
def svd_device(self):
Expand Down Expand Up @@ -330,6 +334,9 @@ def reset_and_halt(self, reset_type=None):

def get_state(self):
return self.selected_core.get_state()

def get_security_state(self):
return self.selected_core.get_security_state()

def set_vector_catch(self, enableMask):
return self.selected_core.set_vector_catch(enableMask)
Expand Down
3 changes: 3 additions & 0 deletions pyocd/core/memory_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ class FlashRegion(MemoryRegion):
- `flash_class`: The class that manages individual flash algorithm operations. Must be either
@ref pyocd.flash.flash.Flash "Flash", which is the default, or a subclass.
- `flash`: After connection, this attribute holds the instance of `flash_class` for this region.
- `are_erased_sectors_readable`: Specifies whether the flash controller allows reads of erased
sectors, or will fault such reads. Default is True.
`sector_size` and `blocksize` are aliases of each other. If one is set via the constructor, the
other will have the same value.
Expand All @@ -294,6 +296,7 @@ class FlashRegion(MemoryRegion):
'program_page_weight': DefaultFlashWeights.PROGRAM_PAGE_WEIGHT,
'erased_byte_value': 0xff,
'access': 'rx', # By default flash is not writable.
'are_erased_sectors_readable': True,
})

def __init__(self, start=0, end=0, length=None, **attrs):
Expand Down
14 changes: 14 additions & 0 deletions pyocd/core/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ class Target(MemoryInterface):
TARGET_RESET = 3 # Core is being held in reset.
TARGET_SLEEPING = 4 # Core is sleeping due to a wfi or wfe instruction.
TARGET_LOCKUP = 5 # Core is locked up.

class SecurityState(Enum):
"""! @brief Security states for a processor with the Security extension."""
## PE is in the Non-secure state.
NONSECURE = 0
## PE is in the Secure state.
SECURE = 1

class ResetType(Enum):
"""! @brief Available reset methods."""
Expand Down Expand Up @@ -125,6 +132,10 @@ def call_delegate(self, method_name, *args, **kwargs):
@property
def svd_device(self):
return self._svd_device

@property
def supported_security_states(self):
raise NotImplementedError()

def is_locked(self):
return False
Expand Down Expand Up @@ -197,6 +208,9 @@ def reset_and_halt(self, reset_type=None):

def get_state(self):
raise NotImplementedError()

def get_security_state(self):
raise NotImplementedError()

@property
def run_token(self):
Expand Down
17 changes: 17 additions & 0 deletions pyocd/coresight/cortex_m.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,15 @@ def default_software_reset_type(self, reset_type):
assert reset_type in (Target.ResetType.SW_SYSRESETREQ, Target.ResetType.SW_VECTRESET,
Target.ResetType.SW_EMULATED)
self._default_software_reset_type = reset_type

@property
def supported_security_states(self):
"""! @brief Tuple of security states supported by the processor.
@return Tuple of @ref pyocd.core.target.Target.SecurityState "Target.SecurityState". For
v6-M and v7-M cores, the return value only contains SecurityState.NONSECURE.
"""
return (Target.SecurityState.NONSECURE,)

def init(self):
"""! @brief Cortex M initialization.
Expand Down Expand Up @@ -934,6 +943,14 @@ def get_state(self):
return Target.TARGET_HALTED
else:
return Target.TARGET_RUNNING

def get_security_state(self):
"""! @brief Returns the current security state of the processor.
@return @ref pyocd.core.target.Target.SecurityState "Target.SecurityState" enumerator. For
v6-M and v7-M cores, SecurityState.NONSECURE is always returned.
"""
return Target.SecurityState.NONSECURE

@property
def run_token(self):
Expand Down
32 changes: 31 additions & 1 deletion pyocd/coresight/cortex_m_v8m.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from .cortex_m import CortexM
from ..core import exceptions
from ..core.target import Target
import logging

LOG = logging.getLogger(__name__)
Expand All @@ -42,6 +43,12 @@ class CortexM_v8M(CortexM):
ARMv8M_BASE = 0xC
ARMv8M_MAIN = 0xF

DSCSR = 0xE000EE08
DSCSR_CDSKEY = 0x00020000
DSCSR_CDS = 0x00010000
DSCSR_SBRSEL = 0x00000002
DSCSR_SBRSELEN = 0x00000001

# Processor Feature Register 1
PFR1 = 0xE000ED44
PFR1_SECURITY_MASK = 0x000000f0
Expand All @@ -52,6 +59,18 @@ def __init__(self, rootTarget, ap, memoryMap=None, core_num=0, cmpid=None, addre

# Only v7-M supports VECTRESET.
self._supports_vectreset = False

@property
def supported_security_states(self):
"""! @brief Tuple of security states supported by the processor.
@return Tuple of @ref pyocd.core.target.Target.SecurityState "Target.SecurityState". The
result depends on whether the Security extension is enabled.
"""
if self.has_security_extension:
return (Target.SecurityState.NONSECURE, Target.SecurityState.SECURE)
else:
return (Target.SecurityState.NONSECURE)

def _read_core_type(self):
"""! @brief Read the CPUID register and determine core type and architecture."""
Expand All @@ -78,4 +97,15 @@ def _read_core_type(self):
LOG.info("CPU core #%d is %s r%dp%d", self.core_number, CORE_TYPE_NAME[self.core_type], self.cpu_revision, self.cpu_patch)
else:
LOG.warning("CPU core #%d type is unrecognized", self.core_number)


def get_security_state(self):
"""! @brief Returns the current security state of the processor.
@return @ref pyocd.core.target.Target.SecurityState "Target.SecurityState" enumerator.
"""
dscsr = self.read32(self.DSCSR)
if (dscsr & self.DSCSR_CDS) != 0:
return Target.SecurityState.SECURE
else:
return Target.SecurityState.NONSECURE

9 changes: 9 additions & 0 deletions pyocd/flash/flash_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ def program(self, chip_erase=None, progress_cb=None, smart_flash=True, fast_veri
Data must have already been added with add_data().
If the flash region's 'are_erased_sectors_readable' attribute is false, then the
smart_flash, fast_verify, and keep_unwritten options are forced disabled.
@param self
@param chip_erase A value of "chip" forces chip erase, "sector" forces sector erase, and a
value of "auto" means that the estimated fastest method should be used. If not
Expand All @@ -379,6 +382,12 @@ def program(self, chip_erase=None, progress_cb=None, smart_flash=True, fast_veri

# Send notification that we're about to program flash.
self.flash.target.session.notify(Target.EVENT_PRE_FLASH_PROGRAM, self)

# Disable options if attempting to read erased sectors will fault.
if not self.flash.region.are_erased_sectors_readable:
smart_flash = False
fast_verify = False
keep_unwritten = False

# Examples
# - lpc4330 -Non 0 base address
Expand Down
145 changes: 143 additions & 2 deletions pyocd/target/builtin/target_LPC55S69JBD100.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from time import sleep

from ...core.target import Target
from ...core.coresight_target import CoreSightTarget
from ...core.memory_map import (FlashRegion, RamRegion, RomRegion, MemoryMap)
from ...coresight.cortex_m import CortexM
from ...coresight.cortex_m_v8m import CortexM_v8M
from ...debug.svd.loader import SVDFile
from ...utility import timeout

FLASH_ALGO = {
'load_address' : 0x20000000,
Expand Down Expand Up @@ -102,15 +108,43 @@
)
}

FPB_CTRL = 0xE0002000
FPB_COMP0 = 0xE0002008
DWT_COMP0 = 0xE0001020
DWT_FUNCTION0 = 0xE0001028
DWT_FUNCTION_MATCH = 0x4 << 0 # Instruction address.
DWT_FUNCTION_ACTION = 0x1 << 4 # Generate debug event.
DWT_FUNCTION_DATAVSIZE = 0x2 << 10 # 4 bytes.

PERIPHERAL_BASE_NS = 0x40000000
PERIPHERAL_BASE_S = 0x50000000

FLASH_CMD = 0x00034000
FLASH_STARTA = 0x00034010
FLASH_STOPA = 0x00034014
FLASH_DATAW0 = 0x00034080
FLASH_INT_STATUS = 0x00034FE0
FLASH_INT_CLR_STATUS = 0x00034FE8
FLASH_CMD_READ_SINGLE_WORD = 0x3

BOOTROM_MAGIC_ADDR = 0x50000040

class LPC55S69JBD100(CoreSightTarget):

memoryMap = MemoryMap(
FlashRegion(name='nsflash', start=0x00000000, length=0x00098000, access='rx',
blocksize=0x200, is_boot_memory=True, algo=FLASH_ALGO),
blocksize=0x200,
is_boot_memory=True,
are_erased_sectors_readable=False,
algo=FLASH_ALGO),
RomRegion( name='nsrom', start=0x03000000, length=0x00020000, access='rx'),
RamRegion( name='nscoderam', start=0x04000000, length=0x00008000, access='rwx'),
FlashRegion(name='sflash', start=0x10000000, length=0x00098000, access='rx',
blocksize=0x200, is_boot_memory=True, algo=FLASH_ALGO, alias='nsflash'),
blocksize=0x200,
is_boot_memory=True,
are_erased_sectors_readable=False,
algo=FLASH_ALGO,
alias='nsflash'),
RomRegion( name='srom', start=0x13000000, length=0x00020000, access='srx',
alias='nsrom'),
RamRegion( name='scoderam', start=0x14000000, length=0x00008000, access='srwx',
Expand All @@ -128,6 +162,7 @@ def create_init_sequence(self):
seq = super(LPC55S69JBD100, self).create_init_sequence()

seq.wrap_task('init_ap_roms', self._modify_ap1)
seq.replace_task('create_cores', self.create_lpc55s69_cores)
seq.insert_before('create_components',
('enable_traceclk', self._enable_traceclk),
)
Expand All @@ -143,6 +178,20 @@ def _modify_ap1(self, seq):

def _set_ap1_nonsec(self):
self.aps[1].hnonsec = 1

def create_lpc55s69_cores(self):
# Create core 0 with a custom class.
core0 = CortexM_LPC55S69(self.session, self.aps[0], self.memory_map, 0)
core0.default_reset_type = self.ResetType.SW_SYSRESETREQ
self.aps[0].core = core0
core0.init()
self.add_core(core0)

core1 = CortexM_v8M(self.session, self.aps[1], self.memory_map, 1)
core1.default_reset_type = self.ResetType.SW_SYSRESETREQ
self.aps[1].core = core1
core1.init()
self.add_core(core1)

def _enable_traceclk(self):
SYSCON_NS_Base_Addr = 0x40000000
Expand All @@ -166,3 +215,95 @@ def trace_start(self):

self.call_delegate('trace_start', target=self, mode=0)

class CortexM_LPC55S69(CortexM_v8M):

def reset_and_halt(self, reset_type=None):
"""! @brief Perform a reset and stop the core on the reset handler. """

catch_mode = 0

delegateResult = self.call_delegate('set_reset_catch', core=self, reset_type=reset_type)

# Save CortexM.DEMCR
demcr = self.read_memory(CortexM.DEMCR)

# enable the vector catch
if not delegateResult:
# This sequence is copied from the NXP LPC55S69_DFP debug sequence.
reset_vector = 0xFFFFFFFF

# Clear reset vector catch.
self.write32(CortexM.DEMCR, demcr & ~CortexM.DEMCR_VC_CORERESET)

# If the processor is in Secure state, we have to access the flash controller
# through the secure alias.
if self.get_security_state() == Target.SecurityState.SECURE:
print("Secure")
base = PERIPHERAL_BASE_S
else:
print("Non-Secure")
base = PERIPHERAL_BASE_NS

# Use the flash programming model to check if the first flash page is readable, since
# attempted accesses to erased pages result in bus faults. The start and stop address
# are both set to 0x0 to probe the sector containing the reset vector.
self.write32(base + FLASH_STARTA, 0x00000000) # Program flash word start address to 0x0
self.write32(base + FLASH_STOPA, 0x00000000) # Program flash word stop address to 0x0
self.write_memory_block32(base + FLASH_DATAW0, [0x00000000] * 8) # Prepare for read
self.write32(base + FLASH_INT_CLR_STATUS, 0x0000000F) # Clear Flash controller status
self.write32(base + FLASH_CMD, FLASH_CMD_READ_SINGLE_WORD) # Read single flash word

# Wait for flash word read to finish.
with timeout.Timeout(5.0) as t_o:
while t_o.check():
if (self.read32(base + FLASH_INT_STATUS) & 0x00000004) != 0:
break
sleep(0.01)

# Check for error reading flash word.
if (self.read32(base + FLASH_INT_STATUS) & 0xB) == 0:
# Read the reset vector address.
reset_vector = self.read32(0x00000004)

# Break on user application reset vector if we have a valid breakpoint address.
if reset_vector != 0xFFFFFFFF:
catch_mode = 1
self.write32(FPB_COMP0, reset_vector|1) # Program FPB Comparator 0 with reset handler address
self.write32(FPB_CTRL, 0x00000003) # Enable FPB
# No valid user application so use watchpoint to break at end of boot ROM. The ROM
# writes a special address to signal when it's done.
else:
catch_mode = 2
self.write32(DWT_FUNCTION0, 0)
self.write32(DWT_COMP0, BOOTROM_MAGIC_ADDR)
self.write32(DWT_FUNCTION0, (DWT_FUNCTION_MATCH | DWT_FUNCTION_ACTION | DWT_FUNCTION_DATAVSIZE))

# Read DHCSR to clear potentially set DHCSR.S_RESET_ST bit
self.read32(CortexM.DHCSR)

self.reset(reset_type)

# wait until the unit resets
with timeout.Timeout(2.0) as t_o:
while t_o.check():
if self.get_state() not in (Target.TARGET_RESET, Target.TARGET_RUNNING):
break
sleep(0.01)

# Make sure the thumb bit is set in XPSR in case the reset handler
# points to an invalid address.
xpsr = self.read_core_register('xpsr')
if xpsr & self.XPSR_THUMB == 0:
self.write_core_register('xpsr', xpsr | self.XPSR_THUMB)

self.call_delegate('clear_reset_catch', core=self, reset_type=reset_type)

# Clear breakpoint or watchpoint.
if catch_mode == 1:
self.write32(0xE0002008, 0)
elif catch_mode == 2:
self.write32(DWT_COMP0, 0)
self.write32(DWT_FUNCTION0, 0)

# restore vector catch setting
self.write_memory(CortexM.DEMCR, demcr)

0 comments on commit 96c125e

Please sign in to comment.