From 936e54b112e185221303696f2d2bea3799c4266e Mon Sep 17 00:00:00 2001 From: Martin Meloun Date: Thu, 22 Aug 2013 16:08:50 +0200 Subject: [PATCH] Add LPC21ISP to host --- host/app/Makefile.omk | 2 +- host/app/lpc21lisp/Makefile | 14 + host/app/lpc21lisp/Makefile.omk | 9 + host/app/lpc21lisp/adprog.c | 325 ++++ host/app/lpc21lisp/adprog.h | 47 + host/app/lpc21lisp/lpc21isp.c | 2479 +++++++++++++++++++++++++++++++ host/app/lpc21lisp/lpc21isp.h | 302 ++++ host/app/lpc21lisp/lpcprog.c | 1649 ++++++++++++++++++++ host/app/lpc21lisp/lpcprog.h | 144 ++ host/app/lpc21lisp/lpcterm.c | 138 ++ host/app/lpc21lisp/lpcterm.h | 43 + host/config.omk | 1 + 12 files changed, 5152 insertions(+), 1 deletion(-) create mode 100644 host/app/lpc21lisp/Makefile create mode 100644 host/app/lpc21lisp/Makefile.omk create mode 100644 host/app/lpc21lisp/adprog.c create mode 100644 host/app/lpc21lisp/adprog.h create mode 100644 host/app/lpc21lisp/lpc21isp.c create mode 100644 host/app/lpc21lisp/lpc21isp.h create mode 100644 host/app/lpc21lisp/lpcprog.c create mode 100644 host/app/lpc21lisp/lpcprog.h create mode 100644 host/app/lpc21lisp/lpcterm.c create mode 100644 host/app/lpc21lisp/lpcterm.h diff --git a/host/app/Makefile.omk b/host/app/Makefile.omk index 8d691bd..9272f1d 100644 --- a/host/app/Makefile.omk +++ b/host/app/Makefile.omk @@ -1 +1 @@ -SUBDIRS = rocon_cmd usb_sendhex +SUBDIRS = rocon_cmd usb_sendhex lpc21lisp diff --git a/host/app/lpc21lisp/Makefile b/host/app/lpc21lisp/Makefile new file mode 100644 index 0000000..b22a357 --- /dev/null +++ b/host/app/lpc21lisp/Makefile @@ -0,0 +1,14 @@ +# Generic directory or leaf node makefile for OCERA make framework + +ifndef MAKERULES_DIR +MAKERULES_DIR := $(shell ( old_pwd="" ; while [ ! -e Makefile.rules ] ; do if [ "$$old_pwd" = `pwd` ] ; then exit 1 ; else old_pwd=`pwd` ; cd -L .. 2>/dev/null ; fi ; done ; pwd ) ) +endif + +ifeq ($(MAKERULES_DIR),) +all : default +.DEFAULT:: + @echo -e "\nThe Makefile.rules has not been found in this or partent directory\n" +else +include $(MAKERULES_DIR)/Makefile.rules +endif + diff --git a/host/app/lpc21lisp/Makefile.omk b/host/app/lpc21lisp/Makefile.omk new file mode 100644 index 0000000..145180b --- /dev/null +++ b/host/app/lpc21lisp/Makefile.omk @@ -0,0 +1,9 @@ +default_CONFIG = CONFIG_APP_LPC21LISP=x + +ifeq ($(CONFIG_APP_LPC21LISP),y) + +bin_PROGRAMS = lpc21isp + +lpc21isp_SOURCES = lpc21isp.c adprog.c lpcprog.c lpcterm.c + +endif #CONFIG_APP_LPC21LISP diff --git a/host/app/lpc21lisp/adprog.c b/host/app/lpc21lisp/adprog.c new file mode 100644 index 0000000..c6b99b7 --- /dev/null +++ b/host/app/lpc21lisp/adprog.c @@ -0,0 +1,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-2011, 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 . +*/ + +#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 diff --git a/host/app/lpc21lisp/adprog.h b/host/app/lpc21lisp/adprog.h new file mode 100644 index 0000000..efd296c --- /dev/null +++ b/host/app/lpc21lisp/adprog.h @@ -0,0 +1,47 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC1000 / LPC2000 family + and Analog Devices ADUC70xx + +Filename: adprog.h + +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-2011, 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 . +*/ + +#define ANALOG_DEVICES_SYNC_CHAR ((BINARY)0x08) +#define ANALOG_DEVICES_SYNC_RESPONSE ("ADuC") +#define ANALOG_DEVICES_SYNC_SIZE (strlen(ANALOG_DEVICES_SYNC_RESPONSE)) +#define ANALOG_DEVICES_ACK 0x6 +#define ANALOG_DEVICES_NAK 0x7 + +typedef struct +{ + BINARY product_id[15]; + BINARY version[3]; + BINARY reserved[4]; + BINARY terminator[2]; +} AD_SYNC_RESPONSE; + +int AnalogDevicesDownload(ISP_ENVIRONMENT *IspEnvironment); diff --git a/host/app/lpc21lisp/lpc21isp.c b/host/app/lpc21lisp/lpc21isp.c new file mode 100644 index 0000000..4357185 --- /dev/null +++ b/host/app/lpc21lisp/lpc21isp.c @@ -0,0 +1,2479 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC family + and Analog Devices ADUC70xx + +Filename: lpc21isp.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-2013, 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 . +*/ + +#if defined(_WIN32) +#if !defined __BORLANDC__ +#include "StdAfx.h" // Precompiled Header for WIN32 +#endif +#endif // defined(_WIN32) +#include "lpc21isp.h" // if using propriatory serial port communication (customize attached lpc21isp.h) +#include "adprog.h" +#include "lpcprog.h" +#include "lpcterm.h" + +/* +Change-History: + +1.00 2004-01-08 Initial Version, tested for MSVC6/7 and GCC under Cygwin +1.01 2004-01-10 Porting to Linux (at least compiling must work) +1.02 2004-01-10 Implemented conversion intel hex format -> binary +1.03 2004-01-25 Preparation to upload to public website +1.04 2004-02-12 Merged in bugfixes by Soeren Gust +1.05 2004-03-14 Implement printing of error codes as text / strings +1.06 2004-03-09 Merged in bugfixes by Charles Manning: + The '?' sychronisation does not reliably respond to the first '?'. + I added some retries. + The LPC2106 sometimes responds to the '?' by echoing them back. + This sometimes causes an attempt to match "?Synchonized". + Added code to strip off any leading '?'s. + Timeouts were too long. + Change from RTS/CTS to no flow control. + Done because many/most people will use only 3-wire comms. + Added some progress tracing. +1.07 2004-03-14 Implement handling of control lines for easier booting +1.08 2004-04-01 Bugfix for upload problem +1.09 2004-04-03 Redesign of upload routine + Now always 180 byte blocks are uploaded, to prevent + small junks in uuencoding +1.10 2004-04-03 Clear buffers before sending commands to LPC21xx, + this prevents synchronizing errors when previously loaded + program does a lot of output, so FIFO of PC runs full +1.11 2004-04-03 Small optimization for controlling reset line + otherwise termonly starts LPC twice, free PC buffers +1.12 2004-04-04 Add switch to enable logging terminal output to lpc21isp.log +1.13 2004-05-19 Merged in improvement by Charles Manning: + Instead of exiting the wrong hex file size is corrected +1.14 2004-07-07 Merged in improvement by Alex Holden: + Remove little/big endian dependancy +1.15 2004-09-27 Temporary improvement by Cyril Holweck: + Removed test (data echoed = data transmited) on the main + data transfert, since this was the biggest failure + reason and is covered by checksome anyway. + Added COMPILE_FOR_LPC21, to have target dump it's own + memory to stdout. +1.16 2004-10-09 Merged in bugfix / improvement by Sinelnikov Evgeny + I found out that Linux and Windows serial port initialization + are different with pinouts states. My board don't get + reset signal at first cycle of DTR pinout moving. + And I add this moving to initalization cycle. +1.17 2004-10-21 Changes by Cyril Holweck + Divide main, take out the real programming function, that can + also be used by a target to copy its own code to another. +1.18 2004-10-26 Changes by Cyril Holweck + Added a "G 0 A\r\n" at end of programming to run code. +1.19 2004-11-03 Changes by Robert Adsett + Add support for Analog Devices. + Separate file load from programming. + Change from a debug on/off flag to debug level + Remove if (debug) tests and replace with DebugPrintf + statements. + Change serial I/O and timing so that the system + dependancies are isolated to a few portability functions. + Add support for binary serial I/O. + Add doxygen support. +1.20 2004-11-07 Preparation for multiport booting (factory support) +1.21 2004-11-08 Bugfix from Robert Adsett + BinaryLength was not initialized +1.22 2004-11-08 Changes from Cyril Holweck / Evgeny Sinelnikov + Forgotten IspEnvironment-> and bugfixes if COMPILE_FOR_LINUX + If COMPILE_FOR_LPC21, PhilipsDownload() 'acts as' main(): + - it should not be static and should return int. + - no sub-function can use exit() but only return () + Use 'char' instead of 'byte' ;) +1.23 2005-01-16 Build in automatic detection of LPC chiptype + (needed for 256 KByte support) +1.24B 2005-06-02 Changes by Thiadmer Riemersma: completed support for other + chip types (LPC213x series and others). +1.24C 2005-06-11 Changes by Thiadmer Riemersma: added the device ID codes for + chip types LPC2131 and LPC2132. +1.25 2005-06-19 Martin Maurer: Setup more parameters in DCB, + otherwise wrong code is downloaded (only Windows and Cygwin) + when a previous program has changed these parameters + Check exact string of "G 0 A\r\n0\r\n" instead of whole received buffer, + to prevent checking of already received by program start + (error on running program, but reports CMD_SUCCESS) + Add ifdefs for all baudrates (needed only for high baudrate, + which seem to be not available on Macs...) +1.26 2005-06-26 Martin Maurer: + Correct check again: "G 0 A\r\n0\r\n" is cutted, because of reboot + (error on running program, but reports CMD_SUCCESS) +1.27 2005-06-29 Martin Maurer: + Add LPC chip ID's (thanks to Robert from Philips) for + missing LPC213x and upcoming new LPC214x chips + (currently untested, because i don't have access to these chips, + please give me feedback !) +1.28 2005-07-27 Anders Rosvall / Embedded Artists AB: + Changed the reset timeout to 500 ms when entering the bootloader. + Some external reset controllers have quite long timeout periods, + so extening the timeout delay would be a good thing. +1.29 2005-09-14 Rob Jansen: + Added functionality to download to RAM and run from there. + In LoadFile() added record types 04 (Extended Linear Address Record) + and 05 (Start Linear Address Record), added address offset + (IspEnvironment->BinaryOffset) and start address (...->StartAddress). + Changed PhilipsDownload to skip all Flash prepare/erase/copy commands. + Note: Tested with VC7 only +1.30 2005-10-04 Rob Jansen: + - forgot to change the version string in 1.29 + - Wrong text in LoadFile corrected (printed text mentions record type 05, + this should be 04 + - Changed LoadFile to accept multiple record types 04 + - Changed LoadFile to check on memory size, will not load more than x MB + if linear extended address records are used +1.31 2005-11-13 Martin Maurer: Thanks to Frank Gutmann + Updated number of sectors in device table + for LPC2194, LPC2292 and LPC2294 +1.32 2005-12-02 Martin Maurer: Corrected missing control of RTS/DTR + in case user selected -termonly and -control + Small correction (typo in debug) +1.33 2006-10-01 Jean-Marc Koller: + Added support for MacOS X (difference on how to set termios baudrate). +1.34 2006-10-01 Cyril Holweck: + Made it compile again for lpc21isp + Added const keyword to constant variables to make it better + code for embeded target. (decrease RAM usage) + Replaced all regular call to printf() by DebugPrintf() + Removed call to scanf() (not much usefull and cost a lot to my target) +1.35 2006-22-01 Cyril Holweck + Added feature for LPC21: will start downloading at Sector 1 and upward, + to finish with Sector 0, the one containing the checksum controling BSL entry +1.36 2006-25-01 Cyril Holweck + PhilipsDownload() will now return a unique error code for each error +1.37 2006-10-03 Jeroen Domburg + Added LPC2103 (and only the 2103, I can't find the IDs for 2101/2102) + Corrected a loop which occured if the program completely fits in sector 0 +1.38 2007-01-05 Ray Molenkamp + Added feature for LPC21: Wipe entire device before programming to enable + reflashing of chips with the lpc codeprotection feature enabled. +1.39 2007-01-12 Martin Maurer + Added initial support for new processors LPC23xx and LPC24xx +1.40 2007-01-22 Martin Maurer + Correction of chip id of LPC2458 +1.41 2007-01-28 Jean-Marc Koller + Modified Terminal() to disable ECHO with termios only once, instead of + modifying and restoring termios in each getch and kbhit call (which caused + a strange echo behaviour in MacOS X). +1.42 2007-01-28 Rob Probin + Added -localecho command to allow local echoing in terminal mode for use + where target does not echo back keystrokes. +1.43 2007-01-29 Martin Maurer + Moved keyboard handling routines to own subroutines, + so they can be used during aborting synchronisation. + Newest cygwin made problems, StringOscillator always contained '\0x0d' + at the end, when calling lpc21isp from batch file +1.44 2007-02-23 Yang Yang + Added feature for LPC21: Verify the data in Flash after every writes + to sector. To detect errors in writing to Flash ROM. +1.45 2007-02-25 Martin Maurer + Replace printf syntax of DumpString by a simple pointer to a string + printf syntax is a nice thing, but it is not working :-( + and therefore makes debugging much more difficult... + Moved VERSION_STR to top of file to avoid possible cosmetical errors +1.46 2007-02-25 Martin Maurer + Again corrected debug output: should solve output of + (FFFFFFB5) instead of (B5) +1.47 2007-02-27 Robert Adsett + Raised timeout on AD send packet function. +1.48 2007-04-20 Martin Maurer + Thanks to Josef Wolf for preventing to overwrite over end of array +1.49 2007-10-16 New Option -halfduplex allow single wire using. + Implemented and tested only for Windows. Data Resend implemented. +1.50 2007-10-31 Changes by Simon Ellwood + Formated the code for readablity + Fixed some c++ compiler issues +1.51 2007-11-20 Changes by Simon Ellwood + Split into seperate files + Made more modular so when used in an embedded mode only the required code is built +1.52 2008-01-22 Changes by Manuel Koeppen + Made compileable again for linux and windows + Fixed bug in ClearSerialPortBuffers (linux) +1.53 2008-02-25 Changes by Michael Roth + Get priority of debug messages with -control right +1.54 2008-03-03 Martin Maurer + Try to bring lpc21isp back to a useable state in Windows, Cygwin, Linux and Mac OS. + Merged in changes by Erika Stefanini, which were done only for old version 1.49: + Added device ids for revision B chips +1.55 2008-03-03 Martin Maurer + Thanks to Fausto Marzoli, bugfix for compiling latest version under Linux +1.56 2008-04-01 Steve Franks + Integrate FreeBSD patch. + Add support for swapping and/or inverting RTS & DTR +1.57 2008-04-06 Mauricio Scaff + Changed OpenSerialPort to work with MacOS + Corrected the number of sectors in some 512K devices (28 instead of 27) + Added support for LPC2387 and LPC2388 + Defined BL error 19 (Code Protected) +1.58 2008-05-10 Herbert Demmel dh2@demmel.com + I had the special requirement to integrate the program into my own Windows + software compiled with Borland C++ Builder 5. I had to do some minor changes + for Borland (see defined __BORLANDC__) and modified to code slightly to have + some simple callbacks for screen i/o (see define INTEGRATED_IN_WIN_APP). + Please note that I do *not* check / modify the part for AnalogDevices !! + Besides that I fixed some minor issues: + added dcb.fOutxCtsFlow = FALSE and dcb.fOutxDsrFlow = FALSE (sometimes required) + Now comparing one character less of answer to "Now launching ... code" command +1.59 2008-07-07 Peter Hayward + Fixed freeze under Windows XP SP2 by removing redundant call to SetCommMask. +1.60 2008-07-21 Martin Maurer + Added uptodate part ids for LPC2458, LPC2468 and LPC2478 + Add comment "obsolete" for older part ids for LPC2458 and LPC2468 + Add ", " between compile date and time +1.61 2008-10-21 Fausto Marzoli (thanks to Geoffrey Wossum for the patches) + Fix for compiling latest version under Linux and "ControlLinesSwapped" issue +1.62 2008-11-19 Martin Maurer + Added (untested) support for LPC2109 + Added (untested) support for LPC2361 / LPC2362 + Heavy update of part identification number of LPC23xx and LPC24xx + Correct bug, that hex file must exist, when "-detectonly" is used + Correct Makefile.vc: use /Fe instead of -o +1.63 2008-11-23 Martin Maurer + Changed to GNU Lesser General Public License +1.64 2009-01-19 Steve Franks + __FREEBSD__ changed to __FreeBSD__ at some point, plus other com port fixes +1.65 2009-03-26 Vito Marolda + Added pre-erasure of sector 0 to invalidate checksum before starting + modification of the other sectors, so that the bootloader restarts + if programming gets aborted while writing on a non-empty part. +1.66 2009-03-26 Vito Marolda + Corrected interpretation of intel hex record 03 which is execution start address + and not data segment address +1.67 2009-04-19 SASANO Takayoshi + Add OpenBSD support +1.68 2009-05-17 Martin Maurer + Merge in changes done by Bruno Quoitin (baudrate problem when __APPLE__ is used) + Remove TABs from source code and replaced them with spaces +1.69 2009-06-18 Martin Maurer + Add support for LPC17xx devices +1.70 2009-06-29 Martin Maurer + Further improvement of LPC17xx support + Workaround for booter (4.1) of LPC17xx, which does not echo all sent characters (0D,0A,...) + ISP command GO seems to be broken: + Sending 'G 196 T(0A)' + Answer(Length=15): 'G 196 T(0A)0(0D)(0A)' + leads to 'prefetch_abort_exception(0D)(0A)1FFF07A5' + No solution known...need your help here... + Manual workaround: Use DTR and RTS toggling to start application (e.g. 2 batch files) +1.71 2009-07-19 Martin Maurer + Added LPC17xx with CPUID starting with 0x26 (not according user manual) +1.72 2009-09-14 Martin Maurer + Add support for LPC13xx devices +1.73 2009-09-14 Martin Maurer + Correct again (hopefully the last time) the CPUIDs for some LPC17xx devices + (Now according to User Manual LPC17xx Version 00.07 (31 July 2009)) +1.74 2009-09-14 Mario Ivancic + Added support for multiple HEX files, besed on internal version 1.37B. + NOTE: this feature is used in production in 1.37B but is not tested in this version. + Added numeric debug level command line switch -debugn, n=[0-5] + Added command line scitch -try n to specify nQuestionMarks limit. Default: 100 + Merged in DoNotStart patch from cgommel_new + Static functions declarations moved from lpc21isp.h to this file + Modified LoadFile() to return error_code instead exit(1) + Removed IspEnvironment.debug_level, all code uses global debug_level +1.75 2010-01-05 Martin Maurer + Added support for LPC11xx devices (not tested at all) + Changed Product in LPC_DEVICE_TYPE from number to string to distinguish new LPC11 devices + Changed "unsigned" to "unsigned int" in LPC_DEVICE_TYPE +1.76 2010-02-01 Published test version without source code +1.77 2010-02-01 Martin Maurer + Corrected chip id of LPC1342 and LPC1343 + Added a new chip type for LPC11xx and LPC13xx microcontrollers + Use higher area of RAM with LPC11xx and LPC13xx, because lower RAM is occupied by ISP + Add code to lpcprog.c to read unique id, but not yet activate. + Adapt block sizes for copying for each model of LPC11xx and LPC13xx +1.78 2010-02-16 Martin Maurer + Corrected chip id of LPC1751 + Added support for LPC1759, LPC1767 and LPC1769 +1.79 2010-02-19 Andrew Pines + Added __APPLE__ flag to CFLAGS in Makefile to detect and handle OS X + Added -Wall to Makefile to report warnings more comprehensively + Added #define in lpc21isp.h to substitute strnicmp with strncasecmp (needed for Unix) + Fixed a few format specifiers in lpcprog.c to eliminate some warnings +1.80 2010-03-04 Philip Munts + Added entries to LPCtypes[] in lpcprog.c for obsolete revisions of LPC2364/6/8/78. + Added entry to LPCtypes[] in lpcprog.c for new LPC2387. +1.81 2011-03-30 Mario Ivancic + As per message #517 from Thiadmer Riemersma, removed WaitForWatchDog and WatchDogSeconds + in PhilipsDownload(). +1.82 2011-06-25 Moses McKnight + Corrected MaxCopySize for a number of the LPC11xx series + Added support for several more LPC11xx and LPC11Cxx series +1.83 2011-08-02 Martin Maurer + Thanks to Conurus for detecting and fixing a bug with patching checksum + (patching was too early, chip id was not yet available) + (Re-)Added code to start downloaded via "G 0 T", when using LPC1xxx + (Starting code at position 0 seems to work, compare to comment of version 1.70) + Changed some occurances of Philips to NXP + Added -static to Makefile (thanks to Camilo) + Added support for LPC1311/01 and LPC1313/01 (they have separate identifiers) + Correct flash size of LPC1342 to 16 KByte (thanks to Decio) + Abort programming when unknown NXP chip id is detected +1.84 2012-09-27 Philip Munts + Added chip id's for more LPC11xx parts, per UM10398 Rev. 11 26 July 2012 +1.85 2012-12-13 Philip Munts + Fixed conditional compilation logic in lpc21isp.h to allow compiling for ARM Linux. +1.86 2012-12-14 diskrepairman + Added devices: LPC1114/203 LPC1114/303 LPC1114/323 LPC1114/333 LPC1115/303 +1.87 2012-12-18 Philip Munts + Added a section of code to ResetTarget() in lpc21isp.c to allow using Linux GPIO pin + to control reset and ISP. +1.88 2013-04-25 Torsten Lang, Uwe Schneider GmbH + Fixed answer evaluation + Added sector tables for LPC1833 + XON/XOFF handling according to LPC manual + Changed COMMTIMEOUTS settings according to MS help + Changed waiting code from tick counting to system time usage + Set MM timers to 1ms resolution (otherwise waiting in the serial driver is limited to multiples of 10ms) + Send all commands with according to NXP UM + Change answer evaluation to match at least LPC17xx and LPC18xx families (LPC17xx just mirrors the first character of + the LF sequence, LPC18xx mirrors the first character and adds an which then will lead to a + sequence, all other lines are terminated with as documented) + Change answer formatting by filtering leading characters because they can be left over from a previous response + Store residual data of an answer (required for the J command which will deliver two words in case of the LPC18xx) + Expanded configuration table by second identification word and usage flag + Do a two stage scan in case that a device with two identification words is detected +1.89 2013-06-27 Martin Maurer + Thanks to Manuel and Henri for bugfixes and speed-ups + Bugfix: In case of LPC8XX, XON/XOFF handling must be switched off, + otherwise download gets broken, because XON/XOFF are filtered out... +1.90 2013-06-27 Martin Maurer + Add checksum calculation for LPC8XX + winmm function only available in MSVC, put ifdefs around + Workaround for lost characters of LPC8XX +1.91 2013-06-28 Torsten Lang, Uwe Schneider GmbH + Minor bugfix for the residual data handling +1.92 2013-06-29 Martin Maurer + Thanks to Phil for reporting Linux compile errors + Update README +1.93 2013-07-05 Andrew Pines + changed Makefile to exclude "-static" from CFLAGS when building for OS X + changed serial timeout for *nix to use select + added -boothold argument to assert ISP throughtout programming sequence + added support for -try command line argument (was in help, didn't actually work) +1.94 2013-08-10 Martin Maurer + Add (assumed) part id values for LPC4333 and LPC4337 + Correct table entries for all LPC43xx part id numbers + (missing flag for two word part ids and second word for LPC4333 and LPC4353) + Merge in optimization (thanks to Stefan) to skip empty sectors + Correct help output of "-boothold" + Add workaround table entry for LPC4357 and word1 equal to 0x0EF60000 + Bugfix for wrong check of word0/word1 combination + Correct a lot entries in lpc property table of LPC18xx and LPC43xx + LPC18xx and LPC43xx: Add warning message, that wipe erases only bank A + +*/ + +// Please don't use TABs in the source code !!! + +// Don't forget to update the version string that is on the next line +#define VERSION_STR "1.94" + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +static char RxTmpBuf[256]; // save received data to this buffer for half-duplex +char * pRxTmpBuf = RxTmpBuf; +#endif + +#if !defined COMPILE_FOR_LPC21 +int debug_level = 2; +#endif + +static void ControlModemLines(ISP_ENVIRONMENT *IspEnvironment, unsigned char DTR, unsigned char RTS); +static unsigned char Ascii2Hex(unsigned char c); + +#ifdef COMPILE_FOR_WINDOWS +static void SerialTimeoutSet(ISP_ENVIRONMENT *IspEnvironment, unsigned timeout_milliseconds); +static int SerialTimeoutCheck(ISP_ENVIRONMENT *IspEnvironment); +#endif // COMPILE_FOR_WINDOWS + +static int AddFileHex(ISP_ENVIRONMENT *IspEnvironment, const char *arg); +static int AddFileBinary(ISP_ENVIRONMENT *IspEnvironment, const char *arg); +static int LoadFile(ISP_ENVIRONMENT *IspEnvironment, const char *filename, int FileFormat); + +/************* Portability layer. Serial and console I/O differences */ +/* are taken care of here. */ + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +static void OpenSerialPort(ISP_ENVIRONMENT *IspEnvironment) +{ + DCB dcb; + COMMTIMEOUTS commtimeouts; + +#ifdef _MSC_VER + /* Torsten Lang 2013-05-06 Switch to higher timer resolution (we want to use 1ms timeouts in the serial device driver!) */ + (void)timeBeginPeriod(1UL); +#endif // _MSC_VER + + IspEnvironment->hCom = CreateFile(IspEnvironment->serial_port, GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + + if (IspEnvironment->hCom == INVALID_HANDLE_VALUE) + { + DebugPrintf(1, "Can't open COM-Port %s ! - Error: %ld\n", IspEnvironment->serial_port, GetLastError()); + exit(2); + } + + DebugPrintf(3, "COM-Port %s opened...\n", IspEnvironment->serial_port); + + GetCommState(IspEnvironment->hCom, &dcb); + dcb.BaudRate = atol(IspEnvironment->baud_rate); + dcb.ByteSize = 8; + dcb.StopBits = ONESTOPBIT; + dcb.Parity = NOPARITY; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fOutX = TRUE; // TL TODO - according to LPC manual! FALSE; + dcb.fInX = TRUE; // TL TODO - according to LPC manual! FALSE; + dcb.fNull = FALSE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + + // added by Herbert Demmel - iF CTS line has the wrong state, we would never send anything! + dcb.fOutxCtsFlow = FALSE; + dcb.fOutxDsrFlow = FALSE; + + if (SetCommState(IspEnvironment->hCom, &dcb) == 0) + { + DebugPrintf(1, "Can't set baudrate %s ! - Error: %ld", IspEnvironment->baud_rate, GetLastError()); + exit(3); + } + + /* + * Peter Hayward 02 July 2008 + * + * The following call is only needed if the WaitCommEvent + * or possibly the GetCommMask functions are used. They are + * *not* in this implimentation. However, under Windows XP SP2 + * on my laptop the use of this call causes XP to freeze (crash) while + * this program is running, e.g. in section 5/6/7 ... of a largish + * download. Removing this *unnecessary* call fixed the problem. + * At the same time I've added a call to SetupComm to request + * (not necessarity honoured) the operating system to provide + * large I/O buffers for high speed I/O without handshaking. + * + * SetCommMask(IspEnvironment->hCom,EV_RXCHAR | EV_TXEMPTY); + */ + SetupComm(IspEnvironment->hCom, 32000, 32000); + + SetCommMask(IspEnvironment->hCom, EV_RXCHAR | EV_TXEMPTY); + + // Torsten Lang 2013-05-06: ReadFile may hang indefinitely with MAXDWORD/0/1/0/0 on FTDI devices!!! + commtimeouts.ReadIntervalTimeout = MAXDWORD; + commtimeouts.ReadTotalTimeoutMultiplier = MAXDWORD; + commtimeouts.ReadTotalTimeoutConstant = 1; + commtimeouts.WriteTotalTimeoutMultiplier = 0; + commtimeouts.WriteTotalTimeoutConstant = 0; + SetCommTimeouts(IspEnvironment->hCom, &commtimeouts); +} +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LINUX +static void OpenSerialPort(ISP_ENVIRONMENT *IspEnvironment) +{ + IspEnvironment->fdCom = open(IspEnvironment->serial_port, O_RDWR | O_NOCTTY | O_NONBLOCK); + + if (IspEnvironment->fdCom < 0) + { + int err = errno; + DebugPrintf(1, "Can't open COM-Port %s ! (Error: %dd (0x%X))\n", IspEnvironment->serial_port, err, err); + exit(2); + } + + DebugPrintf(3, "COM-Port %s opened...\n", IspEnvironment->serial_port); + + /* clear input & output buffers, then switch to "blocking mode" */ + tcflush(IspEnvironment->fdCom, TCOFLUSH); + tcflush(IspEnvironment->fdCom, TCIFLUSH); + fcntl(IspEnvironment->fdCom, F_SETFL, fcntl(IspEnvironment->fdCom, F_GETFL) & ~O_NONBLOCK); + + tcgetattr(IspEnvironment->fdCom, &IspEnvironment->oldtio); /* save current port settings */ + + bzero(&IspEnvironment->newtio, sizeof(IspEnvironment->newtio)); + IspEnvironment->newtio.c_cflag = CS8 | CLOCAL | CREAD; + +#if defined(__FreeBSD__) || defined(__OpenBSD__) + + if(cfsetspeed(&IspEnvironment->newtio,(speed_t) strtol(IspEnvironment->baud_rate,NULL,10))) { + DebugPrintf(1, "baudrate %s not supported\n", IspEnvironment->baud_rate); + exit(3); + }; +#else + +#ifdef __APPLE__ +#define NEWTERMIOS_SETBAUDARTE(bps) IspEnvironment->newtio.c_ispeed = IspEnvironment->newtio.c_ospeed = bps; +#else +#define NEWTERMIOS_SETBAUDARTE(bps) IspEnvironment->newtio.c_cflag |= bps; +#endif + + switch (atol(IspEnvironment->baud_rate)) + { +#ifdef B1152000 + case 1152000: NEWTERMIOS_SETBAUDARTE(B1152000); break; +#endif // B1152000 +#ifdef B576000 + case 576000: NEWTERMIOS_SETBAUDARTE(B576000); break; +#endif // B576000 +#ifdef B230400 + case 230400: NEWTERMIOS_SETBAUDARTE(B230400); break; +#endif // B230400 +#ifdef B115200 + case 115200: NEWTERMIOS_SETBAUDARTE(B115200); break; +#endif // B115200 +#ifdef B57600 + case 57600: NEWTERMIOS_SETBAUDARTE(B57600); break; +#endif // B57600 +#ifdef B38400 + case 38400: NEWTERMIOS_SETBAUDARTE(B38400); break; +#endif // B38400 +#ifdef B19200 + case 19200: NEWTERMIOS_SETBAUDARTE(B19200); break; +#endif // B19200 +#ifdef B9600 + case 9600: NEWTERMIOS_SETBAUDARTE(B9600); break; +#endif // B9600 + + // Special value + // case 32000: NEWTERMIOS_SETBAUDARTE(32000); break; + + default: + { + DebugPrintf(1, "unknown baudrate %s\n", IspEnvironment->baud_rate); + exit(3); + } + } + +#endif + + IspEnvironment->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF; + IspEnvironment->newtio.c_oflag = 0; + + /* set input mode (non-canonical, no echo,...) */ + IspEnvironment->newtio.c_lflag = 0; + + cfmakeraw(&IspEnvironment->newtio); + IspEnvironment->newtio.c_cc[VTIME] = 1; /* inter-character timer used */ + IspEnvironment->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */ + + tcflush(IspEnvironment->fdCom, TCIFLUSH); + if(tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->newtio)) + { + DebugPrintf(1, "Could not change serial port behaviour (wrong baudrate?)\n"); + exit(3); + } + +} +#endif // defined COMPILE_FOR_LINUX + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +static void CloseSerialPort(ISP_ENVIRONMENT *IspEnvironment) +{ + CloseHandle(IspEnvironment->hCom); + +#ifdef _MSC_VER + /* Torsten Lang 2013-05-06 Switch back timer resolution */ + (void)timeEndPeriod(1UL); +#endif // _MSC_VER +} + +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LINUX +static void CloseSerialPort(ISP_ENVIRONMENT *IspEnvironment) +{ + tcflush(IspEnvironment->fdCom, TCOFLUSH); + tcflush(IspEnvironment->fdCom, TCIFLUSH); + tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->oldtio); + + close(IspEnvironment->fdCom); +} +#endif // defined COMPILE_FOR_LINUX + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +void ControlXonXoffSerialPort(ISP_ENVIRONMENT *IspEnvironment, unsigned char XonXoff) +{ + DCB dcb; + + GetCommState(IspEnvironment->hCom, &dcb); + + if(XonXoff) + { + dcb.fOutX = TRUE; + dcb.fInX = TRUE; + } + else + { + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + } + + if (SetCommState(IspEnvironment->hCom, &dcb) == 0) + { + DebugPrintf(1, "Can't set XonXoff ! - Error: %ld", GetLastError()); + exit(3); + } +} + +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LINUX +void ControlXonXoffSerialPort(ISP_ENVIRONMENT *IspEnvironment, unsigned char XonXoff) +{ + if(tcgetattr(IspEnvironment->fdCom, &IspEnvironment->newtio)) + { + DebugPrintf(1, "Could not get serial port behaviour\n"); + exit(3); + } + + if(XonXoff) + { + IspEnvironment->newtio.c_iflag |= IXON; + IspEnvironment->newtio.c_iflag |= IXOFF; + } + else + { + IspEnvironment->newtio.c_iflag &= ~IXON; + IspEnvironment->newtio.c_iflag &= ~IXOFF; + } + + if(tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->newtio)) + { + DebugPrintf(1, "Could not set serial port behaviour\n"); + exit(3); + } +} +#endif // defined COMPILE_FOR_LINUX + +/***************************** SendComPortBlock *************************/ +/** Sends a block of bytes out the opened com port. +\param [in] s block to send. +\param [in] n size of the block. +*/ +void SendComPortBlock(ISP_ENVIRONMENT *IspEnvironment, const void *s, size_t n) +{ +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + + unsigned long realsize; + size_t m; + unsigned long rxsize; + char * pch; + char * rxpch; +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + + DumpString(4, s, n, "Sending "); + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + + if (IspEnvironment->HalfDuplex == 0) + { + WriteFile(IspEnvironment->hCom, s, n, &realsize, NULL); + } + else + { + pch = (char *)s; + rxpch = RxTmpBuf; + pRxTmpBuf = RxTmpBuf; + + // avoid buffer otherflow + if (n > sizeof (RxTmpBuf)) + n = sizeof (RxTmpBuf); + + for (m = 0; m < n; m++) + { + WriteFile(IspEnvironment->hCom, pch, 1, &realsize, NULL); + + if ((*pch != '?') || (n != 1)) + { + do + { + ReadFile(IspEnvironment->hCom, rxpch, 1, &rxsize, NULL); + }while (rxsize == 0); + } + pch++; + rxpch++; + } + *rxpch = 0; // terminate echo string + } +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21 + + write(IspEnvironment->fdCom, s, n); + +#endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21 +} + +/***************************** SendComPort ******************************/ +/** Sends a string out the opened com port. +\param [in] s string to send. +*/ +void SendComPort(ISP_ENVIRONMENT *IspEnvironment, const char *s) +{ + SendComPortBlock(IspEnvironment, s, strlen(s)); +} + +/***************************** SerialTimeoutTick ************************/ +/** Performs a timer tick. In this simple case all we do is count down +with protection against underflow and wrapping at the low end. +*/ +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +static void SerialTimeoutTick(ISP_ENVIRONMENT *IspEnvironment) +{ + if (IspEnvironment->serial_timeout_count <= 1) + { + IspEnvironment->serial_timeout_count = 0; + } + else + { + IspEnvironment->serial_timeout_count--; + } +} +#endif + +/***************************** ReceiveComPortBlock **********************/ +/** Receives a buffer from the open com port. Returns all the characters +ready (waits for up to 'n' milliseconds before accepting that no more +characters are ready) or when the buffer is full. 'n' is system dependant, +see SerialTimeout routines. +\param [out] answer buffer to hold the bytes read from the serial port. +\param [in] max_size the size of buffer pointed to by answer. +\param [out] real_size pointer to a long that returns the amout of the +buffer that is actually used. +*/ +static void ReceiveComPortBlock(ISP_ENVIRONMENT *IspEnvironment, + void *answer, unsigned long max_size, + unsigned long *real_size) +{ + char tmp_string[32]; + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + + if (IspEnvironment->HalfDuplex == 0) + ReadFile(IspEnvironment->hCom, answer, max_size, real_size, NULL); + else + { + *real_size = strlen (pRxTmpBuf); + if (*real_size) + { + if (max_size >= *real_size) + { + strncpy((char*) answer, pRxTmpBuf, *real_size); + RxTmpBuf[0] = 0; + pRxTmpBuf = RxTmpBuf; + } + else + { + strncpy((char*) answer, pRxTmpBuf, max_size); + *real_size = max_size; + pRxTmpBuf += max_size; + } + } + else + ReadFile(IspEnvironment->hCom, answer, max_size, real_size, NULL); + } + +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LPC21 + + *real_size = read(IspEnvironment->fdCom, answer, max_size); + +#endif // defined COMPILE_FOR_LPC21 + +#if defined COMPILE_FOR_LINUX + { + fd_set + readSet; + struct timeval + timeVal; + + FD_ZERO(&readSet); // clear the set + FD_SET(IspEnvironment->fdCom,&readSet); // add this descriptor to the set + timeVal.tv_sec=0; // set up the timeout waiting for one to come ready (500ms) + timeVal.tv_usec=500*1000; + if(select(FD_SETSIZE,&readSet,NULL,NULL,&timeVal)==1) // wait up to 500 ms or until our data is ready + { + *real_size=read(IspEnvironment->fdCom, answer, max_size); + } + else + { + // timed out, show no characters received and timer expired + *real_size=0; + IspEnvironment->serial_timeout_count=0; + } + } +#endif // defined COMPILE_FOR_LINUX + + sprintf(tmp_string, "Read(Length=%ld): ", (*real_size)); + DumpString(5, answer, (*real_size), tmp_string); + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + if (*real_size == 0) + { + SerialTimeoutTick(IspEnvironment); + } +#endif +} + + +/***************************** SerialTimeoutSet *************************/ +/** Sets (or resets) the timeout to the timout period requested. Starts +counting to this period. This timeout support is a little odd in that the +timeout specifies the accumulated deadtime waiting to read not the total +time waiting to read. They should be close enought to the same for this +use. Used by the serial input routines, the actual counting takes place in +ReceiveComPortBlock. +\param [in] timeout_milliseconds the time in milliseconds to use for +timeout. Note that just because it is set in milliseconds doesn't mean +that the granularity is that fine. In many cases (particularly Linux) it +will be coarser. +*/ +static void SerialTimeoutSet(ISP_ENVIRONMENT *IspEnvironment, unsigned timeout_milliseconds) +{ +#if defined COMPILE_FOR_LINUX + IspEnvironment->serial_timeout_count = timeout_milliseconds / 100; +#elif defined COMPILE_FOR_LPC21 + IspEnvironment->serial_timeout_count = timeout_milliseconds * 200; +#else +#ifdef _MSC_VER + IspEnvironment->serial_timeout_count = timeGetTime() + timeout_milliseconds; +#else + IspEnvironment->serial_timeout_count = timeout_milliseconds; +#endif // _MSC_VER +#endif +} + + + +/***************************** SerialTimeoutCheck ***********************/ +/** Check to see if the serial timeout timer has run down. +\retval 1 if timer has run out. +\retval 0 if timer still has time left. +*/ +static int SerialTimeoutCheck(ISP_ENVIRONMENT *IspEnvironment) +{ +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +#ifdef _MSC_VER + if ((signed long)(IspEnvironment->serial_timeout_count - timeGetTime()) < 0) + { + return 1; + } +#else + if (IspEnvironment->serial_timeout_count == 0) + { + return 1; + } +#endif // _MSC_VER +#else + if (IspEnvironment->serial_timeout_count == 0) + { + return 1; + } +#endif + return 0; +} + + +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN +/***************************** getch ************************************/ +/** Replacement for the common dos function of the same name. Reads a +single unbuffered character from the 'keyboard'. +\return The character read from the keyboard. +*/ +int getch(void) +{ + char ch; + + /* Read in one character */ + read(0,&ch,1); + + return ch; +} +#endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN +/***************************** kbhit ************************************/ +/** Replacement for the common dos function of the same name. Indicates if +there are characters to be read from the console. +\retval 0 No characters ready. +\retval 1 Characters from the console ready to be read. +*/ +int kbhit(void) +{ + /* return 0 for no key pressed, 1 for key pressed */ + int return_value = 0; + + /* time struct for the select() function, to only wait a little while */ + struct timeval select_time; + /* file descriptor variable for the select() call */ + fd_set readset; + + /* we're only interested in STDIN */ + FD_ZERO(&readset); + FD_SET(STDIN_FILENO, &readset); + + /* how long to block for - this must be > 0.0, but could be changed + to some other setting. 10-18msec seems to work well and only + minimally load the system (0% CPU loading) */ + select_time.tv_sec = 0; + select_time.tv_usec = 10; + + /* is there a keystroke there? */ + if (select(1, &readset, NULL, NULL, &select_time)) + { + /* yes, remember it */ + return_value = 1; + } + + + /* return with what we found out */ + return return_value; +} +struct termios keyboard_origtty; +#endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN + + +/***************************** PrepareKeyboardTtySettings ***************/ +/** Set the keyboard tty to be able to check for new characters via kbhit +getting them via getch +*/ + +void PrepareKeyboardTtySettings(void) +{ +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN + /* store the current tty settings */ + if (!tcgetattr(0, &keyboard_origtty)) + { + struct termios tty; + /* start with the current settings */ + tty = keyboard_origtty; + /* make modifications to put it in raw mode, turn off echo */ + tty.c_lflag &= ~ICANON; + tty.c_lflag &= ~ECHO; + tty.c_lflag &= ~ISIG; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + /* put the settings into effect */ + tcsetattr(0, TCSADRAIN, &tty); + } +#endif +} + + +/***************************** ResetKeyboardTtySettings *****************/ +/** Reset the keyboard tty to original settings +*/ +void ResetKeyboardTtySettings(void) +{ +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN + /* reset the tty to its original settings */ + tcsetattr(0, TCSADRAIN, &keyboard_origtty); +#endif +} + + +#if !defined COMPILE_FOR_LPC21 +/***************************** ControlModemLines ************************/ +/** Controls the modem lines to place the microcontroller into various +states during the programming process. +error rather abruptly terminates the program. +\param [in] DTR the state to set the DTR line to. +\param [in] RTS the state to set the RTS line to. +*/ +static void ControlModemLines(ISP_ENVIRONMENT *IspEnvironment, unsigned char DTR, unsigned char RTS) +{ + //handle wether to invert the control lines: + DTR ^= IspEnvironment->ControlLinesInverted; + RTS ^= IspEnvironment->ControlLinesInverted; + + //handle wether to swap the control lines + if (IspEnvironment->ControlLinesSwapped) + { + unsigned char tempRTS; + tempRTS = RTS; + RTS = DTR; + DTR = tempRTS; + } + +#if defined COMPILE_FOR_LINUX + int status; + + if (ioctl(IspEnvironment->fdCom, TIOCMGET, &status) == 0) + { + DebugPrintf(3, "ioctl get ok, status = %X\n",status); + } + else + { + DebugPrintf(1, "ioctl get failed\n"); + } + + if (DTR) status |= TIOCM_DTR; + else status &= ~TIOCM_DTR; + + if (RTS) status |= TIOCM_RTS; + else status &= ~TIOCM_RTS; + + if (ioctl(IspEnvironment->fdCom, TIOCMSET, &status) == 0) + { + DebugPrintf(3, "ioctl set ok, status = %X\n",status); + } + else + { + DebugPrintf(1, "ioctl set failed\n"); + } + + if (ioctl(IspEnvironment->fdCom, TIOCMGET, &status) == 0) + { + DebugPrintf(3, "ioctl get ok, status = %X\n",status); + } + else + { + DebugPrintf(1, "ioctl get failed\n"); + } + +#endif // defined COMPILE_FOR_LINUX +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + + if (DTR) EscapeCommFunction(IspEnvironment->hCom, SETDTR); + else EscapeCommFunction(IspEnvironment->hCom, CLRDTR); + + if (RTS) EscapeCommFunction(IspEnvironment->hCom, SETRTS); + else EscapeCommFunction(IspEnvironment->hCom, CLRRTS); + +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LPC21 + LPC_RESET(DTR); + LPC_BSL(RTS); +#endif + + DebugPrintf(3, "DTR (%d), RTS (%d)\n", DTR, RTS); +} + + +/***************************** ClearSerialPortBuffers********************/ +/** Empty the serial port buffers. Cleans things to a known state. +*/ +void ClearSerialPortBuffers(ISP_ENVIRONMENT *IspEnvironment) +{ +#if defined COMPILE_FOR_LINUX + /* variables to store the current tty state, create a new one */ + struct termios origtty, tty; + + /* store the current tty settings */ + tcgetattr(IspEnvironment->fdCom, &origtty); + + // Flush input and output buffers + tty=origtty; + tcsetattr(IspEnvironment->fdCom, TCSAFLUSH, &tty); + + /* reset the tty to its original settings */ + tcsetattr(IspEnvironment->fdCom, TCSADRAIN, &origtty); +#endif // defined COMPILE_FOR_LINUX +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + PurgeComm(IspEnvironment->hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +} +#endif // !defined COMPILE_FOR_LPC21 + + +#if defined COMPILE_FOR_LINUX +/***************************** Sleep ************************************/ +/** Provide linux replacement for windows function. +\param [in] Milliseconds the time to wait for in milliseconds. +*/ +void Sleep(unsigned long MilliSeconds) +{ + usleep(MilliSeconds*1000); //convert to microseconds +} +#endif // defined COMPILE_FOR_LINUX + + +#if defined COMPILE_FOR_LPC21 +/** Provide linux replacement for windows function. +\note I implement that one in my private header file today... +\param [in] Milliseconds the time to wait for in milliseconds. +*/ +/*static void Sleep(unsigned long MilliSeconds) +{ +# warning Sleep function not implemented +} +*/ +#endif // defined COMPILE_FOR_LPC21 + + + +/************* Applicationlayer. */ + +#if !defined COMPILE_FOR_LPC21 +/***************************** DebugPrintf ******************************/ +/** Prints a debug string depending the current debug level. The higher +the debug level the more detail that will be printed. Each print +has an associated level, the higher the level the more detailed the +debugging information being sent. +\param [in] level the debug level of the print statement, if the level +is less than or equal to the current debug level it will be printed. +\param [in] fmt a standard printf style format string. +\param [in] ... the usual printf parameters. +*/ +#if !defined INTEGRATED_IN_WIN_APP +void DebugPrintf(int level, const char *fmt, ...) +{ + va_list ap; + + if (level <= debug_level) + { + char pTemp[2000]; + va_start(ap, fmt); + //vprintf(fmt, ap); + vsprintf(pTemp, fmt, ap); + TRACE(pTemp); + va_end(ap); + fflush(stdout); + } +} +#endif +#endif // !defined COMPILE_FOR_LPC21 + + +/***************************** ReceiveComPort ***************************/ +/** Receives a buffer from the open com port. Returns when the buffer is +filled, the numer of requested linefeeds has been received or the timeout +period has passed. The bootloaders may send 0x0d,0x0a,0x0a or 0x0d,0x0a as +linefeed pattern +2013-06-28 Torsten Lang +Note: We *could* filter out surplus 0x0a characters like in +but as we don't know how the individual bootloader behaves we don't want +to wait for possible surplus (which would slow down the transfer). +Thus, we just terminate after the expected number of sequences +and leave it to the command handler in lpcprog.c to filter out surplus + characters which then occur as leading character in answers or +echoed commands. +\param [in] ISPEnvironment. +\param [out] Answer buffer to hold the bytes read from the serial port. +\param [in] MaxSize the size of buffer pointed to by Answer. +\param [out] RealSize pointer to a long that returns the amout of the +buffer that is actually used. +\param [in] WantedNr0x0A the maximum number of linefeeds to accept before +returning. +\param [in] timeOutMilliseconds the maximum amount of time to wait before +reading with an incomplete buffer. +*/ +void ReceiveComPort(ISP_ENVIRONMENT *IspEnvironment, + const char *Ans, unsigned long MaxSize, + unsigned long *RealSize, unsigned long WantedNr0x0A, + unsigned timeOutMilliseconds) +{ + unsigned long tmp_realsize; + unsigned long nr_of_0x0A = 0; + unsigned long nr_of_0x0D = 0; + int eof = 0; + unsigned long p; + unsigned char *Answer; + unsigned char *endPtr; + char tmp_string[32]; + static char residual_data[128] = {'\0'}; + int lf = 0; + + Answer = (unsigned char*) Ans; + + SerialTimeoutSet(IspEnvironment, timeOutMilliseconds); + + *RealSize = 0; + endPtr = NULL; + + do + { + if (residual_data[0] == '\0') + { + /* Receive new data */ + ReceiveComPortBlock(IspEnvironment, Answer + (*RealSize), MaxSize - 1 - (*RealSize), &tmp_realsize); + } + else + { + /* Take over any old residual data */ + strcpy((char *)Answer, residual_data); + tmp_realsize = strlen((char *)Answer); + residual_data[0] = '\0'; + } + + if (tmp_realsize != 0) + { + for (p = (*RealSize); p < (*RealSize) + tmp_realsize; p++) + { + /* Torsten Lang 2013-05-06 Scan for 0x0d,0x0a,0x0a and 0x0d,0x0a as linefeed pattern */ + if (Answer[p] == 0x0a) + { + if (lf != 0) + { + nr_of_0x0A++; + lf = 0; + if (nr_of_0x0A >= WantedNr0x0A) + { + endPtr = &Answer[p+1]; + } + } + } + else if (Answer[p] == 0x0d) + { + nr_of_0x0D++; + lf = 1; + } + else if (((signed char) Answer[p]) < 0) + { + eof = 1; + lf = 0; + } + else if (lf != 0) + { + nr_of_0x0D++; + nr_of_0x0A++; + lf = 0; + if (nr_of_0x0A >= WantedNr0x0A) + { + endPtr = &Answer[p+1]; + } + } + } + (*RealSize) += tmp_realsize; + } + } while (((*RealSize) < MaxSize) && (SerialTimeoutCheck(IspEnvironment) == 0) && (nr_of_0x0A < WantedNr0x0A) && !eof); + + /* Torsten Lang 2013-05-06 Store residual data and cut answer after expected nr. of 0x0a */ + Answer[*RealSize] = '\0'; + if (endPtr != NULL) + { + strcpy(residual_data, (char *)endPtr); + *endPtr = '\0'; + /* Torsten Lang 2013-06-28 Update size info */ + *RealSize = endPtr-Answer; + } + + sprintf(tmp_string, "Answer(Length=%ld): ", (*RealSize)); + DumpString(3, Answer, (*RealSize), tmp_string); +} + + +#if !defined COMPILE_FOR_LPC21 + +/***************************** ReceiveComPortBlockComplete **************/ +/** Receives a fixed block from the open com port. Returns when the +block is completely filled or the timeout period has passed +\param [out] block buffer to hold the bytes read from the serial port. +\param [in] size the size of the buffer pointed to by block. +\param [in] timeOut the maximum amount of time to wait before guvung up on +completing the read. +\return 0 if successful, non-zero otherwise. +*/ +int ReceiveComPortBlockComplete(ISP_ENVIRONMENT *IspEnvironment, + void *block, size_t size, unsigned timeout) +{ + unsigned long realsize = 0, read; + char *result; + char tmp_string[32]; + + result = (char*) block; + + SerialTimeoutSet(IspEnvironment, timeout); + + do + { + ReceiveComPortBlock(IspEnvironment, result + realsize, size - realsize, &read); + + realsize += read; + + } while ((realsize < size) && (SerialTimeoutCheck(IspEnvironment) == 0)); + + sprintf(tmp_string, "Answer(Length=%ld): ", realsize); + DumpString(3, result, realsize, tmp_string); + + if (realsize != size) + { + return 1; + } + return 0; +} + +/***************************** ReadArguments ****************************/ +/** Reads the command line arguments and parses it for the various +options. Uses the same arguments as main. Used to separate the command +line parsing from main and improve its readability. This should also make +it easier to modify the command line parsing in the future. +\param [in] argc the number of arguments. +\param [in] argv an array of pointers to the arguments. +*/ +static void ReadArguments(ISP_ENVIRONMENT *IspEnvironment, unsigned int argc, char *argv[]) +{ + unsigned int i; + + if (argc >= 5) + { + for (i = 1; i < argc - 3; i++) + { + if (stricmp(argv[i], "-wipe") == 0) + { + IspEnvironment->WipeDevice = 1; + DebugPrintf(3, "Wipe entire device before writing.\n"); + continue; + } + + if (stricmp(argv[i], "-bin") == 0) + { + IspEnvironment->FileFormat = FORMAT_BINARY; + DebugPrintf(3, "Binary format file input.\n"); + continue; + } + + if (stricmp(argv[i], "-hex") == 0) + { + IspEnvironment->FileFormat = FORMAT_HEX; + DebugPrintf(3, "Hex format file input.\n"); + continue; + } + + if (stricmp(argv[i], "-logfile") == 0) + { + IspEnvironment->LogFile = 1; + DebugPrintf(3, "Log terminal output.\n"); + continue; + } + + if (stricmp(argv[i], "-detectonly") == 0) + { + IspEnvironment->DetectOnly = 1; + IspEnvironment->ProgramChip = 0; + DebugPrintf(3, "Only detect LPC chip part id.\n"); + continue; + } + + if(strnicmp(argv[i],"-debug", 6) == 0) + { + char* num; + num = argv[i] + 6; + while(*num && isdigit(*num) == 0) num++; + if(isdigit(*num) != 0) debug_level = atoi( num); + else debug_level = 4; + DebugPrintf(3, "Turn on debug, level: %d.\n", debug_level); + continue; + } + + if (stricmp(argv[i], "-boothold") == 0) + { + IspEnvironment->BootHold = 1; + DebugPrintf(3, "hold EnableBootLoader asserted throughout programming sequence.\n"); + continue; + } + + if (stricmp(argv[i], "-donotstart") == 0) + { + IspEnvironment->DoNotStart = 1; + DebugPrintf(3, "Do NOT start MCU after programming.\n"); + continue; + } + + if(strnicmp(argv[i],"-try", 4) == 0) + { + int + retry; + retry=atoi(&argv[i][4]); + if(retry>0) + { + IspEnvironment->nQuestionMarks=retry; + DebugPrintf(3, "Retry count: %d.\n", IspEnvironment->nQuestionMarks); + } + else + { + fprintf(stderr,"invalid argument for -try: \"%s\"\n",argv[i]); + } + continue; + } + + + if (stricmp(argv[i], "-control") == 0) + { + IspEnvironment->ControlLines = 1; + DebugPrintf(3, "Use RTS/DTR to control target state.\n"); + continue; + } + + if (stricmp(argv[i], "-controlswap") == 0) + { + IspEnvironment->ControlLinesSwapped = 1; + DebugPrintf(3, "Use RTS to control reset, and DTR to control P0.14(ISP).\n"); + continue; + } + + if (stricmp(argv[i], "-controlinv") == 0) + { + IspEnvironment->ControlLinesInverted = 1; + DebugPrintf(3, "Invert state of RTS & DTR (0=true/assert/set, 1=false/deassert/clear).\n"); + continue; + } + + if (stricmp(argv[i], "-halfduplex") == 0) + { + IspEnvironment->HalfDuplex = 1; + DebugPrintf(3, "halfduplex serial communication.\n"); + continue; + } + + if (stricmp(argv[i], "-ADARM") == 0) + { + IspEnvironment->micro = ANALOG_DEVICES_ARM; + DebugPrintf(2, "Target: Analog Devices.\n"); + continue; + } + + if (stricmp(argv[i], "-NXPARM") == 0 || stricmp(argv[i], "-PHILIPSARM") == 0) + { + IspEnvironment->micro = NXP_ARM; + DebugPrintf(2, "Target: NXP.\n"); + continue; + } + + if (stricmp(argv[i], "-Verify") == 0) + { + IspEnvironment->Verify = 1; + DebugPrintf(2, "Verify after copy RAM to Flash.\n"); + continue; + } + +#ifdef INTEGRATED_IN_WIN_APP + if (stricmp(argv[i], "-nosync") == 0) + { + IspEnvironment->NoSync = 1; + DebugPrintf(2, "Performing no syncing, already done.\n"); + continue; + } +#endif + +#ifdef TERMINAL_SUPPORT + if (CheckTerminalParameters(IspEnvironment, argv[i])) + { + continue; + } +#endif + + if(*argv[i] == '-') DebugPrintf( 2, "Unknown command line option: \"%s\"\n", argv[i]); + else + { + int ret_val; + if(IspEnvironment->FileFormat == FORMAT_HEX) + { + ret_val = AddFileHex(IspEnvironment, argv[i]); + } + else + { + ret_val = AddFileBinary(IspEnvironment, argv[i]); + } + if( ret_val != 0) + { + DebugPrintf( 2, "Unknown command line option: \"%s\"\n", argv[i]); + } + } + } + + // Newest cygwin delivers a '\x0d' at the end of argument + // when calling lpc21isp from batch file + for (i = 0; i < strlen(argv[argc - 1]) && i < (sizeof(IspEnvironment->StringOscillator) - 1) && + argv[argc - 1][i] >= '0' && argv[argc - 1][i] <= '9'; i++) + { + IspEnvironment->StringOscillator[i] = argv[argc - 1][i]; + } + IspEnvironment->StringOscillator[i] = 0; + + IspEnvironment->serial_port = argv[argc - 3]; + IspEnvironment->baud_rate = argv[argc - 2]; + } + + if (argc < 5) + { + debug_level = (debug_level < 2) ? 2 : debug_level; + } + + if (argc < 5) + { + DebugPrintf(2, "\n" + "Portable command line ISP\n" + "for NXP LPC family and Analog Devices ADUC 70xx\n" + "Version " VERSION_STR " compiled for " COMPILED_FOR ": " __DATE__ ", " __TIME__ "\n" + "Copyright (c) by Martin Maurer, 2003-2013, Email: Martin.Maurer@clibb.de\n" + "Portions Copyright (c) by Aeolus Development 2004, www.aeolusdevelopment.com\n" + "\n"); + + DebugPrintf(1, "Syntax: lpc21isp [Options] file[ file[ ...]] comport baudrate Oscillator_in_kHz\n\n" + "Example: lpc21isp test.hex com1 115200 14746\n\n" + "Options: -bin for uploading binary file\n" + " -hex for uploading file in intel hex format (default)\n" + " -term for starting terminal after upload\n" + " -termonly for starting terminal without an upload\n" + " -localecho for local echo in terminal\n" + " -detectonly detect only used LPC chiptype (NXPARM only)\n" + " -debug0 for no debug\n" + " -debug3 for progress info only\n" + " -debug5 for full debug\n" + " -donotstart do not start MCU after download\n" + " -try try n times to synchronise\n" + " -wipe Erase entire device before upload\n" + " -control for controlling RS232 lines for easier booting\n" + " (Reset = DTR, EnableBootLoader = RTS)\n" + " -boothold hold EnableBootLoader asserted throughout sequence\n" +#ifdef INTEGRATED_IN_WIN_APP + " -nosync Do not synchronize device via '?'\n" +#endif + " -controlswap swap RS232 control lines\n" + " (Reset = RTS, EnableBootLoader = DTR)\n" + " -controlinv Invert state of RTS & DTR \n" + " (0=true/assert/set, 1=false/deassert/clear).\n" + " -verify Verify the data in Flash after every writes to\n" + " sector. To detect errors in writing to Flash ROM\n" + " -logfile for enabling logging of terminal output to lpc21isp.log\n" + " -halfduplex use halfduplex serial communication (i.e. with K-Line)\n" + " -ADARM for downloading to an Analog Devices\n" + " ARM microcontroller ADUC70xx\n" + " -NXPARM for downloading to a chip of NXP LPC family (default)\n"); + + exit(1); + } + + if (IspEnvironment->micro == NXP_ARM) + { + // If StringOscillator is bigger than 100 MHz, there seems to be something wrong + if (strlen(IspEnvironment->StringOscillator) > 5) + { + DebugPrintf(1, "Invalid crystal frequency %s\n", IspEnvironment->StringOscillator); + exit(1); + } + } +} + +/***************************** ResetTarget ******************************/ +/** Resets the target leaving it in either download (program) mode or +run mode. +\param [in] mode the mode to leave the target in. +*/ +void ResetTarget(ISP_ENVIRONMENT *IspEnvironment, TARGET_MODE mode) +{ +#if defined(__linux__) && defined(GPIO_RST) && defined(GPIO_ISP) + +// This code section allows using Linux GPIO pins to control the -RST and -ISP +// signals of the target microcontroller. +// +// Build lpc21isp to use Linux GPIO like this: +// +// make CFLAGS="-Wall -DGPIO_ISP=23 -DGPIO_RST=18" +// +// The GPIO pins must be pre-configured in /etc/rc.local (or other startup script) +// similar to the following: +// +// # Configure -ISP signal +// echo 23 >/sys/class/gpio/export +// echo out >/sys/class/gpio/gpio23/direction +// echo 1 >/sys/class/gpio/gpio23/value +// chown root.gpio /sys/class/gpio/gpio23/value +// chmod 660 /sys/class/gpio/gpio23/value +// +// # Configure -RST signal +// echo 18 >/sys/class/gpio/export +// echo out >/sys/class/gpio/gpio18/direction +// echo 1 >/sys/class/gpio/gpio18/value +// chown root.gpio /sys/class/gpio/gpio18/value +// chmod 660 /sys/class/gpio/gpio18/value +// +// Then if the user is a member of the gpio group, lpc21isp will not requre any +// special permissions to access the GPIO signals. + + char gpio_isp_filename[256]; + char gpio_rst_filename[256]; + int gpio_isp; + int gpio_rst; + + memset(gpio_isp_filename, 0, sizeof(gpio_isp_filename)); + sprintf(gpio_isp_filename, "/sys/class/gpio/gpio%d/value", GPIO_ISP); + + memset(gpio_rst_filename, 0, sizeof(gpio_rst_filename)); + sprintf(gpio_rst_filename, "/sys/class/gpio/gpio%d/value", GPIO_RST); + + gpio_isp = open(gpio_isp_filename, O_WRONLY); + if (gpio_isp < 0) + { + fprintf(stderr, "ERROR: open() for %s failed, %s\n", gpio_isp_filename, strerror(errno)); + exit(1); + } + + gpio_rst = open(gpio_rst_filename, O_WRONLY); + if (gpio_rst < 0) + { + fprintf(stderr, "ERROR: open() for %s failed, %s\n", gpio_rst_filename, strerror(errno)); + exit(1); + } + + switch (mode) + { + case PROGRAM_MODE : + write(gpio_isp, "0\n", 2); // Assert -ISP + Sleep(100); + write(gpio_rst, "0\n", 2); // Assert -RST + Sleep(500); + write(gpio_rst, "1\n", 2); // Deassert -RST + Sleep(100); + write(gpio_isp, "1\n", 2); // Deassert -ISP + Sleep(100); + break;; + + case RUN_MODE : + write(gpio_rst, "0\n", 2); // Assert -RST + Sleep(500); + write(gpio_rst, "1\n", 2); // Deassert -ISP + Sleep(100); + break;; + } + + close(gpio_isp); + close(gpio_rst); + + return; +#endif + + if (IspEnvironment->ControlLines) + { + switch (mode) + { + /* Reset and jump to boot loader. */ + case PROGRAM_MODE: + ControlModemLines(IspEnvironment, 1, 1); + Sleep(100); + ClearSerialPortBuffers(IspEnvironment); + Sleep(100); + ControlModemLines(IspEnvironment, 0, 1); + //Longer delay is the Reset signal is conected to an external rest controller + Sleep(500); + // Clear the RTS line after having reset the micro + // Needed for the "GO
" ISP command to work */ + if(!IspEnvironment->BootHold) + { + ControlModemLines(IspEnvironment, 0, 0); + } + break; + + /* Reset and start uploaded program */ + case RUN_MODE: + ControlModemLines(IspEnvironment, 1, 0); + Sleep(100); + ClearSerialPortBuffers(IspEnvironment); + Sleep(100); + ControlModemLines(IspEnvironment, 0, 0); + Sleep(100); + break; + } + } +} + + +/***************************** Ascii2Hex ********************************/ +/** Converts a hex character to its equivalent number value. In case of an +error rather abruptly terminates the program. +\param [in] c the hex digit to convert. +\return the value of the hex digit. +*/ +static unsigned char Ascii2Hex(unsigned char c) +{ + if (c >= '0' && c <= '9') + { + return (unsigned char)(c - '0'); + } + + if (c >= 'A' && c <= 'F') + { + return (unsigned char)(c - 'A' + 10); + } + + if (c >= 'a' && c <= 'f') + { + return (unsigned char)(c - 'a' + 10); + } + + DebugPrintf(1, "Wrong Hex-Nibble %c (%02X)\n", c, c); + exit(1); + + return 0; // this "return" will never be reached, but some compilers give a warning if it is not present +} + + +/***************************** AddFileHex *******************************/ +/** Add a file to the list of files to read in, flag it as hex format. +\param [in] IspEnvironment Programming environment. +\param [in] arg The argument that was passed to the program as a file name. +\return 0 on success, an error code otherwise. +*/ +static int AddFileHex(ISP_ENVIRONMENT *IspEnvironment, const char *arg) +{ + FILE_LIST *entry; + + // Add file to list. If cannot allocate storage for node return an error. + entry = malloc(sizeof(FILE_LIST)); + if( entry == 0) + { + DebugPrintf(1, "Error %d Could not allocated memory for file node %s\n", ERR_ALLOC_FILE_LIST, arg); + return ERR_ALLOC_FILE_LIST; + } + + // Build up entry and insert it at the start of the list. + entry->name = arg; + entry->prev = IspEnvironment->f_list; + entry->hex_flag = 1; + IspEnvironment->f_list = entry; + + return 0; // Success. +} + + +/***************************** AddFileBinary ****************************/ +/** Add a file to the list of files to read in, flag it as binary format. +\param [in] IspEnvironment Programming environment. +\param [in] arg The argument that was passed to the program as a file name. +\return 0 on success, an error code otherwise. +*/ +static int AddFileBinary(ISP_ENVIRONMENT *IspEnvironment, const char *arg) +{ + FILE_LIST *entry; + + // Add file to list. If cannot allocate storage for node return an error. + entry = malloc(sizeof(FILE_LIST)); + if( entry == 0) + { + DebugPrintf( 1, "Error %d Could not allocated memory for file node %s\n", ERR_ALLOC_FILE_LIST, arg); + return ERR_ALLOC_FILE_LIST; + } + + // Build up entry and insert it at the start of the list. + entry->name = arg; + entry->prev = IspEnvironment->f_list; + entry->hex_flag = 0; + IspEnvironment->f_list = entry; + + return 0; // Success. +} + +#if 0 +void ReadHexFile(ISP_ENVIRONMENT *IspEnvironment) +{ + LoadFile(IspEnvironment); + + if (IspEnvironment->BinaryLength) + { + BINARY* FileContent = IspEnvironment->FileContent; + + unsigned long Pos; + unsigned char RecordLength; + unsigned short RecordAddress; + unsigned long RealAddress = 0; + unsigned char RecordType; + unsigned char Hexvalue; + unsigned long StartAddress; + int BinaryOffsetDefined = 0; + unsigned char i; + + + DebugPrintf(3, "Converting file %s to binary format...\n", IspEnvironment->input_file); + + Pos = 0; + while (Pos < IspEnvironment->BinaryLength) + { + if (FileContent[Pos] == '\r') + { + Pos++; + continue; + } + + if (FileContent[Pos] == '\n') + { + Pos++; + continue; + } + + if (FileContent[Pos] != ':') + { + DebugPrintf(1, "Missing start of record (':') wrong byte %c / %02X\n", FileContent[Pos], FileContent[Pos]); + exit(1); + } + + Pos++; + + RecordLength = Ascii2Hex(FileContent[Pos++]); + RecordLength <<= 4; + RecordLength |= Ascii2Hex(FileContent[Pos++]); + + DebugPrintf(4, "RecordLength = %02X\n", RecordLength); + + RecordAddress = Ascii2Hex(FileContent[Pos++]); + RecordAddress <<= 4; + RecordAddress |= Ascii2Hex(FileContent[Pos++]); + RecordAddress <<= 4; + RecordAddress |= Ascii2Hex(FileContent[Pos++]); + RecordAddress <<= 4; + RecordAddress |= Ascii2Hex(FileContent[Pos++]); + + DebugPrintf(4, "RecordAddress = %04X\n", RecordAddress); + + RealAddress = RealAddress - (RealAddress & 0xffff) + RecordAddress; + + DebugPrintf(4, "RealAddress = %08lX\n", RealAddress); + + RecordType = Ascii2Hex(FileContent[Pos++]); + RecordType <<= 4; + RecordType |= Ascii2Hex(FileContent[Pos++]); + + DebugPrintf(4, "RecordType = %02X\n", RecordType); + + if (RecordType == 0x00) // 00 - Data record + { + /* + * Binary Offset is defined as soon as first data record read + */ + + //BinaryOffsetDefined = 1; + + // Memory for binary file big enough ? + while ((RealAddress + RecordLength - IspEnvironment->BinaryOffset) > IspEnvironment->BinaryMemSize) + { + IspEnvironment->BinaryMemSize <<= 1; // Double the size allocated !!! + IspEnvironment->BinaryContent = (BINARY*) realloc(IspEnvironment->BinaryContent, IspEnvironment->BinaryMemSize); + } + + // We need to know, what the highest address is, + // how many bytes / sectors we must flash + if (RealAddress + RecordLength - IspEnvironment->BinaryOffset > IspEnvironment->BinaryLength) + { + IspEnvironment->BinaryLength = RealAddress + RecordLength - IspEnvironment->BinaryOffset; + DebugPrintf(3, "Image size now: %ld\n", IspEnvironment->BinaryLength); + } + + for (i = 0; i < RecordLength; i++) + { + Hexvalue = Ascii2Hex(FileContent[Pos++]); + Hexvalue <<= 4; + Hexvalue |= Ascii2Hex(FileContent[Pos++]); + IspEnvironment->BinaryContent[RealAddress + i - IspEnvironment->BinaryOffset] = Hexvalue; + } + } + else if (RecordType == 0x01) // 01 - End of file record + { + break; + } + else if (RecordType == 0x02) // 02 - Extended segment address record + { + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + RealAddress <<= 4; + if (i == 0) + { + RealAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + RealAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + RealAddress <<= 4; + } + else if (RecordType == 0x03) // 03 - Start segment address record + { + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + RealAddress <<= 4; + if (i == 0) + { + RealAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + RealAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + RealAddress <<= 8; + } + else if (RecordType == 0x04) // 04 - Extended linear address record, used by IAR + { + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + RealAddress <<= 4; + if (i == 0) + { + RealAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + RealAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + RealAddress <<= 16; + if (!BinaryOffsetDefined) + { + // set startaddress of BinaryContent + // use of LPC_FLASHMASK to allow a memory range, not taking the first + // [04] record as actual start-address. + IspEnvironment->BinaryOffset = RealAddress & LPC_FLASHMASK; + } + else + { + if ((RealAddress & LPC_FLASHMASK) != IspEnvironment->BinaryOffset) + { + DebugPrintf(1, "New Extended Linear Address Record [04] out of memory range\n" + "Current Memory starts at: 0x%08X, new Address is: 0x%08X", + IspEnvironment->BinaryOffset, RealAddress); + exit(1); + } + } + } + else if (RecordType == 0x05) // 05 - Start linear address record + { + StartAddress = 0; + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + StartAddress <<= 4; + if (i == 0) + { + StartAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + StartAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress); + IspEnvironment->StartAddress = StartAddress; + } + + while (FileContent[Pos++] != 0x0a) // Search till line end + { + } + } + + DebugPrintf(2, "\tconverted to binary format...\n"); + + // When debugging is switched on, output result of conversion to file debugout.bin + if (debug_level >= 4) + { + int fdout; + fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777); + write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength); + close(fdout); + } + } +} +#endif // #if 0 + + +/***************************** LoadFile *********************************/ +/** Loads the requested file to download into memory. +\param [in] IspEnvironment structure containing input filename +\param [in] filename the name of the file to read in. +\param [in] FileFormat the format of the file to read in (FORMAT_HEX or FORMAT_BINARY) +\return 0 if successful, otherwise an error code. +*/ +static int LoadFile(ISP_ENVIRONMENT *IspEnvironment, const char *filename, int FileFormat) +{ + int fd; + int i; + int BinaryOffsetDefined; + unsigned long Pos; + unsigned long FileLength; + BINARY *FileContent; /**< Used to store the content of a hex */ + /* file before converting to binary. */ + unsigned long BinaryMemSize; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd == -1) + { + DebugPrintf(1, "Can't open file %s\n", filename); + return ERR_FILE_OPEN_HEX; + } + + FileLength = lseek(fd, 0L, 2); // Get file size + + if (FileLength == (size_t)-1) + { + DebugPrintf(1, "\nFileLength = -1 !?!\n"); + return ERR_FILE_SIZE_HEX; + } + + lseek(fd, 0L, 0); + + // Just read the entire file into memory to parse. + FileContent = (BINARY*) malloc(FileLength); + + if( FileContent == 0) + { + DebugPrintf( 1, "\nCouldn't allocate enough memory for file.\n"); + return ERR_FILE_ALLOC_HEX; + } + + BinaryOffsetDefined = 0; + + BinaryMemSize = IspEnvironment->BinaryLength; + + read(fd, FileContent, FileLength); + + close(fd); + + DebugPrintf(2, "File %s:\n\tloaded...\n", filename); + + // Intel-Hex -> Binary Conversion + + if (FileFormat == FORMAT_HEX) + { + unsigned char RecordLength; + unsigned short RecordAddress; + unsigned long RealAddress = 0; + unsigned char RecordType; + unsigned char Hexvalue; + unsigned long StartAddress; + + DebugPrintf(3, "Converting file %s to binary format...\n", filename); + + Pos = 0; + while (Pos < FileLength) + { + if (FileContent[Pos] == '\r') + { + Pos++; + continue; + } + + if (FileContent[Pos] == '\n') + { + Pos++; + continue; + } + + if (FileContent[Pos] != ':') + { + DebugPrintf(1, "Missing start of record (':') wrong byte %c / %02X\n", FileContent[Pos], FileContent[Pos]); + exit(1); + } + + Pos++; + + RecordLength = Ascii2Hex(FileContent[Pos++]); + RecordLength <<= 4; + RecordLength |= Ascii2Hex(FileContent[Pos++]); + + DebugPrintf(4, "RecordLength = %02X\n", RecordLength); + + RecordAddress = Ascii2Hex(FileContent[Pos++]); + RecordAddress <<= 4; + RecordAddress |= Ascii2Hex(FileContent[Pos++]); + RecordAddress <<= 4; + RecordAddress |= Ascii2Hex(FileContent[Pos++]); + RecordAddress <<= 4; + RecordAddress |= Ascii2Hex(FileContent[Pos++]); + + DebugPrintf(4, "RecordAddress = %04X\n", RecordAddress); + + RealAddress = RealAddress - (RealAddress & 0xffff) + RecordAddress; + + DebugPrintf(4, "RealAddress = %08lX\n", RealAddress); + + RecordType = Ascii2Hex(FileContent[Pos++]); + RecordType <<= 4; + RecordType |= Ascii2Hex(FileContent[Pos++]); + + DebugPrintf(4, "RecordType = %02X\n", RecordType); + + if (RecordType == 0x00) // 00 - Data record + { + /* + * Binary Offset is defined as soon as first data record read + */ + BinaryOffsetDefined = 1; + // Memory for binary file big enough ? + while (RealAddress + RecordLength - IspEnvironment->BinaryOffset > BinaryMemSize) + { + if(!BinaryMemSize) BinaryMemSize = FileLength * 2; + else BinaryMemSize <<= 1; + IspEnvironment->BinaryContent = realloc(IspEnvironment->BinaryContent, BinaryMemSize); + } + + // We need to know, what the highest address is, + // how many bytes / sectors we must flash + if (RealAddress + RecordLength - IspEnvironment->BinaryOffset > IspEnvironment->BinaryLength) + { + IspEnvironment->BinaryLength = RealAddress + RecordLength - IspEnvironment->BinaryOffset; + DebugPrintf(3, "Image size now: %ld\n", IspEnvironment->BinaryLength); + } + + for (i = 0; i < RecordLength; i++) + { + Hexvalue = Ascii2Hex(FileContent[Pos++]); + Hexvalue <<= 4; + Hexvalue |= Ascii2Hex(FileContent[Pos++]); + IspEnvironment->BinaryContent[RealAddress + i - IspEnvironment->BinaryOffset] = Hexvalue; + } + } + else if (RecordType == 0x01) // 01 - End of file record + { + break; + } + else if (RecordType == 0x02) // 02 - Extended segment address record + { + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + RealAddress <<= 4; + if (i == 0) + { + RealAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + RealAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + RealAddress <<= 4; + } + else if (RecordType == 0x03) // 03 - Start segment address record + { + unsigned long cs,ip; + StartAddress = 0; + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + StartAddress <<= 4; + if (i == 0) + { + StartAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + StartAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + cs = StartAddress >> 16; //high part + ip = StartAddress & 0xffff; //low part + StartAddress = cs*16+ip; //segmented 20-bit space + DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress); + IspEnvironment->StartAddress = StartAddress; + } + else if (RecordType == 0x04) // 04 - Extended linear address record, used by IAR + { + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + RealAddress <<= 4; + if (i == 0) + { + RealAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + RealAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + RealAddress <<= 16; + if (!BinaryOffsetDefined) + { + // set startaddress of BinaryContent + // use of LPC_FLASHMASK to allow a memory range, not taking the first + // [04] record as actual start-address. + IspEnvironment->BinaryOffset = RealAddress & LPC_FLASHMASK; + } + else + { + if ((RealAddress & LPC_FLASHMASK) != IspEnvironment->BinaryOffset) + { + DebugPrintf(1, "New Extended Linear Address Record [04] out of memory range\n"); + DebugPrintf(1, "Current Memory starts at: 0x%08X, new Address is: 0x%08X", + IspEnvironment->BinaryOffset, RealAddress); + return ERR_MEMORY_RANGE; + } + } + } + else if (RecordType == 0x05) // 05 - Start linear address record + { + StartAddress = 0; + for (i = 0; i < RecordLength * 2; i++) // double amount of nibbles + { + StartAddress <<= 4; + if (i == 0) + { + StartAddress = Ascii2Hex(FileContent[Pos++]); + } + else + { + StartAddress |= Ascii2Hex(FileContent[Pos++]); + } + } + DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress); + IspEnvironment->StartAddress = StartAddress; + } + else + { + free( FileContent); + DebugPrintf( 1, "Error %d RecordType %02X not yet implemented\n", ERR_RECORD_TYPE_LOADFILE, RecordType); + return( ERR_RECORD_TYPE_LOADFILE); + } + + while (FileContent[Pos++] != 0x0a) // Search till line end + { + } + } + + DebugPrintf(2, "\tconverted to binary format...\n"); + + // When debugging is switched on, output result of conversion to file debugout.bin + if (debug_level >= 4) + { + int fdout; + fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777); + write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength); + close(fdout); + } + + free( FileContent); // Done with file contents + } + else // FORMAT_BINARY + { + IspEnvironment->BinaryContent = FileContent; + IspEnvironment->BinaryLength = FileLength; + } + + DebugPrintf(2, "\timage size : %ld\n", IspEnvironment->BinaryLength); + + return 0; +} + +/***************************** LoadFiles1 ********************************/ +/** Loads the requested files to download into memory. +\param [in] IspEnvironment structure containing input filename(s). +\param [in] file simple linked list of files to read +\return 0 if successful, otherwise an error code. +*/ +static int LoadFiles1(ISP_ENVIRONMENT *IspEnvironment, const FILE_LIST *file) +{ + int ret_val; + + if( file->prev != 0) + { + DebugPrintf( 3, "Follow file list %s\n", file->name); + + ret_val = LoadFiles1( IspEnvironment, file->prev); + if( ret_val != 0) + { + return ret_val; + } + } + + DebugPrintf( 3, "Attempt to read File %s\n", file->name); + if(file->hex_flag != 0) + { + ret_val = LoadFile(IspEnvironment, file->name, FORMAT_HEX); + } + else + { + ret_val = LoadFile(IspEnvironment, file->name, FORMAT_BINARY); + } + if( ret_val != 0) + { + return ret_val; + } + + return 0; +} + +/***************************** LoadFiles ********************************/ +/** Loads the requested files to download into memory. +\param [in] IspEnvironment structure containing input filename(s). +\param [in] file simple linked list of files to read +\return 0 if successful, otherwise an error code. +*/ +static int LoadFiles(ISP_ENVIRONMENT *IspEnvironment) +{ + int ret_val; + + ret_val = LoadFiles1(IspEnvironment, IspEnvironment->f_list); + if( ret_val != 0) + { + exit(1); // return ret_val; + } + + DebugPrintf( 2, "Image size : %ld\n", IspEnvironment->BinaryLength); + + // check length to flash for correct alignment, can happen with broken ld-scripts + if (IspEnvironment->BinaryLength % 4 != 0) + { + unsigned long NewBinaryLength = ((IspEnvironment->BinaryLength + 3)/4) * 4; + + DebugPrintf( 2, "Warning: data not aligned to 32 bits, padded (length was %lX, now %lX)\n", IspEnvironment->BinaryLength, NewBinaryLength); + + IspEnvironment->BinaryLength = NewBinaryLength; + } + + // When debugging is switched on, output result of conversion to file debugout.bin + if(debug_level >= 4) + { + int fdout; + DebugPrintf( 1, "Dumping image file.\n"); + fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777); + write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength); + close(fdout); + } + return 0; +} +#endif // !defined COMPILE_FOR_LPC21 + +#ifndef COMPILE_FOR_LPC21 +int PerformActions(ISP_ENVIRONMENT *IspEnvironment) +{ + int downloadResult = -1; + + DebugPrintf(2, "lpc21isp version " VERSION_STR "\n"); + + /* Download requested, read in the input file. */ + if (IspEnvironment->ProgramChip) + { + LoadFiles(IspEnvironment); + } + + OpenSerialPort(IspEnvironment); /* Open the serial port to the microcontroller. */ + + ResetTarget(IspEnvironment, PROGRAM_MODE); + + ClearSerialPortBuffers(IspEnvironment); + + /* Perform the requested download. */ + if (IspEnvironment->ProgramChip || IspEnvironment->DetectOnly) + { + switch (IspEnvironment->micro) + { +#ifdef LPC_SUPPORT + case NXP_ARM: + downloadResult = NxpDownload(IspEnvironment); + break; +#endif + +#ifdef AD_SUPPORT + case ANALOG_DEVICES_ARM: + downloadResult = AnalogDevicesDownload(IspEnvironment); + break; +#endif + } + + if (downloadResult != 0) + { + CloseSerialPort(IspEnvironment); + exit(downloadResult); + } + } + + if (IspEnvironment->StartAddress == 0 || IspEnvironment->TerminalOnly) + { + /* Only reset target if startaddress = 0 + * Otherwise stay with the running program as started in Download() + */ + ResetTarget(IspEnvironment, RUN_MODE); + } + + debug_level = 1; /* From now on there is no more debug output !! */ + /* Therefore switch it off... */ + +#ifdef TERMINAL_SUPPORT + // Pass control to Terminal which will provide a terminal if one was asked for + // User asked for terminal emulation, provide a really dumb terminal. + Terminal(IspEnvironment); +#endif + + CloseSerialPort(IspEnvironment); /* All done, close the serial port to the */ + + return 0; +} +#endif + +/***************************** main *************************************/ +/** main. Everything starts from here. +\param [in] argc the number of arguments. +\param [in] argv an array of pointers to the arguments. +*/ + +#if !defined COMPILE_FOR_LPC21 + +#if defined INTEGRATED_IN_WIN_APP +int AppDoProgram(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + ISP_ENVIRONMENT IspEnvironment; + + // Initialize debug level + debug_level = 2; + + // Initialize ISP Environment + memset(&IspEnvironment, 0, sizeof(IspEnvironment)); // Clear the IspEnviroment to a known value + IspEnvironment.micro = NXP_ARM; // Default Micro + IspEnvironment.FileFormat = FORMAT_HEX; // Default File Format + IspEnvironment.ProgramChip = TRUE; // Default to Programming the chip + IspEnvironment.nQuestionMarks = 100; + IspEnvironment.DoNotStart = 0; + IspEnvironment.BootHold = 0; + ReadArguments(&IspEnvironment, argc, argv); // Read and parse the command line + + return PerformActions(&IspEnvironment); // Do as requested ! +} + +#endif // !defined COMPILE_FOR_LPC21 + +/***************************** DumpString ******************************/ +/** Prints an area of memory to stdout. Converts non-printables to hex. +\param [in] level the debug level of the block to be dumped. If this is +less than or equal to the current debug level than the dump will happen +otherwise this just returns. +\param [in] b pointer to an area of memory. +\param [in] size the length of the memory block to print. +\param [in] prefix string is a pointer to a prefix string. +*/ +void DumpString(int level, const void *b, size_t size, const char *prefix_string) +{ + size_t i; + const char * s = (const char*) b; + unsigned char c; + + DebugPrintf(level, prefix_string); + + DebugPrintf(level, "'"); + for (i = 0; i < size; i++) + { + c = s[i]; + if (c >= 0x20 && c <= 0x7e) /*isprint?*/ + { + DebugPrintf(level, "%c", c); + } + else + { + DebugPrintf(level, "(%02X)", c); + } + } + DebugPrintf(level, "'\n"); +} + diff --git a/host/app/lpc21lisp/lpc21isp.h b/host/app/lpc21lisp/lpc21isp.h new file mode 100644 index 0000000..a7fffcb --- /dev/null +++ b/host/app/lpc21lisp/lpc21isp.h @@ -0,0 +1,302 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC1000 / LPC2000 family + and Analog Devices ADUC70xx + +Filename: lsp21isp.h + +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-2011, 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 . +*/ + +// #define INTEGRATED_IN_WIN_APP + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define COMPILE_FOR_WINDOWS +#define COMPILED_FOR "Windows" +#elif defined(__CYGWIN__) +#define COMPILE_FOR_CYGWIN +#define COMPILED_FOR "Cygwin" +#elif (defined(__arm__) || defined(__thumb__)) && !defined(__linux__) +#define COMPILE_FOR_LPC21 +#define COMPILED_FOR "ARM" +#define printf iprintf +#elif defined(__APPLE__) +#define COMPILE_FOR_LINUX +#define COMPILED_FOR "Apple MacOS X" +#elif defined(__FreeBSD__) +#define COMPILE_FOR_LINUX +#define COMPILED_FOR "FreeBSD" +#elif defined(__OpenBSD__) +#define COMPILE_FOR_LINUX +#define COMPILED_FOR "OpenBSD" +#else +#define COMPILE_FOR_LINUX +#define COMPILED_FOR "Linux" +#endif + +// The Required features can be enabled / disabled here +#define LPC_SUPPORT + +#ifndef COMPILE_FOR_LPC21 +#define AD_SUPPORT +#define TERMINAL_SUPPORT +#endif + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN +#include +#include +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_WINDOWS +#include +//#define TRACE(x) OutputDebugString(x) +#define TRACE(x) printf("%s",x) +#endif // defined COMPILE_FOR_WINDOWS + +#if defined COMPILE_FOR_CYGWIN +//#define TRACE(x) OutputDebugString(x) +#define TRACE(x) printf("%s",x) +#endif // defined COMPILE_FOR_WINDOWS + +#if defined COMPILE_FOR_LINUX +#include +#include +#include +#include +#include +#include +extern void Sleep(unsigned long MilliSeconds); +#define TRACE(x) printf("%s",x) +#endif // defined COMPILE_FOR_LINUX + +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN +#include +#include // for read and return value of lseek +#include // for select_time +extern int kbhit(void); +extern int getch(void); +extern struct termios keyboard_origtty; +#endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN + +#include // isdigit() +#include // stdout +#include +#include +#if defined (COMPILE_FOR_LINUX) +#if defined(__OpenBSD__) +#include +#else +#include +#endif +#endif + +#if defined COMPILE_FOR_LPC21 +#include +#include +//#include // if using libc serial port communication +#else +#include +#endif + +typedef enum +{ + NXP_ARM, + ANALOG_DEVICES_ARM +} TARGET; + +typedef enum +{ + PROGRAM_MODE, + RUN_MODE +} TARGET_MODE; + +typedef enum +{ + FORMAT_BINARY, + FORMAT_HEX +} FILE_FORMAT_TYPE; + +typedef unsigned char BINARY; // Data type used for microcontroller + +/** Used to create list of files to read in. */ +typedef struct file_list FILE_LIST; + +#define ERR_RECORD_TYPE_LOADFILE 55 /**< File record type not yet implemented. */ +#define ERR_ALLOC_FILE_LIST 60 /**< Error allocation file list. */ +#define ERR_FILE_OPEN_HEX 61 /**< Couldn't open hex file. */ +#define ERR_FILE_SIZE_HEX 62 /**< Unexpected hex file size. */ +#define ERR_FILE_ALLOC_HEX 63 /**< Couldn't allocate enough memory for hex file. */ +#define ERR_MEMORY_RANGE 69 /**< Out of memory range. */ + +/** Structure used to build list of input files. */ +struct file_list +{ + const char *name; /**< The name of the input file. */ + FILE_LIST *prev; /**< The previous file name in the list.*/ + char hex_flag; /**< True if the input file is hex. */ +}; + +typedef struct +{ +#if !defined COMPILE_FOR_LPC21 + TARGET micro; // The type of micro that will be programmed. + FILE_FORMAT_TYPE FileFormat; + unsigned char ProgramChip; // Normally set + + unsigned char ControlLines; + unsigned char ControlLinesSwapped; + unsigned char ControlLinesInverted; + unsigned char LogFile; + FILE_LIST *f_list; // List of files to read in. + int nQuestionMarks; // how many times to try to synchronise + int DoNotStart; + int BootHold; + char *serial_port; // Name of the serial port to use to + // communicate with the microcontroller. + // Read from the command line. +#endif // !defined COMPILE_FOR_LPC21 + + unsigned char TerminalOnly; // Declared here for lazyness saves ifdef's +#ifdef TERMINAL_SUPPORT + unsigned char TerminalAfterUpload; + unsigned char LocalEcho; +#endif + + unsigned char HalfDuplex; // Only used for LPC Programming + unsigned char DetectOnly; + unsigned char WipeDevice; + unsigned char Verify; + int DetectedDevice; /* index in LPCtypes[] array */ + char *baud_rate; /**< Baud rate to use on the serial + * port communicating with the + * microcontroller. Read from the + * command line. */ + + char StringOscillator[6]; /**< Holds representation of oscillator + * speed from the command line. */ + + BINARY *FileContent; + BINARY *BinaryContent; /**< Binary image of the */ + /* microcontroller's memory. */ + unsigned long BinaryLength; + unsigned long BinaryOffset; + unsigned long StartAddress; + unsigned long BinaryMemSize; + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + HANDLE hCom; +#endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + +#if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21 + int fdCom; +#endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21 + +#if defined COMPILE_FOR_LINUX + struct termios oldtio, newtio; +#endif // defined COMPILE_FOR_LINUX + +#ifdef INTEGRATED_IN_WIN_APP + unsigned char NoSync; +#endif + +#if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN + unsigned long serial_timeout_count; /**< Local used to track timeouts on serial port read. */ +#else + unsigned serial_timeout_count; /**< Local used to track timeouts on serial port read. */ +#endif + +} ISP_ENVIRONMENT; + +#if defined COMPILE_FOR_LPC21 + +#define DebugPrintf(in, ...) + +#else +extern int debug_level; + +#if defined INTEGRATED_IN_WIN_APP + +#define DebugPrintf AppDebugPrintf +void AppDebugPrintf(int level, const char *fmt, ...); + +#define exit(val) AppException(val) +void AppException(int exception_level); + +int AppDoProgram(int argc, char *argv[]); + +#define Exclude_kbhit 1 +int AppSyncing(int trials); +void AppWritten(int size); + +#else +void DebugPrintf(int level, const char *fmt, ...); +//#define DebugPrintf(level, ...) if (level <= debug_level) { TRACE( __VA_ARGS__ ); } +#endif + +void ClearSerialPortBuffers(ISP_ENVIRONMENT *IspEnvironment); +void ControlXonXoffSerialPort(ISP_ENVIRONMENT *IspEnvironment, unsigned char XonXoff); + +#endif + + +#if defined COMPILE_FOR_LINUX +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif // defined COMPILE_FOR_LINUX + +#ifndef O_BINARY +#define O_BINARY 0 +#endif // O_BINARY + +#ifndef DWORD +#define DWORD unsigned long +#endif // DWORD + +/* +debug levels +0 - very quiet - Nothing gets printed at this level +1 - quiet - Only error messages should be printed +2 - indicate progress - Add progress messages +3 - first level debug - Major level tracing +4 - second level debug - Add detailed debugging +5 - log comm's - log serial I/O +*/ + + +void ReceiveComPort(ISP_ENVIRONMENT *IspEnvironment, + const char *Ans, unsigned long MaxSize, + unsigned long *RealSize, unsigned long WantedNr0x0A, + unsigned timeOutMilliseconds); +void PrepareKeyboardTtySettings(void); +void ResetKeyboardTtySettings(void); +void ResetTarget(ISP_ENVIRONMENT *IspEnvironment, TARGET_MODE mode); + +void DumpString(int level, const void *s, size_t size, const char *prefix_string); +void SendComPort(ISP_ENVIRONMENT *IspEnvironment, const char *s); +void SendComPortBlock(ISP_ENVIRONMENT *IspEnvironment, const void *s, size_t n); +int ReceiveComPortBlockComplete(ISP_ENVIRONMENT *IspEnvironment, void *block, size_t size, unsigned timeout); +void ClearSerialPortBuffers(ISP_ENVIRONMENT *IspEnvironment); +void ControlXonXoffSerialPort(ISP_ENVIRONMENT *IspEnvironment, unsigned char XonXoff); + diff --git a/host/app/lpc21lisp/lpcprog.c b/host/app/lpc21lisp/lpcprog.c new file mode 100644 index 0000000..2077bd6 --- /dev/null +++ b/host/app/lpc21lisp/lpcprog.c @@ -0,0 +1,1649 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC1000 / LPC2000 family + and Analog Devices ADUC70xx + +Filename: lpcprog.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-2011, 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 . +*/ + +// This file is for the Actual Programming of the LPC Chips + +#if defined(_WIN32) +#include "malloc.h" +#if !defined __BORLANDC__ +#include "StdAfx.h" +#endif +#endif // defined(_WIN32) +#include "lpc21isp.h" + +#ifdef LPC_SUPPORT +#include "lpcprog.h" + +static const unsigned int SectorTable_210x[] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192 +}; + +static const unsigned int SectorTable_2103[] = +{ + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096 +}; + +static const unsigned int SectorTable_2109[] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 +}; + +static const unsigned int SectorTable_211x[] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, +}; + +static const unsigned int SectorTable_212x[] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 65536, 65536, 8192, 8192, 8192, 8192, 8192, 8192, 8192 +}; + +// Used for devices with 500K (LPC2138 and LPC2148) and +// for devices with 504K (1 extra 4k block at the end) +static const unsigned int SectorTable_213x[] = +{ + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, + 32768, 32768, 32768, 32768, 32768, 32768, 4096, 4096, + 4096, 4096, 4096, 4096 +}; + +// Used for LPC17xx devices +static const unsigned int SectorTable_17xx[] = +{ + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, + 32768, 32768, 32768, 32768, 32768, 32768 +}; + +// Used for LPC18xx devices +static const unsigned int SectorTable_18xx[] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 65536, 65536, 65536, 65536, 65536, 65536, 65536 +}; + +// Used for LPC43xx devices +static const unsigned int SectorTable_43xx[] = +{ + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 65536, 65536, 65536, 65536, 65536, 65536, 65536 +}; + +// Used for LPC8xx devices +static const unsigned int SectorTable_8xx[] = +{ + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 +}; + +static int unsigned SectorTable_RAM[] = { 65000 }; + +static LPC_DEVICE_TYPE LPCtypes[] = +{ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, CHIP_VARIANT_NONE }, /* unknown */ + + // id, id2, use id2, name of product, flash size, ram size, total number of sector, max copy size, sector table, chip variant + + { 0x00008100, 0x00000000, 0, "810M021FN8", 4, 1, 4, 256, SectorTable_8xx, CHIP_VARIANT_LPC8XX }, + { 0x00008110, 0x00000000, 0, "811M001FDH16", 8, 2, 8, 1024, SectorTable_8xx, CHIP_VARIANT_LPC8XX }, + { 0x00008120, 0x00000000, 0, "812M101FDH16", 16, 4, 16, 1024, SectorTable_8xx, CHIP_VARIANT_LPC8XX }, + { 0x00008121, 0x00000000, 0, "812M101FD20", 16, 4, 16, 1024, SectorTable_8xx, CHIP_VARIANT_LPC8XX }, + { 0x00008122, 0x00000000, 0, "812M101FDH20", 16, 4, 16, 1024, SectorTable_8xx, CHIP_VARIANT_LPC8XX }, + + { 0x2500102B, 0x00000000, 0, "1102", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + + { 0x0A07102B, 0x00000000, 0, "1110.../002", 4, 1, 1, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1A07102B, 0x00000000, 0, "1110.../002", 4, 1, 1, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0A16D02B, 0x00000000, 0, "1111.../002", 8, 2, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1A16D02B, 0x00000000, 0, "1111.../002", 8, 2, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x041E502B, 0x00000000, 0, "1111.../101", 8, 2, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2516D02B, 0x00000000, 0, "1111.../102", 8, 2, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0416502B, 0x00000000, 0, "1111.../201", 8, 4, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2516902B, 0x00000000, 0, "1111.../202", 8, 4, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x042D502B, 0x00000000, 0, "1112.../101", 16, 2, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2524D02B, 0x00000000, 0, "1112.../102", 16, 2, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0A24902B, 0x00000000, 0, "1112.../102", 16, 4, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1A24902B, 0x00000000, 0, "1112.../102", 16, 4, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0425502B, 0x00000000, 0, "1112.../201", 16, 4, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2524902B, 0x00000000, 0, "1112.../202", 16, 4, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0434502B, 0x00000000, 0, "1113.../201", 24, 4, 6, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2532902B, 0x00000000, 0, "1113.../202", 24, 4, 6, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0434102B, 0x00000000, 0, "1113.../301", 24, 8, 6, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2532102B, 0x00000000, 0, "1113.../302", 24, 8, 6, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0A40902B, 0x00000000, 0, "1114.../102", 32, 4, 8, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1A40902B, 0x00000000, 0, "1114.../102", 32, 4, 8, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0444502B, 0x00000000, 0, "1114.../201", 32, 4, 8, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2540902B, 0x00000000, 0, "1114.../202", 32, 4, 8, 1024, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0444102B, 0x00000000, 0, "1114.../301", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x2540102B, 0x00000000, 0, "1114.../302", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + + { 0x00040042, 0x00000000, 0, "1114.../203", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x00040040, 0x00000000, 0, "1114.../303", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x00040060, 0x00000000, 0, "1114.../323", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x00040070, 0x00000000, 0, "1114.../333", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x00050080, 0x00000000, 0, "1115.../303", 64, 8, 16, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + + { 0x1421102B, 0x00000000, 0, "11C12.../301", 16, 8, 4, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1440102B, 0x00000000, 0, "11C14.../301", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1431102B, 0x00000000, 0, "11C22.../301", 16, 8, 4, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x1430102B, 0x00000000, 0, "11C24.../301", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + + { 0x0364002B, 0x00000000, 0, "1224.../101", 32, 8, 4, 2048, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0364202B, 0x00000000, 0, "1224.../121", 48, 12, 32, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0365002B, 0x00000000, 0, "1225.../301", 64, 16, 32, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0365202B, 0x00000000, 0, "1225.../321", 80, 20, 32, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0366002B, 0x00000000, 0, "1226", 96, 24, 32, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + { 0x0367002B, 0x00000000, 0, "1227", 128, 32, 32, 4096, SectorTable_17xx, CHIP_VARIANT_LPC11XX }, + + { 0x2C42502B, 0x00000000, 0, "1311", 8, 4, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC13XX }, + { 0x1816902B, 0x00000000, 0, "1311/01", 8, 4, 2, 1024, SectorTable_17xx, CHIP_VARIANT_LPC13XX }, + { 0x2C40102B, 0x00000000, 0, "1313", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC13XX }, + { 0x1830102B, 0x00000000, 0, "1313/01", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC13XX }, + { 0x3D01402B, 0x00000000, 0, "1342", 16, 4, 4, 1024, SectorTable_17xx, CHIP_VARIANT_LPC13XX }, + { 0x3D00002B, 0x00000000, 0, "1343", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC13XX }, + + { 0x25001118, 0x00000000, 0, "1751", 32, 8, 8, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x25001121, 0x00000000, 0, "1752", 64, 16, 16, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x25011722, 0x00000000, 0, "1754", 128, 32, 18, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x25011723, 0x00000000, 0, "1756", 256, 32, 22, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x25013F37, 0x00000000, 0, "1758", 512, 64, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x25113737, 0x00000000, 0, "1759", 512, 64, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x26011922, 0x00000000, 0, "1764", 128, 32, 18, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x26013733, 0x00000000, 0, "1765", 256, 64, 22, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x26013F33, 0x00000000, 0, "1766", 256, 64, 22, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x26012837, 0x00000000, 0, "1767", 512, 64, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x26013F37, 0x00000000, 0, "1768", 512, 64, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x26113F37, 0x00000000, 0, "1769", 512, 64, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + + { 0x27011132, 0x00000000, 0, "1774", 128, 40, 18, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x27191F43, 0x00000000, 0, "1776", 256, 80, 22, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x27193747, 0x00000000, 0, "1777", 512, 96, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x27193F47, 0x00000000, 0, "1778", 512, 96, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x281D1743, 0x00000000, 0, "1785", 256, 80, 22, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x281D1F43, 0x00000000, 0, "1786", 256, 80, 22, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x281D3747, 0x00000000, 0, "1787", 512, 96, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + { 0x281D3F47, 0x00000000, 0, "1788", 512, 96, 30, 4096, SectorTable_17xx, CHIP_VARIANT_LPC17XX }, + + // LPC18xx + { 0xF00B1B3F, 0x00000000, 1, "1810", 0, 32, 0, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, // Flashless + { 0xF00A9B3C, 0x00000000, 1, "1820", 0, 32, 0, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, // Flashless + { 0xF0009A30, 0x00000000, 1, "1830", 0, 32, 0, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, // Flashless + { 0xF001DA30, 0x00000044, 1, "1833", 512, 32, 11, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, + { 0xF001DA30, 0x00000000, 1, "1837", 1024, 32, 15, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, + { 0xF0009830, 0x00000000, 1, "1850", 0, 32, 0, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, // Flashless + { 0xF001D830, 0x00000044, 1, "1853", 512, 32, 11, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, // TODO - distinguish these parts (word 1) + { 0xF001D830, 0x00000000, 1, "1857", 1024, 32, 15, 8192, SectorTable_18xx, CHIP_VARIANT_LPC18XX }, // TODO - distinguish these parts (word 1) + + { 0x0004FF11, 0x00000000, 0, "2103", 32, 8, 8, 4096, SectorTable_2103, CHIP_VARIANT_LPC2XXX }, + { 0xFFF0FF12, 0x00000000, 0, "2104", 128, 16, 15, 8192, SectorTable_210x, CHIP_VARIANT_LPC2XXX }, + { 0xFFF0FF22, 0x00000000, 0, "2105", 128, 32, 15, 8192, SectorTable_210x, CHIP_VARIANT_LPC2XXX }, + { 0xFFF0FF32, 0x00000000, 0, "2106", 128, 64, 15, 8192, SectorTable_210x, CHIP_VARIANT_LPC2XXX }, + { 0x0201FF01, 0x00000000, 0, "2109", 64, 8, 8, 4096, SectorTable_2109, CHIP_VARIANT_LPC2XXX }, + { 0x0101FF12, 0x00000000, 0, "2114", 128, 16, 15, 8192, SectorTable_211x, CHIP_VARIANT_LPC2XXX }, + { 0x0201FF12, 0x00000000, 0, "2119", 128, 16, 15, 8192, SectorTable_211x, CHIP_VARIANT_LPC2XXX }, + { 0x0101FF13, 0x00000000, 0, "2124", 256, 16, 17, 8192, SectorTable_212x, CHIP_VARIANT_LPC2XXX }, + { 0x0201FF13, 0x00000000, 0, "2129", 256, 16, 17, 8192, SectorTable_212x, CHIP_VARIANT_LPC2XXX }, + { 0x0002FF01, 0x00000000, 0, "2131", 32, 8, 8, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0002FF11, 0x00000000, 0, "2132", 64, 16, 9, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0002FF12, 0x00000000, 0, "2134", 128, 16, 11, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0002FF23, 0x00000000, 0, "2136", 256, 32, 15, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0002FF25, 0x00000000, 0, "2138", 512, 32, 27, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0402FF01, 0x00000000, 0, "2141", 32, 8, 8, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0402FF11, 0x00000000, 0, "2142", 64, 16, 9, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0402FF12, 0x00000000, 0, "2144", 128, 16, 11, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0402FF23, 0x00000000, 0, "2146", 256, 40, 15, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0402FF25, 0x00000000, 0, "2148", 512, 40, 27, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0301FF13, 0x00000000, 0, "2194", 256, 16, 17, 8192, SectorTable_212x, CHIP_VARIANT_LPC2XXX }, + { 0x0301FF12, 0x00000000, 0, "2210", 0, 16, 0, 8192, SectorTable_211x, CHIP_VARIANT_LPC2XXX }, /* table is a "don't care" */ + { 0x0401FF12, 0x00000000, 0, "2212", 128, 16, 15, 8192, SectorTable_211x, CHIP_VARIANT_LPC2XXX }, + { 0x0601FF13, 0x00000000, 0, "2214", 256, 16, 17, 8192, SectorTable_212x, CHIP_VARIANT_LPC2XXX }, + /* "2290"; same id as the LPC2210 */ + { 0x0401FF13, 0x00000000, 0, "2292", 256, 16, 17, 8192, SectorTable_212x, CHIP_VARIANT_LPC2XXX }, + { 0x0501FF13, 0x00000000, 0, "2294", 256, 16, 17, 8192, SectorTable_212x, CHIP_VARIANT_LPC2XXX }, + { 0x1600F701, 0x00000000, 0, "2361", 128, 34, 11, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 4.1 -- 5 Sep 2012 */ + { 0x1600FF22, 0x00000000, 0, "2362", 128, 34, 11, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 4.1 -- 5 Sep 2012 */ + { 0x0603FB02, 0x00000000, 0, "2364", 128, 34, 11, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 01 -- 6 July 2007 */ + { 0x1600F902, 0x00000000, 0, "2364", 128, 34, 11, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1600E823, 0x00000000, 0, "2365", 256, 58, 15, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0603FB23, 0x00000000, 0, "2366", 256, 58, 15, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 01 -- 6 July 2007 */ + { 0x1600F923, 0x00000000, 0, "2366", 256, 58, 15, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1600E825, 0x00000000, 0, "2367", 512, 58, 15, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0603FB25, 0x00000000, 0, "2368", 512, 58, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 01 -- 6 July 2007 */ + { 0x1600F925, 0x00000000, 0, "2368", 512, 58, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1700E825, 0x00000000, 0, "2377", 512, 58, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x0703FF25, 0x00000000, 0, "2378", 512, 58, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 01 -- 6 July 2007 */ + { 0x1600FD25, 0x00000000, 0, "2378", 512, 58, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 01 -- 29 October 2007 */ + { 0x1700FD25, 0x00000000, 0, "2378", 512, 58, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1700FF35, 0x00000000, 0, "2387", 512, 98, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, /* From UM10211 Rev. 03 -- 25 August 2008 */ + { 0x1800F935, 0x00000000, 0, "2387", 512, 98, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1800FF35, 0x00000000, 0, "2388", 512, 98, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1500FF35, 0x00000000, 0, "2458", 512, 98, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1600FF30, 0x00000000, 0, "2460", 0, 98, 0, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1600FF35, 0x00000000, 0, "2468", 512, 98, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1701FF30, 0x00000000, 0, "2470", 0, 98, 0, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + { 0x1701FF35, 0x00000000, 0, "2478", 512, 98, 28, 4096, SectorTable_213x, CHIP_VARIANT_LPC2XXX }, + + { 0xA00A8B3F, 0x00000000, 1, "4310", 0, 168, 0, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* From UM10503 Rev. 1.4 -- 3 Sep 2012 */ + { 0xA0008B3C, 0x00000000, 1, "4320", 0, 200, 0, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* From UM10503 Rev. 1.4 -- 3 Sep 2012 */ + { 0xA0000A30, 0x00000000, 1, "4330", 0, 264, 0, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* From UM10503 Rev. 1.4 -- 3 Sep 2012 */ + { 0xA001CA30, 0x00000044, 1, "4333", 512, 512, 11, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* info not yet available */ + { 0xA001CA30, 0x00000000, 1, "4337", 1024, 512, 15, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* info not yet available */ + { 0xA0000830, 0x00000000, 1, "4350", 0, 264, 0, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* From UM10503 Rev. 1.4 -- 3 Sep 2012 */ + { 0xA001C830, 0x00000044, 1, "4353", 512, 512, 11, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* From UM10503 Rev. 1.4 -- 3 Sep 2012 */ + { 0xA001C830, 0x00000000, 1, "4357", 1024, 512, 15, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX }, /* From UM10503 Rev. 1.4 -- 3 Sep 2012 */ + { 0xA001C830, 0x0EF60000, 1, "4357", 1024, 512, 15, 4096, SectorTable_43xx, CHIP_VARIANT_LPC43XX } /* info not yet available */ +}; + +/***************************** NXP Download *********************************/ +/** Download the file from the internal memory image to the NXP microcontroller. +* This function is visible from outside if COMPILE_FOR_LPC21 +*/ + +/***************************** FormatCommand ********************************/ +/** 2013-06-28 Torsten Lang, Uwe Schneider GmbH +According to the various NXP user manuals the ISP bootloader commands should +be terminated with , the echo and/or answer should have the same line +termination. So far for the theory... +In fact, the bootloader also accepts as line termination, but it may or +may not echo the linebreak character. Some bootloaders convert the character +into , some leave the and append another one ( in the +answer). Furthermore, during uuencoded data transfer the bootloader may or +may not append an additional character at the end of the answer +(leading to a sequence). +A reliable way to handle these deviations from the UM is to strictly send the +commands according to the description in the UM and to re-format commands +and answers after a transfer. +FormatCommand works in a way that it drops any leading linefeeds which only +can be surplus characters from a previous answer. It then converts any +sequence of and into a single character. +FormatCommand can work in place, meaning that In==Out is allowed! +\param [in] In Pointer to input buffer. +\param [out] Out Pointer to output buffer. +*/ + +static void FormatCommand(const char *In, char *Out) +{ + size_t i, j; + for (i = 0, j = 0; In[j] != '\0'; i++, j++) + { + if ((In[j] == '\r') || (In[j] == '\n')) + { + if (i > 0) // Ignore leading line breaks (they must be leftovers from a previous answer) + { + Out[i] = '\n'; + } + else + { + i--; + } + while ((In[j+1] == '\r') || (In[j+1] == '\n')) + { + j++; + } + } + else + { + Out[i] = In[j]; + } + } + Out[i] = '\0'; +} + +static int SendAndVerify(ISP_ENVIRONMENT *IspEnvironment, const char *Command, + char *AnswerBuffer, int AnswerLength) +{ + unsigned long realsize; + int cmdlen; + char *FormattedCommand; + + SendComPort(IspEnvironment, Command); + ReceiveComPort(IspEnvironment, AnswerBuffer, AnswerLength - 1, &realsize, 2, 5000); + + cmdlen = strlen(Command); + FormattedCommand = (char *)alloca(cmdlen+1); + FormatCommand(Command, FormattedCommand); + FormatCommand(AnswerBuffer, AnswerBuffer); + cmdlen = strlen(FormattedCommand); + return (strncmp(AnswerBuffer, FormattedCommand, cmdlen) == 0 + && strcmp(AnswerBuffer + cmdlen, "0\n") == 0); +} + + + +/***************************** NxpOutputErrorMessage ***********************/ +/** Given an error number find and print the appropriate error message. +\param [in] ErrorNumber The number of the error. +*/ +#if defined COMPILE_FOR_LPC21 + +#define NxpOutputErrorMessage(in) // Cleanly remove this feature from the embedded version !! + +#else + +static void NxpOutputErrorMessage(unsigned char ErrorNumber) +{ + switch (ErrorNumber) + { + case 0: + DebugPrintf(1, "CMD_SUCCESS\n"); + break; + + case 1: + DebugPrintf(1, "INVALID_COMMAND\n"); + break; + + case 2: + DebugPrintf(1, "SRC_ADDR_ERROR: Source address is not on word boundary.\n"); + break; + case 3: + DebugPrintf(1, "DST_ADDR_ERROR: Destination address is not on a correct boundary.\n"); + break; + + case 4: + DebugPrintf(1, "SRC_ADDR_NOT_MAPPED: Source address is not mapped in the memory map.\n" + " Count value is taken into consideration where applicable.\n"); + break; + + case 5: + DebugPrintf(1, "DST_ADDR_NOT_MAPPED: Destination address is not mapped in the memory map.\n" + " Count value is taken into consideration where applicable.\n"); + break; + + case 6: + DebugPrintf(1, "COUNT_ERROR: Byte count is not multiple of 4 or is not a permitted value.\n"); + break; + + case 7: + DebugPrintf(1, "INVALID_SECTOR: Sector number is invalid or end sector number is\n" + " greater than start sector number.\n"); + break; + + case 8: + DebugPrintf(1, "SECTOR_NOT_BLANK\n"); + break; + + case 9: + DebugPrintf(1, "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION:\n" + "Command to prepare sector for write operation was not executed.\n"); + break; + + case 10: + DebugPrintf(1, "COMPARE_ERROR: Source and destination data not equal.\n"); + break; + + case 11: + DebugPrintf(1, "BUSY: Flash programming hardware interface is busy.\n"); + break; + + case 12: + DebugPrintf(1, "PARAM_ERROR: Insufficient number of parameters or invalid parameter.\n"); + break; + + case 13: + DebugPrintf(1, "ADDR_ERROR: Address is not on word boundary.\n"); + break; + + case 14: + DebugPrintf(1, "ADDR_NOT_MAPPED: Address is not mapped in the memory map.\n" + " Count value is taken in to consideration where applicable.\n"); + break; + + case 15: + DebugPrintf(1, "CMD_LOCKED\n"); + break; + + case 16: + DebugPrintf(1, "INVALID_CODE: Unlock code is invalid.\n"); + break; + + case 17: + DebugPrintf(1, "INVALID_BAUD_RATE: Invalid baud rate setting.\n"); + break; + + case 18: + DebugPrintf(1, "INVALID_STOP_BIT: Invalid stop bit setting.\n"); + break; + + case 19: + DebugPrintf( 1, "CODE READ PROTECTION ENABLED\n"); + break; + + case 255: + break; + + default: + DebugPrintf(1, "unknown error %u\n", ErrorNumber); + break; + } + + //DebugPrintf(1, "error (%u), see NxpOutputErrorMessage() in lpc21isp.c for help \n\r", ErrorNumber); +} +#endif // !defined COMPILE_FOR_LPC21 + +/***************************** GetAndReportErrorNumber ***************************/ +/** Find error number in string. This will normally be the string +returned from the microcontroller. +\param [in] Answer the buffer to search for the error number. +\return the error number found, if no linefeed found before the end of the +string an error value of 255 is returned. If a non-numeric value is found +then it is printed to stdout and an error value of 255 is returned. +*/ +static unsigned char GetAndReportErrorNumber(const char *Answer) +{ + unsigned char Result = 0xFF; // Error !!! + unsigned int i = 0; + + while (1) + { + if (Answer[i] == 0x00) + { + break; + } + + if (Answer[i] == 0x0a) + { + i++; + + if (Answer[i] < '0' || Answer[i] > '9') + { + DebugPrintf(1, "ErrorString: %s", &Answer[i]); + break; + } + + Result = (unsigned char) (atoi(&Answer[i])); + break; + } + + i++; + } + + NxpOutputErrorMessage(Result); + + return Result; +} + + +int NxpDownload(ISP_ENVIRONMENT *IspEnvironment) +{ + unsigned long realsize; + char Answer[128]; + char ExpectedAnswer[128]; + char temp[128]; + /*const*/ char *strippedAnswer, *endPtr; + int strippedsize; + int nQuestionMarks; + int found; + unsigned long Sector; + unsigned long SectorLength; + unsigned long SectorStart, SectorOffset, SectorChunk; + char tmpString[128]; + char uuencode_table[64]; + int Line; + unsigned long tmpStringPos; + unsigned long BlockOffset; + unsigned long Block; + unsigned long Pos; + unsigned long Id[2]; + unsigned long CopyLength; + int c,k=0,i; + unsigned long ivt_CRC; // CRC over interrupt vector table + unsigned long block_CRC; + time_t tStartUpload=0, tDoneUpload=0; + char tmp_string[64]; + char * cmdstr; + +#if !defined COMPILE_FOR_LPC21 + +#if defined __BORLANDC__ +#define local_static static +#else +#define local_static +#endif + +// char * cmdstr; + int repeat = 0; + // Puffer for data to resend after "RESEND\r\n" Target responce + local_static char sendbuf0[128]; + local_static char sendbuf1[128]; + local_static char sendbuf2[128]; + local_static char sendbuf3[128]; + local_static char sendbuf4[128]; + local_static char sendbuf5[128]; + local_static char sendbuf6[128]; + local_static char sendbuf7[128]; + local_static char sendbuf8[128]; + local_static char sendbuf9[128]; + local_static char sendbuf10[128]; + local_static char sendbuf11[128]; + local_static char sendbuf12[128]; + local_static char sendbuf13[128]; + local_static char sendbuf14[128]; + local_static char sendbuf15[128]; + local_static char sendbuf16[128]; + local_static char sendbuf17[128]; + local_static char sendbuf18[128]; + local_static char sendbuf19[128]; + + char * sendbuf[20] = { sendbuf0, sendbuf1, sendbuf2, sendbuf3, sendbuf4, + sendbuf5, sendbuf6, sendbuf7, sendbuf8, sendbuf9, + sendbuf10, sendbuf11, sendbuf12, sendbuf13, sendbuf14, + sendbuf15, sendbuf16, sendbuf17, sendbuf18, sendbuf19}; +#endif + + DebugPrintf(2, "Synchronizing (ESC to abort)"); + + PrepareKeyboardTtySettings(); + +#if defined INTEGRATED_IN_WIN_APP + if (IspEnvironment->NoSync) + { + found = 1; + } + else +#endif + { + for (nQuestionMarks = found = 0; !found && nQuestionMarks < IspEnvironment->nQuestionMarks; nQuestionMarks++) + { +#if defined INTEGRATED_IN_WIN_APP + // allow calling application to abort when syncing takes too long + + if (!AppSyncing(nQuestionMarks)) + { + return (USER_ABORT_SYNC); + } +#else +#ifndef Exclude_kbhit + if (kbhit()) + { + if (getch() == 0x1b) + { + ResetKeyboardTtySettings(); + DebugPrintf(2, "\nUser aborted during synchronisation\n"); + return (USER_ABORT_SYNC); + } + } +#endif +#endif + + DebugPrintf(2, "."); + SendComPort(IspEnvironment, "?"); + + memset(Answer,0,sizeof(Answer)); + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 1,100); + + strippedAnswer = Answer; + strippedsize = realsize; + while ((strippedsize > 0) && ((*strippedAnswer == '?') || (*strippedAnswer == 0))) + { + strippedAnswer++; + strippedsize--; + } + + sprintf(tmp_string, "StrippedAnswer(Length=%d): ", strippedsize); + DumpString(3, strippedAnswer, strippedsize, tmp_string); + + tStartUpload = time(NULL); + + FormatCommand(strippedAnswer, strippedAnswer); + if (strcmp(strippedAnswer, "Synchronized\n") == 0) + { + found = 1; + } +#if !defined COMPILE_FOR_LPC21 + else + { + ResetTarget(IspEnvironment, PROGRAM_MODE); + } +#endif + } + } + + ResetKeyboardTtySettings(); + + if (!found) + { + DebugPrintf(1, " no answer on '?'\n"); + return (NO_ANSWER_QM); + } + +#if defined INTEGRATED_IN_WIN_APP + AppSyncing(-1); // flag syncing done +#endif + + DebugPrintf(2, " OK\n"); + + SendComPort(IspEnvironment, "Synchronized\r\n"); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer) - 1, &realsize, 2, 1000); + + FormatCommand(Answer, Answer); + if (strcmp(Answer, "Synchronized\nOK\n") != 0) + { + DebugPrintf(1, "No answer on 'Synchronized'\n"); + return (NO_ANSWER_SYNC); + } + + DebugPrintf(3, "Synchronized 1\n"); + + DebugPrintf(3, "Setting oscillator\n"); + + sprintf(temp, "%s\r\n", IspEnvironment->StringOscillator); + + SendComPort(IspEnvironment, temp); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 2, 1000); + + sprintf(temp, "%s\nOK\n", IspEnvironment->StringOscillator); + + FormatCommand(Answer, Answer); + if (strcmp(Answer, temp) != 0) + { + DebugPrintf(1, "No answer on Oscillator-Command\n"); + return (NO_ANSWER_OSC); + } + + DebugPrintf(3, "Unlock\n"); + + cmdstr = "U 23130\r\n"; + + if (!SendAndVerify(IspEnvironment, cmdstr, Answer, sizeof Answer)) + { + DebugPrintf(1, "Unlock-Command:\n"); + return (UNLOCK_ERROR + GetAndReportErrorNumber(Answer)); + } + + DebugPrintf(2, "Read bootcode version: "); + + cmdstr = "K\r\n"; + + SendComPort(IspEnvironment, cmdstr); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 4,5000); + + FormatCommand(cmdstr, temp); + FormatCommand(Answer, Answer); + if (strncmp(Answer, temp, strlen(temp)) != 0) + { + DebugPrintf(1, "no answer on Read Boot Code Version\n"); + return (NO_ANSWER_RBV); + } + + if (strncmp(Answer + strlen(temp), "0\n", 2) == 0) + { + strippedAnswer = Answer + strlen(temp) + 2; + /* + int maj, min, build; + if (sscanf(strippedAnswer, "%d %d %d", &build, &min, &maj) == 2) { + maj = min; + min = build; + build = 0; + } // if + DebugPrintf(2, "%d.%d.%d\n", maj, min, build); + */ + DebugPrintf(2, strippedAnswer); + } + else + { + DebugPrintf(2, "unknown\n"); + } + + DebugPrintf(2, "Read part ID: "); + + cmdstr = "J\r\n"; + + SendComPort(IspEnvironment, cmdstr); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 3, 5000); + + FormatCommand(cmdstr, temp); + FormatCommand(Answer, Answer); + if (strncmp(Answer, temp, strlen(temp)) != 0) + { + DebugPrintf(1, "no answer on Read Part Id\n"); + return (NO_ANSWER_RPID); + } + + strippedAnswer = (strncmp(Answer, "J\n0\n", 4) == 0) ? Answer + 4 : Answer; + + Id[0] = strtoul(strippedAnswer, &endPtr, 10); + Id[1] = 0UL; + *endPtr = '\0'; /* delete \r\n */ + for (i = sizeof LPCtypes / sizeof LPCtypes[0] - 1; i > 0 && LPCtypes[i].id != Id[0]; i--) + /* nothing */; + IspEnvironment->DetectedDevice = i; + if (LPCtypes[IspEnvironment->DetectedDevice].EvalId2 != 0) + { + /* Read out the second configuration word and run the search again */ + *endPtr = '\n'; + endPtr++; + if ((endPtr[0] == '\0') || (endPtr[strlen(endPtr)-1] != '\n')) + { + /* No or incomplete word 2 */ + ReceiveComPort(IspEnvironment, endPtr, sizeof(Answer)-(endPtr-Answer)-1, &realsize, 1, 100); + } + + FormatCommand(endPtr, endPtr); + if ((*endPtr == '\0') || (*endPtr == '\n')) + { + DebugPrintf(1, "incomplete answer on Read Part Id (second configuration word missing)\n"); + return (NO_ANSWER_RPID); + } + + Id[1] = strtoul(endPtr, &endPtr, 10); + *endPtr = '\0'; /* delete \r\n */ + + /* now search the table again */ + for (i = sizeof LPCtypes / sizeof LPCtypes[0] - 1; i > 0 && (LPCtypes[i].id != Id[0] || LPCtypes[i].id2 != Id[1]); i--) + /* nothing */; + IspEnvironment->DetectedDevice = i; + } + if (IspEnvironment->DetectedDevice == 0) { + DebugPrintf(2, "unknown"); + } + else { + DebugPrintf(2, "LPC%s, %d kiB FLASH / %d kiB SRAM", + LPCtypes[IspEnvironment->DetectedDevice].Product, + LPCtypes[IspEnvironment->DetectedDevice].FlashSize, + LPCtypes[IspEnvironment->DetectedDevice].RAMSize); + } + if (LPCtypes[IspEnvironment->DetectedDevice].EvalId2 != 0) + { + DebugPrintf(2, " (0x%08lX / 0x%08lX)\n", Id[0], Id[1]); + } + else + { + DebugPrintf(2, " (0x%08lX)\n", Id[0]); + } + + if (!IspEnvironment->DetectOnly) + { + // Build up uuencode table + uuencode_table[0] = 0x60; // 0x20 is translated to 0x60 ! + + for (i = 1; i < 64; i++) + { + uuencode_table[i] = (char)(0x20 + i); + } + + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX) + { + // Patch 0x14, otherwise it is not running and jumps to boot mode + + ivt_CRC = 0; + + // Clear the vector at 0x14 so it doesn't affect the checksum: + for (i = 0; i < 4; i++) + { + IspEnvironment->BinaryContent[i + 0x14] = 0; + } + + // Calculate a native checksum of the little endian vector table: + for (i = 0; i < (4 * 8);) { + ivt_CRC += IspEnvironment->BinaryContent[i++]; + ivt_CRC += IspEnvironment->BinaryContent[i++] << 8; + ivt_CRC += IspEnvironment->BinaryContent[i++] << 16; + ivt_CRC += IspEnvironment->BinaryContent[i++] << 24; + } + + /* Negate the result and place in the vector at 0x14 as little endian + * again. The resulting vector table should checksum to 0. */ + ivt_CRC = (unsigned long) (0 - ivt_CRC); + for (i = 0; i < 4; i++) + { + IspEnvironment->BinaryContent[i + 0x14] = (unsigned char)(ivt_CRC >> (8 * i)); + } + + DebugPrintf(3, "Position 0x14 patched: ivt_CRC = 0x%08lX\n", ivt_CRC); + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + // Patch 0x1C, otherwise it is not running and jumps to boot mode + + ivt_CRC = 0; + + // Clear the vector at 0x1C so it doesn't affect the checksum: + for (i = 0; i < 4; i++) + { + IspEnvironment->BinaryContent[i + 0x1C] = 0; + } + + // Calculate a native checksum of the little endian vector table: + for (i = 0; i < (4 * 8);) { + ivt_CRC += IspEnvironment->BinaryContent[i++]; + ivt_CRC += IspEnvironment->BinaryContent[i++] << 8; + ivt_CRC += IspEnvironment->BinaryContent[i++] << 16; + ivt_CRC += IspEnvironment->BinaryContent[i++] << 24; + } + + /* Negate the result and place in the vector at 0x1C as little endian + * again. The resulting vector table should checksum to 0. */ + ivt_CRC = (unsigned long) (0 - ivt_CRC); + for (i = 0; i < 4; i++) + { + IspEnvironment->BinaryContent[i + 0x1C] = (unsigned char)(ivt_CRC >> (8 * i)); + } + + DebugPrintf(3, "Position 0x1C patched: ivt_CRC = 0x%08lX\n", ivt_CRC); + } + else + { + DebugPrintf(1, "Internal error: wrong chip variant %d (detected device %d)\n", LPCtypes[IspEnvironment->DetectedDevice].ChipVariant, IspEnvironment->DetectedDevice); + exit(1); + } + } + +#if 0 + DebugPrintf(2, "Read Unique ID:\n"); + + cmdstr = "N\r\n"; + + SendComPort(IspEnvironment, cmdstr); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 5,5000); + + FormatCommand(cmdstr, temp); + FormatCommand(Answer, Answer); + if (strncmp(Answer, temp, strlen(temp)) != 0) + { + DebugPrintf(1, "no answer on Read Unique ID\n"); + return (NO_ANSWER_RBV); + } + + if (strncmp(Answer + strlen(cmdstr), "0\n", 2) == 0) + { + strippedAnswer = Answer + strlen(temp) + 2; + DebugPrintf(2, strippedAnswer); + } + else + { + DebugPrintf(2, "unknown\n"); + } +#endif // 0 + + /* In case of a download to RAM, use full RAM for downloading + * set the flash parameters to full RAM also. + * This makes sure that all code is downloaded as one big sector + */ + + if ( (IspEnvironment->BinaryOffset >= ReturnValueLpcRamStart(IspEnvironment)) + &&(IspEnvironment->BinaryOffset + IspEnvironment->BinaryLength <= ReturnValueLpcRamStart(IspEnvironment)+(LPCtypes[IspEnvironment->DetectedDevice].RAMSize*1024))) + { + LPCtypes[IspEnvironment->DetectedDevice].FlashSectors = 1; + LPCtypes[IspEnvironment->DetectedDevice].MaxCopySize = LPCtypes[IspEnvironment->DetectedDevice].RAMSize*1024 - (ReturnValueLpcRamBase(IspEnvironment) - ReturnValueLpcRamStart(IspEnvironment)); + LPCtypes[IspEnvironment->DetectedDevice].SectorTable = SectorTable_RAM; + SectorTable_RAM[0] = LPCtypes[IspEnvironment->DetectedDevice].MaxCopySize; + } + if (IspEnvironment->DetectOnly) + return (0); + + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + // XON/XOFF must be switched off for LPC8XX + // otherwise problem during binary transmission of data to LPC8XX + DebugPrintf(3, "Switch off XON/XOFF !!!\n"); + ControlXonXoffSerialPort(IspEnvironment, 0); + } + + // Start with sector 1 and go upward... Sector 0 containing the interrupt vectors + // will be loaded last, since it contains a checksum and device will re-enter + // bootloader mode as long as this checksum is invalid. + DebugPrintf(2, "Will start programming at Sector 1 if possible, and conclude with Sector 0 to ensure that checksum is written last.\n"); + if (LPCtypes[IspEnvironment->DetectedDevice].SectorTable[0] >= IspEnvironment->BinaryLength) + { + Sector = 0; + SectorStart = 0; + } + else + { + SectorStart = LPCtypes[IspEnvironment->DetectedDevice].SectorTable[0]; + Sector = 1; + } + + if (IspEnvironment->WipeDevice == 1) + { + DebugPrintf(2, "Wiping Device. "); + + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "P %d %d 0\r\n", 0, LPCtypes[IspEnvironment->DetectedDevice].FlashSectors-1); + } + else + { + sprintf(tmpString, "P %d %d\r\n", 0, LPCtypes[IspEnvironment->DetectedDevice].FlashSectors-1); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Prepare-Command\n"); + return (WRONG_ANSWER_PREP + GetAndReportErrorNumber(Answer)); + } + + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "E %d %d 0\r\n", 0, LPCtypes[IspEnvironment->DetectedDevice].FlashSectors-1); + } + else + { + sprintf(tmpString, "E %d %d\r\n", 0, LPCtypes[IspEnvironment->DetectedDevice].FlashSectors-1); + } + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Erase-Command\n"); + return (WRONG_ANSWER_ERAS + GetAndReportErrorNumber(Answer)); + } + DebugPrintf(2, "OK \n"); + + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + DebugPrintf(2, "ATTENTION: Only bank A was wiped!!!\n"); + } + } + else{ + //no wiping requested: erasing sector 0 first + DebugPrintf(2, "Erasing sector 0 first, to invalidate checksum. "); + + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "P %d %d 0\r\n", 0, 0); + } + else + { + sprintf(tmpString, "P %d %d\r\n", 0, 0); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Prepare-Command\n"); + return (WRONG_ANSWER_PREP + GetAndReportErrorNumber(Answer)); + } + + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "E %d %d 0\r\n", 0, 0); + } + else + { + sprintf(tmpString, "E %d %d\r\n", 0, 0); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Erase-Command\n"); + return (WRONG_ANSWER_ERAS + GetAndReportErrorNumber(Answer)); + } + DebugPrintf(2, "OK \n"); + } + while (1) + { + if (Sector >= LPCtypes[IspEnvironment->DetectedDevice].FlashSectors) + { + DebugPrintf(1, "Program too large; running out of Flash sectors.\n"); + return (PROGRAM_TOO_LARGE); + } + + DebugPrintf(2, "Sector %ld: ", Sector); + fflush(stdout); + + if ( (IspEnvironment->BinaryOffset < ReturnValueLpcRamStart(IspEnvironment)) // Skip Erase when running from RAM + ||(IspEnvironment->BinaryOffset >= ReturnValueLpcRamStart(IspEnvironment)+(LPCtypes[IspEnvironment->DetectedDevice].RAMSize*1024))) + { + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "P %ld %ld 0\r\n", Sector, Sector); + } + else + { + sprintf(tmpString, "P %ld %ld\r\n", Sector, Sector); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Prepare-Command (1) (Sector %ld)\n", Sector); + return (WRONG_ANSWER_PREP + GetAndReportErrorNumber(Answer)); + } + + DebugPrintf(2, "."); + fflush(stdout); + if (IspEnvironment->WipeDevice == 0 && (Sector!=0)) //Sector 0 already erased + { + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "E %ld %ld 0\r\n", Sector, Sector); + } + else + { + sprintf(tmpString, "E %ld %ld\r\n", Sector, Sector); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Erase-Command (Sector %ld)\n", Sector); + return (WRONG_ANSWER_ERAS + GetAndReportErrorNumber(Answer)); + } + + DebugPrintf(2, "."); + fflush(stdout); + } + } + + SectorLength = LPCtypes[IspEnvironment->DetectedDevice].SectorTable[Sector]; + if (SectorLength > IspEnvironment->BinaryLength - SectorStart) + { + SectorLength = IspEnvironment->BinaryLength - SectorStart; + } + + for (SectorOffset = 0; SectorOffset < SectorLength; SectorOffset += SectorChunk) + { + // Check if we are to write only 0xFFs - it would be just a waste of time.. + if (SectorOffset == 0) { + for (SectorOffset = 0; SectorOffset < SectorLength; ++SectorOffset) + { + if (IspEnvironment->BinaryContent[SectorStart + SectorOffset] != 0xFF) + break; + } + if (SectorOffset == SectorLength) // all data contents were 0xFFs + { + DebugPrintf(2, "Whole sector contents is 0xFFs, skipping programming."); + fflush(stdout); + break; + } + SectorOffset = 0; // re-set otherwise + } + + if (SectorOffset > 0) + { + // Add a visible marker between segments in a sector + DebugPrintf(2, "|"); /* means: partial segment copied */ + fflush(stdout); + } + + // If the Flash ROM sector size is bigger than the number of bytes + // we can copy from RAM to Flash, we must "chop up" the sector and + // copy these individually. + // This is especially needed in the case where a Flash sector is + // bigger than the amount of SRAM. + SectorChunk = SectorLength - SectorOffset; + if (SectorChunk > (unsigned)LPCtypes[IspEnvironment->DetectedDevice].MaxCopySize) + { + SectorChunk = LPCtypes[IspEnvironment->DetectedDevice].MaxCopySize; + } + + // Write multiple of 45 * 4 Byte blocks to RAM, but copy maximum of on sector to Flash + // In worst case we transfer up to 180 byte too much to RAM + // but then we can always use full 45 byte blocks and length is multiple of 4 + CopyLength = SectorChunk; + + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX) + { + if ((CopyLength % (45 * 4)) != 0) + { + CopyLength += ((45 * 4) - (CopyLength % (45 * 4))); + } + } + + sprintf(tmpString, "W %ld %ld\r\n", ReturnValueLpcRamBase(IspEnvironment), CopyLength); + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Write-Command\n"); + return (WRONG_ANSWER_WRIT + GetAndReportErrorNumber(Answer)); + } + + DebugPrintf(2, "."); + fflush(stdout); + + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX) + { + block_CRC = 0; + Line = 0; + + // Transfer blocks of 45 * 4 bytes to RAM + for (Pos = SectorStart + SectorOffset; (Pos < SectorStart + SectorOffset + CopyLength) && (Pos < IspEnvironment->BinaryLength); Pos += (45 * 4)) + { + for (Block = 0; Block < 4; Block++) // Each block 45 bytes + { + DebugPrintf(2, "."); + fflush(stdout); + +#if defined INTEGRATED_IN_WIN_APP + // inform the calling application about having written another chuck of data + AppWritten(45); +#endif + + // Uuencode one 45 byte block + tmpStringPos = 0; + +#if !defined COMPILE_FOR_LPC21 + sendbuf[Line][tmpStringPos++] = (char)(' ' + 45); // Encode Length of block +#else + tmpString[tmpStringPos++] = (char)(' ' + 45); // Encode Length of block +#endif + + for (BlockOffset = 0; BlockOffset < 45; BlockOffset++) + { + if ( (IspEnvironment->BinaryOffset < ReturnValueLpcRamStart(IspEnvironment)) + ||(IspEnvironment->BinaryOffset >= ReturnValueLpcRamStart(IspEnvironment)+(LPCtypes[IspEnvironment->DetectedDevice].RAMSize*1024))) + { // Flash: use full memory + c = IspEnvironment->BinaryContent[Pos + Block * 45 + BlockOffset]; + } + else + { // RAM: Skip first 0x200 bytes, these are used by the download program in LPC21xx + c = IspEnvironment->BinaryContent[Pos + Block * 45 + BlockOffset + 0x200]; + } + + block_CRC += c; + + k = (k << 8) + (c & 255); + + if ((BlockOffset % 3) == 2) // Collecting always 3 Bytes, then do processing in 4 Bytes + { +#if !defined COMPILE_FOR_LPC21 + sendbuf[Line][tmpStringPos++] = uuencode_table[(k >> 18) & 63]; + sendbuf[Line][tmpStringPos++] = uuencode_table[(k >> 12) & 63]; + sendbuf[Line][tmpStringPos++] = uuencode_table[(k >> 6) & 63]; + sendbuf[Line][tmpStringPos++] = uuencode_table[ k & 63]; +#else + tmpString[tmpStringPos++] = uuencode_table[(k >> 18) & 63]; + tmpString[tmpStringPos++] = uuencode_table[(k >> 12) & 63]; + tmpString[tmpStringPos++] = uuencode_table[(k >> 6) & 63]; + tmpString[tmpStringPos++] = uuencode_table[ k & 63]; +#endif + } + } + + +#if !defined COMPILE_FOR_LPC21 + sendbuf[Line][tmpStringPos++] = '\r'; + sendbuf[Line][tmpStringPos++] = '\n'; + sendbuf[Line][tmpStringPos++] = 0; + + SendComPort(IspEnvironment, sendbuf[Line]); + // receive only for debug proposes + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 1, 5000); + FormatCommand(sendbuf[Line], tmpString); + FormatCommand(Answer, Answer); + if (strncmp(Answer, tmpString, strlen(tmpString)) != 0) + { + DebugPrintf(1, "Error on writing data (1)\n"); + return (ERROR_WRITE_DATA); + } +#else + tmpString[tmpStringPos++] = '\r'; + tmpString[tmpStringPos++] = '\n'; + tmpString[tmpStringPos++] = 0; + + SendComPort(IspEnvironment, tmpString); + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 1, 5000); + FormatCommand(tmpString, tmpString); + FormatCommand(Answer, Answer); + if (strncmp(Answer, tmpString, tmpStringPos) != 0) + { + DebugPrintf(1, "Error on writing data (1)\n"); + return (ERROR_WRITE_DATA); + } +#endif + + Line++; + + DebugPrintf(3, "Line = %d\n", Line); + + if (Line == 20) + { +#if !defined COMPILE_FOR_LPC21 + for (repeat = 0; repeat < 3; repeat++) + { + + // DebugPrintf(1, "block_CRC = %ld\n", block_CRC); + + sprintf(tmpString, "%ld\r\n", block_CRC); + + SendComPort(IspEnvironment, tmpString); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 2, 5000); + + sprintf(tmpString, "%ld\nOK\n", block_CRC); + + FormatCommand(tmpString, tmpString); + FormatCommand(Answer, Answer); + if (strcmp(Answer, tmpString) != 0) + { + for (i = 0; i < Line; i++) + { + SendComPort(IspEnvironment, sendbuf[i]); + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 1, 5000); + } + } + else + break; + } + + if (repeat >= 3) + { + DebugPrintf(1, "Error on writing block_CRC (1)\n"); + return (ERROR_WRITE_CRC); + } +#else + // DebugPrintf(1, "block_CRC = %ld\n", block_CRC); + sprintf(tmpString, "%ld\r\n", block_CRC); + SendComPort(IspEnvironment, tmpString); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 2,5000); + + sprintf(tmpString, "%ld\nOK\n", block_CRC); + FormatCommand(tmpString, tmpString); + FormatCommand(Answer, Answer); + if (strcmp(Answer, tmpString) != 0) + { + DebugPrintf(1, "Error on writing block_CRC (2)\n"); + return (ERROR_WRITE_CRC); + } +#endif + Line = 0; + block_CRC = 0; + } + } + } + + if (Line != 0) + { +#if !defined COMPILE_FOR_LPC21 + for (repeat = 0; repeat < 3; repeat++) + { + sprintf(tmpString, "%ld\r\n", block_CRC); + + SendComPort(IspEnvironment, tmpString); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 2,5000); + + sprintf(tmpString, "%ld\nOK\n", block_CRC); + + FormatCommand(tmpString, tmpString); + FormatCommand(Answer, Answer); + if (strcmp(Answer, tmpString) != 0) + { + for (i = 0; i < Line; i++) + { + SendComPort(IspEnvironment, sendbuf[i]); + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 1,5000); + } + } + else + break; + } + + if (repeat >= 3) + { + DebugPrintf(1, "Error on writing block_CRC (3)\n"); + return (ERROR_WRITE_CRC2); + } +#else + sprintf(tmpString, "%ld\r\n", block_CRC); + SendComPort(IspEnvironment, tmpString); + + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 2,5000); + + sprintf(tmpString, "%ld\nOK\n", block_CRC); + FormatCommand(tmpString, tmpString); + FormatCommand(Answer, Answer); + if (strcmp(Answer, tmpString) != 0) + { + DebugPrintf(1, "Error on writing block_CRC (4)\n"); + return (ERROR_WRITE_CRC2); + } +#endif + } + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + unsigned char BigAnswer[4096]; + unsigned long CopyLengthPartialOffset = 0; + unsigned long CopyLengthPartialRemainingBytes; + + while(CopyLengthPartialOffset < CopyLength) + { + CopyLengthPartialRemainingBytes = CopyLength - CopyLengthPartialOffset; + if(CopyLengthPartialRemainingBytes > 256) + { + // There seems to be an error in LPC812: + // When too much bytes are written at high speed, + // bytes get lost + // Workaround: Use smaller blocks + CopyLengthPartialRemainingBytes = 256; + } + + SendComPortBlock(IspEnvironment, &IspEnvironment->BinaryContent[SectorStart + SectorOffset + CopyLengthPartialOffset], CopyLengthPartialRemainingBytes); + + if (ReceiveComPortBlockComplete(IspEnvironment, &BigAnswer, CopyLengthPartialRemainingBytes, 10000) != 0) + { + return (ERROR_WRITE_DATA); + } + + if(memcmp(&IspEnvironment->BinaryContent[SectorStart + SectorOffset + CopyLengthPartialOffset], BigAnswer, CopyLengthPartialRemainingBytes)) + { + return (ERROR_WRITE_DATA); + } + + CopyLengthPartialOffset += CopyLengthPartialRemainingBytes; + } + } + + if ( (IspEnvironment->BinaryOffset < ReturnValueLpcRamStart(IspEnvironment)) + ||(IspEnvironment->BinaryOffset >= ReturnValueLpcRamStart(IspEnvironment)+(LPCtypes[IspEnvironment->DetectedDevice].RAMSize*1024))) + { + // Prepare command must be repeated before every write + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + // TODO: Quick and dirty hack to address bank 0 + sprintf(tmpString, "P %ld %ld 0\r\n", Sector, Sector); + } + else + { + sprintf(tmpString, "P %ld %ld\r\n", Sector, Sector); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Prepare-Command (2) (Sector %ld)\n", Sector); + return (WRONG_ANSWER_PREP2 + GetAndReportErrorNumber(Answer)); + } + + // Round CopyLength up to one of the following values: 512, 1024, + // 4096, 8192; but do not exceed the maximum copy size (usually + // 8192, but chip-dependent) + if (CopyLength < 512) + { + CopyLength = 512; + } + else if (SectorLength < 1024) + { + CopyLength = 1024; + } + else if (SectorLength < 4096) + { + CopyLength = 4096; + } + else + { + CopyLength = 8192; + } + if (CopyLength > (unsigned)LPCtypes[IspEnvironment->DetectedDevice].MaxCopySize) + { + CopyLength = LPCtypes[IspEnvironment->DetectedDevice].MaxCopySize; + } + + sprintf(tmpString, "C %ld %ld %ld\r\n", IspEnvironment->BinaryOffset + SectorStart + SectorOffset, ReturnValueLpcRamBase(IspEnvironment), CopyLength); + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Copy-Command\n"); + return (WRONG_ANSWER_COPY + GetAndReportErrorNumber(Answer)); + } + + if (IspEnvironment->Verify) + { + + //Avoid compare first 64 bytes. + //Because first 64 bytes are re-mapped to flash boot sector, + //and the compare result may not be correct. + if (SectorStart + SectorOffset<64) + { + sprintf(tmpString, "M %d %ld %ld\r\n", 64, ReturnValueLpcRamBase(IspEnvironment) + (64 - SectorStart - SectorOffset), CopyLength-(64 - SectorStart - SectorOffset)); + } + else + { + sprintf(tmpString, "M %ld %ld %ld\r\n", SectorStart + SectorOffset, ReturnValueLpcRamBase(IspEnvironment), CopyLength); + } + + if (!SendAndVerify(IspEnvironment, tmpString, Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on Compare-Command\n"); + return (WRONG_ANSWER_COPY + GetAndReportErrorNumber(Answer)); + } + } + } + } + + DebugPrintf(2, "\n"); + fflush(stdout); + + if ((SectorStart + SectorLength) >= IspEnvironment->BinaryLength && Sector!=0) + { + Sector = 0; + SectorStart = 0; + } + else if (Sector == 0) { + break; + } + else { + SectorStart += LPCtypes[IspEnvironment->DetectedDevice].SectorTable[Sector]; + Sector++; + } + } + + tDoneUpload = time(NULL); + if (IspEnvironment->Verify) + DebugPrintf(2, "Download Finished and Verified correct... taking %d seconds\n", tDoneUpload - tStartUpload); + else + DebugPrintf(2, "Download Finished... taking %d seconds\n", tDoneUpload - tStartUpload); + + // For LPC18xx set boot bank to 0 + if (LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + if (!SendAndVerify(IspEnvironment, "S 0\r\n", Answer, sizeof Answer)) + { + DebugPrintf(1, "Wrong answer on SetActiveBootFlashBank-Command\n"); + return (WRONG_ANSWER_BTBNK + GetAndReportErrorNumber(Answer)); + } + } + + if(IspEnvironment->DoNotStart == 0) + { + DebugPrintf(2, "Now launching the brand new code\n"); + fflush(stdout); + + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX) + { + sprintf(tmpString, "G %ld A\r\n", IspEnvironment->StartAddress); + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX) + { + sprintf(tmpString, "G %ld T\r\n", IspEnvironment->StartAddress & ~1); + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + sprintf(tmpString, "G 0 T\r\n"); + } + else + { + DebugPrintf(1, "Internal Error %s %d\n", __FILE__, __LINE__); + exit(1); + } + + SendComPort(IspEnvironment, tmpString); //goto 0 : run this fresh new downloaded code code + if ( (IspEnvironment->BinaryOffset < ReturnValueLpcRamStart(IspEnvironment)) + ||(IspEnvironment->BinaryOffset >= ReturnValueLpcRamStart(IspEnvironment)+(LPCtypes[IspEnvironment->DetectedDevice].RAMSize*1024))) + { // Skip response on G command - show response on Terminal instead + ReceiveComPort(IspEnvironment, Answer, sizeof(Answer)-1, &realsize, 2, 5000); + /* the reply string is frequently terminated with a -1 (EOF) because the + * connection gets broken; zero-terminate the string ourselves + */ + while (realsize > 0 && ((signed char) Answer[(int)realsize - 1]) < 0) + realsize--; + Answer[(int)realsize] = '\0'; + /* Better to check only the first 9 chars instead of complete receive buffer, + * because the answer can contain the output by the started programm + */ + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX) + { + sprintf(ExpectedAnswer, "G %ld A\n0", IspEnvironment->StartAddress); + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX || + LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX) + { + sprintf(ExpectedAnswer, "G %ld T\n0", IspEnvironment->StartAddress & ~1); + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + sprintf(ExpectedAnswer, "G 0 T\n0"); + } + else + { + DebugPrintf(1, "Internal Error %s %d\n", __FILE__, __LINE__); + exit(1); + } + + FormatCommand(Answer, Answer); + if (realsize == 0 || strncmp((const char *)Answer, /*cmdstr*/ExpectedAnswer, strlen(/*cmdstr*/ExpectedAnswer)) != 0) + { + DebugPrintf(2, "Failed to run the new downloaded code: "); + return (FAILED_RUN + GetAndReportErrorNumber(Answer)); + } + } + + fflush(stdout); + } + return (0); +} +#endif // LPC_SUPPORT + + +unsigned long ReturnValueLpcRamStart(ISP_ENVIRONMENT *IspEnvironment) +{ + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX) + { + return LPC_RAMSTART_LPC43XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX) + { + return LPC_RAMSTART_LPC2XXX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + return LPC_RAMSTART_LPC18XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX) + { + return LPC_RAMSTART_LPC17XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX) + { + return LPC_RAMSTART_LPC13XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX) + { + return LPC_RAMSTART_LPC11XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + return LPC_RAMSTART_LPC8XX; + } + DebugPrintf(1, "Error in ReturnValueLpcRamStart (%d)\n", LPCtypes[IspEnvironment->DetectedDevice].ChipVariant); + exit(1); +} + + +unsigned long ReturnValueLpcRamBase(ISP_ENVIRONMENT *IspEnvironment) +{ + if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC43XX) + { + return LPC_RAMBASE_LPC43XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC2XXX) + { + return LPC_RAMBASE_LPC2XXX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC18XX) + { + return LPC_RAMBASE_LPC18XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC17XX) + { + return LPC_RAMBASE_LPC17XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC13XX) + { + return LPC_RAMBASE_LPC13XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC11XX) + { + return LPC_RAMBASE_LPC11XX; + } + else if(LPCtypes[IspEnvironment->DetectedDevice].ChipVariant == CHIP_VARIANT_LPC8XX) + { + return LPC_RAMBASE_LPC8XX; + } + DebugPrintf(1, "Error in ReturnValueLpcRamBase (%d)\n", LPCtypes[IspEnvironment->DetectedDevice].ChipVariant); + exit(1); +} diff --git a/host/app/lpc21lisp/lpcprog.h b/host/app/lpc21lisp/lpcprog.h new file mode 100644 index 0000000..3e60b3e --- /dev/null +++ b/host/app/lpc21lisp/lpcprog.h @@ -0,0 +1,144 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC1000 / LPC2000 family + and Analog Devices ADUC70xx + +Filename: lpcprog.h + +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-2011, 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 . +*/ + +/* LPC_RAMSTART, LPC_RAMBASE +* +* Used in NxpDownload() to decide whether to Flash code or just place in in RAM +* (works for .hex files only) +* +* LPC_RAMSTART - the Physical start address of the SRAM +* LPC_RAMBASE - the base address where downloading starts. +* Note that any code in the .hex file that resides in 0x4000,0000 ~ 0x4000,0200 +* will _not_ be written to the LPCs SRAM. +* This is due to the fact that 0x4000,0040 - 0x4000,0200 is used by the bootrom. +* Any interrupt vectors must be copied to 0x4000,0000 and remapped to 0x0000,0000 +* by the startup code. +*/ +#define LPC_RAMSTART_LPC43XX 0x10000000L +#define LPC_RAMBASE_LPC43XX 0x10000200L + +#define LPC_RAMSTART_LPC2XXX 0x40000000L +#define LPC_RAMBASE_LPC2XXX 0x40000200L + +#define LPC_RAMSTART_LPC18XX 0x10000000L +#define LPC_RAMBASE_LPC18XX 0x10000200L + +#define LPC_RAMSTART_LPC17XX 0x10000000L +#define LPC_RAMBASE_LPC17XX 0x10000200L + +#define LPC_RAMSTART_LPC13XX 0x10000000L +#define LPC_RAMBASE_LPC13XX 0x10000300L + +#define LPC_RAMSTART_LPC11XX 0x10000000L +#define LPC_RAMBASE_LPC11XX 0x10000300L + +#define LPC_RAMSTART_LPC8XX 0x10000000L +#define LPC_RAMBASE_LPC8XX 0x10000270L + +/* Return values used by NxpDownload(): reserving all values from 0x1000 to 0x1FFF */ + +#define NO_ANSWER_WDT 0x1000 +#define NO_ANSWER_QM 0x1001 +#define NO_ANSWER_SYNC 0x1002 +#define NO_ANSWER_OSC 0x1003 +#define NO_ANSWER_RBV 0x1004 +#define NO_ANSWER_RPID 0x1005 +#define ERROR_WRITE_DATA 0x1006 +#define ERROR_WRITE_CRC 0x1007 +#define ERROR_WRITE_CRC2 0x1008 +#define PROGRAM_TOO_LARGE 0x1009 + +#define USER_ABORT_SYNC 0x100A /* User aborted synchronisation process */ + +#define UNKNOWN_LPC 0x100B /* Unknown LPC detected */ + +#define UNLOCK_ERROR 0x1100 /* return value is 0x1100 + NXP ISP returned value (0 to 255) */ +#define WRONG_ANSWER_PREP 0x1200 /* return value is 0x1200 + NXP ISP returned value (0 to 255) */ +#define WRONG_ANSWER_ERAS 0x1300 /* return value is 0x1300 + NXP ISP returned value (0 to 255) */ +#define WRONG_ANSWER_WRIT 0x1400 /* return value is 0x1400 + NXP ISP returned value (0 to 255) */ +#define WRONG_ANSWER_PREP2 0x1500 /* return value is 0x1500 + NXP ISP returned value (0 to 255) */ +#define WRONG_ANSWER_COPY 0x1600 /* return value is 0x1600 + NXP ISP returned value (0 to 255) */ +#define FAILED_RUN 0x1700 /* return value is 0x1700 + NXP ISP returned value (0 to 255) */ +#define WRONG_ANSWER_BTBNK 0x1800 /* return value is 0x1800 + NXP ISP returned value (0 to 255) */ + +#if defined COMPILE_FOR_LPC21 +#ifndef WIN32 +#define LPC_BSL_PIN 13 +#define LPC_RESET_PIN 47 +#define LPC_RESET(in) NAsetGPIOpin(LPC_RESET_PIN, (in)) +#define LPC_BSL(in) NAsetGPIOpin(LPC_BSL_PIN, (in)) +#endif // WIN32 +#endif // COMPILE_FOR_LPC21 + + +/* LPC_FLASHMASK +* +* LPC_FLASHMASK - bitmask to define the maximum size of the Filesize to download. +* LoadFile() will check any new segment address record (03) or extended linear +* address record (04) to see if the addressed 64 kByte data block still falls +* in the max. flash size. +* LoadFile() will not load any files that are larger than this size. +*/ +#define LPC_FLASHMASK 0xFFC00000 /* 22 bits = 4 MB */ + +typedef enum + { + CHIP_VARIANT_NONE, + CHIP_VARIANT_LPC43XX, + CHIP_VARIANT_LPC2XXX, + CHIP_VARIANT_LPC18XX, + CHIP_VARIANT_LPC17XX, + CHIP_VARIANT_LPC13XX, + CHIP_VARIANT_LPC11XX, + CHIP_VARIANT_LPC8XX + } CHIP_VARIANT; + +typedef struct +{ + const unsigned long id; + const unsigned long id2; + const unsigned int EvalId2; + const char *Product; + const unsigned int FlashSize; /* in kiB, for informational purposes only */ + const unsigned int RAMSize; /* in kiB, for informational purposes only */ + unsigned int FlashSectors; /* total number of sectors */ + unsigned int MaxCopySize; /* maximum size that can be copied to Flash in a single command */ + const unsigned int *SectorTable; /* pointer to a sector table with constant the sector sizes */ + const CHIP_VARIANT ChipVariant; +} LPC_DEVICE_TYPE; + +int NxpDownload(ISP_ENVIRONMENT *IspEnvironment); + +unsigned long ReturnValueLpcRamStart(ISP_ENVIRONMENT *IspEnvironment); + +unsigned long ReturnValueLpcRamBase(ISP_ENVIRONMENT *IspEnvironment); + diff --git a/host/app/lpc21lisp/lpcterm.c b/host/app/lpc21lisp/lpcterm.c new file mode 100644 index 0000000..e176a6d --- /dev/null +++ b/host/app/lpc21lisp/lpcterm.c @@ -0,0 +1,138 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC1000 / LPC2000 family + and Analog Devices ADUC70xx + +Filename: lpcterm.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-2011, 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 . +*/ + +#if defined(_WIN32) +#if !defined __BORLANDC__ +#include "StdAfx.h" +#endif +#endif // defined(_WIN32) +#include "lpc21isp.h" +#include "lpcterm.h" + +#ifdef TERMINAL_SUPPORT +/***************************** Terminal *********************************/ +/** Acts as a simple dumb terminal. Press 'ESC' to exit. +*/ +BOOL CheckTerminalParameters(ISP_ENVIRONMENT *IspEnvironment, char* pstr) +{ + if (stricmp(pstr, "-localecho") == 0) + { + IspEnvironment->LocalEcho = 1; + DebugPrintf(3, "Local echo in terminal mode.\n"); + return TRUE; + } + + if (stricmp(pstr, "-term") == 0) + { + IspEnvironment->TerminalAfterUpload = 1; + DebugPrintf(3, "Invoke terminal after upload.\n"); + return TRUE; + } + + if (stricmp(pstr, "-termonly") == 0) + { + IspEnvironment->TerminalOnly = 1; + IspEnvironment->ProgramChip = 0; + DebugPrintf(3, "Only provide terminal.\n"); + return TRUE; + } + + return FALSE; +} + +void Terminal(ISP_ENVIRONMENT *IspEnvironment) +{ + if (IspEnvironment->TerminalAfterUpload || IspEnvironment->TerminalOnly) + { + int ch = 0; + char buffer[128]; + int fdlogfile = -1; + unsigned long realsize; + + // When logging is switched on, output terminal output to lpc21isp.log + if (IspEnvironment->LogFile) + { + fdlogfile = open("lpc21isp.log", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777); + } + + PrepareKeyboardTtySettings(); + + DebugPrintf(1, "Terminal started (press Escape to abort)\n\n"); + fflush(stdout); + + do + { + ReceiveComPort(IspEnvironment, buffer, sizeof(buffer) - 1, &realsize, 0,200); // Check for received characters + + if (realsize) + { + write(1, buffer, realsize); + fflush(stdout); + if (IspEnvironment->LogFile) // When logging is turned on, then copy output to logfile + { + write(fdlogfile, buffer, realsize); + } + } + + // check for keypress, and write any out the port. + if (kbhit()) + { + ch = getch(); + if (ch == 0x1b) + { + break; + } + buffer[0] = (unsigned char)ch; + buffer[1] = 0; + + if (IspEnvironment->LocalEcho) + { + write(1, buffer, 1); + } + + SendComPort(IspEnvironment, buffer); + } + } + while (ch != 0x1b); + + DebugPrintf(1, "\n\nTerminal stopped\n\n"); + fflush(stdout); + + ResetKeyboardTtySettings(); + + if (IspEnvironment->LogFile) + { + close(fdlogfile); + } + } +} +#endif diff --git a/host/app/lpc21lisp/lpcterm.h b/host/app/lpc21lisp/lpcterm.h new file mode 100644 index 0000000..3fda95d --- /dev/null +++ b/host/app/lpc21lisp/lpcterm.h @@ -0,0 +1,43 @@ +/****************************************************************************** + +Project: Portable command line ISP for NXP LPC1000 / LPC2000 family + and Analog Devices ADUC70xx + +Filename: lpcterm.h + +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-2011, 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 . +*/ + +#ifndef TRUE +#define TRUE (1) +#endif +#ifndef FALSE +#define FALSE (0) +#endif + +typedef int BOOL; + +void Terminal(ISP_ENVIRONMENT *IspEnvironment); +BOOL CheckTerminalParameters(ISP_ENVIRONMENT *IspEnvironment, char* pstr); diff --git a/host/config.omk b/host/config.omk index a10eb74..1f47def 100644 --- a/host/config.omk +++ b/host/config.omk @@ -2,6 +2,7 @@ LN_HEADERS=y CONFIG_APP_ROCON_CMD=y CONFIG_APP_USB_SENDHEX=y +CONFIG_APP_LPC21LISP=y # Fails CONFIG_OC_ULUT=n -- 2.39.2