AN352 - ARM DS-5 Technical introduction to file-based flash programming

Application Note 352



Application Note 352

ARM DS-5 Technical introduction to file-based flash programming

Document number: ARM DAI 0352A

 

Non-Confidential

 

 


Application Note 352

ARM DS-5 Technical introduction to file-based flash programming

Copyright 2013 ARM Limited. All rights reserved.

Release information

The following table lists the changes made to this document.

Change history

Date

Issue

Change

January 2013

A

First release for DS-5 v5.13

Proprietary notice

Words and logos marked with and are registered trademarks or trademarks of ARM in the EU and other countries, except as otherwise stated below in this proprietary notice. Other brands and names mentioned herein may be the trademarks of their respective owners.

Neither the whole nor any part of the information contained in, or the product described in, this document may be adapted or reproduced in any material form except with the prior written permission of the copyright holder.

The product described in this document is subject to continuous developments and improvements. All particulars of the product and its use contained in this document are given by ARM in good faith. However, all warranties implied or expressed, including but not limited to implied warranties of merchantability, or fitness for purpose, are excluded.

This document is intended only to assist the reader in the use of the product. ARM shall not be liable for any loss or damage arising from the use of any information in this document, or any error or omission in such information, or any incorrect use of the product.

Where the term ARM is used it means ARM or any of its subsidiaries as appropriate.

Confidentiality status

This document is Non-Confidential. The right to use, copy and disclose this document may be subject to license restrictions in accordance with the terms of the agreement entered into by ARM and the party that ARM delivered this document to.

Feedback on this application note

If you have any comments on content then send an e-mail to errata@arm.com. Give:

         the document title

         the document number ARM DAI 0352A

         the page numbers to which your comments apply

         a concise explanation of your comments.

ARM also welcomes general suggestions for additions and improvements.

ARM web address

http://www.arm.com

 


Table of Contents

1 Introduction................................................................................................................................ 4

2 Terms and abbreviations............................................................................................................ 5

3 Use cases................................................................................................................................... 6

4 DS-5 File Flash Programming Architecture................................................................................. 7

4.1 Overview............................................................................................................................ 7

5 Flash Programming Configuration Details.................................................................................. 9

5.1 Configuration Files.............................................................................................................. 9

5.2 Configuration Files Location.............................................................................................. 11

6 Using/Extending the supplied Keil Flash Method...................................................................... 12

6.1 Adding flash support to an existing platform using an existing Keil Flash Algorithm............. 12

6.2 Adding flash support to an existing target platform using a new Keil Flash Algorithm........... 13

7 Keil flash algorithm Worked Example..................................................................................... 14

7.1 Creating the Keil flash algorithm......................................................................................... 14

7.2 Adding the Keil flash algorithm to the Versatile Express Cortex-A9x4 RTSM........................ 14

7.3 Using the Keil flash algorithm............................................................................................ 15

8 Creating a new Flash Method.................................................................................................... 17

8.1 Using the default implementation 'FlashMethodv1'.............................................................. 17

8.2 Creating the Flash Method Python script............................................................................ 17

8.3 Testing the Flash configuration.......................................................................................... 21

8.4 Flash Method Parameters.................................................................................................. 21

8.5 Getting data to the flash algorithm..................................................................................... 22

8.6 Interacting with the target................................................................................................... 22

9 Custom Flash Method - Worked Example.................................................................................. 30

9.1 Example files.................................................................................................................... 30

9.2 Adding the example flash support to the Versatile Express Cortex-A9x4 RTSM.................... 34

 


1             Introduction

This document describes the DS-5 file-based flash programming architecture, how to add support for new boards and how to add support for new types of flash device.

This document applies to DS-5 v5.13 and later.

Readers of this document should be familiar with Java, Python (Jython) and XML.

Example code can be found at: http://infocenter.arm.com/help/topic/com.arm.doc.dai0352a/flash_example.zip

2             Terms and abbreviations

This document uses the following terms and abbreviations.

Term

Meaning

DSTREAM

ARM DSTREAM combined debug and trace unit

RDDI

RealView Device Debug Interface. A C level API which allows access to target debug/trace functionality, typically via a DSTREAM box

jRDDI

The Java API implementation of RDDI

DTSL

Debug and Trace Service Layer a scriptable software layer within DS-5 which provides target configuration and connectivity. DTSL layers on top of jRDDI

DS-5

The ARM Eclipse based development environment (IDE, Compiler, Debugger, Profiler...)

Jython

An implementation of the Python language which is closely integrated with Java (see www.jython.org)

Flash Method

A technique, or 'way' of performing flash programming. For example running an external program (as supplied by a 3rd party) is one flash method. Another would be the downloading of a Flash Algorithm to the target system and repeatedly running the algorithm on a data set would be another.

Flash Algorithm

A specific technique used to program data into a flash device. These are typically algorithms which are downloaded to a target system and repeatedly executed to program blocks of data into a flash device.

AAPCS

ARM Architecture Procedure Call Standard

(http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf )

3             Use cases

The first use case to be supported by the DS-5 Flash Programming system is to allow a file to be programmed into flash. The file flash programming operation(s) supports the following features:

1.     The programming of ELF files (.axf) into flash.

2.     Support for the ELF file containing multiple flash areas which can each be programmed into a flash device or possible several (different) flash devices.

3.     Support for many and varied flash programming methods (initial support has been focused towards the Keil flash programming method. This means support is provided for all of the Keil flash programming algorithms).

4.     Support for target board setup/teardown to prepare it for flash programming.

5.     Support for the DS-5 configuration database to know about target flash devices (so the user does not have to get involved in flash configuration) and the options required for flash programming on a specific board/SoC.

6.     Support for a simple flash programming user interface where the user specifies a minimum of configuration/option information.

7.     Support for flash program option modification so that the user has the ability to modify the default flash options.

8.     Support for reporting progress to the user both in a graphical way (within Eclipse) and on a text only type console (when used with the debugger outside Eclipse), along with the ability to cancel the programming operation.

9.     Support for displaying warnings and error messages to the user.

4             DS-5 File Flash Programming Architecture

Figure 1: DS-5 File Flash Architecture

DS-5 File Flash Architecture

4.1         Overview

The DS-5 configdb platform entry for a board can contain a flash definition section. This can define one or more areas of flash each with its own flash method and configuration parameters.

NOTE: You can use the DS-5 Debugger info flash command to view the flash configuration for your board

Flash Methods are implemented in Jython and are typically located within the configdb itself. Each flash method has knowledge about a specific 'way' of programming flash. This might involve running an external program (as supplied by a third party) to program a file into flash or it may even be as simple as copying a file to a file system mount point (as implemented in the ARM Versatile Express designs). However, another typical 'way' is to download a code algorithm into the target system and to keep running that algorithm on a data set (typically a flash sector) until the entire flash device has been programmed. An example of the latter are the Keil flash programming algorithms which are fully supported by DS-5 Debugger. For the Keil Flash Method, one of the method configuration items is the algorithm to use to perform the flash programming. These algorithms all follow the same top level S/W interface and so the same DS-5 Keil Flash Method can be used to program many types of flash. This means that DS-5 Debugger should be able to make direct use of any existing Keil flash algorithm.

All Flash Methods which directly interact with the target should do so using the DS-5 Debugger's DTSL connection.

5             Flash Programming Configuration Details

5.1         Configuration Files

Each target platform supported by DS-5 has an entry in the DS-5 configuration database. To add support for flash programming, a target's platform entry in the database must define both the flash programming method and any required parameters. The information is stored across two files in the configuration database:

