CrossStudio for ARM supports Flash programming (and subsequent debugging)
by loading a program into the RAM of the target and transmitting it the data
to be programmed.
The use of a target loader is determined by the value of the Loader
File Path project property defined for the appropriate configuration of
the project. The Loader File Path property specifies the location of
the loader executable to use, if this is defined the loader executable will
be downloaded onto the target an run prior to download of the main
application.
In addition to the Loader File Path property, the Loader File
Type project property must be specified. This tells CrossStudio how to
communicate with the loader program. The various communication mechanisms
available are explained in more detail later. The Load File Type
property may be set to one of the following:
- Comms Channel Loader - The ARM debug comms channel is used to
communicate with the loader.
- Fast Comms Channel Loader - The ARM debug comms channel is used
to communicate with the loader. This scheme is significantly faster at
downloading than Comms Channel Loader because it makes the
assumption that the loader program is always ready to read data and
therefore does not check the ARM comms channel status before transmitting
data. This may not be suitable for all targets or loaders. If you
experience reliability problems downloading and verifying programs using
this setting, you should revert to the Comms Channel Loader
setting.
- RAM Loader - The target's RAM is used to communicate with the
loader.
The functionality a loader provides to CrossStudio is:
- Erase all non-volatile memory.
- Erase a block of non-volatile memory.
- Write a block of data into volatile or
non-volatile memory.
- Read a block of data from volatile or non-volatile memory.
- Set a block of volatile or non-volatile memory to a specific
value.
- Verify a block of volatile or non-volatile memory.
CrossStudio can communicate with the loader running on the ARM in one of
two ways:
- ARM Debug Comms Port - All transactions with the loader are carried out
over the ARM debug comms port. This is generally quicker than using RAM
communication, however the ARM debug comms port is not supported on all
targets.
- RAM - All transactions with the loader are carried out by the host
writing data to target RAM, executing code and then reading the results out
of target RAM. This system has the advantage that it will run on all
targets, however it is not necessarily as quick as using the ARM debug
comms port and can be hard to use if RAM is scarce.
To simplify the creation of a new loader program, a number of files have
been supplied in the target/loader directory:
- loader.h - This file contains prototypes for all the loader
functions and a number of useful macros.
- loader_main.c - This file contains the main entry point of a
loader. It handles the reading of commands from the host and calling the
appropriate loader entry points.
- loader_comm.c & loader_ram.c - These files implement
the ARM debug comms port and RAM communication mechanisms used by the
loader. Each file implements a version of the waitForCommand,
loaderReadWord and loaderWriteWord functions. A loader that
uses the ARM debug comms port should link in loader_comm.c and a
loader that uses RAM should link in loader_ram.c. A loader using
loader_comm.cshould have the Loader File Type project
property set to either Comms Channel Loader or Fast Comms Channel
Loader. A loader using loader_ram.cshould have the Loader
File Type project property set to RAM Loader.
In order to implement a loader, the following loader entry points should
be implemented:
- void loaderBegin() - This function is called before the loader
enters it main loop, it can be used to initialize the loader if
required.
- void loaderEnd()- This function is called when the loader exits
it main loop, it can be used to clean up after the loader if required.
- int loaderPoke(unsigned char *address, unsigned int length) -
This function is called when the host requests a write to memory. The
address parameter specifies the address to start writing to, the
length parameter specifies the number of bytes to write. The data to
write should be read from the host using the loaderReadWord
function, the bytes are stored in each word in little endian order. A
non-zero value should be returned on success.
- int loaderMemset(unsigned char *address, unsigned int length,
unsigned char c) - This function is called when the host request memory
to be set to particular value. The address parameter specifies the
address to start writing to, the length parameter specifies the
number of bytes to write and the c parameter specifies the value to
write. A non-zero value should be returned on success.
- int loaderErase(unsigned char *address, unsigned int length) -
This function is called when the host requests a block of non-volatile
memory to be erased. The address parameter specifies the starting
address of the block to erase, the length parameter specifies the
length of the block in bytes. A non-zero value should be returned on
success.
- int loaderEraseAll() - This function is called when the host
requests all non-volatile memory to be erased. A non-zero value should be
returned on success.
- int loaderSetParameter(unsigned int parameter, unsigned int
value) - This function is called when the host attempts to set a loader
specific property. The parameter parameter specifies the parameter
to set, this is currently always set to zero. The value parameter
specifies the value being set. The parameter value to be passed to the
loader can be specified in the Loader Parameter project
property.
A loader that uses loader_ram.c must also define the program
section in RAM called .comm_buffer. The RAM this section occupies is
used to write the data sent to and from the loader. The size to set the
.comm_buffer section to is dependent on how much RAM you have free,
however the larger you set the .comm_buffer the faster the loader will
run.
The loader projects and source code for all the supported targets can be
found in the target-specific directories contained in the targets
directory
The following code demonstrates the structure of a loader
implementation:
#include "../loader/loader.h"
void
loaderBegin()
{
}
void
loaderEnd()
{
}
int
loaderPoke(unsigned char *address, unsigned int length)
{
while (length)
{
unsigned int data = loaderReadWord();
int i;
for (i = 4; i && length; --i)
{
if
(ADDRESS_IN_FLASH(address))
flash_write_byte(address++, (unsigned char)data);
else
*address++
= (unsigned
char)data;
data >>=
8;
length--;
}
}
return 1;
}
int
loaderMemset(unsigned char *address, unsigned int length, unsigned char
c)
{
while(length--)
{
if (ADDRESS_IN_FLASH(address))
flash_write_byte(address++,
(unsigned char)c);
else
*address++ = (unsigned
char)c;
}
return 1;
}
int
loaderErase(unsigned char *address, unsigned int length)
{
if (!is_erased(address, length))
flash_erase(address, length);
return 1;
}
int
loaderEraseAll()
{
if (!is_erased(FLASH_START_ADDRESS, FLASH_END_ADDRESS))
flash_erase_all(FLASH_START_ADDRESS);
return 1;
}
The targets directory contains a directory for each supported
target. The loader source code for each target can be found in these
directories. In order to view, edit and build a loader project open the
Loader.hzp solution for the required target. By default CrossStudio
picks the loaders from the Release/Loader.exe directory of each target
directory.