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