1.     project_types.xml - This file describes the debug operations supported for the platform and may contain a reference to a flash configuration file. This is indicated by a tag such as
<flash_config>CDB://flash.xml</flash_config>
The CDB:// tag indicates a path relative to the target's platform directory (usually the one that contains the project_types.xml file). The relative path can be above the directory using ".." - this allows the flash configuration file to be shared between a number of targets with the same chip and same flash configuration, for example:
<flash_config>CDB://../../../Flash/STM32/flash.xml</flash_config>

2.     flash configuration file (e.g. flash.xml) - This is an xml file describing the flash devices on a target, including which memory regions they are mapped to and what parameters need to be passed to the flash programming method.

The flash configuration must always specify the flash programming method to use, but can also optionally specify a setup script and a teardown script. These are used to prepare the target platform for flash programming and to re-initialize it when flash programming is complete. Clearly these scripts may be very specific to the target platform whereas the flash programming method may be generic.

Below is an example flash.xml (taken from the Keil MCBSTM32E platform). Note that this example defines two flash devices (actually, there is only one flash device the built-in one in the STM32E, but there are two different algorithms used to program the main flash and the flash option bytes). Note the way the Flash Method is set to the keil_flash.py script and note how the parameters for that method are subsequently defined.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--Copyright (C) 2012 ARM Limited. All rights reserved.-->
<flash_config
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.arm.com/flash_config"
xsi:schemaLocation="http://www.arm.com/flash_config flash_config.xsd">
<devices>
<!-- STM32F1xx has 2 flash sections: main flash for program code and option
flash for device configuration. These are viewed as separate devices
when programming -->
<!-- The main flash device -->
<device name="MainFlash">
<programming_type type="FILE">
<!-- Use the standard method for running Keil algorithms -->
<method language="JYTHON" script="FDB://keil_flash.py" class="KeilFlash" method_config="Main"/>
<!-- Target specific script to get target in a suitable state for programming -->
<setup script="FDB://stm32_setup.py" method="setup"/>
</programming_type>
</device>

<!-- The option flash device -->
<device name="OptionFlash">
<programming_type type="FILE">
<method language="JYTHON" script="FDB://keil_flash.py" class="KeilFlash" method_config="Option"/>
<setup script="FDB://stm32_setup.py" method="setup"/>
</programming_type>
</device>
</devices>
<method_configs>
<!-- Parameters for programming the main flash -->
<method_config id="Main">
<params>
<!-- Programming algorithm binary to load to target -->
<param name="algorithm" type="string" value="FDB://algorithms/STM32F10x_512.FLM"/>
<!-- The core in the target to run the algorithm -->
<param name="coreName" type="string" value="Cortex-M3"/>
<!-- RAM location & size for algorithm code and write buffers -->
<param name="ramAddress" type="integer" value="0x20000000"/>
<param name="ramSize" type="integer" value="0x10000"/>
<!-- Allow timeouts to be disabled -->
<param name="disableTimeouts" type="string" value="false"/>
<!-- Set to false to skip the verification stage -->
<param name="verify" type="string" value="true"/>
</params>
</method_config>

<!-- Parameters for programming the option flash -->
<method_config id="Option">
<params>
<!-- Programming algorithm binary to load to target -->
<param name="algorithm" type="string" value="FDB://algorithms/STM32F10x_OPT.FLM"/>
<!-- The core in the target to run the algorithm -->
<param name="coreName" type="string" value="Cortex-M3"/>
<!-- RAM location & size for algorithm code and write buffers -->
<param name="ramAddress" type="integer" value="0x20000000"/>
<param name="ramSize" type="integer" value="0x10000"/>
<!-- Allow timeouts to be disabled -->
<param name="disableTimeouts" type="string" value="false"/>
<!-- Set to false to skip the verification stage -->
<param name="verify" type="string" value="true"/>
</params>
</method_config>
</method_configs>
</flash_config>

5.2         Configuration Files Location

This document outlines modification and additions to the DS-5 configuration database. However for many DS-5 Installations, it is not possible (or desirable) to modify the installed configuration database.

DS-5 Debugger supports the user creating their own configuration databases and using them to extend the default installed database. Using the DS-5 Debugger Eclipse Preferences it is possible to inform DS-5 Debugger of the location of the database extensions and so is possible for a user to modify and extend the database as required.

To create an extension configuration database, just create a new directory with a name of your choice and then create both Boards and Flash subdirectories. Inform DS-5 Debugger about the new location using the DS-5 Debugger Eclipse Preferences.

To manually add new board entries, create a directory under Boards for the manufacturer and then create a further subdirectory below the manufacturer using a suitable board name for example:

Boards

\---> MegaSoc-Co

\---> Acme-Board-2000

project_types.xml

 

Flash

\---> Algorithms

Acme-Board-2000.flm

Acme-Board-2000-Flash.py

Within the project_types.xml file for your platform, any reference to a CDB:// location will resolve to the Boards/<manufacturer>/<board> directory (the one which contains the project_types.xml file). Any reference to a FDB:// location will resolve to the Flash directory.

6             Using/Extending the supplied Keil Flash Method

DS-5 Debugger (v5.13 and later) contains a full implementation of the Keil Flash Programming method. This may be used to program any flash device supported by Keils MDK product. It may also be used to support any future device for which a Keil Flash Programming algorithm can be created. For details on creating new Keil Flash Programming algorithms, see http://www.keil.com/support/man/docs/ulink2/ulink2_alg_func.htm and http://www.keil.com/support/man/docs/ulink2/ulink2_su_newalgorithms.htm, though these pages apply to the Keil Vision product. To aid in the creation of new Keil Flash Programming algorithms within DS-5, DS-5 Debugger contains a full platform flash example for the Keil MCBSTM32E board. This may be used as a template for new flash support.

As an alternative to the real flash support added to the Keil MCBSTM32E board, we also show how to create a new Keil algorithm for a fake flash device within the RTSM for the Cortex-A9x4 platform (a simulation platform distributed with DS-5).

6.1         Adding flash support to an existing platform using an existing Keil Flash Algorithm

To use the Keil MDK flash algorithms within DS-5, the algorithm binary needs to be imported into the target configuration database and the flash configuration files created to reference the keil_flash.py script. The supplied flash configuration for the Keil MCBSTM32E board (as shown above) may be used as a template to add support for another board, for example a board named the Acme-Board-2000 made by MegaSoc-Co (Manufacturer 'MegaSoc-Co', Board ' Acme-Board-2000'):

1.   Copy the algorithm binary (.FLM) into the configuration database Flash/algorithms directory.

2.   Copy the flash configuration file from Boards/Keil/MCBSTM32E/keil-mcbstm32e_flash.xml to Boards/MegaSoc-Co/Acme-Board-2000/flash.xml

3.   Edit the platform's project_types.xml to reference the flash.xml file by inserting the following line:

<flash_config>CDB://flash.xml</flash_config>

below the platform_data definition, for example:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!--Copyright (C) 2009-2012 ARM Limited. All rights reserved.-->

<platform_data xmlns="http://www.arm.com/project_type" xmlns:peripheral="http://com.arm.targetconfigurationeditor" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" type="HARDWARE" xsi:schemaLocation="http://www.arm.com/project_type ../../../Schemas/platform_data-1.xsd">

<flash_config>CDB://flash.xml</flash_config>

4.   Edit the devices section, creating a <device> block for each flash device on the target. The method_config attribute should refer to a unique <method_config> block for that device in the <method_configs> section.

5.   Create and then reference any setup or teardown script required for your board. If your board does not need these then do not add the

<setup script="FDB://Acme-Board-2000-Flash.py" method="setup"/>

<teardown script="FDB://Acme-Board-2000-Flash.py" method="teardown"/>

lines to your configuration (they are optional)

6.   Edit the method_configs section, creating a <method_config> block for each device:

a)   The value for the algorithm parameter should be changed to the path to the algorithm copied in step 1. The FDB:// prefix is used to indicate the file can be found in the configuration database Flash directory.

