1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
|
/******************************************************************************
Project: Portable command line ISP for NXP LPC1000 / LPC2000 family
and Analog Devices ADUC70xx
Filename: adprog.c
Compiler: Microsoft VC 6/7, Microsoft VS2008, Microsoft VS2010,
GCC Cygwin, GCC Linux, GCC ARM ELF
Author: Martin Maurer (Martin.Maurer@clibb.de)
Copyright: (c) Martin Maurer 2003-2014, All rights reserved
Portions Copyright (c) by Aeolus Development 2004 http://www.aeolusdevelopment.com
This file is part of lpc21isp.
lpc21isp is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
lpc21isp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
and GNU General Public License along with lpc21isp.
If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(_WIN32)
#if !defined __BORLANDC__
#include "StdAfx.h"
#endif
#endif // defined(_WIN32)
#include "lpc21isp.h"
#ifdef AD_SUPPORT
#include "adprog.h"
/***************************** AnalogDevicesSync ************************/
/** Attempt to synchronize with an Analog Device ARM micro. Sends a
backspace and reads back the microcontrollers response. Performs
multiple retries. Exits the program on error, returns to caller in the
case of success.
*/
static void AnalogDevicesSync(ISP_ENVIRONMENT *IspEnvironment)
{
BINARY sync; /* Holds sync command. */
AD_SYNC_RESPONSE response; /* Response from micro. */
int sync_attempts; /* Number of retries. */
/* Make sure we don't read garbage later instead of the */
/* response we expect from the micro. */
ClearSerialPortBuffers(IspEnvironment);
DebugPrintf(2, "Synchronizing\n"); /* Progress report. */
sync = ANALOG_DEVICES_SYNC_CHAR; /* Build up sync command. */
/* Perform the actual sync attempt. First send the sync */
/* character, the attempt to read back the response. For the */
/* AD ARM micro this is a fixed length block. If response is */
/* received attempt to validate it by comparing the first */
/* characters to those expected. If the received block does */
/* not validate or is incomplete empty the serial buffer and */
/* retry. */
for (sync_attempts = 0; sync_attempts < 5; sync_attempts++)
{
SendComPortBlock(IspEnvironment, &sync, 1);
if (ReceiveComPortBlockComplete(IspEnvironment, &response, sizeof(response),
500) == 0)
{
if (memcmp(response.product_id, ANALOG_DEVICES_SYNC_RESPONSE,
ANALOG_DEVICES_SYNC_SIZE) == 0)
{
return;
}
else
{
DumpString(3, &response, sizeof(response),
"Unexpected response to sync attempt ");
}
}
else
{
DebugPrintf(3, "No (or incomplete) answer on sync attempt\n");
}
ClearSerialPortBuffers(IspEnvironment);
}
DebugPrintf(1, "No (or unacceptable) answer on sync attempt\n");
exit(4);
}
typedef struct {
char start1;
char start2;
BINARY bytes;
char cmd;
BINARY address_h;
BINARY address_u;
BINARY address_m;
BINARY address_l;
BINARY data[251];
} AD_PACKET;
/***************************** AnalogDevicesFormPacket ******************/
/** Create an Analog Devices communication packet from the constituent
elements.
\param [in] cmd The command being sent, one of 'E' for erase, 'W' for
write, 'V' for verify or 'R' for run..
\param [in] no_bytes the number of data bytes to send with the command in
the packet.
\param [in] address the address to apply the command to.
\param [in] data the data to send with the packet, may be null if no_bytes
is zero.
\param[out] packet that will be filled.
*/
static void AnalogDevicesFormPacket(ISP_ENVIRONMENT *IspEnvironment,
char cmd, int no_bytes, unsigned int address,
const void *data, AD_PACKET *packet)
{
BINARY checksum;
const BINARY *data_in;
int i;
(void)IspEnvironment; /* never used in this function */
/* Some sanity checking on the arguments. These should only */
/* fail if there is a bug in the caller. */
/* Check 1) that the number of data bytes is in an acceptable */
/* range, 2) that we have a non-null pointer if data is being */
/* put in the packet and 3) that we have a non-null pointer to */
/* the packet to be filled. We just exit with an error message */
/* if any of these tests fail. */
if ((no_bytes < 0) || (no_bytes > 250))
{
DebugPrintf(1,
"The number of bytes (%d) passed to FormPacket is invalid.\n",
no_bytes);
exit(-1);
}
if ((data == 0) && (no_bytes != 0))
{
DebugPrintf(1,
"A null pointer to data paased to FormPacket when data was expected.\n");
exit(-1);
}
if (packet == 0)
{
DebugPrintf(1,
"A null packet pointer was passed to FormPacket.\n");
exit(-1);
}
checksum = 0; /* Checksum starts at zero. */
data_in = (BINARY*) data; /* Pointer pun so we can walk through */
/* the data. */
packet->start1 = 0x7; /* The start of the packet is constant.*/
packet->start2 = 0xE;
/* Fill in the rest of the packet and calculate the checksum */
/* as we go. */
/* The number of bytes is the number of data bytes + the */
/* address bytes + the command byte. */
packet->bytes = (BINARY)(no_bytes + 5);
checksum += packet->bytes;
/* The command for the packet being sent. No error checking */
/* done on this. */
packet->cmd = cmd;
checksum += cmd;
/* Now break up the address and place in the proper packet */
/* locations. */
packet->address_l = (BINARY)(address & 0xFF);
packet->address_m = (BINARY)((address >> 8) & 0xFF);
packet->address_u = (BINARY)((address >> 16) & 0xFF);
packet->address_h = (BINARY)((address >> 24) & 0xFF);
checksum += packet->address_l;
checksum += packet->address_m;
checksum += packet->address_u;
checksum += packet->address_h;
/* Copy the data bytes into the packet. We could use memcpy */
/* but we have to calculate the checksum anyway. */
for (i = 0; i < no_bytes; i++)
{
packet->data[i] = data_in[i];
checksum += data_in[i];
}
/* Finally, add the checksum to the end of the packet. */
packet->data[i] = (BINARY)-checksum;
}
/***************************** AnalogDevicesSendPacket ******************/
/** Send a previously form Analog Devices communication. Retry a
couple of times if needed but fail by exiting the program if no ACK is
forthcoming.
\param [in] packet the packet to send.
*/
static void AnalogDevicesSendPacket(ISP_ENVIRONMENT *IspEnvironment,
const AD_PACKET * packet)
{
BINARY response;
int retry = 0;
do {
retry++;
/* Make sure we don't read garbage later instead of */
/* the response we expect from the micro. */
ClearSerialPortBuffers(IspEnvironment);
/* Send the packet, the size is the number of data */
/* bytes in the packet plus 3 bytes worth of header */
/* plus checksum. */
SendComPortBlock(IspEnvironment, packet, packet->bytes + 4);
/* Receive the response and check, return to caller */
/* if successful. */
if (ReceiveComPortBlockComplete(IspEnvironment, &response, 1, 5000) == 0)
{
if (response == ANALOG_DEVICES_ACK)
{
DebugPrintf(3, "Packet Sent\n");
return;
}
if (response != ANALOG_DEVICES_NAK)
{
DebugPrintf(3, "Unexpected response to packet (%x)\n", (int)response);
}
DebugPrintf(2, "*");
}
} while (retry < 3);
DebugPrintf(1, "Send packet failed\n");
exit(-1);
}
/***************************** AnalogDevicesErase ***********************/
/** Erase the Analog Devices micro. We take the simple way out and
just erase the whole thing.
*/
static void AnalogDevicesErase(ISP_ENVIRONMENT *IspEnvironment)
{
BINARY pages;
AD_PACKET packet;
pages = 0;
DebugPrintf(2, "Erasing .. ");
AnalogDevicesFormPacket(IspEnvironment, 'E', 1, 0, &pages, &packet);
AnalogDevicesSendPacket(IspEnvironment, &packet);
DebugPrintf(2, "Erased\n");
}
#define AD_PACKET_SIZE (250)
/***************************** AnalogDevicesWrite ***********************/
/** Write the program.
\param [in] data the program to download to the micro.
\param [in] address where to start placing the program.
\param [in] bytes the size of the progrm to download.
*/
static void AnalogDevicesWrite(ISP_ENVIRONMENT *IspEnvironment,
const void *data, long address, size_t bytes)
{
AD_PACKET packet;
const BINARY *prog_data;
DebugPrintf(2, "Writing %d bytes ", bytes);
prog_data = (const BINARY*) data;
while (bytes > AD_PACKET_SIZE)
{
AnalogDevicesFormPacket(IspEnvironment, 'W', AD_PACKET_SIZE, address, prog_data, &packet);
AnalogDevicesSendPacket(IspEnvironment, &packet);
address += AD_PACKET_SIZE;
prog_data += AD_PACKET_SIZE;
bytes -= AD_PACKET_SIZE;
DebugPrintf(2, ".");
}
if (bytes > 0)
{
AnalogDevicesFormPacket(IspEnvironment, 'W', bytes, address, prog_data, &packet);
AnalogDevicesSendPacket(IspEnvironment, &packet);
DebugPrintf(2, ".");
}
}
/***************************** AnalogDevicesDownload ********************/
/** Perform the download into an Analog Devices micro. As a quick and
* dirty hack against flash relocations at 0x80000
* \return 0 if ok, error code else
* \ToDo: possible to implement the return value instead of calling
* exit() in sub-functions
*/
int AnalogDevicesDownload(ISP_ENVIRONMENT *IspEnvironment)
{
AnalogDevicesSync(IspEnvironment);
AnalogDevicesErase(IspEnvironment);
if (IspEnvironment->BinaryLength > 0x80000)
{
DebugPrintf(2, "Note: Flash remapped 0x80000 to 0.\n");
AnalogDevicesWrite(IspEnvironment, IspEnvironment->BinaryContent + 0x80000, 0, IspEnvironment->BinaryLength-0x80000);
}
else
{
AnalogDevicesWrite(IspEnvironment, IspEnvironment->BinaryContent, 0, IspEnvironment->BinaryLength);
}
return (0);
}
#endif // AD_SUPPORT
|