b)   The coreName parameter should be the name of the core on the target that will run the algorithm. This must be the same name as used in the <core> definition within project_types.xml.


For example.

<core connection_id="Cortex-M3" core_definition="Cortex-M3"/>

c)   The ramAddress and ramSize parameters should be set to an area of RAM that the algorithm can be downloaded in to and used as working RAM. It should be big enough to hold the algorithm, stack plus scratch areas required to run the algorithm and a sufficiently big area to download image data.

d)   The other parameters do not normally need to be changed

6.2         Adding flash support to an existing target platform using a new Keil Flash Algorithm

The first step is to create the new Keil flash algorithm. This is a specially crafted ELF file which contains several functions which when installed onto the target system provide the flash programming functionality used by the Keil flash method.

Details of the functions required can be found here: http://www.keil.com/support/man/docs/ulink2/ulink2_alg_func.htm

DS-5 ships with a complete Keil flash algorithm example for the STM32 device family. You can use this template for creating and building your new flash algorithm. Locate the Bare-metal_examples.zip file within the DS-5/Examples directory. Extract the DS-5Examples\flash_algo-STM32F10x directory to your file system and then import this project into your DS-5 Eclipse Workspace. Using this as your template, create a new project, copy the content from the example into your new project and modify as appropriate.

Once you have successfully built your .FLM file(s), proceed as outlined in section 6.1.

7             Keil flash algorithm Worked Example

The previous Keil flash examples have focused on flash support for a Cortex-M3 class device. This section shows how to create a new Keil flash algorithm for a Cortex-A9 device and how to add it to the Versatile Express Cortex-A9x4 RTSM (as shipped with DS-5). Further, since the Versatile Express Cortex-A9x4 RTSM platform is available to all DS-5 Debugger users it means this example can be tried out by all DS-5 Debugger users.

Everything required to try out this example out is contained within flash_example.zip.

7.1         Creating the Keil flash algorithm

The full source code and project files for the algorithm are contained within flash_example.zip in the flash_algo-RTSM_VE_Cortex_A9x4 folder.

To import the algorithm project into DS-5, right click in the Project Explorer and select Import. In the General section of the Import dialog, select Existing projects into Workspace and click Next >. On the Import Projects page, choose the Select archive file radio button and browse to the flash_example.zip file. The project should appear in the Projects: section and should be automatically selected. Finally, click the Finish button to import the project into your workspace.

The algorithm itself does not actually program any flash. Instead it just copies the flash data into RAM memory, starting at address 0x80000000. However the example does show how to build and use a Keil flash algorithm to run on a Cortex-A9 core. The main file of interest in the project is the FlashPrg.c file. This shows implementations for the required functions according to the specification at http://www.keil.com/support/man/docs/ulink2/ulink2_alg_func.htm

Go ahead and build the project to generate the RTSM_VE_Cortex-A9x4.FLM file (the Keil flash algorithm).

7.2         Adding the Keil flash algorithm to the Versatile Express Cortex-A9x4 RTSM

As previously mentioned, you should not modify the installed platform entry for the Versatile Express Cortex-A9x4 RTSM. Either follow the instructions in section 9.2.1 to make a writable copy of the Versatile Express Cortex-A9x4 RTSM platform (located in <configdb>/Boards/ARM/RTSM_VE_Cortex_A9x4) or use the updated configdb entry delivered within flash_example.zip (see the configdb folder). Remember to let DS-5 know about the extra configdb location using the DS-5 Debugger Eclipse Preferences.

If a copy of the installed platform has been made, modify the copied platforms project_types.xml file as outlined in section 6.1 to reference a new flash.xml file.

The flash.xml file for the platform should contain:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!--Copyright (C) 2012 ARM Limited. All rights reserved.-->

<flash_config

xmlns:xi="http://www.w3.org/2001/XInclude"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://www.arm.com/flash_config"

xsi:schemaLocation="http://www.arm.com/flash_config ../../../Schemas/flash_config.xsd">

<devices>

<device name="FlashKeil">

<programming_type type="FILE">

<!-- Use the standard method for running Keil algorithms -->

<method language="JYTHON" script="FDB://keil_flash.py" class="KeilFlash" method_config="Keil"/>

</programming_type>

</device>

</devices>

<method_configs>

<method_config id="Keil">

<params>

<!-- Programming algorithm binary to load to target -->

<param name="algorithm" type="string" value="FDB://algorithms/RTSM_VE_Cortex-A9x4.FLM"/>

<!-- The core in the target to run the algorithm -->

<param name="coreName" type="string" value="ARM_Cortex-A9MP_0"/>

<!-- RAM location & size for algorithm code and write buffers -->

<param name="ramAddress" type="integer" value="0x90010000"/>

<param name="ramSize" type="integer" value="0x10000"/>

<!-- Allow timeouts to be disabled -->

<param name="disableTimeouts" type="string" value="false"/>

<!-- Set to false to skip the verification stage -->

<param name="verify" type="string" value="true"/>

</params>

</method_config>

</method_configs>

</flash_config>

This defines a fake flash address area of 0x80000000..0x8007FFFF (as defined in the RTSM_VE_Cortex-A9x4.FLM see FlashDev.c) which is really a RAM area within the RTSM. The xml defines a target RAM area of 0x90010000..0x9001FFFF into which the flash programming code and data buffers may be loaded.

7.3         Using the Keil flash algorithm

To use the new flash algorithm you must create a launch configuration which uses the modified platform. If you are using the updated configdb entry from flash_example.zip, the new platform is called RTSM_VE_Cortex-A9x4-, WithFlash. On the Connection Tab, select the Bare Metal Debug, Debug Cortex-A9_0 debug operation. On the Debugger Tab select Connect only as the Run Control option. It should then be possible to launch the debug session.

Once the session has launched, the info flash command can be issued from the Commands view. This will display the information on the known flash devices. If the installed configdb entry was manually modified, you will see one flash device called FlashKeil. If the configdb entry from flash_example.zip was used you will see two flash devices, the FlashKeil one and the FlashCustom one. The FlashCustom device is explained later in this document see section 9.

info flash

FlashKeil

regions: 0x80000000-0x8007FFFF

parameters: programPageTimeout: 500

driverVersion: 257

programPageSize: 0x1000

eraseSectorTimeout: 500

sectorSizes: ((0x1000, 0x00000000))

valEmpty: 0xff

type: 1

size: 0x00080000

name: RTSM VE Cortex-A9x4 Flash

address: 0x80000000

algorithm: FDB://algorithms/RTSM_VE_Cortex-A9x4.FLM

coreName: ARM_Cortex-A9MP_0

ramAddress: 0x90010000

ramSize: 0x10000

disableTimeouts: false

verify: true

 

FlashCustom

regions: 0x90000000-0x9000FFFF

parameters: coreName: ARM_Cortex-A9MP_0

ramAddress: 0x90010000

ramSize: 0x10000

To see what happens when programming flash we need to issue the flash load command from the Commands view. The flash_example.zip contains an image called FlashImage0x80000000.axf which is suitable for loading into flash as it contains data for the 0x80000000..0x8007FFFF address range.

To load this file you can issue the:

flash load "<path>\FlashImage0x80000000.axf"

command, with <path> replaced by the full path to where you have extracted the file. If all is well, you should see the flash progress monitor displayed and can view the progress of the flash programming operation.

flash load "<path>\FlashImage0x80000000.axf"

Writing segment 0x80000000 ~ 0x80080000 (size 0x80000)

WARNING(LOG123): Segment 0x80000000 ~ 0x80100000 can only partially be written as it does not fully correspond to selected device regions

Flash programming completed OK (target state was not preserved)

Note that the warning message can be ignored as the .axf file contains more data than will fit into the flash area.

8             Creating a new Flash Method

If there is no existing Flash Method that covers your requirements (this means, the Keil Flash Method is inappropriate for your requirements), it is necessary to create a new one. The following steps outline the process of creating a new flash programming method.

Programming methods are implemented in Jython (Python, utilizing the Jython runtime). The use of Jython allows access to the DTSL APIs used by the DS-5 debugger. DS-5 includes the PyDev tools to assist in writing Python scripts.

Note that the Flash directory of the DS-5 configuration database contains a number of Python files in the flashprogrammer subdirectory that contain utility methods used in the following example.

8.1         Using the default implementation 'FlashMethodv1'

Flash programming methods are written as Python classes that are required to implement the com.arm.debug.flashprogrammer.IFlashMethod interface. This interface defines the methods the flash programming layer of DS-5 Debugger may invoke. A default implementation com.arm.debug.flashprogrammer.FlashMethodv1 is provided that has empty implementations of all functions - this allows a Python class derived from this object to only implement the functions it requires. See flash_method_v1.py for the details.

Running a flash programming method is split into three phases:

1.     Setup - the setup() function should prepare the target for performing flash programming. This may involve reading and validating parameters passed from the configuration file, opening a connection to the target, preparing the target state (for example, initialize flash controller) and loading any flash programming algorithms to the target

2.     Programming - the program() function is called for each section of data to be written. Images may have multiple load regions, so program() may be called several times. The data to write is passed to this function and the method should write the data into flash at this stage

3.     Teardown - the teardown() function is called after all sections have been programmed. At this stage the target state can be restored (for example, take the flash controller out of write mode, or reset the target) and any debug connection closed.

NOTE: Do not confuse the setup() and teardown() functions with the target platform optional setup() and teardown() scripts. The setup() and teardown() functions define in the flash method class are for the method itself not the board.

8.2         Creating the Flash Method Python script

For the purposes of this example we assume the Python script is called example_flash.py.

The script should start by importing the objects required in the script:

from flashprogrammer.flash_method_v1 import FlashMethodv1

from com.arm.debug.flashprogrammer import TargetStatus

It then needs to define the class implementing the method:

class ExampleFlashWriter(FlashMethodv1):

def __init__(self, methodServices):

FlashMethodv1.__init__(self, methodServices)

 

def setup(self):

# perform any setup for the method here

pass

 

def teardown(self):

# perform any clean up for the method here

# return the target status

return TargetStatus.STATE_RETAINED

 

def program(self, regionID, offset, data):

# program a block of data to the flash

# regionID indicates the region within the device (as defined in the flash configuration file)

# offset is the byte offset within the region

 

# perform programming here

 

# return the target status

return TargetStatus.STATE_RETAINED

The __init__ function is the constructor and is called when the class instance is created. methodServices allows the method to make calls into the flash programmer - it should not be accessed directly: FlashMethodv1 provides functions described in the following sections that the method can call while programming.

The program() and teardown() methods should return a value that describes the state the target has been left in. This can be one of:

         STATE_RETAINED - the target state has not been altered from the state when programming started, this means register and memory contents have been preserved or restored

         STATE_LOST - register and memory contents have been altered, but a system reset is not required

         RESET_REQUIRED - It is required or recommended that the target be reset

         POWER_CYCLE_REQUIRED - It is required that the target be manually power cycled (for example, a debugger driven reset is not possible or not sufficient to reinitialize the target)

8.2.1       Creating the target platform setup and teardown scripts

If the hardware platform itself requires some setup (operations to be performed prior to flash programming) and/or teardown (operations to be performed after flash programming) functionality, you must create one or more scripts which contain setup() and teardown() functions. These can be in separate script files or may be combined onto one. Let us proceed assuming a single file called file_target.py has been created with the following used as a template:

from com.arm.debug.flashprogrammer.IFlashClient import MessageLevel
from flashprogrammer.device import ensureDeviceOpen
from flashprogrammer.execution import ensureDeviceStopped
from flashprogrammer.device_memory import writeToTarget

def setup(client, services):
# get a connection to the core
conn = services.getConnection()
dev = conn.getDeviceInterfaces().get("Cortex-M3")
ensureDeviceOpen(dev)
ensureDeviceStopped(dev)

# Perform some target writes to enable flash programming
writeToTarget(dev, FLASH_EN, intToBytes(0x81))

def teardown(client, services):
# get a connection to the core
conn = services.getConnection()
dev = conn.getDeviceInterfaces().get("Cortex-M3")
ensureDeviceOpen(dev)
ensureDeviceStopped(dev)

# Perform some target writes to disable flash programming
writeToTarget(dev, FLASH_EN, intToBytes(0))

This file should be placed into the configdb Flash directory so that it can be referenced using a FDB:// prefix in the flash configuration file.


8.2.2       Creating the Flash Configuration File

To use the method to program flash, a configuration file must be created that describes the flash device, the method to use and any parameters or other information required. This is an xml file and is typically stored in the same directory as the target's other configuration files (Boards/<Manufacturer>/<Board name>) as it contains target specific information.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<flash_config

xmlns:xi="http://www.w3.org/2001/XInclude"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://www.arm.com/flash_config"

xsi:schemaLocation="http://www.arm.com/flash_config flash_config.xsd">

<devices>

<device name="Example">

<regions>

<region address="0x8000" size="0x10000"/>

</regions>

<programming_type type="FILE">

<method language="JYTHON" script="FDB://example_flash.py" class="ExampleFlashWriter" method_config="Default"/>

<setup script="FDB://file_target.py" method="setup"/>

<teardown script="FDB://file_target.py" method="teardown"/>

</programming_type>

</device>

</devices>

<method_configs>

<method_config id="Default">

<params>

<!-- Use last 2K of RAM -->

<param name="ramAddress" type="integer" value="0x00100000"/>

<param name="ramSize" type="integer" value="0x800"/>

</params>

</method_config>

</method_configs>

</flash_config>

The flash_config tag defines the XML spaces and schemas used. This does not usually need to be changed.

Under the flash_config tag, a devices tag is required. This contains a number of device tags, each representing one flash device on the target.

The device tag defines the name of the device - this is the name reported by the info flash command and is used when only programming to a specific device. It also defines a number of regions where the flash device appears in the target's memory - the addresses of each region are matched against the address of each load region of the image being programmed.

The programming_type tag defines the programming method and setup/teardown scripts to be used for a flash programming operation (currently only "FILE" is supported).

The method tag defines the script which implements the programming method. Currently, only "JYTHON" is supported for the language attribute. The script and class attributes define which script file to load and the name of the class that implements the programming method within the script. The method_config attributes define which set of parameters are used by the device (this allows multiple devices to share a set of parameters).

The programming_type may also have optional setup and teardown tags. These define a script and a method within that script to call before/after flash programming.

Within the method_configs tag, the parameters for each device are contained within method_config tags.

Parameters must have a unique name and a default value. The value passed to the method can be overridden by the user see the help for the flash load command within DS-5 Debugger.

Where the configuration file references another file (for example, the script files), the FDB:// prefix is used to indicate that the file is located in the Flash/ subdirectory of the configuration database. Where multiple databases are used, the Flash/ subdirectory of each is searched until the file is found.

The last file that needs to be changed is the project_types.xml file in the target's directory to tell DS-5 that the flash configuration can be found in the file created above. The following line should be added under the top-level platform_data tag:

<flash_config>CDB://flash.xml</flash_config>

The CDB:// prefix tells DS-5 that the flash.xml file is located in the same directory as the project_types.xml file

8.3         Testing the Flash configuration

With the files described in the previous sections in place, it should be possible to make a connection to the target in DS-5 and inspect the flash devices available and program an image (although, with the files in their current form, no data will actually be written to flash).

If DS-5 is already open and project_types.xml is changed, it will be necessary to rebuild the configuration database (See the DS-5 documentation).

Open the target connection to DS-5 and enter the following command into the Commands view:

info flash

This should print out the following:

Example

regions: 0x8000-0x18000

parameters:

The Flash programming operation can be tested by attempting to program with a test ELF file (use any ELF (.axf) file which contains data within the configured address range):

flash load flashyprogram.axf

Writing segment 0x00008000 ~ 0x0000810C (size 0x10C)

Flash programming completed OK (target state has been preserved)

8.4         Flash Method Parameters

Programming methods can take parameters that serve to change the behavior of the flash programming operation. Example parameters could be:

         the programming algorithm image to load (for example, the Keil Flash Algorithm file)

         the location & size of RAM the method can use for running code, buffers etc

         clock speeds

         timeouts

         programming & erase page sizes

The default values of the parameters are taken from the flash configuration file. The user can override the parameters from the DS-5 command line.

The programming method can obtain the value of the parameters with:

         getParameter(name): returns the value of a parameter as a string. The method can covert this to integers etc as required. 'None' is returned if no value is set for this parameter

         getParameters(): returns a map of all parameters to values. Values can then be obtained with the [] operator.

For example:

def setup(self):

# get the name of the core to connect to

coreName = self.getParameter("coreName")

 

# get parameters for working RAM

self.ramAddr = int(self.getParameter("ramAddress"), 0)

self.ramSize = int(self.getParameter("ramSize"), 0)

8.5         Getting data to the flash algorithm

Data is passed to the program() function by the data parameter. This is an object that provides the following functions:

         getSize(): returns the amount of data available in bytes

         getData(sz): returns a buffer of up to sz data bytes (may be less for example,. at end of data). The read position is advanced

         seek(pos): move the read position

         getUnderlyingFile(): gets the file containing the data (None if not backed by a file). This allows the method to pass the file to an external tool

The method can process the data with:

def program(self, regionID, offset, data):

data.seek(0)

bytesWritten = 0

while bytesWritten < data.getSize():

# get next block of data

buf = data.getData(self.pageSize)

 

# write buf to flash

bytesWritten += len(buf)

8.6         Interacting with the target

To perform the flash programming, the programming method may need to access the target. The flash programmer provides access to the DTSL APIs for this and the programming method can get a connection with the getConnection() function of class FlashMethodv1. This should be called in the setup() function of the programming method. If there is already an open connection (for example, from the DS-5 debugger), this will be re-used.

def setup(self):

# connect to core

self.conn = self.getConnection()

8.6.1       Accessing the core

It may also be necessary to open a connection to the core. As the debugger may already have an open connection, a new connection is not always possible. To assist with this, a utility function, ensureDeviceOpen(), is provided that will open the connection only if required. It will return true if the connection was opened and so should be closed after programming in the teardown() function.

Access to the core's registers and memory will required the core to be stopped. The ensureDeviceStopped() function is provided to assist with this.

def setup(self):

# connect to core & stop

self.conn = self.getConnection()

coreName = self.getParameter("coreName")

self.dev = self.conn.getDeviceInterfaces().get(coreName)

self.deviceOpened = ensureDeviceOpen(self.dev)

ensureDeviceStopped(self.dev)

 

def teardown(self):

if self.deviceOpened:

# close device connection if opened by this script

self.dev.closeConn()

8.6.2       Reading/writing memory

The core's memory can be accessed via the memWrite(), memFill() and memRead() functions of the dev object (IDevice).

from com.arm.rddi import RDDI

from com.arm.rddi import RDDI_ACC_SIZE

from jarray import zeros

 

...

 

def program(self):

...

self.dev.memFill(0, addr, RDDI_ACC_SIZE.RDDI_ACC_WORD,

RDDI.RDDI_MRUL_NORMAL, False, words, 0)

self.dev.memWrite(0, addr, RDDI_ACC_SIZE.RDDI_ACC_WORD,

RDDI.RDDI_MRUL_NORMAL, False, len(buf), buf)

...

 

def verify(self):

...

readBuf = zeros(len(buf), 'b')

self.dev.memRead(0, addr, RDDI_ACC_SIZE.RDDI_ACC_WORD,

RDDI.RDDI_MRUL_NORMAL, len(readBuf), readBuf)

...

 

Utility routines to make the method code clearer are provided in device_memory:

from flashprogrammer.device_memory import writeToTarget, readFromTarget

 

...

 

def program(self):

...

writeToTarget(self.dev, address, buf)

...

 

def verify(self):

...

readBuf = readFromTarget(self.dev, addr, count)

...

8.6.3       Reading/writing registers

The core's registers can be read/written using the regReadList() and regWriteList() functions of Idevice (but note you must be careful only pass int values, not long values). These identify registers using numeric IDs. These IDs are target specific (for example, R0 is register 1 on a Cortex-A device, but register 0 on a Cortex-M device). execution.py provides functions that map register names to numbers and allow reading/writing by name:

writeRegs(device, regs): writes a number of registers to a device. regs is a list of (name, value) pairs, for example.

writeRegs(self.dev, [ ("R0", 0), ("R1", 1234), ("PC", 0x8000) ]

will set R0, R1 and PC (R15)

readReg(device, reg): reads a named register, for example:

value = readReg("R0")

will read R0 and return its value.

8.6.4       Running code on the core

The core can be started and stopped via the go() and stop() functions. Breakpoints can be set with the setSWBreak() or setHWBreak() functions and cleared with the clearSWBreak() or clearHWBreak() functions. As it may take some time to reach the breakpoint, the script should wait for the breakpoint to be hit and the core stopped before any further access to the target. execution.py provides utility methods to assist with running code on the target:

stopDevice(device, timeout=1.0):

request the core to stop and waits for the stop status event to be received, raising an error if no event is received before timeout elapses.

ensureDeviceStopped(device, timeout=1.0):

checks the device's status and calls stopDevice() if it is not stopped

runAndWaitForStop(device, timeout=1.0):

starts the core and waits for it to stop, forcing the core to stop and raising an error if it doesn't stop before timeout elapses. The caller should have set the registers appropriately and have set a breakpoint or vector catch to cause the core to stop at the desired address.

runToBreakpoint(device, addr, bpFlags = RDDI.RDDI_BRUL_STD, timeout=1.0):

sets a software breakpoint at addr, starts the core and waits for it to stop by calling runAndWaitForStop(). The caller should have set the registers appropriately.

Flash programming algorithms are often implemented as functions that are run on the target itself. These functions may take parameters where the parameters are passed in via registers. funcCall() allows methods to call functions that follow AAPCS (with some restrictions):

         Up to the first four parameters are passed in registers R0-R3

         Any parameters above this are passed via the stack

         Only integer up to 32bit or pointer parameters are supported, floating point or 64bit integers are not

         The result is returned in R0

We can use the above to simulate flash programming by writing the data to RAM (see example_method_1.py). This

         Connects to the target on setup()

         Fills the destination RAM with 0s to simulate erase

         Writes data to a write buffer in working RAM

         Runs a routine that copies the data from the write buffer to the destination RAM

         Verifies the write by reading from the destination RAM

8.6.5       Loading Programming Algorithm images onto the target

Programming algorithms are often compiled into .elf images.

FlashMethodv1.locateFile() locates a file for example, from a parameter, resolving any FDB:// prefix to absolute paths.

symfile.py provides a class, SymbolFileReader, that allows the programming method to load an image file and get the locations of symbols:

For example, to get the location of a function

# load the algorithm image

algorithmFile = self.locateFile(self.getParameter('algorithm'))

algoReader = SymbolFileReader(algorithmFile)

 

# Find the address of the Program() function

funcInfo = algoReader.getFunctionInfo()['Program']

programAddr = funcInfo['address']

if funcInfo['thumb']:

# set bit 0 if symbol is thumb

programAddr |= 1

image_loader.py provides routines to load the image to the target:

# load algorithm into working RAM

algoAddr = self.ramAddr + 0x1000 # allow space for stack, buffers etc

loadAllCodeSegmentsToTarget(self.dev, algoReader, algoAddr)

If the algorithm binary was linked as position independent, the addresses of the symbols are relative to the load address and this offset should be applied when running the code on the target:

programAddr += algoAddr

args = [ writeBuffer, destAddr, pageSize ]

funcCall(self.dev, programAddr, args, self.stackTop)

8.6.6       Progress reporting

Flash programming can be a slow process, so it is desirable to report progress to the user. The method can do this by calling operationStarted(). This returns an object with functions:

         progress(): Update the reported progress

         complete(): Report the operation as completed, with a success or failure

Progress reporting can be added to the program() function in the previous example:

def program(self, regionID, offset, data):

# calculate the address to write to

region = self.getRegion(regionID)

addr = region.getAddress() + offset

# Report progress, assuming erase takes 20% of the time, program 50%

# and verify 30%

progress = self.operationStarted(

'Programming 0x%x bytes to 0x%08x' % (data.getSize(), addr),

100)

 

self.doErase(addr, data.getSize())

progress.progress('Erasing completed', 20)

 

self.doWrite(addr, data)

progress.progress('Writing completed', 20+50)

 

self.doVerify(addr, data)

progress.progress('Verifying completed', 20+50+30)

 

progress.completed(OperationResult.SUCCESS, 'All done')

 

# register values have been changed

return TargetStatus.STATE_LOST

The above example only has coarse progress reporting, only reporting at the end of each phase. Better resolution can be achieved by allow each sub-task to have a progress monitor. subOperation() will create a child progress monitor.

Care should be taken to ensure completed() is called on the progress monitor when an error occurs. It is recommended that a try: ... except: block is placed around the code after a progress monitor is created :

import java.lang.Exception

def program(self, regionID, offset, data):

progress = self.operationStarted(

'Programming 0x%x bytes to 0x%08x' % (data.getSize(), addr),

100)

try:

# Do programming

except (Exception, java.lang.Exception), e:

# exceptions may be derived from Java Exception or Python Exception

# report failure to progress monitor & rethrow

progress.completed(OperationResult.FAILURE, 'Failed')

raise

Note the import of java.lang.Exception. If you omit import and a Java exception is thrown, you may get a confusing error report from Jython indicating that it cant find the Java namespace. Further the python line location indicated as the source of the error will not be accurate.

8.6.7       Cancellation

The user may also wish to abort a long running flash operation. Programming methods can call isCancelled() to check if the user has cancelled. If this returns true, the method should stop programming. Note that the teardown() functions are still called.

8.6.8       Messages

The programming method can report messages to the user by calling the following:

         warning(): Reports a warning message

         info(): Reports an informational message

         debug(): Reports a debug message - not normally shown to the user

8.6.9       Locating/resolving files

FlashMethodv1.locateFile() locates a file for example, from a parameter, resolving any FDB:// prefix to absolute paths.

The paths searched are the Flash subdirectories of all configuration databases the user has configured in DS-5, for example.:

         <DS5_INSTALL_DIR>/sw/debugger/configdb/Flash/

         c:\MyDB\Flash

8.6.10    Error handling

Exceptions are thrown when errors occur. Errors from the API calls made by the programming method will be com.arm.debug.flashprogrammer.FlashProgrammerException (or derived from this). Methods may also report errors using Python's "raise" keyword, for example, if verification fails:

# compare contents

res = compareBuffers(buf, readBuf)

if res != len(buf):

raise FlashProgrammerRuntimeException, "Verify failed at address: %08x" % (addr + res)

Should a programming method need to ensure cleanup occurs when an exception is thrown, the following code forms a template:

import java.lang.Exception

...

try:

# Do programming

except (Exception, java.lang.Exception), e:

# exceptions may be derived from Java Exception or Python Exception

# report failure to progress monitor & rethrow

# Handle errors here

# Rethrow original exception

raise

finally:

# This is always executed on success or failure

# Close resources here

See the progress handler section for an example use of this.

Note the import of java.lang.Exception. If you miss this import out and a Java exception is thrown, you may get a confusing error report from Jython along the lines that it cant find the Java namespace. Further the python line location indicated as the source of the error will not be accurate.

8.6.11    Running an external tool

Some targets may already have a standalone flash programming tool. It is possible to create a DS-5 Debugger programming method to call this tool passing it the path of the image to load. The following example shows how to do this, using the fromelf tool in place of a real flash programming tool.

from flashprogrammer.flash_method_v1 import FlashMethodv1

from com.arm.debug.flashprogrammer.IProgress import OperationResult

from com.arm.debug.flashprogrammer import TargetStatus

import java.lang.Exception

import subprocess

 

class RunProgrammer(FlashMethodv1):

def __init__(self, methodServices):

FlashMethodv1.__init__(self, methodServices)

 

 

def program(self, regionID, offset, data):

 

progress = self.operationStarted(

'Programming 0x%x bytes with command %s' % (data.getSize(), ' '.join(cmd)),

100)

try:

# Get the path of the image file

file = data.getUnderlyingFile().getCanonicalPath()

cmd = [ 'fromelf', file ]

self.info("Running %s" % ' '.join(cmd))

# run command

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)

out, err = proc.communicate()

# pass command output to user as info message

self.info(out)

progress.progress('Completed', 100)

progress.completed(OperationResult.SUCCESS, 'All done')

 

except (Exception, java.lang.Exception), e:

# exceptions may be derived from Java Exception or Python Exception

# report failure to progress monitor & rethrow

progress.completed(OperationResult.FAILURE, 'Failed')

raise

return TargetStatus.STATE_RETAINED

os.environ can be used to lookup environment variables, for example the location of a target's toolchain:

programmerTool = os.path.join(os.environ['TOOLCHAIN_INSTALL'], 'flashprogrammer')

8.6.12    Setup / teardown

The flash configuration file can specify scripts to be run before and after flash programming. These are termed setup and teardown scripts and are defined using setup and teardown tags. The setup script should put the target into a state ready for flash programming. This may involve one or more of:

         resetting the target

         disabling interrupts

         disable peripherals that may interfere with flash programming

         setup DRAM

         enable flash control

         setup clocks appropriately

The teardown script should return the target to a usable state following flash programming.

In both cases, it may be necessary to reset the target. The following code can be used to stop the core on the reset vector (but note that it assumes the core supports the RSET vector catch feature):

def setup(client, services):

# get a connection to the core

conn = services.getConnection()

dev = conn.getDeviceInterfaces().get("Cortex-M3")

ensureDeviceOpen(dev)

ensureDeviceStopped(dev)

dev.setProcBreak("RSET")

dev.systemReset(0)

# TODO: wait for stop!

dev.clearProcBreak("RSET")

8.6.13    Other ways of providing Flash Method parameters

The flash configuration file can provide flash region information and flash parameter information encoded into the XML. However for some methods, this information may need to be extracted from the flash algorithm itself.

Programming methods can extend any information in the flash configuration file (if any) with address regions and parameters for the method by overriding a pair of class methods - getDefaultRegions() and getDefaultParameters().

from com.arm.debug.flashprogrammer import FlashRegion

 

...

class ProgrammingMethod(FlashMethodv1):

...

 

def getDefaultRegions(self):

return [ FlashRegion(0x00100000, 0x10000), FlashRegion(0x00200000, 0x10000) ]

 

def getDefaultParameters(self):

params = {}

params['param1'] = "DefaultValue1"

params['param2'] = "DefaultValue2"

return params

The above code defines two 64kb regions at 0x00100000 and 0x00200000. Regions supplied by this method are only used if no regions are specified for the device in the configuration file.

The above code defines 2 extra parameters. These parameters are added to the parameters in the flash configuration. If a parameter is defined in both, the default value in the flash configuration file is used.

This region and parameter information can be extracted from the algorithm binary itself (rather than being hard coded in the above example). The Keil algorithm images contain a data structure defining the regions covered by the device and the programming parameters for the device. The Keil programming method loads the algorithm binary (specified by a parameter in the configuration file) and extracts this information to return in these calls.

9             Custom Flash Method - Worked Example

The example shows the programming of a fake flash device for which the programming operations end up writing to RAM memory. The erase operation clears the memory to 0 and the programming operation just writes the flash data to RAM.

To enable this example to be tested and experimented with, the Versatile Express Cortex-A9x4 RTSM is used as the target (this model is shipped as part of DS-5).

9.1         Example files

The example uses three files;

1.     The flash configuration XML (flash.xml)

2.     The flash programming method written in Jython (flash_example.py)

3.     An example image to load into 'flash' (FlashImage0x90000000.axf)

9.1.1       The configuration file flash.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flash_config
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.arm.com/flash_config"
xsi:schemaLocation="http://www.arm.com/flash_config flash_config.xsd">
<devices>
<device name="Flash Example">
<regions>
<region address="0x90000000" size="0x10000"/>
</regions>
<programming_type type="FILE">
<method language="JYTHON" script="FDB://flash_example.py" class="ExampleWriter" method_config="Default"/>
</programming_type>
</device>
</devices>
<method_configs>
<method_config id="Default">
<params>
<param name="coreName" type="string" value="ARM_Cortex-A9MP_0"/>
<!-- Use last 2kb of RAM -->
<param name="ramAddress" type="integer" value="0x90010000"/>
<param name="ramSize" type="integer" value="0x800"/>
</params>
</method_config>
</method_configs>
</flash_config>

This simple configuration file declares:

         a flash device called Flash Example

         the flash address range as 0x90000000..0x9000FFFF (64K of RAM). For this example, this defines the RAM address range to which the example writes the Flash data

         the flash method class as ExampleWriter contained within the flash_example.py file

         the parameters for the flash method

   the core name to use for the programming operation in this example it is set to ARM_Cortex-A9MP_0 as declared in the project_types.xml for the target platform.

   the RAM address range to use for the programming algorithm 0x90010000..0x900007FF. In this example the flash method will write some code to this address range to perform the programming operations

9.1.2       The flash method flash_example.py

from flashprogrammer.flash_method_v1 import FlashMethodv1
from com.arm.debug.flashprogrammer import FlashProgrammerRuntimeException
from com.arm.debug.flashprogrammer.IProgress import OperationResult
from com.arm.debug.flashprogrammer import TargetStatus
import java.lang.Exception
import os.path
from com.arm.debug.dtsl import IDevice
from com.arm.rddi import RDDI
from com.arm.rddi import RDDI_ACC_SIZE
from jarray import zeros
import struct

from flashprogrammer.device import ensureDeviceOpen
from flashprogrammer.execution import ensureDeviceStopped, funcCall
from flashprogrammer.device_memory import writeToTarget

MEMCPY = [ # myMemCpy
0x00, 0x25, # MOVS r5,#0
# myMemCpyLoop
0x44, 0x59, # LDR r4,[r0,r5]
0x4c, 0x51, # STR r4,[r1,r5]
0x2d, 0x1d, # ADDS r5,r5,#4
0x52, 0x1e, # SUBS r2,r2,#1
0xfa, 0xd1, # BNE myMemCpyLoop
0x70, 0x47, # BX lr
0x00, 0x00,
]

def toBytes(buf):
# Pack bytes into buffer for writing to target
return ''.join(map(chr, buf))


class ExampleWriter(FlashMethodv1):
def __init__(self, methodServices):
FlashMethodv1.__init__(self, methodServices)


def setup(self):
# connect to core & stop
self.conn = self.getConnection()
coreName = self.getParameter("coreName")
self.dev = self.conn.getDeviceInterfaces().get(coreName)
self.deviceOpened = ensureDeviceOpen(self.dev)
ensureDeviceStopped(self.dev)

# get parameters for working RAM
self.ramAddr = int(self.getParameter("ramAddress"), 0)
self.ramSize = int(self.getParameter("ramSize"), 0)

# calculate addresses of algorithm code, stack & write buffer in working RAM
self.codeAddr = self.ramAddr
self.stackBottom = self.codeAddr + len(MEMCPY)
self.stackTop = self.stackBottom + 0x100 - 4
self.writeBuffer = self.stackTop + 4
self.writeBufferSize = 1024
self.pageSize = 1024

self.debug("Loading algorithm to %08x, stack: %08x..%08x, writeBuffer: %08x" % (
self.codeAddr, self.stackBottom, self.stackTop, self.writeBuffer)
)

# load the mem copy routine to working RAM
writeToTarget(self.dev, self.codeAddr, toBytes(MEMCPY))


def teardown(self):
if self.deviceOpened:
# close device connection if opened by this script
self.dev.closeConn()
# register values have been changed
return TargetStatus.STATE_LOST


def program(self, regionID, offset, data):
# calculate the address to write to
region = self.getRegion(regionID)
addr = region.getAddress() + offset

progress = self.operationStarted(
'Programming 0x%x bytes to 0x%08x' % (data.getSize(), addr),
100)

try:
self.doErase(addr, data.getSize(), self.subOperation(progress, 'Erasing', data.getSize(), 20))
progress.progress('Erasing completed', 20)

self.doWrite(addr, data, self.subOperation(progress, 'Writing', data.getSize(), 50))
progress.progress('Writing completed', 20+50)

self.doVerify(addr, data, self.subOperation(progress, 'Verifying', -1, 30))
progress.progress('Verifying completed', 20+50+30)

progress.completed(OperationResult.SUCCESS, 'All done')

except (Exception, java.lang.Exception), e:
# exceptions may be derived from Java Exception or Python Exception
# report failure to progress monitor & rethrow
progress.completed(OperationResult.FAILURE, 'Failed')
raise

# register values have been changed
return TargetStatus.STATE_LOST


def doErase(self, addr, size, progress):
try:
eraseBlock = 0x400
bytesErased = 0
while bytesErased < size:
# blank out memory in 1kb chunks
self.dev.memFill(0, addr, RDDI_ACC_SIZE.RDDI_ACC_WORD,
RDDI.RDDI_MRUL_NORMAL, False, eraseBlock/4, 0)

addr += eraseBlock
bytesErased += eraseBlock
progress.progress('Erased %d bytes' % bytesErased, bytesErased)

progress.completed(OperationResult.SUCCESS, 'Erasing completed')

except (Exception, java.lang.Exception), e:
# exceptions may be derived from Java Exception or Python Exception
# report failure to progress monitor & rethrow
progress.completed(OperationResult.FAILURE, 'Erasing failed')
raise


def doWrite(self, addr, data, progress):
try:
data.seek(0)
bytesWritten = 0
while bytesWritten < data.getSize():
# get next block of data
buf = data.getData(self.pageSize)

# write to buffer
self.dev.memWrite(0, self.writeBuffer, RDDI_ACC_SIZE.RDDI_ACC_WORD,
RDDI.RDDI_MRUL_NORMAL, False, len(buf), buf)

# run copy routine
args = [ self.writeBuffer, addr, len(buf)/4 ]
funcAddr = self.codeAddr | 1 # code is Thumb, so set bit 0
funcCall(self.dev, funcAddr, args, self.stackTop)

bytesWritten += len(buf)
addr += len(buf)
progress.progress('Written %d bytes' % bytesWritten, bytesWritten)

progress.completed(OperationResult.SUCCESS, 'Writing completed')

except (Exception, java.lang.Exception), e:
# exceptions may be derived from Java Exception or Python Exception
# report failure to progress monitor & rethrow
progress.completed(OperationResult.FAILURE, 'Writing failed')
raise


def doVerify(self, addr, data, progress):
try:
data.seek(0)
bytesVerified = 0
while bytesVerified < data.getSize():
# get next block of data
buf = data.getData(self.pageSize)

# read from the destination address
readBuf = zeros(len(buf), 'b')
self.dev.memRead(0, addr, RDDI_ACC_SIZE.RDDI_ACC_WORD,
RDDI.RDDI_MRUL_NORMAL, len(readBuf), readBuf)

# check the buffers match
if readBuf != buf:
raise FlashProgrammerRuntimeException, "Verify failed: %s != %s" % (buf, readBuf)

bytesVerified += len(buf)
addr += len(buf)
progress.progress('Verified %d bytes' % bytesVerified, bytesVerified)

progress.completed(OperationResult.SUCCESS, 'Verifying completed')

except (Exception, java.lang.Exception), e:
# exceptions may be derived from Java Exception or Python Exception
# report failure to progress monitor & rethrow
progress.completed(OperationResult.FAILURE, 'Verify failed')
raise

This example flash method installs a small code fragment onto the target (starting at address 0x90010000) which is used to write the flash data to RAM. Note that a typical flash method would install code which actually programmed the flash data to a flash device. However, to provide a simple example, the code used here will just copy the flash data into RAM.

The flash method implements the following methods as part of the API contract with the DS-5 flash programmer:

         setup(): this example method:

   makes a connection to the configured core

   makes sure the core is halted

   downloads the example code snippet to the target

         teardown(): this example method:

   disconnects from the core

         program(): this example method:

   erases the memory area the DS-5 flash programmer is trying to write to (in this case it just writes 0s to the memory region)

   programs the flash data (in this example it invokes the target code snippet to copy the data to RAM)

   verifies the memory was written ok

Throughout the programming operation, the method informs the DS-5 flash programmer as to its progress by telling it what operation it is currently performing and how far through the total operation is has progressed.

Note that at the end of the programming operation the flash method returns the TargetStatus.STATE_LOST status to the DS-5 flash programmer. This tells the DS-5 flash programmer that there will be a difference between the debuggers current view of the target state and its actual state (registers and memory have been changed). There are a couple of alternate strategies that the flash method could employ:

1.     The setup() method could save the target registers and memory areas that the method uses and the teardown() method could restore them. If the target state was then fully preserved, the programming method could then return TargetStatus.STATE_RETAINED.

2.     The setup() method and/or the teardown() method could reset the target. In this case the programming method could then return TargetStatus.HAS_RESET.

Note that both the program() method and the teardown() method can inform the DS-5 flash programmer about the TargetStatus.

9.2         Adding the example flash support to the Versatile Express Cortex-A9x4 RTSM

The example_flash.zip file contains a modified Versatile Express Cortex-A9x4 RTSM configdb entry which already includes all the changes outlined below. You can use that one directly or follow the instructions below on how to add the support to the already installed Versatile Express Cortex-A9x4 RTSM configdb entry.

The instructions contained within this section require modification to a platform entry in the target configuration database as installed by DS-5. It is not recommended to modify the DS-5 installation itself, so a copy of the relevant sections of the configuration database need to be performed and DS-5 will need to be directed to include the copy in its database search path.

9.2.1       Creating a copy of the configdb entries

         Create a writeable directory entry called configdb somewhere in your file system

         Locate the DS-5 installation directory (on Windows the default is C:\Program Files (x86)\DS-5\sw\debugger\configdb)

         Copy the entire contents of the Flash directory from the installed configdb directory to below your writeable configdb directory

         Copy the entire contents of the Scripts directory from the installed configdb directory to below your writeable configdb directory (note that in future releases of DS-5 this step will not be required)

         Create a Boards directory within your writeable configdb directory

         Create an ARM-New directory below your writeable configdb/Boards directory (note that in DS-5 v5.13 this name must not clash with existing board names in the installed configdb. This restriction will be removed in future releases of DS-5)

         Copy the installed Boards/ARM/RTSM_VE_Cortex_A9x4 directory and contents to your writeable configdb/Boards/ARM-New/RTSM_VE_Cortex_A9x4 directory

You should now have the following directory structure:

configdb

Flash

Scripts

...

Boards

ARM-New

RTSM_VE_Cortex_A9x4

9.2.2       Modifying the RTSM_VE_Cortex_A9x4 platform configuration

Place the flash_example.py file into the configdb/Flash directory.

Place the flash.xml file into the configdb/Boards/ARM-New/RTSM_VE_Cortex_A9x4 directory.

Modify the configdb/Boards/ARM-New/RTSM_VE_Cortex_A9x4/project_types.xml file to point to the flash_example.xml file by adding the bold line indicated below:

<?xml version="1.0" encoding="UTF-8"?>

 

<platform_data xmlns:xi="http://www.w3.org/2001/XInclude"

xmlns="http://www.arm.com/project_type"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:peripheral="http://com.arm.targetconfigurationeditor"

xsi:schemaLocation="http://www.arm.com/project_type ../../../Schemas/platform_data-1.xsd"

type="RTSM">

<flash_config>CDB://flash.xml</flash_config>

<project_type_list>

...

9.2.3       Pointing DS-5 at your modified configuration files

Within the DS-5 Eclipse IDE, select the Windows->Preferences menu item. A dialog will then be displayed showing the Eclipse preferences. Expand the DS-5 entry in the left hand list and select Configuration Database. Click the Add button to add a new User Configuration Database entry. Give the new entry a name of your choice and use the Browse... button to locate your writeable configdb directory location. Click OK to close the Add configuration database location dialog. Click the Rebuild Database... button and when complete, close the Eclipse preferences dialog.

9.2.4       Testing the flash support

Create a new launch configuration which uses a Bare Metal SMP connection to the Versatile Express Cortex-A9x4 RTSM;

         Make sure the DS-5 Debugger perspective is selected

         Right click in the Debug Control View and select Debug Configurations

         Within the Debug Configurations dialog, In the left hand side list, select DS-5 Debugger, right click it and choose New from the pop-up menu.

         Give the new configuration a suitable name (for example: FlashExample)

         In the Target filter box, type A9x4 and then select the ARM-New, RTSM_VE_Cortex_A9x4 platform. Expand this platform and its Bare Metal Debug project type entry to select the Debug Cortex-A9_0 debug operation (make sure you select the ARM-New manufacturer entry and not the existing ARM one)

         Figure 2: DS-5 Debug Configurations dialog box selection

         DS-5 Debug Configurations dialog box selection

 

         Select the Debugger tab and then select the Connect Only Run Control operation

         You should now be able to click the Debug button to start the debug session

When the launch operation is complete;

         Within the debugger command view, type the info flash' command. This should show the available flash devices and their assigned target address ranges. Note that if using the configdb entry contained in the flash_example.zip file, you will see another flash device listed as well.

info flash

flash Example

regions: 0x90000000-0x9000FFFF

parameters: coreName: ARM_Cortex-A9MP_0

ramAddress: 0x90010000

ramSize: 0x800

         Within the debugger command view, type the flash load' command giving it the FlashImage0x90000000.axf file to load.

Flash load "FlashImage0x90000000.axf"

The FlashImage0x90000000.axf provided with this technical note has been constructed to write a pattern to address 0x90000000 onwards. After the flash load command has completed you should be able to use the DS-5 Debugger memory view to see this pattern in memory.

Copyright © 2013 ARM Limited. All rights reserved. ARM DAI0352A
Non-Confidential