summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2010-01-06 17:55:16 +0000
committerDimitri Sokolyuk <demon@dim13.org>2010-01-06 17:55:16 +0000
commit09381c6097773b08622c810428a84840b5b08070 (patch)
treef62afce58620ebbffe6abcf1b8e1d8df6a09a5b8
AVR SP12 programmer
-rw-r--r--COPYING.txt351
-rw-r--r--_sp12dev1067
-rw-r--r--changes.txt1085
-rw-r--r--dongle.gifbin0 -> 10037 bytes
-rw-r--r--dongle.txt27
-rw-r--r--hardware.txt65
-rw-r--r--icp_intr.gifbin0 -> 7545 bytes
-rw-r--r--progrmmr.gifbin0 -> 8373 bytes
-rw-r--r--readme.dos130
-rw-r--r--readme.linux152
-rw-r--r--readme.win163
-rwxr-xr-xsp12bin0 -> 54800 bytes
-rw-r--r--sp12.txt1045
-rw-r--r--sp12dev.txt218
-rw-r--r--sp12rc.txt159
-rw-r--r--src/buffer.c691
-rw-r--r--src/device.c434
-rw-r--r--src/dos_cpt.h53
-rw-r--r--src/eeprom.c125
-rw-r--r--src/flash.c292
-rw-r--r--src/init.c854
-rw-r--r--src/makefile58
-rw-r--r--src/sp12.c1136
-rw-r--r--src/sp12.h520
-rw-r--r--src/winnt.c75
25 files changed, 8700 insertions, 0 deletions
diff --git a/COPYING.txt b/COPYING.txt
new file mode 100644
index 0000000..8ce13c8
--- /dev/null
+++ b/COPYING.txt
@@ -0,0 +1,351 @@
+GNU GENERAL PUBLIC LICENSE
+
+ Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+ The licenses for most software are designed to take away your freedom
+ to share and change it. By contrast, the GNU General Public License
+ is intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users. This
+ General Public License applies to most of the Free Software
+ Foundation's software and to any other program whose authors commit
+ to using it. (Some other Free Software Foundation software is covered
+ by the GNU Library General Public License instead.) You can apply it
+ to your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge
+ for this service if you wish), that you receive source code or can
+ get it if you want it, that you can change the software or use pieces
+ of it in new free programs; and that you know you can do these
+ things.
+
+ To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the
+ rights. These restrictions translate to certain responsibilities for
+ you if you distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+ gratis or for a fee, you must give the recipients all the rights that
+ you have. You must make sure that they, too, receive or can get the
+ source code. And you must show them these terms so they know their
+ rights.
+
+ We protect your rights with two steps: (1) copyright the software,
+ and (2) offer you this license which gives you legal permission to
+ copy, distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+ that everyone understands that there is no warranty for this free
+ software. If the software is modified by someone else and passed on,
+ we want its recipients to know that what they have is not the
+ original, so that any problems introduced by others will not reflect
+ on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that redistributors of a free
+ program will individually obtain patent licenses, in effect making
+ the program proprietary. To prevent this, we have made it clear that
+ any patent must be licensed for everyone's free use or not licensed
+ at all.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains a
+ notice placed by the copyright holder saying it may be distributed
+ under the terms of this General Public License. The "Program", below,
+ refers to any such program or work, and a "work based on the Program"
+ means either the Program or any derivative work under copyright law:
+ that is to say, a work containing the Program or a portion of it,
+ either verbatim or with modifications and/or translated into another
+ language. (Hereinafter, translation is included without limitation in
+ the term "modification".) Each licensee is addressed as "you".
+
+ Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of
+ running the Program is not restricted, and the output from the
+ Program is covered only if its contents constitute a work based on
+ the Program (independent of having been made by running the Program).
+ Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+ source code as you receive it, in any medium, provided that you
+ conspicuously and appropriately publish on each copy an appropriate
+ copyright notice and disclaimer of warranty; keep intact all the
+ notices that refer to this License and to the absence of any
+ warranty; and give any other recipients of the Program a copy of this
+ License along with the Program.
+
+ You may charge a fee for the physical act of transferring a copy, and
+ you may at your option offer warranty protection in exchange for a
+ fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+ of it, thus forming a work based on the Program, and copy and
+ distribute such modifications or work under the terms of Section 1
+ above, provided that you also meet all of these conditions:
+
+ * a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+ * b) You must cause any work that you distribute or publish, that
+ in whole or in part contains or is derived from the Program or
+ any part thereof, to be licensed as a whole at no charge to all
+ third parties under the terms of this License.
+ * c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you
+ provide a warranty) and that users may redistribute the program
+ under these conditions, and telling the user how to view a copy
+ of this License. (Exception: if the Program itself is interactive
+ but does not normally print such an announcement, your work based
+ on the Program is not required to print an announcement.)
+
+ These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Program,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Program, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.
+
+ Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Program.
+
+ In addition, mere aggregation of another work not based on the
+ Program with the Program (or with a work based on the Program) on a
+ volume of a storage or distribution medium does not bring the other
+ work under the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the terms of
+ Sections 1 and 2 above provided that you also do one of the
+ following:
+ * a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Sections 1 and 2 above on a medium customarily used for software
+ interchange; or,
+ * b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+ * c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+ The source code for a work means the preferred form of the work for
+ making modifications to it. For an executable work, complete source
+ code means all the source code for all modules it contains, plus any
+ associated interface definition files, plus the scripts used to
+ control compilation and installation of the executable. However, as a
+ special exception, the source code distributed need not include
+ anything that is normally distributed (in either source or binary
+ form) with the major components (compiler, kernel, and so on) of the
+ operating system on which the executable runs, unless that component
+ itself accompanies the executable.
+
+ If distribution of executable or object code is made by offering
+ access to copy from a designated place, then offering equivalent
+ access to copy the source code from the same place counts as
+ distribution of the source code, even though third parties are not
+ compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License. Any attempt
+ otherwise to copy, modify, sublicense or distribute the Program is
+ void, and will automatically terminate your rights under this
+ License. However, parties who have received copies, or rights, from
+ you under this License will not have their licenses terminated so
+ long as such parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to modify or
+ distribute the Program or its derivative works. These actions are
+ prohibited by law if you do not accept this License. Therefore, by
+ modifying or distributing the Program (or any work based on the
+ Program), you indicate your acceptance of this License to do so, and
+ all its terms and conditions for copying, distributing or modifying
+ the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from the
+ original licensor to copy, distribute or modify the Program subject
+ to these terms and conditions. You may not impose any further
+ restrictions on the recipients' exercise of the rights granted
+ herein. You are not responsible for enforcing compliance by third
+ parties to this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent issues),
+ conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do
+ not excuse you from the conditions of this License. If you cannot
+ distribute so as to satisfy simultaneously your obligations under
+ this License and any other pertinent obligations, then as a
+ consequence you may not distribute the Program at all. For example,
+ if a patent license would not permit royalty-free redistribution of
+ the Program by all those who receive copies directly or indirectly
+ through you, then the only way you could satisfy both it and this
+ License would be to refrain entirely from distribution of the
+ Program.
+
+ If any portion of this section is held invalid or unenforceable under
+ any particular circumstance, the balance of the section is intended
+ to apply and the section as a whole is intended to apply in other
+ circumstances.
+
+ It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of any
+ such claims; this section has the sole purpose of protecting the
+ integrity of the free software distribution system, which is
+ implemented by public license practices. Many people have made
+ generous contributions to the wide range of software distributed
+ through that system in reliance on consistent application of that
+ system; it is up to the author/donor to decide if he or she is
+ willing to distribute software through any other system and a
+ licensee cannot impose that choice.
+
+ This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted interfaces, the
+ original copyright holder who places the Program under this License
+ may add an explicit geographical distribution limitation excluding
+ those countries, so that distribution is permitted only in or among
+ countries not thus excluded. In such case, this License incorporates
+ the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new
+ versions of the General Public License from time to time. Such new
+ versions will be similar in spirit to the present version, but may
+ differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and
+ "any later version", you have the option of following the terms and
+ conditions either of that version or of any later version published
+ by the Free Software Foundation. If the Program does not specify a
+ version number of this License, you may choose any version ever
+ published by the Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to the
+ author to ask for permission. For software which is copyrighted by
+ the Free Software Foundation, write to the Free Software Foundation;
+ we sometimes make exceptions for this. Our decision will be guided by
+ the two goals of preserving the free status of all derivatives of our
+ free software and of promoting the sharing and reuse of software
+ generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+ WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+ OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+ PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
+ THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+ AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make
+ it free software which everyone can redistribute and change under
+ these terms.
+
+ To do so, attach the following notices to the program. It is safest
+ to attach them to the start of each source file to most effectively
+ convey the exclusion of warranty; and each file should have at least
+ the "copyright" line and a pointer to where the full notice is found.
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) 19yy name of author
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Also add information on how to contact you by electronic and paper
+ mail.
+
+ If the program is interactive, make it output a short notice like
+ this when it starts in an interactive mode:
+
+Gnomovision version 69, Copyright (C) 19yy name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+
+ The hypothetical commands `show w' and `show c' should show the
+ appropriate parts of the General Public License. Of course, the
+ commands you use may be called something other than `show w' and
+ `show c'; they could even be mouse-clicks or menu items--whatever
+ suits your program.
+
+ You should also get your employer (if you work as a programmer) or
+ your school, if any, to sign a "copyright disclaimer" for the
+ program, if necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written
+by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+ This General Public License does not permit incorporating your
+ program into proprietary programs. If your program is a subroutine
+ library, you may consider it more useful to permit linking
+ proprietary applications with the library. If this is what you want
+ to do, use the GNU Library General Public License instead of this
+ License.
diff --git a/_sp12dev b/_sp12dev
new file mode 100644
index 0000000..e4f0ed7
--- /dev/null
+++ b/_sp12dev
@@ -0,0 +1,1067 @@
+begin 0190
+-i190
+-iS1200
+DEVICENAME = AT90S1200(A)
+FLASHSIZE = 512
+EEPROMSIZE = 64
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES =
+READ_FUSES =
+FUSES_MESSAGE =
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0191
+-i191
+-iS2313
+DEVICENAME = AT90S2313
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES =
+READ_FUSES =
+FUSES_MESSAGE =
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0193
+-i193
+-iS8515
+DEVICENAME = AT90S8515
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhx x21x xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES =
+READ_FUSES =
+FUSES_MESSAGE =
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0192
+-i192
+-iS4414
+DEVICENAME = AT90S4414
+FLASHSIZE = 2048
+EEPROMSIZE = 256
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhx x21x xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES =
+READ_FUSES =
+FUSES_MESSAGE =
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0291
+-i291
+-iS2323
+DEVICENAME = AT90S2323
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhh hhhF xxxx xxxx xxxx xxxx
+READ_FUSES = lhlh hlll xxxx xxxx xxxx xxxx 12Sx xxxF
+FUSES_MESSAGE = 11xccccx - no lock
+FUSES_MESSAGE = 01xccccx - write protected
+FUSES_MESSAGE = 00xccccx - read/write protected
+FUSES_MESSAGE = xx0ccccx - serial programming enabled
+FUSES_MESSAGE = xxxcccc0 - FSTRT reset delay, datasheet p22
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0292
+-i292
+-iS4434
+DEVICENAME = AT90S4434
+FLASHSIZE = 2048
+EEPROMSIZE = 256
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhh hhhF xxxx xxxx xxxx xxxx
+READ_FUSES = lhlh hlll xxxx xxxx xxxx xxxx 12Sx xxxF
+FUSES_MESSAGE = 11xccccx - no lock
+FUSES_MESSAGE = 01xccccx - write protected
+FUSES_MESSAGE = 00xccccx - read/write protected
+FUSES_MESSAGE = xx0ccccx - serial programming enabled
+FUSES_MESSAGE = xxxcccc0 - FSTRT reset delay, datasheet p20
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0393
+-i393
+-iS8535
+DEVICENAME = AT90S8535
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhh hhhF xxxx xxxx xxxx xxxx
+READ_FUSES = lhlh hlll xxxx xxxx xxxx xxxx 12Sx xxxF
+FUSES_MESSAGE = 11xccccx - no lock
+FUSES_MESSAGE = 01xccccx - write protected
+FUSES_MESSAGE = 00xccccx - read/write protected
+FUSES_MESSAGE = xx0ccccx - serial programming enabled
+FUSES_MESSAGE = xxxcccc0 - FSTRT reset delay, datasheet p20
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0391
+-i391
+-iS2343
+DEVICENAME = AT90S2343 or Tiny22
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhh hhhR xxxx xxxx xxxx xxxx
+READ_FUSES = lhlh hlll xxxx xxxx xxxx xxxx 12Sx xxxR
+FUSES_MESSAGE = 11xccccx - no lock
+FUSES_MESSAGE = 01xccccx - write protected
+FUSES_MESSAGE = 00xccccx - read/write protected
+FUSES_MESSAGE = xx0ccccx - serial programming enabled
+FUSES_MESSAGE = xxxcccc0 - internal RC clock enabled
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0691
+-i691
+-iT22
+DEVICENAME = ATtiny22L
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK =
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES =
+READ_FUSES = lhlh hlll xxxx xxxx xxxx xxxx 12Sx xxxl
+FUSES_MESSAGE = 11xccccx - no lock
+FUSES_MESSAGE = 01xccccx - write protected
+FUSES_MESSAGE = 00xccccx - read/write protected
+FUSES_MESSAGE = xx0ccccx - serial programming enabled
+FUSES_MESSAGE = xxxcccc0 - internal RC clock enabled
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0591
+-i591
+-iS2333
+DEVICENAME = AT90S2333
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlh7 6543 xxxx xxxx xxxx xxxx
+READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx xx87 6543
+FUSES_MESSAGE = 0xxxxx - serial programming enabled
+FUSES_MESSAGE = x0xxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = xx0xxx - brownout detection enabled
+FUSES_MESSAGE = xxxCKS - reset delay select (datasheet p20)
+FUSES_MESSAGE = NOTE: (re)enabling brownout detection
+FUSES_MESSAGE = often causes the 2333 to hang. In that
+FUSES_MESSAGE = case power must be switched off and back
+FUSES_MESSAGE = on again before programming can continue.
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0392
+-i392
+-iS4433
+DEVICENAME = AT90S4433
+FLASHSIZE = 2048
+EEPROMSIZE = 256
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlh7 6543 xxxx xxxx xxxx xxxx
+READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx xx87 6543
+FUSES_MESSAGE = 0xxxxx - serial programming enabled
+FUSES_MESSAGE = x0xxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = xx0xxx - brownout detection enabled
+FUSES_MESSAGE = xxxCKS - reset delay select (datasheet p20)
+FUSES_MESSAGE = NOTE: (re)enabling brownout detection
+FUSES_MESSAGE = often causes the 4433 to hang. In that
+FUSES_MESSAGE = case power must be switched off and back
+FUSES_MESSAGE = on again before programming can continue.
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0590
+-i590
+-iT12
+DEVICENAME = ATtiny12
+FLASHSIZE = 512
+EEPROMSIZE = 64
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhx xxxx xxxx xxxx A9lh 6543
+READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx A987 6543
+FUSES_MESSAGE = 0x01xxxx - BODLEVEL 2.7V (alternative 1.8V datasheet p22 p20)
+FUSES_MESSAGE = x001xxxx - brownout detection enabled
+FUSES_MESSAGE = xx01CKSL - clock and delay (datasheet p5 p20)
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (datasheet p45)
+
+begin 0690
+-i690
+-iT15
+DEVICENAME = ATtiny15L
+FLASHSIZE = 512
+EEPROMSIZE = 64
+PAGEMODE = 0
+PAGESIZE =
+READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhx xxxx xxxx xxxx 87lh hh43
+READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx 8765 xx43
+FUSES_MESSAGE = 0x0111xx - BODLEVEL 4V (alternative 2.7V)
+FUSES_MESSAGE = x00111xx - brownout detection enabled
+FUSES_MESSAGE = xx0111CK - reset delay select (datasheet p15)
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (datasheet p55)
+
+begin 0991
+-i991
+-iT26
+DEVICENAME = ATtiny26
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 1
+PAGESIZE = 16
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxxx xxoo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhhh hhii
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+FUSES_MESSAGE = 0xxxxxxx - PLLCK - Use PLL for internal clock
+FUSES_MESSAGE = x0xxxxxx - Enable internal XTAL caps 36pF (datasheet p29)
+FUSES_MESSAGE = xxSUxxxx - start-up time (page 29)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (datasheet p27,28)
+FUSES_MESSAGE = xxxx0001 - CKSEL (default 0001 - 1MHz sys clock internal)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx xxxh liii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx xxxx xooo
+HIGH_FUSES_MESSAGE = 0xx - EEPROM preserved in chip erase
+HIGH_FUSES_MESSAGE = x1x - BODLEVEL 2.7V (alternative 4V)
+HIGH_FUSES_MESSAGE = xx0 - BrownOut detection disabled
+HIGH_FUSES_MESSAGE = Note: RSTDISBL 1, SPIEN 0
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = Four Calibration Bytes available -- 1, 2, 4, 8MHz (p31 p108)
+CALIB_MESSAGE = Current Calibration Byte for 1MHz
+
+begin 0891
+-i891
+-iT25
+DEVICENAME = ATtiny25
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 1
+PAGESIZE = 16
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxxx xxoo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhhh hhii
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - Divide clock by 8 (0)
+FUSES_MESSAGE = x0xxxxxx - CKOUT - Clock Output Enable (1)
+FUSES_MESSAGE = xxSUxxxx - start-up time (page 27) (10)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (datasheet p27,28) (0010)
+FUSES_MESSAGE = xxxx0010 - CKSEL (default 0010 - 8MHz sys clock internal)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhli iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - RSTDISBL - External Reset disable !!(1)
+HIGH_FUSES_MESSAGE = x0xxxxxx - DWEN - DebugWire enable !!(1)
+HIGH_FUSES_MESSAGE = xx0xxxxx - SPIEN - Enable Serial Programming !!(0)
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDTON - Watchdogtimer always on (1)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EESAVE - EEPROM preserved in chip erase (1)
+HIGH_FUSES_MESSAGE = xxxxxBOD - BODLEVEL - BrownOutDetector trigger level(111)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xxxi
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx xxxx xxxo
+EXTD_FUSES_MESSAGE = 0 - SELFPRGEN - Self-Programming Enable (1)
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single Calibration Byte (p27 p153)
+
+begin 0692
+-i692
+-iT45
+DEVICENAME = ATtiny45
+FLASHSIZE = 2048
+EEPROMSIZE = 256
+PAGEMODE = 1
+PAGESIZE = 32
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxxx xxoo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhhh hhii
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - Divide clock by 8 (0)
+FUSES_MESSAGE = x0xxxxxx - CKOUT - Clock Output Enable (1)
+FUSES_MESSAGE = xxSUxxxx - start-up time (page 27) (10)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (datasheet p27,28) (0010)
+FUSES_MESSAGE = xxxx0010 - CKSEL (default 0010 - 8MHz sys clock internal)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhli iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - RSTDISBL - External Reset disable !!(1)
+HIGH_FUSES_MESSAGE = x0xxxxxx - DWEN - DebugWire enable !!(1)
+HIGH_FUSES_MESSAGE = xx0xxxxx - SPIEN - Enable Serial Programming !!(0)
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDTON - Watchdogtimer always on (1)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EESAVE - EEPROM preserved in chip erase (1)
+HIGH_FUSES_MESSAGE = xxxxxBOD - BODLEVEL - BrownOutDetector trigger level(111)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xxxi
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx xxxx xxxo
+EXTD_FUSES_MESSAGE = 0 - SELFPRGEN - Self-Programming Enable (1)
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single Calibration Byte (p27 p153)
+
+begin 0B93
+-iB93
+-iT85
+DEVICENAME = ATtiny85
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 32
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxxx xxoo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhhh hhii
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - Divide clock by 8 (0)
+FUSES_MESSAGE = x0xxxxxx - CKOUT - Clock Output Enable (1)
+FUSES_MESSAGE = xxSUxxxx - start-up time (page 27) (10)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (datasheet p27,28) (0010)
+FUSES_MESSAGE = xxxx0010 - CKSEL (default 0010 - 8MHz sys clock internal)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhli iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - RSTDISBL - External Reset disable !!(1)
+HIGH_FUSES_MESSAGE = x0xxxxxx - DWEN - DebugWire enable !!(1)
+HIGH_FUSES_MESSAGE = xx0xxxxx - SPIEN - Enable Serial Programming !!(0)
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDTON - Watchdogtimer always on (1)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EESAVE - EEPROM preserved in chip erase (1)
+HIGH_FUSES_MESSAGE = xxxxxBOD - BODLEVEL - BrownOutDetector trigger level(111)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xxxi
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx xxxx xxxo
+EXTD_FUSES_MESSAGE = 0 - SELFPRGEN - Self-Programming Enable (1)
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single Calibration Byte (p27 p153)
+
+begin 0A91
+-iA91
+-iT2313
+DEVICENAME = ATtiny2313
+FLASHSIZE = 1024
+EEPROMSIZE = 128
+PAGEMODE = 1
+PAGESIZE = 16
+POLL_RDY_BSY = hhhh llll llll llll xxxx xxxx xxxx xxxo
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - divide clock by 8 (page 22)
+FUSES_MESSAGE = x0xxxxxx - CKOUT output clock on pin D2
+FUSES_MESSAGE = xxSUxxxx - start-up time (datasheet page 24)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (datasheet page 22-24)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hili iiih
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - debugWire enabled
+HIGH_FUSES_MESSAGE = x0xxxxxx - EEPROM preserved in chip erase
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDT always on (page 41)
+HIGH_FUSES_MESSAGE = xxxxBODx - BODLEVEL (page 34)
+HIGH_FUSES_MESSAGE = xxxxxxx1 - reset-pin enabled (page 52)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xxxi
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxxxxxx0 - self-programming enabled
+READ_CALIBRATION = llhh hlll lllx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (page 24, 25, 159)
+
+begin 0790
+-i790
+-iT13
+DEVICENAME = ATtiny13
+FLASHSIZE = 512
+EEPROMSIZE = 64
+PAGEMODE = 1
+PAGESIZE = 16
+POLL_RDY_BSY = hhhh llll llll llll xxxx xxxx xxxx xxxo
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx liii iiii
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+FUSES_MESSAGE = 0xxxxxxx - serial programming enabled
+FUSES_MESSAGE = x0xxxxxx - EEPROM preserved in chip erase
+FUSES_MESSAGE = xx0xxxxx - WDT always on (datasheet page 37, 101)
+FUSES_MESSAGE = xxx0xxxx - CKDIV8 - divide clock by 8 (page 24, 101)
+FUSES_MESSAGE = xxxxSUxx - start-up time (datasheet page 22, 101)
+FUSES_MESSAGE = xxxxxxCK - CKSEL (page 22, 101)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhhi hiih
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx xxxo oooo
+HIGH_FUSES_MESSAGE = xxx0xxxx - self-programming enabled
+HIGH_FUSES_MESSAGE = xxxx0xxx - debugWire enabled
+HIGH_FUSES_MESSAGE = xxxxxBDx - BODLEVEL (page 32, 101)
+HIGH_FUSES_MESSAGE = xxxxxxx0 - reset-pin disabled (page 49, 101)
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll lllx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (page 22, 23, 101)
+
+begin 0197
+begin 0101
+-i197
+-iM103
+DEVICENAME = ATmega103
+FLASHSIZE = 65536
+EEPROMSIZE = 4096
+PAGEMODE = 1
+PAGESIZE = 128
+READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx xx5x 6h43
+WRITE_FUSES = hlhl hhll hlhh 6h43 xxxx xxxx xxxx xxxx
+FUSES_MESSAGE = 01x1xx - serial programming enabled
+FUSES_MESSAGE = x101xx - 'chip erase' does not erase eeprom
+FUSES_MESSAGE = x1x1SU - start-up delay, datasheet p23
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0196
+-i196
+-iM603
+DEVICENAME = ATmega603
+FLASHSIZE = 32768
+EEPROMSIZE = 2048
+PAGEMODE = 1
+PAGESIZE = 128
+READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+LOCK_MESSAGE = 11 - no lock
+LOCK_MESSAGE = 10 - write protected
+LOCK_MESSAGE = 00 - read/write protected
+READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx xx5x 6h43
+WRITE_FUSES = hlhl hhll hlhh 6h43 xxxx xxxx xxxx xxxx
+FUSES_MESSAGE = 01x1xx - serial programming enabled
+FUSES_MESSAGE = x101xx - 'chip erase' does not erase eeprom
+FUSES_MESSAGE = x1x1SU - start-up delay, datasheet p23
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0194
+-i194
+-iM161
+DEVICENAME = ATmega161
+FLASHSIZE = 8192
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 64
+READ_LOCK = lhlh hlll llll llll xxxx lxxx xx65 4321
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hh65 4321
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p116
+READ_FUSES = lhlh llll llll llll xxxx xxxx xDCB h987
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx hDhB h987
+FUSES_MESSAGE = 0cxcxxx - Boot reset address 0x1E00
+FUSES_MESSAGE = xcScCKS - reset delay select, datasheet p26
+WRITE_HIGH_FUSES =
+READ_HIGH_FUSES =
+HIGH_FUSES_MESSAGE =
+HIGH_FUSES_MESSAGE =
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =
+CALIB_MESSAGE =
+
+begin 0494
+-i494
+-iM162
+DEVICENAME = ATmega162
+FLASHSIZE = 8192
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 64
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock (datasheet page 218, 229)
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - divide clock by 8 (page 40)
+FUSES_MESSAGE = x0xxxxxx - CKOUT output clock on pin B0
+FUSES_MESSAGE = xxSUxxxx - start-up time (datasheet page 36-38)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (page 35-37)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx iili iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - Enable OCD (note 3, page 231)
+HIGH_FUSES_MESSAGE = x0xxxxxx - Enable JTAG (page 195)
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDT always on (page 50)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EEPROM preserved in chip erase
+HIGH_FUSES_MESSAGE = xxxxxBZx - Boot Size (datasheet page 227)
+HIGH_FUSES_MESSAGE = xxxxxxx0 - Select Reset Vector (page 219)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx hhhi iiih
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxx0xxxx - ATmega161 compatibility mode (page 5)
+EXTD_FUSES_MESSAGE = xxxxBODx - BODLEVEL (datasheet page 8)
+READ_CALIBRATION = llhh hlll llxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (page 37, 38, 232)
+
+begin 0294
+-i294
+-iM163
+DEVICENAME = ATmega163
+FLASHSIZE = 8192
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 64
+READ_LOCK = lhlh hlll llll llll xxxx lxxx xx65 4321
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hh65 4321
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p123
+READ_FUSES = lhlh llll llll llll xxxx xxxx CBxx A987
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx CBhh A987
+FUSES_MESSAGE = 0x11xxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = x011xxxx - brownout detection enabled
+FUSES_MESSAGE = xx11CKSE - clock and reset select, datasheet p5 p25
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhhh hFED
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx xxxx hFED
+HIGH_FUSES_MESSAGE = BZx - BootSZ, datasheet p134
+HIGH_FUSES_MESSAGE = xx0 - Boot reset at flash, default address zero
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (datasheet p37 p144)
+
+begin 0694
+-i694
+-iM168
+DEVICENAME = ATmega168
+FLASHSIZE = 8192
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 64
+POLL_RDY_BSY = hhhh llll llll llll xxxx xxxx xxxx xxxo
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock (datasheet page 259, 270)
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - divide clock by 8 (page 33, 273)
+FUSES_MESSAGE = x0xxxxxx - CKOUT output clock on pin B0
+FUSES_MESSAGE = xxSUxxxx - start-up time (datasheet page 27, 29-32, 273)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (page 25, 27, 29, 273)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhli iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - reset-pin disabled (page 73, 273)
+HIGH_FUSES_MESSAGE = x0xxxxxx - debugWire enabled
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDT always on (page 39, 273)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EEPROM preserved in chip erase
+HIGH_FUSES_MESSAGE = xxxxxBOD - BODLEVEL (datasheet page 43, 273)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xiii
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxxxxBZx - boot size (page 268, 269, 272)
+EXTD_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader (page 13, 271, 272)
+READ_CALIBRATION = llhh hlll lllx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (datasheet page 30, 274)
+
+begin 0693
+-i693
+-iM8515
+DEVICENAME =ATmega8515
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE =32
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock, datasheet p177
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p177
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V, datasheet p45 p179)
+FUSES_MESSAGE = x0xxxxxx - BODEN Brown-out detection enabled
+FUSES_MESSAGE = xxSUxxxx - SUT Select startup time p38
+FUSES_MESSAGE = xxxxCKSE - CKSEL Select Clock source p34
+READ_HIGH_FUSES =lhlh hlll llll hlll xxxx xxxx oooo oooo
+WRITE_HIGH_FUSES =hlhl hhll hlhl hlll xxxx xxxx iili iiii
+HIGH_FUSES_MESSAGE = 0xxxxxxx - S8515C AT90S4414/8515 compatibility mode
+HIGH_FUSES_MESSAGE = x0xxxxxx - WDTON Watchdog Timer always on
+HIGH_FUSES_MESSAGE = xx0xxxxx - SPIEN serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - CKOPT Oscillator options p34
+HIGH_FUSES_MESSAGE = xxxx0xxx - EESAVE EEPROM is preserved through Chip Erase
+HIGH_FUSES_MESSAGE = xxxxxBZx - BOOTSZ Select Boot Size p175
+HIGH_FUSES_MESSAGE = xxxxxxx0 - BOOTRST Select Reset Vector p167
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =llhh hlll llxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes, datasheet p179 p38
+
+begin 0893
+-i893
+-iM8535
+DEVICENAME =ATmega8535
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 32
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock, datasheet p234
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p234
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V, datasheet p35 p236)
+FUSES_MESSAGE = x0xxxxxx - brownout detection enabled
+FUSES_MESSAGE = xxSUxxxx - reset delay, datasheet p28
+FUSES_MESSAGE = xxxxCKSE - clock select, datasheet p23
+READ_HIGH_FUSES =lhlh hlll llll hlll xxxx xxxx oooo oooo
+WRITE_HIGH_FUSES =hlhl hhll hlhl hlll xxxx xxxx iili iiii
+HIGH_FUSES_MESSAGE = 0xxxxxxx - S8535 compatible mode
+HIGH_FUSES_MESSAGE = x0xxxxxx - WDT always on
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - CKOPT max, datasheet p23
+HIGH_FUSES_MESSAGE = xxxx0xxx - eeprom not erased
+HIGH_FUSES_MESSAGE = xxxxxBZx - boot size, datasheet p232
+HIGH_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader, p221
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION =llhh hlll llxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes, datasheet p236 p28
+
+begin 0793
+-i793
+-iM8
+DEVICENAME = ATmega8
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 32
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p116
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = x0xxxxxx - brownout detection enabled
+FUSES_MESSAGE = xxSUxxxx - reset delay, datasheet p28
+FUSES_MESSAGE = xxxxCKSE - clock select, datasheet p24
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hili iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx xooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxx - WDT always on
+HIGH_FUSES_MESSAGE = x0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xx0xxxx - CKOPT max, datasheet p24
+HIGH_FUSES_MESSAGE = xxx0xxx - eeprom not erased
+HIGH_FUSES_MESSAGE = xxxxBZx - boot size, datasheet p215
+HIGH_FUSES_MESSAGE = xxxxxx0 - reset at boot loader, p204
+HIGH_FUSES_MESSAGE = Note: RSTDISBL is 1
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll llxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes (datasheet p28 p29 p218)
+
+begin 0394
+-i394
+-iM16
+DEVICENAME = ATmega16
+FLASHSIZE = 8192
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 64
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p254
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = x0xxxxxx - brownout detection enabled
+FUSES_MESSAGE = xxSUxxxx - reset delay, datasheet p25
+FUSES_MESSAGE = xxxxCKSE - clock select, datasheet p23
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hili iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 1xxxxxxx - Disable OCD (See note 4 p.260)
+HIGH_FUSES_MESSAGE = x0xxxxxx - Enable JTAG
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - CKOPT max, datasheet p27
+HIGH_FUSES_MESSAGE = xxxx0xxx - eeprom not erased
+HIGH_FUSES_MESSAGE = xxxxxBZx - boot size, datasheet p252
+HIGH_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader, p255
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll llxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes (datasheet p27 p28 p256)
+
+begin 0295
+-i295
+-iM32
+DEVICENAME = ATmega32
+FLASHSIZE = 16384
+EEPROMSIZE = 1024
+PAGEMODE = 1
+PAGESIZE = 64
+READ_LOCK = lhlh hlll llll llll xxxx lxxx xx65 4321
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hh65 4321
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p254
+READ_FUSES = lhlh llll llll llll xxxx xxxx EDCB A987
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx EDCB A987
+FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = x0xxxxxx - brownout detection enabled
+FUSES_MESSAGE = xxSUxxxx - startup time, p25ff
+FUSES_MESSAGE = xxxxCKSE - clock select, p23ff
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx MLKJ IHGF
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx MLKJ IHGF
+HIGH_FUSES_MESSAGE = 0xxxxxxx - OCDEN 1:OCD disabled
+HIGH_FUSES_MESSAGE = x0xxxxxx - JTAGEN 1:JTAG disabled
+HIGH_FUSES_MESSAGE = xx0xxxxx - SPIEN 1: disabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - CKOPT, p24
+HIGH_FUSES_MESSAGE = xxxx0xxx - 0:EESAVE 1:EE erase
+HIGH_FUSES_MESSAGE = xxxxxBZx - BootSZ
+HIGH_FUSES_MESSAGE = xxxxxxx0 - Boot reset 1:0000 0:Bootblock reset
+WRITE_EXTD_FUSES =
+READ_EXTD_FUSES =
+EXTD_FUSES_MESSAGE =
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes
+
+begin 0592
+-i592
+-iM48
+DEVICENAME = ATmega48
+FLASHSIZE = 2048
+EEPROMSIZE = 256
+PAGEMODE = 1
+PAGESIZE = 32
+POLL_RDY_BSY = hhhh llll llll llll xxxx xxxx xxxx xxxo
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - divide clock by 8 (page 33, 273)
+FUSES_MESSAGE = x0xxxxxx - CKOUT output clock on pin B0
+FUSES_MESSAGE = xxSUxxxx - start-up time (datasheet page 27, 29-32, 273)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (page 25, 27, 29, 273)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhli iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - reset-pin disabled (page 73, 273)
+HIGH_FUSES_MESSAGE = x0xxxxxx - debugWire enabled
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDT always on (page 39, 273)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EEPROM preserved in chip erase
+HIGH_FUSES_MESSAGE = xxxxxBOD - BODLEVEL (datasheet page 43, 273)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xxxi
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxxxxxx0 - self-programming enabled
+READ_CALIBRATION = llhh hlll lllx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (datasheet page 30, 274)
+
+begin 0A93
+-iA93
+-iM88
+DEVICENAME = ATmega88
+FLASHSIZE = 4096
+EEPROMSIZE = 512
+PAGEMODE = 1
+PAGESIZE = 32
+POLL_RDY_BSY = hhhh llll llll llll xxxx xxxx xxxx xxxo
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock (datasheet page 259, 270)
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - CKDIV8 - divide clock by 8 (page 33, 273)
+FUSES_MESSAGE = x0xxxxxx - CKOUT output clock on pin B0
+FUSES_MESSAGE = xxSUxxxx - start-up time (datasheet page 27, 29-32, 273)
+FUSES_MESSAGE = xxxxCKSE - CKSEL (page 25, 27, 29, 273)
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hhli iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - reset-pin disabled (page 73, 273)
+HIGH_FUSES_MESSAGE = x0xxxxxx - debugWire enabled
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - WDT always on (page 39, 273)
+HIGH_FUSES_MESSAGE = xxxx0xxx - EEPROM preserved in chip erase
+HIGH_FUSES_MESSAGE = xxxxxBOD - BODLEVEL (datasheet page 43, 273)
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xiii
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxxxxBZx - boot size (page 268, 269, 272)
+EXTD_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader (page 13, 271, 272)
+READ_CALIBRATION = llhh hlll lllx xxxx llll llll oooo oooo
+CALIB_MESSAGE = single calibration byte (datasheet page 30, 274)
+
+begin 0297
+-i297
+-iM128
+DEVICENAME = ATmega128
+FLASHSIZE = 65536
+EEPROMSIZE = 4096
+PAGEMODE = 1
+PAGESIZE = 128
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p282
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V)
+FUSES_MESSAGE = x0xxxxxx - brownout detection enabled
+FUSES_MESSAGE = xxSUxxxx - reset delay, datasheet p38
+FUSES_MESSAGE = xxxxCKSE - clock select, datasheet p34
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx iiii iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - OCDEN enabled
+HIGH_FUSES_MESSAGE = x0xxxxxx - JTAG enabled
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - CKOPT max, datasheet p34
+HIGH_FUSES_MESSAGE = xxxx0xxx - eeprom not erased
+HIGH_FUSES_MESSAGE = xxxxxBZx - boot size, datasheet p280
+HIGH_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader, p272
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xxii
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxxxxx0x - ATmega103 compatability mode
+EXTD_FUSES_MESSAGE = xxxxxxx0 - WDT always on
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes (datasheet p39 p288)
+
+begin 0298
+-i298
+-iM2561
+DEVICENAME = ATmega2561
+FLASHSIZE = 131072
+EEPROMSIZE = 4096
+PAGEMODE = 1
+PAGESIZE = 128
+READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+LOCK_MESSAGE = xxxx11 - no lock
+LOCK_MESSAGE = xxxx10 - write protected
+LOCK_MESSAGE = xxxx00 - read/write protected
+LOCK_MESSAGE = BTLKxx - Boot lock
+READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+FUSES_MESSAGE = 0xxxxxxx - Devide clock by 8
+FUSES_MESSAGE = x0xxxxxx - Clock output
+FUSES_MESSAGE = xxSUxxxx - reset delay
+FUSES_MESSAGE = xxxxCKSE - clock select
+WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx iiii iiii
+READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+HIGH_FUSES_MESSAGE = 0xxxxxxx - OCDEN enabled
+HIGH_FUSES_MESSAGE = x0xxxxxx - JTAG enabled
+HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+HIGH_FUSES_MESSAGE = xxx0xxxx - WATCHDOG Timer always on
+HIGH_FUSES_MESSAGE = xxxx0xxx - eeprom not erased
+HIGH_FUSES_MESSAGE = xxxxxBZx - boot size
+HIGH_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader
+WRITE_EXTD_FUSES = hlhl hhll hlhl lhll xxxx xxxx xxxx xiii
+READ_EXTD_FUSES = lhlh llll llll hlll xxxx xxxx oooo oooo
+EXTD_FUSES_MESSAGE = xxxxx0xx - BODLEVEL2 Brown-out Detector trigger level
+EXTD_FUSES_MESSAGE = xxxxxx0x - BODLEVEL1 Brown-out Detector trigger level
+EXTD_FUSES_MESSAGE = xxxxxxx0 - BODLEVEL0 Brown-out Detector trigger level
+READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+CALIB_MESSAGE = four calibration bytes
diff --git a/changes.txt b/changes.txt
new file mode 100644
index 0000000..2a380d9
--- /dev/null
+++ b/changes.txt
@@ -0,0 +1,1085 @@
+ CHANGES FROM VERSION 2.1.0 TO 2.1.1
+
+ Artur Pundsack added support for the extended addressing
+ demanded by big AVR uCs like the Mega2561. The new "load
+ extended address byte" command is `hard-wired' (not part
+ of _sp12dev), so the change should be transparent even to
+ those who write their own _sp12dev entries.
+
+
+ CHANGES FROM VERSION 2.0.7 TO 2.1.0
+
+ Corrected a minor bug which prevented sp12 from dealing with the
+ ATtiny2313 - the hexadecimal part of the device code (0A91)
+ wasn't recognised.
+ Added the new programming command `poll rdy/bsy', introduced in
+ the Tiny2313. When this command is part of an _sp12dev entry (see
+ sp12dev.txt), the -o option is ignored. And for devices which obey
+ this new programming command, -o must be ignored, as -o1 would cause
+ programming errors.
+
+ Btw, you'll find that programming the Tiny2313 is a zippy process.
+ It took about 14 seconds to completely fill the flash of the old
+ AT90S2313, or nearly half a minute without optimization. Uploading the
+ same stuff to the Tiny takes just a little more than 1 second! (Or 5
+ seconds without optimization.)
+
+ A few other improvements were made:
+
+ 1) When they can't find a working parallel port, previous versions
+ tend to segfault and leave a corrupt _sp12rc behind.
+ Version 2.1 exits gracefully.
+
+ 2) Speedier blank check, thanks to Petr Slansky.
+
+ 3) Because several users put things like -rc2 and -rc3 on the
+ command line (instead of -rc10 -rc11), and were flummoxed by
+ the result, sp12 now accepts decimal calibration byte addresses.
+
+
+ CHANGES FROM VERSION 2.0.6 TO 2.0.7
+
+ Added support for Windows NT/XP. Note, the MingW (www.mingw.org)
+ compiler is used to build the Windows version.
+
+
+ CHANGES FROM VERSION 2.0.5 TO 2.0.6
+
+ Timing optimization is now available when programming page mode
+ uCs (ATmega's). In previous versions, pages were allowed to
+ settle for 64ms, as demanded by the old Mega103. Optimization
+ allows you to fully program a Mega8 in about 3 seconds instead
+ of 11 seconds.
+ However, there are combinations of target and program cable
+ (without `dongle') which cause optimization to fail; a few
+ locations which have been programmed and verified may revert to
+ 0xff while programming another page. So it was decided to keep
+ `no optimization' as the default behaviour. To increase speed,
+ use -o1. For example:
+
+ sp12 -M4 -o1 -wpf foo.hex
+
+ To make sure that optimization is alright for your hardware,
+ it should be tested with QUERY=1 in _sp12rc, or a command like
+
+ sp12 -M4 -o1 -wpfC foo.hex -Cpf foo.hex
+
+ The checksums should be equal.
+
+
+ CHANGES FROM VERSION 2.0.4 TO 2.0.5
+
+ The `read calibration byte' command is now addressable,
+ so you can read the four bytes inside for instance the ATmega8.
+ Byte 0: sp12 -rc or sp12 -rc00
+ Byte 1: sp12 -rc01
+ Byte 2: sp12 -rc10
+ Byte 3: sp12 -rc11
+
+ `CALIB_MESSAGE' has been added to _sp12dev
+
+ In the -i[nnn] command line option, nnn may now be equal to
+ either the device code (with or without leading zeroes) or the
+ device name, which can be something like AT90S1200, AT90LS1200,
+ AT90LS1200A or abbreviations like S1200, Mega128 and M8L. See
+ sp12dev.txt for more information about device names.
+
+
+ CHANGES FROM VERSION 2.0.3 TO 2.0.4
+
+ Steve broke -T and -P; repaired.
+ Increased buffer space for locks and fuses messages in _sp12dev;
+ Check on buffer overrun for same;
+ Trailing spaces quietly removed from commands in _sp12dev,
+ before checking string length.
+
+
+ CHANGES FROM VERSION 2.0.2 TO 2.0.3
+
+ Page mode now properly deals with overlays.
+ Timing now less dependent on compiler optimization setting.
+
+
+ CHANGES FROM VERSION 1.0.3 TO 2.0.2
+
+ The entire locks and fuses command set has been replaced;
+ a compatibility jump made inevitable by the proliferation of
+ fuses in the AVR family.
+
+ A plain text runtime configuration file (_sp12dev) now contains
+ the locks and fuses command definitions as well as parameters
+ like flash and eeprom size. Maintenance will hopefully be a
+ matter of adding entries to and editing this file. Have a look
+ at sp12dev.txt.
+
+ The -H is now reserved for reading and writing the `high
+ fuses'. Its old function (hex dump with ascii translation
+ modifier for the -r(ead) option) is available as -h.
+
+ Other new commands are -rc (to read the calibration byte of uCs
+ like the Tiny15, Mega8 and Mega163, command defined in _sp12dev),
+ -s (reads the list of supported uCs from _sp12dev and shows
+ them on screen) and -t, which shows a progress bar lasting
+ about ten seconds, for checking the autocalibrated timing.
+
+ The -i[nnn] option now uses the device codes:
+
+ AT90S1200(A) -i190
+ AT90S2313 -i191
+ AT90S8515 -i193
+ AT90S4414 -i192
+ AT90S2323 -i291
+ AT90S4434 -i292
+ AT90S8535 -i393
+ AT90S2343 or Tiny22 -i391
+ Tiny22L -i691
+ AT90S2333 -i591
+ AT90S4433 -i392
+ ATtiny15L -i690
+ ATmega103 -i197
+ ATmega603 -i196
+ ATmega161 -i194
+ ATmega163 -i294
+ ATmega8 -i793
+ ATmega128 -i297
+
+ And when 'KANDA' in _sp12rc is removed or set to 3, sp12 will look
+ at the name by which the program is called (sp12 or sp12.kanda,
+ sp12.exe or sp12k.exe in Dos/Windows), and adapt its parallel
+ port pinout accordingly.
+
+ No version 2.0 younger than patch level 2 has been published;
+ 1.0.3 is the final instance of version 1.0.
+
+
+ CHANGES FROM VERSION 1.0.2 TO 1.0.3
+
+ Were made according to a patch mailed to us by Eric Norum.
+ His way of dealing with root permissions is safer, because
+ sp12 now drops root permissions before accessing the file
+ system.
+
+ CHANGES FROM VERSION 1.0.1 TO 1.0.2
+
+ While making sp12 compatible with both the sp12 cable/dongle
+ and the cable/dongles supplied with the Kanda STK200/300 starter
+ kits, Steve partly broke the `port control' option (-P[nnn]).
+ Corrected.
+
+ CHANGES FROM VERSION 1.0 TO 1.0.1
+
+ A few bugs were squashed in the Intel Hex code, which caused
+ records type 2 to be misinterpreted.
+
+ CHANGES FROM VERSION 0.9 TO 1.0
+
+ The improved Intel Hex file support and multiple uC programming
+ were conceived by Kevin Towers, who also provided a large part of
+ the new code.
+ NOTE: Be sure to erase any previous runtime configuration file
+ (_sp12rc) and let this version make a new one.
+
+ NEW _sp12rc SETTINGS
+
+ You can set KANDA=1 (default is 0). SP12 1.0 is compatible with
+ three programming cables; the one as used with previous
+ versions - with or without Ken Huntington's `dongle' - and the
+ cable/dongles supplied with the Kanda STK200/300 starter kits.
+ The latter two are functionally equivalent. When `Kanda' is
+ set, the parallel port pin usage is then adapted to Kanda's,
+ which means that the port control option (see below) is of
+ limited use.
+
+ You can set a log path/file, where SP12 will log its write and
+ lock operations. The default is "sp12log.txt" in the current
+ directory.
+
+ You can set LOGGING=1 (Default is 0.) When `logging' is set,
+ every write and lock operation will cause a single line to be
+ appended to the log.
+
+ You can also set QUERY=1 (Default is 0). SP12 normally checks
+ each location (or ATmega page) right after writing; if the
+ content doesn't match what was written, SP12 retries a couple
+ of times before giving up. This procedure achieves correct
+ programming when conditions or memory cells are marginal, and
+ also catches the large majority of hard errors. But defects and
+ averse conditions may sometimes cause the content of one
+ address to change, while another is being written to. You can
+ catch these (extremely rare) errors by setting both `logging'
+ and `query'. After writing a file content into the designated
+ memory area, the flash or eeprom will then be read back and
+ compared with the file, address by address. When all is well, a
+ checksum is calculated and added to the log; else "readback
+ ERROR" is reported. For instance:
+
+AT90S2313 -wpf diz_2.hex checksum cb46 Sat Sep 23 18:43:49 2000
+AT90S2313 -wef diz_2.eep checksum 0f37 Sat Sep 23 18:43:53 2000
+AT90S2313 -wea 00000052:0xaa verified Sat Sep 23 18:43:54 2000
+AT90S2313 -wpa 00000006:0x5679 readback ERROR Sat Sep 23 19:30:24 2000
+AT90S2313 -wpf diz_2.hex readback ERROR Fri Sep 23 19:33:02 2000
+
+ NOTE: The overlay option modifies the `query' behaviour; see
+ below.
+ Lock operations are preceded by memory checksum calculations,
+ and results are logged like this:
+
+AT90S1200(A) -L3 flash cb46 eeprom 11cf Sat Sep 23 18:47:08 2000
+
+ When logging is set but query is not, the address by address
+ comparison is not performed, and writes are logged like this:
+
+AT90S2313 -wpf diz_2.hex not queried Fri Sep 29 14:42:21 2000
+AT90S2313 -wef diz_2.eep not queried Fri Sep 29 14:42:22 2000
+
+ ERROR CODES RETURNED ON PROGRAM EXIT
+
+ 0 - accomplished writing/reading task - "life is wonderful :)"
+ 1 - no device present - "nothing to do"
+ 2 - bad command line options, corrupt _sp12rc, file not found,
+ unable to write to file - "don't know what to do"
+ 3 - verification or blank check error - "device doesn't respond
+ as expected"
+
+ PROGRESS BARS
+
+ During area read and write operations, you will see a
+ progress bar like this:
+ oooooooooooooooooooooooo.......................................
+
+ NEW AND CHANGED OPTIONS
+
+ -A EESAVE fuse bit
+ The command -A0 programs the EESAVE fuse on an ATmega103
+ or 603, causing the eeprom NOT to be erased when a `chip
+ erase' is executed (by -E or -wpf). Command -A1 unprograms
+ the fuse.
+ This option can be used on its own or in combination with
+ option U, forming a word like -A0U10.
+ NOTE: When a device is locked, this fuse bit can't be
+ programmed or unprogrammed.
+
+ -H Hex dump with ascii translation modifier for the -r (read)
+ option, see below.
+
+ -I Intel Hex modifier for the -r (read) option, see below.
+
+ -i[NNN] init
+ As before, except for a few additions to the list:
+
+ Force recognition
+ with:
+ AT90S1200 -i12
+ AT90S2313 -i13
+ AT90S2323 -i23
+ AT90S2333 -i233
+ AT90S2343 -i43
+ AT90S4414 -i14
+ AT90S4433 -i433
+ AT90S4434 -i34
+ AT90S8515 -i15
+ AT90S8535 -i35
+ ATTiny22 -i22
+ ATmega103 -i103
+ ATmega603 -i603
+
+ -M[n.n] uC clock frequency
+ n.n is the uCs clock speed in MHz, not lower than 0.1.
+ _sp12rc contains autocalibrated timing data (delay caused
+ by outportb(), loop count/s), from which an Sck frequency is
+ calculated, fitting the uC's clock speed as indicated by
+ -Mn.n. You can safely set -Mn.n lower than the default (also
+ in _sp12rc), but only if the command precedes all others
+ except -i<nn>. For instance:
+
+ sp12 -M4 -wpf foo.hex
+ sp12 -i103 -M4 -wpf foo.hex
+
+ When this option is not on the command line, the default
+ is used. Unless you change it (in _sp12rc), the default
+ makes sp12 version 1.0 behave like previous versions, which
+ means that the Sck frequency and wave form will be suitable
+ for uCs running on an internal RC clock, at fairly low Vcc.
+ WARNING: When -Mn.n is set too high, the uC will misread
+ commands and fill its memory with garbage.
+ NOTE: In practice, the outportb() function needs a certain
+ amount of time to actually change a parallel port data bit.
+ Depending on the hardware, this is likely to limit the
+ shortest timing to about 1.3us for an Sck half cycle. Most
+ AVR uCs need the Sck low and high phases to be at least two
+ clock cycles long; the AT89S1200 is an exception, needing an
+ Sck high phase of at least four clock cycles.
+ So while SP12 works correctly with very fast uCs, the time
+ needed to execute a command line is not likely to decrease
+ for Mnn settings above 3MHz for the 1200, and 1.5MHz for
+ the other family members. SP12 reports the timing achieved.
+
+ -O overlay
+ The commands -wpf and -wef cause SP12 to read files into
+ 0xFFFF or 0xFF padded buffers, and to make sure that the
+ flash or eeprom area contains the buffer image after
+ programming is done. -wpf is automatically preceded by a
+ `chip erase', and -wef writes 0xFF into all addresses which
+ don't have their content specified by the file (addresses
+ which already contain 0xFF are skipped). This guarantees
+ that programming is actually possible (new uploads to
+ flash could easily conflict with `leftovers' from previous
+ work). It also results in equal checksums for uC content
+ and file.
+ However, You may sometimes want to add calibration
+ constants, configuration data and/or serial numbers to
+ what's already in flash or eeprom. To overlay files on
+ data already in the uC's memory, you'd do:
+
+ sp12 -Owpf foo.hex -Owef foo.eep
+
+ In combination with -wpf, the -O precludes chip erase.
+ If there is a conflict, the flash overlay will stop with an
+ error report - it isn't possible to write a 1 over a 0 in an
+ AVR flash location. However, foo.eep is always written, even
+ if it (partially) replaces earlier data.
+ Both -Owpf and -Owef only upload the file (as opposed to
+ the buffer) and cause a query (performed when `logging' and
+ `query' are set in _sp12rc) to also be limited to the
+ file, or where the flash area is concerned, to addresses
+ which according to the file should contain something other
+ than 0xffff.
+ Checksums are always calculated for the entire area, as the
+ commands -Cp and -Ce refer to the entire uC areas. So
+ after an -Owpf or -Owef, the log will show a checksum
+ which only matches area content. The overlayed files each
+ have their own checksum.
+
+ -P[nnn] Port control
+ When used as the final option on the command line, this
+ option leaves the parallel port data pins in the state
+ determined by NNN, which can be a decimal or hexadecimal
+ number: For instance, -P124 and -P0x7C both leave the
+ port in 01111100 state. When used like this:
+
+ SP12 -P4 -wpf uC1.hex -P8 -wpf uC2.hex -P2
+
+ The first two -P's are limited to controlling pins 2-6
+ (those not used for the programming interface itself).
+ Kevin invented this usage for programming two AVR uCs
+ on a single board, using a single connector and a single
+ command. There is a 10ms delay after each -P, to give
+ analog switches on the target board some time to do their
+ job.
+ NOTE: You can't use Ken Huntington's `dongle' together
+ with option -P, since buffers inside it are powered as well
+ as high-Z/enabled using the data 2-6 pins. So only the exit
+ state of the parallel port can be set, as with the old -T
+ option (see below).
+ NOTE: it is possible to set different communication speeds
+ for each uC, using the -Mn.n command, but you have to put
+ the -P first on the command line:
+
+ SP12 -P4 -M0.2 -wpf uC1.hex -P8 -M4 -wpf uC2.hex -P2
+
+ NOTE: -P has immediate control over data pins 2-6 only
+ when it's the first option on the command line. In this
+ case:
+ SP12 -iNNN -P4 -wpf ...
+
+ Pins 2-6 will all be high during init, which takes about a
+ quarter of a second, depending on settings in _sp12rc and
+ the possible need for resynchronization of the uC's
+ programming interface.
+
+ NOTE: When sp12 is used with the Kanda STK200 cable/dongle,
+ a -P which is not the final option on the command line will
+ control only data bits 0, 1 and 6. Bits 2 and 3 have to be
+ used to high-Z/enable buffers inside the Kanda dongle; bits
+ 4 and 7 are programming lines, and bit 7 handles reset.
+
+ -r read
+ To read from either program or eeprom area, a single address
+ (-rpa address, or -rea address) or the whole area. In the
+ latter case output can be directed to a file using the -f
+ option: -rpf foo.rom reads the program area and writes an
+ image into foo.rom. Use of the `I' modifier (-rpfI foo.hex)
+ changes the format from `native' avrasm to Intel Hex, while
+ use of `H' (-rpH to screen or -rpfH foo.dmp to file)
+ results in a hex dump with ascii translation, ending with
+ a checksum:
+
+ 000078 95 08 24 ee 24 ff 27 cc 77 d7 ..$.$.'.w.......
+ 000080 bf 02 2f 4d 70 47 30 45 f0 10 ../MpG0E..=...h.
+ 000088 e0 00 16 e0 f0 89 16 f0 f0 79 .........y...i..
+ 000090 f4 18 16 fc f4 08 c0 04 14 fe ...........0...
+ Checksum: cb46
+
+ The above is just a sample of (shortened) lines taken from
+ actual output.
+ NOTE: 16-bit word addresses are used when displaying the
+ program space, and words are shown hi byte first.
+ By default, data read from the eeprom area is presented in
+ this format:
+
+ Address: Data in hex, dec, oct, bin
+ 0000: 0xc0 192 0300 11000000
+ 0x01: 0x99 153 0231 10011001
+
+ Or in this format when a single address is read to the screen
+ (stdout):
+
+ The byte 0x99 (153, 0231, B10011001) was read from
+ eeprom address 0x0001
+
+ But you can also use the commands -reH, -refH or -refI
+ with appropriate effect. Byte addressing is used for the
+ hex dump display.
+
+
+ -T This option was retained to remain compatible with older
+ versions, but option -P offers much more control over the
+ parallel port.
+ By default, SP12 will leave the Centronics parallel port
+ databits all zero on exit. Command -T1 leaves the reset
+ pin high, so a connected device will start running immediately
+ after SP12 has finished, assuming it uses an external power
+ source. Command -T2 also leaves the `powerbits' (2-6, as
+ shown by progrmmr.gif) high, to run a device without external
+ power.
+
+ -U[nn] SUT fuse bits
+ The command -U[nn] programs the SUT fuses on an ATmega103
+ or 603, thus enabling various reset delays as detailed in
+ the datasheet (page 23/24, tables 5 and 6, 11/1999).
+ This option can be used on its own or in combination with
+ option A, forming words like -A0U10 (see `examples' below).
+
+ EXAMPLES OF THE NEW OPTIONS
+
+ When an ATmega103 or 603 is connected, the command
+ SP12 -rF
+ Will result in something like:
+
+ The following information was read from the
+ lock and fuse bits:
+ Start-up time code selected is 3 (16K WDT cycles)
+ EEPROM is NOT preserved thru chip erase
+ Device is not protected
+
+ When an AT90S2333 or 4433 is connected, the command
+ SP12 -rF
+ Will result in something like:
+
+ The following information was read from the
+ lock and fuse bits:
+ Brown-out detection enabled.
+ Brown-out trigger set at 4.0V.
+ CKSEL = 100 (datasheet page 20, table 5)
+ Device is not protected
+ Writing 0 to all Centronics data bits.
+
+ But when an AT90S2343 is connected, you might see
+
+ The following information was read from the
+ lock and fuse bits:
+ Internal RC clock enabled.
+ Device is write-protected.
+
+ And when an AT90S4434 or 8535 is connected, the report might be:
+
+ The following information was read from the
+ lock and fuse bits:
+ Short start-up time selected.
+ Device is write-protected.
+
+ The command:
+ SP12 -A0U10
+ Will cause the eeprom NOT to be erased when a `chip erase' is
+ executed (by -E or -wpf). The reset delay is set at 4K WDT
+ cycles. SP12 will report:
+
+ The following information was read back from
+ the fuse bits:
+ Start-up time code selected is 2 (4K WDT cycles)
+ EEPROM is preserved thru chip erase
+
+ The command:
+ SP12 -M4 -wpf foo.hex
+ Will attempt to set communication timing to match a device
+ clock speed of 4MHz. Hardware will usually limit the achievable
+ com speed, so while SP12 works correctly with very fast uCs, the
+ time needed to execute a command line is not likely to decrease
+ for Mnn settings above 1.5MHz. SP12 will report the speed
+ actually achieved. For instance:
+
+ Sck timing set for 1.5MHz or higher.
+
+ The command:
+ SP12 -Owpf foo.hex -Owef foo.eep
+ Will NOT erase the device before writing in the new data.
+ The files foo.hex and foo.eep are added to what is already in the
+ flash and eeprom area's. If there is a conflict, the flash
+ overlay will stop with an error report - it isn't possible to
+ write a 1 over a 0 in an AVR flash location. However, foo.eep is
+ always written, even if it (partially) replaces earlier data.
+
+ With suitable hardware, this command:
+ SP12 -P4 -wpf uC1.hex -P8 -wpf uC2.hex -P2
+ will program two uCs on a single target board, using a single
+ command line. The first -P would make parallel port data bit 3
+ high, making a set of analog switches route the programming lines
+ to the first uC. The second -P disconnects the first and connects
+ the second uC. Finally, the third -P leaves reset high when SP12
+ exits, allowing the new software to run. There is a 10ms delay
+ after each -P, to give analog switches on the target board some
+ time to do their job.
+
+ The command:
+ SP12 -rpfH foo.dmp
+ Reads the program area and writes a `hex dump with ascii
+ translation' into the file foo.dmp. If you type just -rpH, the
+ output is directed to the screen (stdout). You can dump the
+ eeprom area using -refH.
+
+ The command:
+ SP12 -rpfI foo.hex
+ Reads the program area and writes it into the Intel HEX file
+ foo.hex. -rpI (without the f) is not a valid command. You can
+ dump the eeprom area using -refI.
+
+
+ CHANGES FROM VERSION 0.8 TO 0.9
+
+ NOTE: Be sure to erase any previous runtime conifiguration file
+ (_sp12rc) and let this version make a new one.
+
+ SP12 0.8 works reliably with most AVR uCs, parallel ports and
+ target boards. But some hardware combinations can be
+ recalcitrant. To deal with start-up transients, SP12 0.9
+ implements the automatic SPI resynchronization procedure as
+ recommended by Atmel. And to increase programming speed as well
+ as reliability at marginal voltages, the Bytewrite time constant
+ is dynamically adjusted (details below).
+ The signal provided by some parallel ports just isn't good
+ enough, no matter what the software does. The new `dongle'
+ designed by Ken Huntington (dongle.gif) takes care of that.
+ It also has the advantage of being high-Z except when SP12
+ is active, and you don't need Sck termination (as shown in
+ progrmmr.gif and icp_intr.gif) when using it.
+
+ NOTE: The dongle is perfectly transparent to the software, so
+ you can still use a plain cable without any changes whatsoever.
+ Power for the dongle is provided by the parallel port, which is
+ still able to provide power for a small target board as well
+ (Icc up to about 5mA).
+ NOTE: when using the dongle, your target board should have a
+ reset circuit - at the very least a 10K resistor between the
+ uC's reset pin and Vcc.
+
+ The software changes in detail:
+
+ 1) All supported AVR uCs except the AT90S1200(A) should answer
+ the programming enable command by echoing 0x53 on Miso, while
+ the third byte of the command is being transmitted. If they
+ don't, the SPI shift register may be desynchronized. This
+ version of SP12 will try to resynchronize in such cases.
+
+ 2) The high pulse on the reset line (part of the power-on sequence)
+ now has a width which can be altered by editing the RESETPULS
+ value in _sp12rc. The default is long enough (100us) to make
+ SP12 live with a 100N cap on the reset line, as shown in
+ icp_intr.gif.
+
+ NEW AND CHANGED OPTIONS
+
+ -o optimization
+ Default (option not on command line): the Bytewrite time
+ constant - which determines how much time a flash or eeprom
+ address gets to settle, after it has been written to - is
+ dynamically adjusted, with the value in _sp12rc as upper limit.
+ This makes SP12 0.9 program significantly faster than the older
+ versions when conditions allow, and should cause less trouble
+ at low Vcc. As older versions of the AT90S1200 were found to
+ react unreliably when a flash address is polled during
+ programming, default behaviour is to not optimize when a
+ 1200(A) is detected, or when its recognition is forced using
+ option -i12.
+ Level 0 (-o0): No optimization for any uC.
+ Level 1 (-o1): forces optimization for all uCs, including the
+ 1200(A).
+ NOTE: If used, this option must be the first option on the
+ command line, or the first after -i[NNN]
+ NOTE: Allow this version to make a new _sp12rc, because it
+ should have 12ms as default.
+
+ Faster performance is achieved only when the program and/or
+ eeprom data file being uploaded to the uC have a certain
+ length, as the algorithm adjusts towards shorter values in
+ steps of default/12, one step per address. Once the time
+ constant appears too short, the algorithm backs up a step and
+ sets a flag. If a survivable verify error occurs after this,
+ the adjustment is restarted at the default value.
+
+ Polling (as mentioned in the AVR datasheets) is used to
+ determine whether the time constant is long enough. So why not
+ just use polling? Because there are values for which polling
+ can't be used, which vary with the uC. An adjusted time
+ constant also prevents quite a bit of PC/uC communication.
+
+ As you can see below, the wait period required before a value
+ written to flash or eeprom `settles' is closely related to Vcc.
+ I tried programming at 2.5 < Vcc < 5V on two 2313-10PCs, a
+ 2313-4PC and a 4433-8PC. Here are the results (fixed pitch font
+ table):
+
+ 2313-10PC 2313-4PC 4433-8PC
+ % of 12ms % of 12ms % of 12ms
+ Vcc -wpf -wef -wpf -wef -wpf -wef
+
+ 5.0 16 16 16 16 16 16
+ 4.5 16 16 16 16 16 16
+ 4.0 25 25 25 25 25 25
+ 3.5 33 33 33 33 33 33
+ 3.0 50 50 50 50 41 41
+ 2.5 83 83 75 75 75 75
+
+ NOTE: All programming runs were perfect; no verify errors,
+ always the same checksums. Nevertheless, 2.5V should be
+ considered to be too low for comfort.
+
+ EXAMPLES OF THE NEW OPTION
+
+ To force byteWrite optimization for a 1200:
+ SP12 -o1 -wpfC foo.hex -Cpf foo.hex
+ Or:
+ SP12 -i12 -o1 -wpfC foo.hex -Cpf foo.hex
+ Compare the two checksums to make sure that the upload was
+ correct.
+ To force a fixed byteWrite equal to the value in _sp12rc
+ (behaviour equal to previous versions):
+ SP12 -o0 -wpf foo.hex
+
+
+ CHANGES FROM VERSION 0.7 TO 0.8
+
+ 1) Support for the AT90S2333 and 4433 has been added, and the
+ FSTRT-bit of the 2323 is now accessible:
+
+ Read, set/clear:
+ Lock RCEN FSTRT BODEN BODLEVEL CKSEL
+ AT90S1200
+ AT90S2313
+ AT90S2323 YES YES
+ AT90S2333 YES YES YES YES
+ AT90S2343 YES YES(*)
+ AT90S4414
+ AT90S4433 YES YES YES YES
+ AT90S4434 YES YES
+ AT90S8515
+ AT90S8535 YES YES
+ ATTiny22 YES YES(*)
+
+ (*) The 2343 is still treated as if it has an RCEN-bit, which
+ may not be true for the series now being sold - the 02/2000
+ errata sheet for the Tiny22 says "If external oscillator is
+ required, use the 100% pin- and code-compatible
+ AT90S/LS2343 which has external clock option only."
+ It appears that the RCEN fuse proved recalcitrant in some
+ cases, and Atmel felt this to be the quick and safe
+ solution.
+ (**) The same errata sheet says that only the Tiny22L is now
+ available, with the internal RC oscillator as the single
+ clock option. However, I have several Tiny22s with a
+ switchable RCEN fuse, making them fully compatible with a
+ number of clock-switchable 2343s I have lying around.
+ Moreover, my Tiny22 (8PC) chips even have the same
+ signature bytes (device code) as my 2343s...
+ To make all versions as useful as possible, it was decided
+ to make SP12 version 0.8 treat all Tiny22s and 2343s as if
+ they are identical, and have a switchable RCEN fuse. It's
+ up to the user to determine or find out the use of of the
+ -R0/R1 option.
+
+ -K[NNN] CKSEL fuse bits
+ The command -Knnn programs the CKSEL fuses on an AT90S2333
+ or 4433, thus enabling various reset delays as detailed in
+ the datasheet (page 20, table 5, 04/1999). This option can
+ be used on its own or in combination with options D and V.
+ NOTE: This option must be the final one on your command
+ line. If options -D and/or -V are also used, you must
+ combine them with -K to form a single command word. (See
+ `examples' below.)
+
+ -D BODEN fuse bit
+ The command -D0 programs the BODEN fuse on an AT90S2333
+ or 4433, enabling brown-out detection. Command -D1
+ unprograms the fuse, switching brown-out detection off.
+ This option can be used on its own or in combination with
+ options K and V.
+ NOTE: This option must be the final one on your command
+ line. If options -K and/or -V are also used, you must
+ combine them with -D to form a single command word. (See
+ `examples' below.)
+
+ -V BODLEVEL fuse bit
+ The command -V0 programs the BODLEVEL fuse on an AT90S2333
+ or 4433, setting the brown-out detection level to 4.0V.
+ Command -V1 unprograms the fuse, setting the lever to 2.7V.
+ This option can be used on its own or in combination with
+ options K and D.
+ NOTE: This option must be the final one on your command
+ line. If options -K and/or -D are also used, you must
+ combine them with -V to form a single command word. (See
+ `examples' below.)
+
+ -i[NNN] init
+ As before, except for a few additions to the list:
+
+ Force recognition
+ with:
+ AT90S1200 -i12
+ AT90S2313 -i13
+ AT90S2323 -i23
+ AT90S2333 -i233
+ AT90S2343 -i43
+ AT90S4414 -i14
+ AT90S4433 -i433
+ AT90S4434 -i34
+ AT90S8515 -i15
+ AT90S8535 -i35
+ ATTiny22 -i22
+
+ EXAMPLES OF THE (NEW) OPTIONS
+
+ When an AT90S2333 or 4433 is connected, the command
+ SP12 -rF
+ Will result in something like:
+
+ The following information was read from the
+ lock and fuse bits:
+ Brown-out detection enabled.
+ Brown-out trigger set at 4.0V.
+ CKSEL = 100 (datasheet page 20, table 5)
+ Device is not protected
+ Writing 0 to all Centronics data bits.
+
+ But when an AT90S2343 is connected, you might see
+
+ The following information was read from the
+ lock and fuse bits:
+ Internal RC clock enabled.
+ Device is write-protected.
+
+ And when an AT90S4434 or 8535 is connected, the report might be:
+
+ The following information was read from the
+ lock and fuse bits:
+ Short start-up time selected.
+ Device is write-protected.
+
+ The command:
+ SP12 -D0V0K100
+ Will switch on the brown-out detection of an AT90S2333 or 4433,
+ set the detection level to 4.0V and provides a start-up delay
+ of 16K CK (datasheet 04/1999, page 20, table 5). SP12 will
+ report:
+
+ Brown-out detection enabled.
+ Brown-out trigger set at 4.0V.
+ CKSEL = 100 (datasheet page 20, table 5)
+ (Re)enabling brown-out detection usually causes the
+ AT90(L)S2333/4433 to hang, so there is nothing further
+ to do for SP12. Before programming can continue, power
+ to the 2333/4433 must be switched off and back on again.
+ Writing 0 to all Centronics data bits.
+
+ Atmel had this to say about the `hangup' mentioned above:
+
+ "This is a known problem with the current revision of the
+ AT90S4433. There is no other workaround than to program the
+ BODEN bit after you have programmed the flash and the EEPROM."
+ (Communication via Mark Korsloot of Alcom, the Dutch
+ distributor of Atmel products, on 27 Apr 2000.)
+
+ When this version of SP12 was prepared, the AT90(L)S2333 was
+ not available. (Re)enabling BOD may or may not cause this uC to
+ hang, but it seems best to make fuse programming the final
+ word on your command line. So if you want to write to eeprom
+ and flash, lock the device and program the fuses in one go,
+ this is the correct order of the command words:
+
+ SP12 -wpf prog.hex -wef data.epr -L3 -D0V0K100
+
+ The flash must be written to first, because that command first
+ erases the device. The fuses can be programmed after locking
+ the device, because in serial programming mode, you have access
+ to the fuse bits even when a device is locked mode 3.
+
+ Using one of the fuse programming options on its own is of
+ course possible. The command:
+ SP12 -V1
+ Sets the brown-out detection level of an AT90S2333 or 4433 to
+ 2.7V.
+
+
+ CHANGES FROM VERSION 0.6 TO 0.7
+
+ 1) Kevin Towers reported:
+ --------------------------------------------------------------------
+ I just downloaded your SP12 programmer source the other day and
+ tried to get it to work. After a few hours, I figured out the
+ timing was inaccurate. I'm running a 400Mhz Celeron A processor.
+ I read your doc files and noted that someone had bumped the numbers
+ by 40%. I found this was not enough.
+ --------------------------------------------------------------------
+
+ The autocalibration of the timing loops has been rewritten and
+ tested in cooperation with Kevin Towers and Ken Huntington. It is
+ now more accurate as well as faster than it used to be.
+
+ NOTE: The timing has been split into autocalibrated loops for the
+ constants which should be shorter than 10 milliseconds (sckLO,
+ sckHI and byteWrite) and delay() calls for the other three. So when
+ upgrading from a previous SP12 version, you MUST erase your old
+ _sp12rc(s), to let version 0.7 write new ones.
+
+ 2) Kevin Towers improved the code for reading Intel HEX files, to be
+ compatible with flash data as generated by the IAR C compiler.
+
+ 3) Atmels AT90S2323 datasheet specifies the wrong signature bytes,
+ which caused SP12 version 0.6 not to recognize this device. Atmel
+ has since confirmed the correct signature, which been compiled into
+ version 0.7.
+
+ 4) An option like this has been demanded by many. It has the
+ disadvantage of leaving the Centronics parallel port in a state
+ other than zero, which may conflict with the next device you
+ connect. Use with care.
+
+ -T By default, SP12 will leave the Centronics parallel port
+ databits all zero on exit. Command -T1 leaves the reset
+ pin high, so a connected device will start running immediately
+ after SP12 has finished, assuming it uses an external power
+ source. Command -T2 also leaves the `powerbits' (2-6, as
+ shown by progrmmr.gif) high, to run a device without external
+ power.
+
+ 5) There is now a single source for the Dos and Linux versions of
+ SP12, as initiated by Jean-Jacques Michel (see linux.doc in the
+ SP12v0_7-linux.tgz or SP12v0_7-linux-static.tgz).
+
+
+ CHANGES FROM VERSION 0.5 TO 0.6
+
+ Chris Jackson reported:
+ --------------------------------------------------------------------
+ I've recently built your SP12 programmer for the Atmel AVR
+ microcontroller. In the documentation you mention that the
+ software apparently doesn't work in a Windows98 DOS box. I'm happy
+ to report that this isn't the case, as it works quite happily in
+ both WIndows95 and Windows98 for me.
+
+ I have had a couple of problems though:
+
+ 1. One of the machines that I tried it on had a Parallel Port
+ PCMCIA adapter installed. Unless the machine was powered up with
+ this device fully disconnected, the driver for it was loaded by
+ Windows. This meant that whenever SP12 set the port lines high,
+ the driver would kick in and set them back low again. Depending on
+ the speed of the driver's response, the programmer would sometimes
+ work, and sometimes not - which caused a bit of confusion at first.
+
+ 2. The software doesn't work reliably on any computer with a
+ PentiumII processor running at >=350MHz. The problem is in the
+ initialization of the timing loop, which doesn't have the
+ resolution to cope with such high speed processors. You can work
+ around this by manually editing the _sp12rc file until the values
+ are large enough to make it work.
+
+ I have recompiled the software using MS VisualC++, using the
+ system's high resolution timer. This gives me reliable software
+ without tweaking the _sp12rc file, but it is more tied to Windows
+ than it was before. Also, Microsoft have removed support for the
+ outportb() and inportb() functions, so I had to use inline
+ assembler for those. It looks as though it will be impossible to
+ access the parallel port in this way when WindowsNT takes over,
+ which will be unfortunate.
+ --------------------------------------------------------------------
+
+ Chris later recompiled SP12 using Borland C++ 4.5 with no changes
+ to the source code. It worked without problems on all machines he
+ tried it on up to a processor speed of 400MHz. When he tried
+ it on a 450MHz machine, it didn't work but increasing the SCKLO and
+ SCKHI values in _sp12rc by just 40% made it work OK. He supposes
+ that this could be accounted for by inaccuracies in the timing
+ initialisation. It now looks as if programs compiled with Turbo C
+ may have problems with newer high speed Pentiums.
+
+ The present 32-bit protected mode version 0.6 was compiled with gcc
+ (Free Software Foundation, as found in the djgpp package). It does
+ a better job of calibrating its timing, which takes care of problem
+ number 2 above, as Chris confirmed. His other remarks remain valid;
+ SP12 has no way to deal with MS Windows related port conflicts and
+ access problems. It isn't Windows software and probably never will
+ be. And Windows-NT does not provide the parallel port access
+ required by SP12.
+
+
+CHANGES FROM VERSION 0.4 TO 0.5
+
+ Support has been added for seven other AVR uCs. On all of them,
+ you have read and write access to the flash and eeprom memory
+ (from/to file or single address), and you can set the lock bits.
+ Some of them offer extra functions as shown in the table:
+
+ Read access to set/clear set/clear
+ lock & fuse bits RCEN FSTRT
+ AT90S1200
+ AT90S2313
+ AT90S2323 YES
+ AT90S2343 YES YES
+ AT90S4414
+ AT90S4434 YES YES
+ AT90S8515
+ AT90S8535 YES YES
+
+ Note that on `YES' marked devices, you have access to the fuse
+ bits even if the device is locked. For instance, you can switch
+ the 2343 from internal to external clock oscillator and back
+ even if you can't read the program inside.
+
+ NEW AND CHANGED OPTIONS
+
+ -C calculate checksum
+ Unchanged, but note the support for files in Intel HEX format:
+ Using files in Intel HEX format makes no difference to the
+ checksum. If foo.rom is the same program as foo.hex, then -Cpf
+ foo.rom and -Cpf foo.hex result in the same checksum.
+ And mark the following note:
+ NOTE: The checksum value depends on what's in the buffer and
+ also on the total size of the buffer. So if you move a file
+ from an AT90S2313 to an AT90S8515, the checksum changes.
+ -i12 -Cpf foo.rom and -i15 -Cpf foo.rom show different
+ checksums for the same file, matching those calculated when
+ doing -Cp with a 1200 or an 8515 connected.
+
+ -E chip erase
+ A blank check no longer follows automatically. Imho there is
+ something to be said for checking results if they can be
+ checked, but it does take time and is in this case necessary
+ only if you suspect trouble.
+ Using options -w, -p and -f together (to write a file
+ from disk to program area) is still automatically preceded by
+ an erase, but not by a blank check. So -wpf foo.rom is now
+ equivalent to -Ewpf foo.rom. -Bwpf foo.rom causes a blank
+ check between the automatic erase and the upload of foo.rom.
+ -E merely does an erase, -EB means erase and blank check.
+
+ -f filename next
+ The upload of files in Intel HEX format is now supported:
+ Program files must be either in the Atmel `generic' format or
+ in Intel HEX format, both as provided by the Atmel assembler
+ (w)avrasm.exe version 1.03 or higher. SP12 recognizes the file
+ by content, so you don't need to use specific extensions;
+ but .rom and .hex do seem logical.
+ The generic format contains only lines like 00000c:99e1 (both
+ address and data in hexadecimal notation without prefix; six
+ digits for the address, four for the data).
+ Eeprom files must be either in SP12 `native' format, or Intel
+ HEX format as provided by (w)avrasm.exe version 1.21 or
+ higher. To conform to SP12 format, the file must contain only
+ lines like 0x0d:0xcf (Address in hexadecimal, decimal or octal
+ notation, data in hexadecimal, decimal, octal or binary
+ notation, all with appropriate prefix. So the lines 0x0d:153,
+ 13:0231 and 015:B10011001 have the same meaning.)
+
+ -F Lock and fuse bits
+ Use in combination with -r to make the command -rF, for
+ reading the lock and fuse bits. Valid only if an AT90S2323,
+ 2343, 4434 or 8535 is connected.
+
+ -i[NN] init
+ As before, except the following:
+ ...Next the device code of your device (contained in the
+ signature bytes) will be read to determine which member of
+ the AVR family has been connected. This enables SP12 to use
+ the correct programming command subset and to know the size
+ of the flash and eeprom memory. When a device has been
+ locked mode 3, the device code (signature bits) will be
+ unreadable. To regain access, you must put a two-ddigit number
+ behind the -i, thus forcing SP12 to assume that a certain
+ device is connected. Here is a table of supported uCs and init
+ numbers:
+ Force recognition
+ with:
+ AT90S1200 -i12
+ AT90S2313 -i13
+ AT90S2323 -i23
+ AT90S2343 -i43
+ AT90S4414 -i14
+ AT90S4434 -i34
+ AT90S8515 -i15
+ AT90S8535 -i35
+
+ -i0, -i or no use of this option (when there are others on
+ the command line) results in automatic init and device check.
+ NOTE: option -iNN must be the first on the command line.
+ NOTE: init is the only valid option if no device is connected,
+ though you might for instance check a file checksum using
+ -i15 -Cpf foo.hex, if foo.hex is intended for the 8515.
+
+ -R RCEN fuse bit
+ The command -R0 programs the RCEN bit on an AT90S2343, thus
+ enabling the internal RC clock oscillator. Command -R1
+ unprograms the bit, switching the internal clock off.
+ While RCEN is available on other AT90S uCs, it can only be
+ accessed by a serial programmer (like SP12) on the 2343.
+
+ -S FSTRT fuse bit
+ The command -S0 programs the FSTRT bit on the AT90S4434 and
+ 8535, thus selecting the fast start-up time. Command -S1
+ unprograms the bit, selecting the default (long) start-up
+ time.
+
+ -w write
+ As before, except:
+ NOTE: All writes are automatically verified; SP12 immediately
+ reads back from the current address and compares the response
+ with the data that was written. If the response is not
+ correct, SP12 tries to write to the same address two more
+ times before coming back with "ERROR: Verify has failed."
+
+ EXAMPLES OF THE NEW OPTIONS
+
+ When an AT90S2343 is connected, the command
+ SP12 -rF
+ Will result in something like:
+ The following information was read from the
+ lock and fuse bits:
+ Internal RC clock enabled.
+ Device is write-protected.
+ But when an AT90S4434 or 8535 is connected, you might see:
+ The following information was read from the
+ lock and fuse bits:
+ Short start-up time selected.
+ Device is write-protected.
+
+ The command:
+ SP12 -R0
+ Will program the RCEN fuse bit on an AT90S2343, enabling the
+ internal RC clock oscillator.
+ On an AT90S4434 or 8535, the command:
+ SP12 -S0
+ programs the FSTRT fuse bit, to select the short start-up time.
+
+INTERACTIVE USE
+ The interactive human interface is still on the `to do' list.
+ It will probably appear in version 0.7.
+
+
+CHANGES FROM EARLIER VERSIONS:
+
+ Version 0.3 and before needed free access to the Reset pin as well
+ as MOSI, MISO and SCK. As of 0.4, the timing has been altered to
+ cater for the use of a 10K resistor and a 100N (100 nano-farad)
+ capacitor, which make power-on reset more reliable. That
+ combination allows SP12 sufficient access to Reset. Check
+ icp_intr.gif for details.
+
+ No operational changes before this.
diff --git a/dongle.gif b/dongle.gif
new file mode 100644
index 0000000..5be5d0f
--- /dev/null
+++ b/dongle.gif
Binary files differ
diff --git a/dongle.txt b/dongle.txt
new file mode 100644
index 0000000..485283e
--- /dev/null
+++ b/dongle.txt
@@ -0,0 +1,27 @@
+The `dongle' shown here (dongle.gif) was designed by Ken Huntington
+(kenh@compmore.net). It is perhaps unique in not `protecting' a
+copyright, being perfectly transparent to the sp12 software - so you
+can still use a plain cable with this version. And the dongle has no
+power requirements; the 74HC126 receives its Vcc from the port. Yet
+it significantly improves the signal quality. The Sck termination
+(as shown in progrmmr.pdf and icp_intr.pdf) becomes superfluous when
+using it. Some parallel ports won't reliably communicate with an AVR
+uC without it. Moreover, the programming lines are high-Z except
+when sp12 is active.
+
+Apart from powering the dongle, your parallel port will also still
+be able to provide power for a small target board (Icc up to about
+5 mA). When using external power, the high-Z lines make the order of
+switch-on and connection less critical. You can switch on the target
+board first and then connect it to the PC, or make the connection
+and switch it on afterwards. But do make sure that your board resets
+properly! The absolute minimal `reset circuit' is a resistor of
+about 10K between Vcc and the uC's reset pin.
+
+A pcb layout for the dongle can be found on the sp12 Web page:
+
+ http://www.xs4all.nl/~sbolt/e-spider_prog.html
+
+There are also photo's of our prototypes. A 74HC126 is preferred,
+but the dongle does seem to work well enough with a 74HCT126, if the
+parallel port provides a reasonable Vcc value.
diff --git a/hardware.txt b/hardware.txt
new file mode 100644
index 0000000..cf327a6
--- /dev/null
+++ b/hardware.txt
@@ -0,0 +1,65 @@
+
+HARDWARE CONNECTIONS
+
+ SP12 expects the AVR uC to be connected to the parallel port of
+ your PC. Look at progrmmr.gif and icp_intr.gif for details.
+ A plain cable as shown in those illustration often works, but
+ adding Ken Huntington's `dongle' (dongle.gif) is recommended. It
+ helps when the parallel port signal is marginal, and avoids the
+ need for Sck termination cap and resistor as shown in the other
+ illustrations. It also makes the cable high-Z except when sp12
+ is active, which can be very useful. And it is perfectly
+ transparent to the software, except that you can't use the port
+ control option (see sp12.txt).
+
+ Sp12 can also adapt its use of the paralel port to the
+ cable/dongles supplied with the Kanda STK200/300 starter kits.
+ (See sp12rc.txt)
+
+ NOTE: when using a dongle, your target board should have a
+ reset circuit - at the very least a 10K resistor between the
+ uC's reset pin and Vcc.
+
+ WARNING: The `VCC' connection should only be made if the pcb
+ containing the microcontroller has to use the parallel port as
+ its power supply. This can be done safely if a supply current of
+ less than 5 mA is sufficient, which is the case if you are using a
+ `stand alone' programmer board with just a clock generator and a
+ Zip socket for the microcontroller. SP12 will then automatically
+ switch the supply current on and off as appropriate. This works
+ with or without the `dongle' mentioned above, which is always
+ powered by the parallel port.
+
+ NOTE: The AVRCOM software found in previous SP12 packages has
+ been replaced by the AVRmon package, which uses the programming
+ lines Sck, Miso and Mosi. It offers interactive access to your
+ AVR target hardware. You'll find it here:
+
+ http://www.xs4all.nl/~sbolt/e-avrMon.html
+
+`STAND ALONE' PROGRAMMING PROCEDURE:
+
+ The PC is switched on. Run SP12 -i to ensure that all parallel
+ data bits are zero. Connect the programmer board to the parallel
+ port. Use SP12 for whatever you wish to do, then switch off and
+ disconnect the programmer board.
+
+ The software is just as suitable for `in circuit' programming. In
+ that case, the target board must allow free access to MOSI (PB5),
+ MISO (PB6), SCK (PB7) and Reset. SCK must be terminated on the
+ target board using a 22pf capacitor and a 100 ohms resistor,
+ except when using the `dongle' mentioned above. On the reset
+ pin, a 10K resistor and a 100N (100 nano-farad) capacitor may
+ be used to make power-on reset more reliable. That combination
+ allows SP12 sufficient access to Reset. Check icp_intr.gif for
+ details. When using the `dongle', the minimum reset circuit is
+ 10K between the uC's reset pin and Vcc.
+
+`IN CIRCUIT' PROGRAMMING PROCEDURE:
+
+ The PC is switched on. Run SP12 -i to ensure that all parallel
+ data bits are zero. Power up the target board (to between 3 and 5
+ volt). Connect it to the PC. Use SP12 for whatever you wish to
+ do, then switch off and disconnect the target board.
+
+
diff --git a/icp_intr.gif b/icp_intr.gif
new file mode 100644
index 0000000..72066a0
--- /dev/null
+++ b/icp_intr.gif
Binary files differ
diff --git a/progrmmr.gif b/progrmmr.gif
new file mode 100644
index 0000000..bd17e4a
--- /dev/null
+++ b/progrmmr.gif
Binary files differ
diff --git a/readme.dos b/readme.dos
new file mode 100644
index 0000000..eaf0d08
--- /dev/null
+++ b/readme.dos
@@ -0,0 +1,130 @@
+
+NAME
+
+ SP12: A serial programmer for working with Atmel AVR uCs.
+ Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ Pitronics can be reached by email: sbolt@xs4all.nl
+ Kevin Towers can be reached by email: ktowers@omnexcontrols.com
+ Ken Huntington can be reached by email: kenh@compmore.net
+
+URL
+ The home page for sp12 is
+ http://www.xs4all.nl/~sbolt/e-spider_prog.html
+
+DESCRIPTION
+
+ Sp12 version 2.0 is a serial mode (in-circuit) programmer for the
+ AVR family of microcontrollers. When new AVR uCs arrive, you can
+ easily add support for them yourself, by adding a plain text entry
+ to the runtime configuration file _sp12dev. Editing this file also
+ allows you to customize the way sp12 deals with existing uCs.
+
+ Customization means, among other things, that you can define the
+ write (high, extended) fuses commands so they won't touch the bits
+ that can lock you out of your uC. For instance, the Mega8 and the
+ Tiny15 both allow serial mode access to RSTDISBL, which can take
+ away the resetpin - thus ending serial mode programming access.
+ The Tiny15 also permits writing to SPIEN. If you use the _sp12dev
+ entries as provided, these fuses will never be altered by user
+ errors.
+
+ Sp12 is one of the few programmers capable of uploading new
+ software to several uCs on a single target, in one go. Yet it is
+ a small and simple command line tool, easy to use in scripts and
+ batch files.
+
+ Depending on your PC and target, the hardware can be as simple as
+ a nearly plain cable between your target and a parallel port.
+ A special `dongle' design is available to improve the signal
+ quality and make the programming lines high-Z unless sp12 is
+ active.
+ Sp12 can also adapt its use of the paralel port to the
+ cable/dongles supplied with the Kanda STK200/300 starter kits.
+
+INSTALLATION
+
+ Sp12.exe should be put somewhere in your PATH. It is advisable
+ to set the environment variable SP12 by adding a line like
+ "Set SP12=C:\SP12\" to your autoexec.bat file. Sp12 looks for two
+ files in the directory pointed to by this variable: _sp12dev and
+ _sp12rc. Without it, you'll need copies of those files in all
+ your project directories.
+
+ Copy _sp12dev into the chosen directory, and run
+
+ sp12 -i
+
+ To make sp12 create an _sp12rc for your system. Depending on your
+ computer it may take a few seconds or somewhat longer to
+ calibrate the timing loop.
+
+ Note: If heavy multitasking is going on, the autocalibration will
+ produce time constants which are too small. Therefore _sp12rc
+ should be created on a lightly loaded system. When you are
+ actually programming an uC, heavy background loads may slow down
+ the job, but they won't really hurt; the AVR serial mode
+ programming time constraints are minimum values.
+ _sp12rc is in plain language and may be edited (with care), for
+ instance to make SP12 use a different parallel port (read
+ _sp12rc and sp12rc.txt for details).
+
+ If you are using plain MS-DOS or something like it without a
+ DPMI host, you must also put CWSDPMI.EXE (found in SP12\CSDPMI\BIN)
+ in your PATH.
+
+ NOTE: Be sure to erase any previous runtime configuration file
+ (_sp12rc) and let this version make a new one.
+
+ Finally, run
+
+ sp12 -t
+
+ The command presents a progress bar, which should take about 10
+ seconds to complete, counting from the moment when you hit the
+ return on the command line. (There may a brief pause before the
+ bar appears, which nevertheless is part of the ten seconds.)
+ I wouldn't worry if it's eight or 15 seconds. But the deviation
+ is large, read `bugs & bother' below.
+
+BUGS & BOTHER
+
+ Certain time constants necessary for proper upload of flash and
+ eeprom data (serial clock sck low & high, write delay) are
+ realized by autocalibration based on timing nearly empty loops.
+
+ So for starters, you should let sp12 generate its runtime
+ configuration file (_sp12rc) while your computer is lightly loaded.
+ If heavy multitasking is going on, the autocalibration will produce
+ time constants which are too small. When you are actually
+ programming an uC, heavy background loads may slow down the job,
+ but they won't really hurt; the AVR serial mode programming time
+ constraints are minimum values.
+
+ There is no obvious alternative for these loops, as for instance
+ the usleep() function is often limited by the timer resolution of
+ the system (to about 10ms). And this method usually works fine.
+ However, trouble may occur when recompiling sp12 with compilers
+ other than gcc.
+
+ If all else fails, you might edit the line
+
+ LOOPCOUNT=<a number representing 1 second>
+
+ in your _sp12rc, referring to the command "sp12 -t" and your
+ watch to get it right.
diff --git a/readme.linux b/readme.linux
new file mode 100644
index 0000000..2149e65
--- /dev/null
+++ b/readme.linux
@@ -0,0 +1,152 @@
+
+NAME
+
+ SP12: A serial programmer for working with Atmel AVR uCs.
+ Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ Pitronics can be reached by email: sbolt@xs4all.nl
+ Kevin Towers can be reached by email: ktowers@omnexcontrols.com
+ Ken Huntington can be reached by email: kenh@compmore.net
+
+URL
+ The home page for sp12 is
+ http://www.xs4all.nl/~sbolt/e-spider_prog.html
+
+DESCRIPTION
+
+ Sp12 version 2.0 is a serial mode (in-circuit) programmer for the
+ AVR family of microcontrollers. When new AVR uCs arrive, you can
+ easily add support for them yourself, by adding a plain text entry
+ to the runtime configuration file _sp12dev. Editing this file also
+ allows you to customize the way sp12 deals with existing uCs.
+
+ Customization means, among other things, that you can define the
+ write (high, extended) fuses commands so they won't touch the bits
+ that can lock you out of your uC. For instance, the Mega8 and the
+ Tiny15 both allow serial mode access to RSTDISBL, which can take
+ away the resetpin - thus ending serial mode programming access.
+ The Tiny15 also permits writing to SPIEN. If you use the _sp12dev
+ entries as provided, these fuses will never be altered by user
+ errors.
+
+ Sp12 is one of the few programmers capable of uploading new
+ software to several uCs on a single target, in one go. Yet it is
+ a small and simple command line tool, easy to use in scripts and
+ batch files.
+
+ Depending on your PC and target, the hardware can be as simple as
+ a nearly plain cable between your target and a parallel port.
+ A special `dongle' design is available to improve the signal
+ quality and make the programming lines high-Z unless sp12 is
+ active.
+ Sp12 can also adapt its use of the paralel port to the
+ cable/dongles supplied with the Kanda STK200/300 starter kits.
+
+INSTALLATION
+
+ This package contains an executable which depends on libc.so.6 and
+ ld-linux.so.2. If it doesn't work on your system, symply compile your
+ own binary by entering the SP12/Source directory and typing `make'.
+ (There used to be a statically linked sp12 binary package, but that's
+ no good anymore, because older kernels need a different binary format.)
+
+ If you do have to compile sp12, be sure to run the timing
+ check when the installation is completed (see below).
+
+ Note: To run sp12 you must have i/o permission on your system, so
+ run as root (not a good idea) or set sp12 permissions and ownership
+ like this:
+
+ -r-sr-xr-x 1 root root 53208 Jan 17 16:35 /usr/local/bin/sp12*
+
+ Which can be achieved by becoming root and using these commands:
+
+ chown root.root sp12
+ chmod 4555 sp12
+
+ Note that sp12 drops root permissions before accessing the file system,
+ so it should be secure enough for general use.
+
+ Put the sp12 executable somewhere in your $PATH, for instance in
+ /usr/local/bin
+ Next, add a line like
+
+ export SP12=/home/<username>/
+
+ to your .bash_profile or similar file. After restarting the shell
+ (normally by opening a new terminal window) this creates the
+ environment variable SP12, which should point to the directory
+ where you want to keep the runtime configuration files _sp12dev
+ and _sp12rc. Copy _sp12dev into that directory, and run
+
+ sp12 -i
+
+ To make sp12 create an _sp12rc for your system. Depending on your
+ computer it may take a few seconds or somewhat longer to
+ calibrate the timing loop.
+
+ Note: If heavy multitasking is going on, the autocalibration will
+ produce time constants which are too small. Therefore _sp12rc
+ should be created on a lightly loaded system. When you are
+ actually programming an uC, heavy background loads may slow down
+ the job, but they won't really hurt; the AVR serial mode
+ programming time constraints are minimum values.
+ _sp12rc is in plain language and may be edited (with care), for
+ instance to make SP12 use a different parallel port (read
+ _sp12rc and sp12rc.txt for details).
+
+ NOTE: Be sure to erase any previous runtime configuration file
+ (_sp12rc) and let this version make a new one.
+
+ Finally, run
+
+ sp12 -t
+
+ The command presents a progress bar, which should take about 10
+ seconds to complete, counting from the moment when you hit the
+ return on the command line. (There may a brief pause before the
+ bar appears, which nevertheless is part of the ten seconds.)
+ I wouldn't worry if it's eight or 15 seconds. But the deviation
+ is large, read `bugs & bother' below.
+
+BUGS & BOTHER
+
+ Certain time constants necessary for proper upload of flash and
+ eeprom data (serial clock sck low & high, write delay) are
+ realized by autocalibration based on timing nearly empty loops.
+
+ So for starters, you should let sp12 generate its runtime
+ configuration file (_sp12rc) while your computer is lightly loaded.
+ If heavy multitasking is going on, the autocalibration will produce
+ time constants which are too small. When you are actually
+ programming an uC, heavy background loads may slow down the job,
+ but they won't really hurt; the AVR serial mode programming time
+ constraints are minimum values.
+
+ There is no obvious alternative for these loops, as for instance
+ the usleep() function is often limited by the timer resolution of
+ the system (to about 10ms). And this method usually works fine.
+ However, trouble may occur when recompiling sp12 with compilers
+ other than gcc.
+
+ If all else fails, you might edit the line
+
+ LOOPCOUNT=<a number representing 1 second>
+
+ in your _sp12rc, referring to the command "sp12 -t" and your
+ watch to get it right.
diff --git a/readme.win b/readme.win
new file mode 100644
index 0000000..477d7b6
--- /dev/null
+++ b/readme.win
@@ -0,0 +1,163 @@
+
+NAME
+
+ SP12: A serial programmer for working with Atmel AVR uCs.
+ Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ Pitronics can be reached by email: sbolt@xs4all.nl
+ Kevin Towers can be reached by email: ktowers@omnexcontrols.com
+ Ken Huntington can be reached by email: kenh@compmore.net
+
+URL
+ The home page for sp12 is
+ http://www.xs4all.nl/~sbolt/e-spider_prog.html
+
+DESCRIPTION
+
+ Sp12 version 2.0 is a serial mode (in-circuit) programmer for the
+ AVR family of microcontrollers. When new AVR uCs arrive, you can
+ easily add support for them yourself, by adding a plain text entry
+ to the runtime configuration file _sp12dev. Editing this file also
+ allows you to customize the way sp12 deals with existing uCs.
+
+ Customization means, among other things, that you can define the
+ write (high, extended) fuses commands so they won't touch the bits
+ that can lock you out of your uC. For instance, the Mega8 and the
+ Tiny15 both allow serial mode access to RSTDISBL, which can take
+ away the resetpin - thus ending serial mode programming access.
+ The Tiny15 also permits writing to SPIEN. If you use the _sp12dev
+ entries as provided, these fuses will never be altered by user
+ errors.
+
+ Sp12 is one of the few programmers capable of uploading new
+ software to several uCs on a single target, in one go. Yet it is
+ a small and simple command line tool, easy to use in scripts and
+ batch files.
+
+ Depending on your PC and target, the hardware can be as simple as
+ a nearly plain cable between your target and a parallel port.
+ A special `dongle' design is available to improve the signal
+ quality and make the programming lines high-Z unless sp12 is
+ active.
+ Sp12 can also adapt its use of the paralel port to the
+ cable/dongles supplied with the Kanda STK200/300 starter kits.
+
+INSTALLATION
+
+ If you are running Win 3.1/95/98, SP12 will run normally without
+ any added device drivers. If you are running Win NT/2000/XP, you
+ will need to install the GIVEIO device driver.
+
+ Installing Giveio:
+
+ To install the device driver you need Dale Roberts' device driver
+ giveio.sys and the program instdrv.exe. Both of these are included
+ in the WinNT sub-directory of the sp12-Win32 package. The
+ original files and documentation for Giveio can be found at
+ (http://www.ddj.com/ftp/1996/1996.05/directio.zip). Instdrv is
+ from the device driver kit (DDK) for Windows NT.
+
+ * Copy the driver giveio.sys from the archive directio.zip into
+ %SystemRoot%\system32\drivers.
+ * Use command line to install the driver using instdrv:
+ instdrv giveio %SystemRoot%\system32\drivers\giveio.sys
+
+ * In order to start this driver at every reboot automatically,
+ change the start up behaviour to automatic:
+ * 2000/XP: start regedit and change the value of the key "Start" in
+ "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\giveio" to 2.
+ * NT: Control Panel->Devices->giveio->Start Up->Automatic.
+
+ Sp12.exe should be put somewhere in your PATH. It is advisable
+ to set the environment variable SP12 by adding a line like
+ "Set SP12=C:\SP12\" to your environment. Sp12 looks for two
+ files in the directory pointed to by this variable: _sp12dev and
+ _sp12rc. Without it, you'll need copies of those files in all
+ your project directories.
+
+ Copy _sp12dev into the chosen directory, and run
+
+ sp12 -i
+
+ To make sp12 create an _sp12rc for your system. Depending on your
+ computer it may take a few seconds or somewhat longer to
+ calibrate the timing loop.
+
+ Note: If heavy multitasking is going on, the autocalibration will
+ produce time constants which are too small. Therefore _sp12rc
+ should be created on a lightly loaded system. When you are
+ actually programming an uC, heavy background loads may slow down
+ the job, but they won't really hurt; the AVR serial mode
+ programming time constraints are minimum values.
+ _sp12rc is in plain language and may be edited (with care), for
+ instance to make SP12 use a different parallel port (read
+ _sp12rc and sp12rc.txt for details).
+
+ Finally, run
+
+ sp12 -t
+
+ The command presents a progress bar, which should take about 10
+ seconds to complete, counting from the moment when you hit the
+ return on the command line. (There may a brief pause before the
+ bar appears, which nevertheless is part of the ten seconds.)
+ I wouldn't worry if it's eight or 15 seconds. But the deviation
+ is large, read `bugs & bother' below.
+
+BUGS & BOTHER
+
+ Certain time constants necessary for proper upload of flash and
+ eeprom data (serial clock sck low & high, write delay) are
+ realized by autocalibration based on timing nearly empty loops.
+
+ So for starters, you should let sp12 generate its runtime
+ configuration file (_sp12rc) while your computer is lightly loaded.
+ If heavy multitasking is going on, the autocalibration will produce
+ time constants which are too small. When you are actually
+ programming an uC, heavy background loads may slow down the job,
+ but they won't really hurt; the AVR serial mode programming time
+ constraints are minimum values.
+
+ There is no obvious alternative for these loops, as for instance
+ the usleep() function is often limited by the timer resolution of
+ the system (to about 10ms). And this method usually works fine.
+ However, trouble may occur when recompiling sp12 with compilers
+ other than gcc.
+
+ If all else fails, you might edit the line
+
+ LOOPCOUNT=<a number representing 1 second>
+
+ in your _sp12rc, referring to the command "sp12 -t" and your
+ watch to get it right.
+
+PCI Cards
+
+ When SP12 first runs, it will search the legacy addresses for existing
+ parallel ports. Any ports found will be listed in the _sp12rc file.
+ PCI parallel cards typically don't get assigned to the legacy addresses
+ (i.e. 0x278, 0x378, etc). Use the Windows device manager to find out
+ where your PCI card was assigned. Then edit _sp12rc to assign this
+ address to the PORT variable.
+
+ eg.
+ PORT=0xe800
+
+
+
+
diff --git a/sp12 b/sp12
new file mode 100755
index 0000000..113c2e6
--- /dev/null
+++ b/sp12
Binary files differ
diff --git a/sp12.txt b/sp12.txt
new file mode 100644
index 0000000..b5c3856
--- /dev/null
+++ b/sp12.txt
@@ -0,0 +1,1045 @@
+
+NAME
+
+ SP12: A serial programmer for working with Atmel AVR uCs.
+ Copyright (C) 1997-2001 Ken Huntington, Kevin Towers, Pitronics.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ Pitronics (Steve) can be reached by email: sbolt@xs4all.nl
+ Kevin Towers can be reached by email: ktowers@omnexcontrols.com
+ Ken Huntington can be reached by email: kenh@compmore.net
+
+URL
+ The home page for sp12 is
+ http://www.xs4all.nl/~sbolt/e-spider_prog.html
+
+SYNOPSIS
+
+ SP12 -<options> [filename or address(:data)] -<options> [filename...
+
+OPTION SUMMARY
+
+ i<nnn> - init E - chip erase
+ e - eprom area B - blank check
+ p - program area C - calculate checksum
+ w - write to L[n...n] - lock fuses
+ r - read from F[n...n] - fuses
+ a - address(:data) next H[n...n] - high fuses
+ f - filename next X[n...n] - extended fuses
+ I - create Intel Hex file c[nn] - calibration byte
+ h - hex dump with ascii M[n.n] - match Sck to uC clock
+ o0, o1 - optimization P[nnn] - parallel port control
+ s - show supported uCs t - timing check
+
+EXAMPLES
+
+ sp12 -rF -rH -rL -rc (reads fuses, locks and calibration if possible)
+ sp12 -wea 0x01:0x99 (Writes 0x99 into eeprom address 0x01)
+
+ A command like this is suitable for rapidly writing a program and
+ some data into a series of devices:
+
+ sp12 -M4 -wF10011 -wpfC prog.hex -wefC eep.hex -wL00
+
+ Timing is set to match a uC clock speed of 4MHz as close as
+ possible. Parallel port speed will probably limit the achieved
+ timing to a lower value, which doesn't matter; only timing which
+ is too fast can make communication impossible.
+ Then the fuses are programmed - note that the string 10011 must
+ exactly match the device's fuses block in length including gaps,
+ as defined in _sp12dev; this one would be appropriate for the
+ AT90S4433. For a Tiny15 it would be something like -wF01011101,
+ despite the fact that only four or at most six of those bits
+ can actually be altered. And since the _sp12dev in this package
+ blocks accidental change of a Tiny2313's high fuses bits
+ 7, 5 and 1, you'd use for instance -wH001110 to preserve its eeprom
+ through chip erase and set its brown-out detection to 1.8V.
+ (See also sp12dev.txt.)
+ Next, the device is erased (this function is automatically
+ included when you use the -wpf group). Prog.hex is written into
+ the program area, and data.hex into the eeprom. Checksums are
+ provided for both. Finally the device is locked against reading
+ and writing. The lock string must also be of the right length;
+ a Mega8 would require something like -wL111100
+ Note that setting the log and query options in _sp12rc may be
+ more useful than asking for checksums. (See sp12rc.txt)
+
+ Within a group, the order of options is not significant, so you
+ could also write -fwCp prog.hex -Cfew data.hex
+
+ However, the order of arguments on the command line *is*
+ significant. The following is wrong:
+
+ sp12 -wefC data.hex -wpfC prog.hex -wL00
+
+ because it writes data.hex to the eeprom area, then erases it
+ (erase being automatically included with the -wpf group), writes
+ prog.hex to the program area and write-protects the device, so you
+ would have to erase the device again to correct this mistake.
+
+ Of course you can use single commands like
+
+ sp12 -wpf prog.hex
+ sp12 -wef data.hex
+ sp12 -wL00
+
+ But the order in which they are given remains just as important.
+
+ Timing optimization is available when programming page mode
+ uCs (ATmega's). In previous versions, pages were allowed to
+ settle for 64ms, as demanded by the old Mega103. Optimization
+ allows you to fully program a Mega8 in about 3 seconds instead
+ of 11 seconds.
+ However, there are combinations of target and program cable
+ (without `dongle') which cause optimization to fail; a few
+ locations which have been programmed and verified may revert to
+ 0xff while programming another page. So it was decided to keep
+ `no optimization' as the default behaviour. To increase speed,
+ use -o1. For example:
+
+ sp12 -M4 -o1 -wpf foo.hex
+
+ To make sure that optimization is alright for your hardware,
+ it should be tested with QUERY=1 in _sp12rc, or a command like
+
+ sp12 -M4 -o1 -wpfC foo.hex -Cpf foo.hex
+
+ The checksums should be equal.
+ NOTE: The new Tiny2313 introduced the programming command
+ `poll rdy/bsy', which allows a different optimization method.
+ When this command is part of an _sp12dev entry (see sp12dev.txt),
+ the -o option is ignored. And for devices which obey this
+ new programming command, -o must be ignored, as -o1 would
+ cause programming errors.
+
+
+ This command outputs checksums for both area's:
+
+ SP12 -Cp -Ce
+
+ NOTE:-Ce and -Cef apply to the eeprom buffer. Of course these
+ options make sense only if your program is not intended to
+ write to eeprom addresses.
+ NOTE: When a device has been locked against reading, and sp12
+ is used with the option -innn on the command line (no check of
+ device code), the program / eeprom area checksums will be
+ invalid.
+
+ These output checksums for both files, equal to what the
+ checksums would be if they are read back from the respective
+ area's, even when no device is connected:
+
+ SP12 -iAT90LS4433 -Cpf prog.hex -Cef data.hex
+ SP12 -i392 -Cpf prog.hex -Cef data.hex
+
+ This command reads the program area and ouputs a hex dump with
+ ascii translation to the screen (stdout):
+
+ SP12 -rph
+
+ While this one reads both area's into files, using the Intel
+ hex format:
+
+ SP12 -rpIf prog.hex -reIf eeprom.hex
+
+ This command erases the device and does a blank check:
+
+ SP12 -EB
+
+ This one does only a blank check:
+
+ SP12 -B
+
+ And this one locks devices with just two lock bits against both
+ writing and reading:
+
+ SP12 -wL00
+
+ NOTE: when a device has been locked againts reading, the device
+ code (signature bits) may be unreadable, making sp12 refuse to
+ do anything whatsoever with the device. If you need to regain
+ access, You will have to erase the device using a command like
+
+ sp12 -iS2313 -E
+ or
+ sp12 -i191 -E
+
+ The use of option -innn bypasses the device code check, see
+ below. For example, -i191 or -iS2313 make sp12 assume an
+ AT90S2313 is connected. Option -E erases the device.
+
+ When an ATmega163 is connected, the command
+
+ SP12 -rF -rH
+
+ Will result in something like:
+
+ 11010010 are the fuse bits read from an ATmega163
+ 0x11xxxx - BODLEVEL 4V (default 2.7V)
+ x011xxxx - brownout detection enabled
+ xx11CKSE - clock and reset select, datasheet p5 p25
+
+ 111 are the high fuse bits read from an ATmega163
+ BZx - BootSZ, datasheet p134
+ xx0 - Boot reset at flash, default address zero
+
+ These messages are defined in _sp12dev and can easily be
+ customized. (See sp12dev.txt)
+
+ When given to an AT90S4433, The command:
+
+ sp12 -wF00100
+
+ Results in:
+
+ 00100 are the fuse bits written into an AT90S4433
+ 0xxxxx - serial programming enabled
+ x0xxxx - BODLEVEL 4V (default 2.7V)
+ xx0xxx - brownout detection enabled
+ xxxCKS - reset delay select (datasheet p20)
+ NOTE: (re)enabling brownout detection
+ often causes the 4433 to hang. In that
+ case power must be switched off and back
+ on again before programming can continue.
+
+ As the message shows (assuming you use a fixed pitch font to
+ get proper alignment), brownout detection is switched on, with
+ the detection level at 4V. A look at p20 of the datasheet tells
+ us that the start-up delay is set to 16K CK.
+
+ Atmel had the following comment on that bit about `hanging'
+ after (re)enabling brownout detection:
+
+ "This is a known problem with the current revision of the
+ AT90S4433. There is no other workaround than to program the
+ BODEN bit after you have programmed the flash and the EEPROM."
+ (Communication via Mark Korsloot of Alcom, the Dutch
+ distributor of Atmel products, on 27 Apr 2000.)
+
+ When this version of sp12 was prepared, the AT90(L)S2333 was
+ not available. (Re)enabling BOD may or may not cause this uC to
+ hang, but it seems best to make fuse programming the final
+ word on your command line. So if you want to write to eeprom
+ and flash, lock the device and program the fuses in one go,
+ this is the correct order of the command words:
+
+ SP12 -wpf prog.hex -wef data.epr -wL00 -wF00100
+
+ The flash must be written to first, because that command first
+ erases the device. The fuses can be programmed after locking
+ the device, because in serial programming mode, you have access
+ to the fuse bits even when this device is locked against reading
+ and writing.
+ Note that many other devices demand that the lock is applied after
+ programming the fuses.
+
+ The command:
+
+ SP12 -M4 -wpf foo.hex
+
+ Will attempt to set communication timing to match a device
+ clock speed of 4MHz. Hardware will usually limit the achievable
+ com speed, so while SP12 works correctly with very fast uCs, the
+ time needed to execute a command line is not likely to decrease
+ for Mnn settings above 1.5MHz. SP12 will report the speed
+ actually achieved. For instance:
+
+ Sck timing set for 1.5MHz or higher.
+
+ The command:
+
+ SP12 -Owpf foo.hex -Owef foo.hex
+
+ Will NOT erase the device before writing in the new data.
+ The files foo.hex and foo.hex are added to what is already in the
+ flash and eeprom area's. If there is a conflict, the flash
+ overlay will stop with an error report - it isn't possible to
+ write a 1 over a 0 in an AVR flash location. However, foo.hex is
+ always written, even if it (partially) replaces earlier data.
+
+ With suitable hardware, this command:
+
+ SP12 -P4 -wpf uC1.hex -P8 -wpf uC2.hex -P2
+
+ will program two uCs on a single target board, using a single
+ command line. The first -P would make parallel port data bit 3
+ high, making a set of analog switches route the programming lines
+ to the first uC. The second -P disconnects the first and connects
+ the second uC. Finally, the third -P leaves reset high when SP12
+ exits, allowing the new software to run. There is a 10ms delay
+ after each -P, to give analog switches on the target board some
+ time to do their job.
+
+ To force timing optimization for a 1200:
+
+ sp12 -o1 -wpfC foo.hex -Cpf foo.hex
+ Or
+ sp12 -i190 -o1 -wpfC foo.hex -Cpf foo.hex
+
+ Compare the two checksums to make sure that the upload was
+ correct.
+ To force a fixed byteWrite for other uCs, equal to the value in
+ _sp12rc (behaviour equal to early sp12 versions):
+
+ sp12 -o0 -wpf foo.hex
+
+ Each option is described in detail under `options' below.
+
+ERROR CODES RETURNED ON PROGRAM EXIT
+
+ 0 - accomplished writing/reading task - "life is wonderful :)"
+ 1 - no device present - "nothing to do"
+ 2 - bad command line options, corrupt _sp12rc, file not found,
+ unable to write to file - "don't know what to do"
+ 3 - verification or blank check error - "device doesn't respond
+ as expected"
+
+OPERATING SYSTEM COMPATIBILITY
+
+ The dynamically linked sp12 binary intended for Linux requires
+ libc.so.6 and ld-linux.so.2. See readme.linux for further information.
+ The 32-bit Dos protected mode executable found in this version of
+ SP12 relies on MS-DOS and BIOS for file I/O and other basic
+ functions such as keyboard input, screen cursor position, etc.
+ It uses "DPMI" (the DOS Protected Mode Interface) to allow
+ DOS/BIOS calls from protected mode.
+ SP12 is known to run in MS-DOS, in a Windows-3.X Dosbox and in
+ a Windows-9X Dosbox, on machines ranging from a slow 386 to a
+ 450MHz Pentium-II. Windows NT, XP and W2000 do not provide the
+ access to the parallel port required by SP12.
+
+INSTALLATION
+
+ Have a look at either readme.dos (also for MS W9x and W3x) or
+ readme.linux as appropriate; also read hardware.txt.
+
+
+DESCRIPTION
+
+ The present version (2.0) should be suitable for all AVR uCs;
+ but _sp12dev only contains definitions for the ones mentioned in
+ the table below. You can easily add definitions for others - have
+ a look at sp12dev.txt.
+ On all of them, you have read and write access to the flash and
+ eeprom memory, and you can set the lock bits. Some of them offer
+ read and write access to various fuse bits, in serial programming
+ mode. This is also supported. Moreover, you can elect to block
+ write permission to fuses you don't want to change by mistake.
+ For instance, the _sp12dev supplied in this package doesn't allow
+ write access to the Tiny15's RSTDSBLE and SPIEN, because changing
+ either of them would put the uC out of action as far as serial
+ mode (in-circuit) programming is concerned. The table below
+ shows the devices for which there are entries in a recent
+ _sp12dev. Note that low voltage versions (AT90LS, mega_L) are
+ also supported.
+
+ device
+ code name
+
+ 0190 AT90S1200(A)
+ 0191 AT90S2313
+ 0193 AT90S8515
+ 0192 AT90S4414
+ 0291 AT90S2323
+ 0292 AT90S4434
+ 0393 AT90S8535
+ 0391 AT90S2343 or Tiny22 (*)
+ 0691 ATtiny22L
+ 0591 AT90S2333
+ 0392 AT90S4433
+ 0590 ATtiny12
+ 0690 ATtiny15L
+ 0991 ATtiny26
+ 0A91 ATtiny2313
+ 0197, 0101 ATmega103
+ 0196 ATmega603
+ 0194 ATmega161
+ 0294 ATmega163
+ 0693 ATmega8515
+ 0893 ATmega8535
+ 0793 ATmega8
+ 0394 ATmega16
+ 0295 ATmega32
+ 0297 ATmega128
+
+ (*) The 2343 is still treated as if it has an RCEN-bit, which
+ may not be true for the series now being sold - the 02/2000
+ errata sheet for the Tiny22 says "If external oscillator is
+ required, use the 100% pin- and code-compatible
+ AT90S/LS2343 which has external clock option only."
+ It appears that the RCEN fuse proved recalcitrant in some
+ cases, and Atmel felt this to be the quick and safe
+ solution.
+ The same errata sheet says that only the Tiny22L is now
+ available, with the internal RC oscillator as the single
+ clock option. However, I have several Tiny22s with a
+ switchable RCEN fuse, making them fully compatible with a
+ number of clock-switchable 2343s I have lying around.
+ Moreover, my Tiny22 (8PC) chips even have the same
+ signature bytes (device code) as my 2343s...
+ The key difference is that switching the Tiny22's RC clock
+ on or off causes some bits in flash to flip, so it has to be
+ done *before* programming the uC. The 2343s don't have this
+ slight disadvantage.
+ The supplied _sp12dev makes sp12 version 2.0 assume that
+ a uC with device code 0391 has a switchable RCEN fuse. It's
+ up to the user to determine or find out the use of of the
+ -R0/R1 option.
+
+ Note that on many devices, you have access to the fuse bits
+ even when the device is locked. For instance, you can switch
+ the 2343 from internal to external clock oscillator and back
+ even if you can't read the program inside.
+ But other devices require you to program the fuses before
+ setting a lock.
+
+OPTIONS
+
+ Options must be used in meaningful groups, but you may use more
+ than one group on a single command line. The command line is
+ processed from left to right, and it is up to you to put the groups
+ in a meaningful order (see EXAMPLES above). Within a group, the
+ order of the options is not significant.
+
+ -a address(:data) next
+ To specify a single address to read from, or an address:data
+ combination for writing. Both address and data can be entered
+ in hexadecimal, decimal or octal format. For eeprom data
+ binary format is also allowed. So the addresses 0x1ff, 511 and
+ 0777 are identical, as are the address:data combinations
+ 0x3f:0xab, 0x3f:171, 63:171, 077:B10101011 and so on.
+
+ -B blank check
+ Checks both program and eeprom area's to see if every address
+ has been erased. Program addresses should contain 0xffff,
+ eeprom addresses 0xff.
+ NOTE: using options -w, -p and -f together (to write a file
+ from disk to program area) cause an automatic erase, but no
+ blank check. So -wpf foo.hex is equivalent to -Ewpf foo.hex.
+ If you want a blank check to precede the actual programming,
+ use -Bwpf foo.hex.
+
+ -C calculate checksum
+ Reads the internal (program or eeprom) buffer and calculates a
+ BSD-type 16-bit checksum. The buffer is an image of the
+ corresponding area in the device, including empty addresses,
+ but the content may be read from device or file. -Cp results
+ in a checksum of the device program area, while -Cpf foo.rom
+ gives you a checksum of the content of file foo.rom, as it
+ would look like when written to the device. So after writing
+ foo.rom to the device (-wpf foo.rom), -Cp and -Cpf foo.rom
+ should result in the same checksum. Using files in Intel HEX
+ format makes no difference to the checksum. If foo.rom is the
+ same program as foo.hex, then -Cpf foo.rom and -Cpf foo.hex
+ result in the same checksum.
+ During a device read, you will see a progress bar like this:
+
+ oooooooooooooooooooooooo.......................................
+
+ NOTE:The combination -wpfC foo.hex writes foo.hex to the
+ device, then reads the program area back into the buffer and
+ calculates the checksum. So -wpfC foo.hex is equal to
+ -wpf foo.hex -Cp
+ NOTE:-Ce and -Cef apply to the eeprom buffer. Of course these
+ options make sense only if your program is not intended to
+ write to eeprom addresses.
+ NOTE: When a device has been locked against reading, and sp12
+ is used with the option -innn on the command line (no check of
+ device code), the program / eeprom area checksums will be
+ invalid.
+
+ -c Calibration byte
+ Valid combinations: -rc to read the calibration for the internal
+ RC clock of uCs like the Tiny15, Mega163 and so on.
+ When there are more calibration bytes, like the four inside
+ the ATmega8 and ATmega128, add a binary address:
+
+ Byte 0: sp12 -rc or sp12 -rc00
+ Byte 1: sp12 -rc01
+ Byte 2: sp12 -rc10
+ Byte 3: sp12 -rc11
+
+ To set a different calibrated internal clock speed, the programmer
+ must read the relevant calibration byte and write it somewhere in
+ flash or eeprom, where your Mega8 software must find it and put it
+ in OSCCAL. To do the first part in one go, you need a script which
+ makes sp12 copy a calibration byte to flash. Here is one for Linux
+ systems:
+
+ #!/bin/sh
+ #
+ # First upload program.hex into the Mega8, and set the fuses:
+ # BODLEVEL 2.7V, brownout detection on, SUT 00, select internal
+ # RC clock 4MHz
+ #
+ sp12 -M4 -wpf program.hex -wF10000011
+ #
+ # Read the calibration byte for 4MHz (binary address 10),
+ # and feed it through the stream editor sed; it looks for
+ # the output line starting with `0x', replacing that with
+ # `000fff:00', resulting in for instance `000fff:0096'.
+ # Everything after that is cut away, and the other lines
+ # are not printed (the `-n and `p' take care of that). The
+ # line containing the highest flash address and the word
+ # `00<calibration byte>' are written into the file
+ # `overlay'.
+ #
+ sp12 -M4 -rc10 | sed -n -e s/^0x/000fff:00/ -e s/" is.*"//p - > overlay
+ #
+ # Finally, upload overlay (which is in the Atmel generic
+ # format) into the Mega8, without first doing an erase.
+ #
+ sp12 -M4 -Owpf overlay
+
+
+ -E chip erase
+ Executes the AVR command `chip erase', which erases both
+ program and eeprom area's. It is not possible to erase just
+ one of the area's, but when writing to the eeprom area each
+ address is automatically erased first. So you can write 0xff
+ to an address containing 0x00. (You can write only 0's to the
+ program area.)
+ NOTE: Using options -w, -p and -f together (to write a file
+ from disk to program area) cause an automatic erase, so -wpf
+ foo.hex is equivalent to -Ewpf foo.hex.
+
+ -e eprom area
+ Targets the eeprom area when used in combination with -r, -w
+ or -C
+
+ -F Fuse bits
+ Valid combinations: -rF and -wF<n...n>. The latter command
+ writes all fuse bits in one go; you must supply the right
+ number of bits as defined in _sp12dev, or sp12 will barf.
+ Refer to your device's datasheet and _sp12dev to see
+ whether there are fuse bits to write, and if so, how many.
+ Note that the string must include any non-fuse or otherwise
+ fixed bits between the writable fuses, while excluding.
+ such fixed bits at either end of the string. For instance,
+ a Tiny15 needs a write command like -wF01011101, despite the
+ fact that only four or at most six of those bits can actually
+ be altered. (See also sp12dev.txt and _sp12dev.)
+ You can write the n...n in hex if you want, but in that case
+ sp12 can't check the number of bits; the command -wF0x3 will
+ write zeroes into the fuse bits 2, 3, 4 and so on, if they
+ happen to exist.
+ Note that there are separate options for `high fuses' (-H)
+ and `extended fuses' (-X).
+
+ -f filename next
+ The next argument on the command line must be a valid
+ filename, or drive:path\filename.
+ Program files must be either in the Atmel `generic' format or
+ in Intel HEX format, both as provided by the Atmel assembler
+ (w)avrasm.exe version 1.03 or higher. SP12 recognizes the file
+ by content, so you don't need to use specific extensions;
+ but .rom and .hex do seem logical.
+ The generic format contains only lines like 00000c:99e1 (both
+ address and data in hexadecimal notation without prefix; six
+ digits for the address, four for the data).
+ Eeprom files must be either in SP12 `native' format, or Intel
+ HEX format as provided by (w)avrasm.exe version 1.21 or
+ higher. To conform to SP12 format, the file must contain only
+ lines like 0x0d:0xcf (Address in hexadecimal, decimal or octal
+ notation, data in hexadecimal, decimal, octal or binary
+ notation, all with appropriate prefix. So the lines 0x0d:153,
+ 13:0231 and 015:B10011001 have the same meaning.)
+
+ -H high fuse bits
+ Valid combinations: -rH and -wH<n...n>. The latter command
+ writes all high fuse bits in one go; you must supply the right
+ number of bits, or sp12 will barf. Refer to your device's
+ datasheet to see whether there are high fuse bits to write,
+ and if so, how many. Note that the string must include any
+ non-fuse or otherwise fixed bits between the writable fuses,
+ while excluding such fixed bits at either end of the string.
+ For instance, the _sp12dev in this package blocks accidental
+ change of a Tiny2313's high fuses bits 7, 5 and 1, you'd use
+ for instance -wH001110 to preserve its eeprom through chip
+ erase and set its brown-out detection to 1.8V, with sp12
+ reporting back:
+
+ 001110 are the high fuse bits written into an ATtiny2313
+ 0xxxxxxx - debugWire enabled
+ x0xxxxxx - EEPROM preserved in chip erase
+ xx0xxxxx - serial programming enabled
+ xxx0xxxx - WDT always on (page 41)
+ xxxxBODx - BODLEVEL (page 34)
+ xxxxxxx1 - reset-pin enabled (page 52)
+
+ (See also sp12dev.txt and _sp12dev.)
+ You can write the n...n in hex if you want, but in that case
+ sp12 can't check the number of bits; the command -wH0x3 will
+ write zeroes into the fuse bits 2, 3, 4 and so on, if they
+ happen to exist.
+ Note that there are separate options for `fuses' (-F)
+ and `extended fuses' (-X).
+
+ -h Hex dump with ascii translation modifier for the -r (read)
+ option, see below.
+
+ -I Intel Hex modifier for the -r (read) option, see below.
+
+ -i[nnn] init [<device code>] [<device name>]
+ First initializes communication with the parallel port and
+ some timing constants. SP12 looks for the runtime config
+ file _sp12rc, in the directory as defined by the
+ environment variable SP12, or in the current directory if
+ this variable is not set. If _sp12rc is not found, a new
+ one is created. Depending on your computer it may take
+ half a minute or longer to calibrate the timing loop.
+ _sp12rc is in plain language and may be edited (with
+ care), for instance to make SP12 use a different parallel
+ port (read _sp12rc and sp12rc.txt for details).
+ Next the device code of your device (contained in the
+ signature bytes) will be read to determine which member of
+ the AVR family has been connected. This enables SP12 to
+ use the correct programming command subset and to know the
+ size of the flash and eeprom memory. When a device has
+ been locked against reading as well as writing, the device
+ code (signature bits) will often be unreadable, making
+ sp12 refuse to do anything whatsoever with the device. If
+ you need to regain access, You will have to erase the
+ device using a command like -innn -EB
+ The use of option -innn bypasses the device code check,
+ nnn being equal to either the device code (with or without
+ leading zeroes) or the device name, which can be something
+ like AT90S1200, AT90LS1200, AT90LS1200A or abbreviations
+ like S1200, Mega128 and M8L. See sp12dev.txt for more
+ information about device names. For example, -i190 makes
+ sp12 assume an AT90S1200 is connected. Command -EB erases
+ the device and performs a blank check.
+ Here is a table of supported uCs and init numbers:
+
+ Force recognition
+ with:
+
+ AT90S1200(A) -i190
+ AT90S2313 -i191
+ AT90S8515 -i193
+ AT90S4414 -i192
+ AT90S2323 -i291
+ AT90S4434 -i292
+ AT90S8535 -i393
+ AT90S2343 or Tiny22 -i391
+ Tiny22L -i691
+ AT90S2333 -i591
+ AT90S4433 -i392
+ ATtiny15L -i690
+ ATmega103 -i197
+ ATmega603 -i196
+ ATmega161 -i194
+ ATmega163 -i294
+ ATmega8 -i793
+ ATmega128 -i297
+
+ -i0, -i or no use of this option (when there are others on
+ the command line) results in automatic init and device check.
+ NOTE: option -innn must be the first on the command line.
+ NOTE: -i, -s and -t are the only valid options if no
+ device is connected, though you might for instance check a
+ file checksum using -i15 -Cpf foo.hex, if foo.hex is
+ intended for the 8515.
+
+ -L lock bits
+ Valid combinations: -rL and -wL<n...n> The latter command
+ writes all lock bits in one go; you must supply the right
+ number of bits, or sp12 will barf. Refer to your device's
+ datasheet to see how many lock bits are supported. Also
+ have a look at sp12dev.txt and _sp12dev.
+ You can write the n...n in hex if you want, but in that case
+ sp12 can't check the number of bits; the command -wH0x3 will
+ write zeroes into the lock bits 2, 3, 4 and so on, if they
+ happen to exist.
+ Lock bits can be reset (to `1') only by erasing the device.
+
+ NOTE: Some AVR uC lock commands reverse the bit sequence
+ on readout, examples being the AT90S8535, 4434, 2323, 2343
+ and Tiny22. And these uCs have no `read locks' command;
+ the locks and fuses are separately programmed, but read
+ together. So you write-protect them with sp12 -wL10 while
+ the result can be read back with sp12 -rF resulting in:
+
+ 01011111 are the fuse bits read from an AT90S8535
+ 11xccccx - no lock
+ 01xccccx - write protected
+ 00xccccx - read/write protected
+ xx0ccccx - serial programming enabled
+ xxxcccc0 - FSTRT reset delay, datasheet p20
+
+ The more often used read and write protection is done with
+ a less confusing sp12 -wL00
+
+ NOTE: when a device has been locked against both writing
+ and reading, the device code (signature bits) will often be
+ unreadable, making sp12 refuse to do anything whatsoever
+ with the device. If you need to regain access, You will
+ have to erase the device using a command like -innn -EB
+ The use of option -innn bypasses the device code check, see
+ above. For example, -i190 makes sp12 assume an AT90S1200 is
+ connected. Command -EB erases the device and performs a blank
+ check.
+
+ -M[n.n] uC clock frequency
+ n.n is the uCs clock speed in MHz, not lower than 0.1.
+ _sp12rc contains autocalibrated timing data (delay caused
+ by outportb(), loop count/s), from which an Sck frequency is
+ calculated, fitting the uC's clock speed as indicated by
+ -Mn.n. You can safely set -Mn.n lower than the default (also
+ in _sp12rc), but only if the command precedes all others
+ except -i[nnn]. For instance:
+
+ sp12 -M4 -wpf foo.hex
+ sp12 -imega128 -M4 -wpf foo.hex
+
+ When this option is not on the command line, the default
+ is used. Unless you change it (in _sp12rc), the default
+ makes sp12 version 1.0 behave like previous versions, which
+ means that the Sck frequency and wave form will be suitable
+ for uCs running on an internal RC clock, at fairly low Vcc.
+ WARNING: When -Mn.n is set too high, the uC will misread
+ commands and fill its memory with garbage.
+ NOTE: In practice, the outportb() function needs a certain
+ amount of time to actually change a parallel port data bit.
+ Depending on the hardware, this is likely to limit the
+ shortest timing to about 1.3us for an Sck half cycle. Most
+ AVR uCs need the Sck low and high phases to be at least two
+ clock cycles long; the AT89S1200 is an exception, needing an
+ Sck high phase of at least four clock cycles.
+ So while SP12 works correctly with very fast uCs, the time
+ needed to execute a command line is not likely to decrease
+ for Mnn settings above 3MHz for the 1200, and 1.5MHz for
+ the other family members. SP12 reports the timing achieved.
+
+ -O overlay
+ The commands -wpf and -wef cause SP12 to read files into
+ 0xFFFF or 0xFF padded buffers, and to make sure that the
+ flash or eeprom area contains the buffer image after
+ programming is done. -wpf is automatically preceded by a
+ `chip erase', and -wef writes 0xFF into all addresses which
+ don't have their content specified by the file (addresses
+ which already contain 0xFF are skipped). This guarantees
+ that programming is actually possible (new uploads to
+ flash could easily conflict with `leftovers' from previous
+ work). It also results in equal checksums for uC content
+ and file.
+ However, You may sometimes want to add calibration
+ constants, configuration data and/or serial numbers to
+ what's already in flash or eeprom. To overlay files on
+ data already in the uC's memory, you'd do:
+
+ sp12 -Owpf foo.hex -Owef foo.hex
+
+ In combination with -wpf, the -O precludes chip erase.
+ If there is a conflict, the flash overlay will stop with an
+ error report - it isn't possible to write a 1 over a 0 in an
+ AVR flash location. However, foo.hex is always written, even
+ if it (partially) replaces earlier data.
+ Both -Owpf and -Owef only upload the file (as opposed to
+ the buffer) and cause a query (performed when `logging' and
+ `query' are set in _sp12rc) to also be limited to the
+ file, or where the flash area is concerned, to addresses
+ which according to the file should contain something other
+ than 0xffff.
+ Checksums are always calculated for the entire area, as the
+ commands -Cp and -Ce refer to the entire uC areas. So
+ after an -Owpf or -Owef, the log will show a checksum
+ which only matches area content. The overlayed files each
+ have their own checksum.
+
+ -o optimization
+ Level 0 (-o0): No optimization for any uC.
+ Level 1 (-o1): forces optimization for all uCs, including
+ the 1200(A).
+ Default (option not on command line) for all `classic' uCs
+ like the AT90S2313 and the ATtiny's, except the AT90S1200:
+ the Bytewrite time constant - which determines how much
+ time a flash or eeprom address gets to settle, after it
+ has been written to - is dynamically adjusted, with the
+ value in _sp12rc as upper limit.
+ Default for the AT90S1200 and the ATmega's: No optimization.
+ Optimization makes sp12 1.0 program significantly faster
+ when conditions allow, and should cause less trouble at
+ low Vcc.
+ For the AT90S1200 and the Mega's, it turns out that there
+ are combinations of target and program cable (without
+ `dongle') which cause optimization to fail; the content of
+ a few locations which have been programmed and verified
+ may change while programming other locations or pages.
+ So it was decided to keep `no optimization' as the default
+ behaviour. To increase speed, use -o1. For example:
+
+ sp12 -M4 -o1 -wpf foo.hex
+
+ To make sure that optimization is alright for your
+ Mega or 1200 hardware, it should be tested with QUERY=1 in
+ _sp12rc, or a command like
+
+ sp12 -M4 -o1 -wpfC foo.hex -Cpf foo.hex
+
+ The checksums must be equal.
+ NOTE: If used, this option must be the first option on the
+ command line, or the first after -i[nnn]
+ NOTE: The new Tiny2313 introduced the programming command
+ `poll rdy/bsy', which allows a different optimization method.
+ When this command is part of an _sp12dev entry (see sp12dev.txt),
+ the -o option is ignored. And for devices which obey this
+ new programming command, -o must be ignored, as -o1 would
+ cause programming errors.
+
+ -P[nnn] Port control
+ When used as the final option on the command line, this
+ option leaves the parallel port data pins in the state
+ determined by NNN, which can be a decimal or hexadecimal
+ number: For instance, -P124 and -P0x7C both leave the
+ port in 01111100 state. When used like this:
+
+ SP12 -P4 -wpf uC1.hex -P8 -wpf uC2.hex -P2
+
+ The first two -P's are limited to controlling pins 2-6
+ (those not used for the programming interface itself).
+ Kevin invented this usage for programming two AVR uCs
+ on a single board, using a single connector and a single
+ command. There is a 10ms delay after each -P, to give
+ analog switches on the target board some time to do their
+ job.
+ NOTE: You can't use Ken Huntington's `dongle' together
+ with option -P, since buffers inside it are powered as well
+ as high-Z/enabled using the data 2-6 pins. So only the exit
+ state of the parallel port can be set, as with the old -T
+ option (see below).
+ NOTE: it is possible to set different communication speeds
+ for each uC, using the -Mn.n command, but you have to put
+ the -P first on the command line:
+
+ SP12 -P4 -M0.2 -wpf uC1.hex -P8 -M4 -wpf uC2.hex -P2
+
+ NOTE: -P has immediate control over data pins 2-6 only
+ when it's the first option on the command line. In this
+ case:
+ SP12 -innn -P4 -wpf ...
+
+ Pins 2-6 will all be high during init, which takes about a
+ quarter of a second, depending on settings in _sp12rc and
+ the possible need for resynchronization of the uC's
+ programming interface.
+
+ NOTE: When sp12 is used with the Kanda STK200 cable/dongle,
+ a -P which is not the final option on the command line will
+ control only data bits 0, 1 and 6. Bits 2 and 3 have to be
+ used to high-Z/enable buffers inside the Kanda dongle; bits
+ 4 and 7 are programming lines, and bit 7 handles reset.
+
+ -p program area
+ Targets the program area when used in combination with -r, -w
+ or -C
+ NOTE: It is possible to write to a single address, by using
+ the command -wpa address:data. In this case the device will
+ *not* be automatically erased first. So unless the address was
+ empty (0xffff), data are unlikely to be written correctly, as
+ you can write only 0's to the program area.
+
+ -r read
+ To read from either program or eeprom area, a single address
+ (-rpa address, or -rea address) or the whole area. In the
+ latter case output can be directed to a file using the -f
+ option: -rpf foo.rom reads the program area and writes an
+ image into foo.rom. Use of the `I' modifier (-rpfI foo.hex)
+ changes the format from `native' avrasm to Intel Hex, while
+ use of `h' (-rph to screen or -rpfh foo.dmp to file)
+ results in a hex dump with ascii translation, ending with
+ a checksum:
+
+ 000078 95 08 24 ee 24 ff 27 cc 77 d7 ..$.$.'.w.......
+ 000080 bf 02 2f 4d 70 47 30 45 f0 10 ../MpG0E..=...h.
+ 000088 e0 00 16 e0 f0 89 16 f0 f0 79 .........y...i..
+ 000090 f4 18 16 fc f4 08 c0 04 14 fe ...........0...
+ Checksum: cb46
+
+ The above is just a sample of (shortened) lines taken from
+ actual output.
+ During a read, you will see a progress bar like this:
+
+ oooooooooooooooooooooooo.......................................
+
+ NOTE: 16-bit word addresses are used when displaying the
+ program space, and words are shown hi byte first.
+ By default, data read from the eeprom area is presented in
+ this format:
+
+ Address: Data in hex, dec, oct, bin
+ 0000: 0xc0 192 0300 11000000
+ 0x01: 0x99 153 0231 10011001
+
+ Or in this format when a single address is read to the screen
+ (stdout):
+
+ The byte 0x99 (153, 0231, B10011001) was read from
+ eeprom address 0x0001
+
+ But you can also use the commands -reH, -refH or -refI
+ with appropriate effect. Byte addressing is used for the
+ hex dump display.
+
+ -s Show supported devices
+ The command sp12 -s reads a list of supported uCs and
+ their device codes from _sp12dev, and shows them on screen.
+
+ -t Timing check
+ The command sp12 -t presents a progress bar which should
+ take about 10 seconds to complete, counting from the moment
+ when you hit the return on the command line. (There may a
+ brief pause before the bar appears, which nevertheless is
+ part of the ten seconds.) The "bugs & bother" section
+ of readme.linux or readme.dos tells you more about its use.
+
+ -T This option was retained to remain compatible with older
+ versions, but option -P offers much more control over the
+ parallel port.
+ By default, SP12 will leave the parallel port databits all
+ zero on exit. Command -T1 leaves the reset pin high, so a
+ connected device will start running immediately after SP12
+ has finished, assuming it uses an external power source.
+ Command -T2 also leaves the `powerbits' (2-6, as shown by
+ progrmmr.gif) high, to run a device without external
+ power.
+
+ -w write
+ To write to either program or eeprom area, a single address
+ (-wpa address:data, or -wea address:data) or the whole area.
+ In the latter case, input has to be taken from a file, so the
+ -f option is mandatory: -wpf foo.hex reads foo.hex and writes
+ to the program area; the device is automatically erased
+ first, unless the overlay option is used (as in -Owpf).
+ -wef foo.hex reads foo.hex and writes to the eeprom area;
+ there is *no* preceding erase, but SP12 will ensure that
+ all locations which are not specifically addressed by the
+ file contain 0xff - unless the overlay option is used.
+ During a write, you will see a progress bar like this:
+
+ oooooooooooooooooooooooo.......................................
+
+ NOTE: All writes are automatically verified; SP12 immediately
+ reads back from the current address and compares the response
+ with the data that was written. If the response is not
+ correct, SP12 tries to write to the same address two more
+ times before coming back with "ERROR: Verify has failed."
+
+ -X Extended fuse bits
+ Valid combinations: -rX and -wX<n...n>. The latter command
+ writes all extended fuse bits in one go; you must supply
+ the right number of bits, or sp12 will barf. Refer to your
+ device's datasheet to see whether there are extended fuse
+ bits to write, and if so, how many. Note that the string
+ must include any non-fuse or otherwise fixed bits between
+ the writable fuses, while excluding such fixed bits at
+ either end of the string. (See also sp12dev.txt and
+ _sp12dev.)
+ You can write the n...n in hex if you want, but in that case
+ sp12 can't check the number of bits; the command -wX0x3 will
+ write zeroes into the fuse bits 2, 3, 4 and so on, if they
+ happen to exist.
+ Note that there are separate options for `fuses' (-F)
+ and `high fuses' (-H).
+
+
+FILES
+ sp12(.exe) The executable.
+ readme.linux,
+ readme.dos Describes software installation on Linux and Dos/MSW
+ sp12.txt This file
+ changes.txt Describes the changes between versions
+ hardware.txt About hardware connections
+ sp12dev.txt,
+ sp12rc.txt Ins and outs of the runtime configuration files
+ _sp12rc The runtime configuration file
+ _sp12dev The runtime device definitions file
+ COPYING.txt The GNU general public licence states the terms and
+ conditions for copying, distribution and modification
+ of this software
+ dongle.txt Describes Ken Huntington's `dongle'.
+ progrmmr.gif Shows the layout and diagram of the programmer board
+ Steve is using.
+ icp_intr.gif Shows the connections between the parallel port
+ and a target board which uses external power, and
+ has an sp12-compatible time constant for providing
+ power-on reset.
+ dongle.gif `Dongle' designed by Ken Huntington. Helps when
+ the parallel port signal is marginal. Avoids
+ the need for Sck termination as shown in the
+ above two .gifs. Makes the cable high-Z except
+ when sp12 is active. Perfectly transparent to
+ the software.
+ SOURCE This directory contains the source files and a
+ makefile for use with gcc or djgpp, see below.
+ CSDPMI This directory contains cwsdpmi. Read the
+ paragraph `installation' for details.
+
+ACKNOWLEDGEMENTS
+ SP12 binaries intended for Linux are compiled with gcc 3.2.
+ The 32-bit Dos protected mode executable found in this version of
+ SP12 was compiled with gcc 2.8.1, as found in the DJGPP packages.
+ You can obtain a copy of this excellent compiler from any
+ SimTel.NET mirror in the pub/simtelnet/gnu/djgpp/ subdirectory, or
+ from one of the CCT mirrors, world-wide. Have a look at
+ http://www.delorie.com/djgpp/getting.html for more information.
+
+ This product includes software developed by the University of
+ California, Berkeley and its contributors.
+
+ The authors would like to thank Chris Jackson for pointing out
+ the timing problems version 0.5 has on very fast machines, and
+ for testing this version on those same machines.
+
+ Kevin Towers improved the code for reading Intel HEX files, to be
+ compatible with flash data as generated by the IAR C compiler.
+ He contributed code to support the ATmega page modes, and conceived
+ the method for programming multiple uCs on a single target, using
+ a single command line.
+ He also noted further timing problems on a fast Celeron with
+ version 0.6; these are solved by the more accurate and faster
+ autocalibration routine in version 0.7 and higher.
+
+ Others who have contributed bug reports and/or suggested
+ improvements:
+ Arian van Dorsten
+ Robert Hyde
+ Zoran Kostic
+ Ludger Manten
+ Walter Waldner
+
+BUGS & BOTHER
+ Please report them to the authors.
+
+ SP12 is known to run in Linux, in MS-DOS, in a Windows 3.X
+ Dosbox and in a Windows 9X Dosbox, on machines ranging from a
+ slow 386 to a 450MHz Pentium-II. Windows NT does not provide
+ the access to the parallel port required by SP12.
+
+ As reported by Chris Jackson:
+ "One of the machines that I tried it on had a Parallel Port
+ PCMCIA adapter installed. Unless the machine was powered up with
+ this device fully disconnected, the driver for it was loaded by
+ Windows. This meant that whenever SP12 set the port lines high,
+ the driver would kick in and set them back low again. Depending on
+ the speed of the driver's response, the programmer would sometimes
+ work, and sometimes not - which caused a bit of confusion at first."
+
+AUTHORS
+ Software: Steven Bolt (sbolt@xs4all.nl)
+ Kevin Towers (ktowers@omnexcontrols.com)
+ Hardware: Ken Huntington (kenh@compmore.net)
diff --git a/sp12dev.txt b/sp12dev.txt
new file mode 100644
index 0000000..3e8d720
--- /dev/null
+++ b/sp12dev.txt
@@ -0,0 +1,218 @@
+
+_SP12DEV RUNTIME COMMAND DEFINITION ENTRIES
+
+ Sp12 version 2.0 is a serial mode (in-circuit) programmer for the
+ AVR family of microcontrollers. It should be able to support all of
+ them, but we've added entries to _sp12dev only for the uCs we use
+ ourselves, and for some very close relatives. You can easily add
+ entries for missing family members; it's mostly a matter of
+ copying parts of the `serial programming instruction set' table
+ in the datasheet.
+
+ Editing _sp12dev also allows you to customize some of sp12's
+ behaviour. Let's have a look at what has been defined for the
+ ATtiny15:
+
+ begin 0690
+ -i690
+ -iT15
+
+ The device code consists of two `signature bytes' which the uC
+ will normally report to sp12. In some cases, two different device
+ codes apply to the same device; in that case, there have to be
+ two `begin' lines. (Have a look at the entry for the ATmega103.)
+ When a device is locked, it may not report a valid device code.
+ In that case, recognition has to be forced with the -i option
+ (see sp12.txt). The line `-i690' tells sp12 to expect the device
+ code as identifier, but you can also use a name like -iTiny15,
+ -iTiny15L, or an abbreviation as short as -iT15.
+ Sp12 attempts to match what's on the command line with the -i<name>
+ definitions in _sp12dev by first looking for the first defined
+ character, in this case the `T' (which has to be upper case in
+ _sp12dev, but case is ignored on the command line). Everything
+ before the `T' is ignored; defined characters following the `T'
+ must all be there, and digits must match (be all there and in
+ the right order, no undefined digits allowed), but superfluous
+ letters are allowed. So -S1200 in _sp12dev matches -iAT90S1200
+ on the command line, and also -iat90ls1200, -iat90s1200a,
+ -iLS1200 and so on. The definition for ATmega8 is just M8, which
+ matches names like -iMega8L, but not -iMega128.
+
+ DEVICENAME = ATtiny15L
+ FLASHSIZE = 512
+ EEPROMSIZE = 64
+ PAGEMODE = 0
+ PAGESIZE =
+
+ The above lines define the name, the flash size in (16-bit) words
+ and the size of the eeprom area, also in (8-bit) words.
+ The page mode is zero because the Tiny15's flash is programmed
+ one address at a time, which means there is no page size to
+ define.
+
+ READ_LOCK = lhlh hlll xxxx xxxx xxxx xxxx xxxx x21x
+ WRITE_LOCK = hlhl hhll hhhh h21h xxxx xxxx xxxx xxxx
+
+ Commands are defined nearly as shown in the `serial programming
+ instruction set'. That table shows for instance:
+
+ Write lock bits 1010 1100 1111 1211 xxxx xxxx xxxx xxxx
+
+ With the `21' marking the lock bits in a slightly different font.
+ Sp12 wants a one belonging to the command written as h, and a
+ zero as l, to get a clear difference between those and the lock
+ or fuse bits, which appear variously as numbers, capital letters
+ or i's and o's.
+
+ LOCK_MESSAGE = 11 - no lock
+ LOCK_MESSAGE = 10 - write protected
+ LOCK_MESSAGE = 00 - read/write protected
+
+ You can define any message you like. To sp12 it's just a string,
+ put on screen when the associated read or write command is used.
+ For instance, sp12 -rL results in:
+
+ 11 are the lock bits read from an ATtiny15L
+ 11 - no lock
+ 10 - write protected
+ 00 - read/write protected
+
+ NOTE: Some AVR uC lock commands reverse the bit sequence on readout,
+ examples being the AT90S8535, 4434, 2323, 2343 and Tiny22. And these
+ uCs have no `read locks' command; the locks and fuses are separately
+ programmed, but read together. So you write-protect them with
+ sp12 -wL10 while the result can be read back with sp12 -rF
+ resulting in:
+
+ 01011111 are the fuse bits read from an AT90S8535
+ 11xccccx - no lock
+ 01xccccx - write protected
+ 00xccccx - read/write protected
+ xx0ccccx - serial programming enabled
+ xxxcccc0 - FSTRT reset delay, datasheet p20
+
+ The more often used read and write protection is done with a less
+ confusing sp12 -wL00
+
+ WRITE_FUSES = hlhl hhll hlhx xxxx xxxx xxxx 87lh hh43
+ READ_FUSES = lhlh llll xxxx xxxx xxxx xxxx 8765 xx43
+
+ Here matters get a little more complicated. The Tiny15 does in
+ fact allow you to write the fuses 6 (SPIEN) and 5 (RSTDSBL).
+ But setting the first to `1' or the second to `0' would block
+ further serial mode programming access, making the uC useless
+ when you have no `high voltage' programmer, or need to program
+ in-circuit. That's why `lh' replaces these fuses in our write
+ command, fixing their values. An accidentally wrong command
+ like sp12 -wF10100010 is largely ignored by the programmer,
+ as shown by its response:
+
+ 10011110 are the fuse bits written into an ATtiny15L
+ 0x0111xx - BODLEVEL 4V (default 2.7V)
+ x00111xx - brownout detection enabled
+ xx0111CK - reset delay select (datasheet p15)
+
+ FUSES_MESSAGE = 0x0111xx - BODLEVEL 4V (default 2.7V)
+ FUSES_MESSAGE = x00111xx - brownout detection enabled
+ FUSES_MESSAGE = xx0111CK - reset delay select (datasheet p15)
+
+ The fuses message can be altered into anything you like.
+
+ WRITE_HIGH_FUSES =
+ READ_HIGH_FUSES =
+ HIGH_FUSES_MESSAGE =
+ WRITE_EXTD_FUSES =
+ READ_EXTD_FUSES =
+ EXTD_FUSES_MESSAGE =
+ READ_CALIBRATION = llhh hlll xxxx xxxx llll llll oooo oooo
+ CALIB_MESSAGE = single calibration byte (datasheet p55)
+
+ The final command to define is `read calibration byte', as the
+ little uC as no high or extended fuses.
+
+
+ An entry for the rather more complex ATmega8 needs a bit more
+ work:
+
+ begin 0793
+ -i793
+ -iM8
+ DEVICENAME = ATmega8
+ FLASHSIZE = 4096
+ EEPROMSIZE = 512
+ PAGEMODE = 1
+ PAGESIZE = 32
+
+ The page size has to be entered in (16-bit) words.
+
+ READ_LOCK = lhlh hlll llll llll xxxx xxxx xxoo oooo
+ WRITE_LOCK = hlhl hhll hhhx xxxx xxxx xxxx hhii iiii
+ LOCK_MESSAGE = xxxx11 - no lock
+ LOCK_MESSAGE = xxxx10 - write protected
+ LOCK_MESSAGE = xxxx00 - read/write protected
+ LOCK_MESSAGE = BTLKxx - Boot lock, datasheet p116
+ READ_FUSES = lhlh llll llll llll xxxx xxxx oooo oooo
+ WRITE_FUSES = hlhl hhll hlhl llll xxxx xxxx iiii iiii
+ FUSES_MESSAGE = 0xxxxxxx - BODLEVEL 4V (default 2.7V)
+ FUSES_MESSAGE = x0xxxxxx - brownout detection enabled
+ FUSES_MESSAGE = xxSUxxxx - reset delay, datasheet p28
+ FUSES_MESSAGE = xxxxCKSE - clock select, datasheet p24
+ WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hili iiii
+ READ_HIGH_FUSES = lhlh hlll llll hlll xxxx xxxx oooo oooo
+
+ Note the h and l between the i's in the write fuses command.
+ Bit-7 is the RSTDSBL fuse; if set to zero, it makes further
+ serial mode programming impossible, so it has been defined high.
+ According to the datasheet we can't change bit-5 (SPIEN), but it
+ has been defined low anyway.
+ Taking away bit-7 causes sp12 to expect a -wH string which is
+ seven bits long, for instance sp12 -wH1010001 resulting in:
+
+ 1010001 are the high fuse bits written into an ATmega8
+ 1xxxxxxx - PC6 is reset pin
+ x0xxxxxx - WDT always on
+ xx0xxxxx - serial programming enabled
+ xxx0xxxx - CKOPT max, datasheet p24
+ xxxx0xxx - eeprom not erased
+ xxxxxBZx - boot size, datasheet p215
+ xxxxxxx0 - reset at boot loader, p204
+
+ Assuming you're using a fixed pitch font, the 7-bit string will
+ be correctly aligned with the 8-bit message lines.
+
+ HIGH_FUSES_MESSAGE = 1xxxxxxx - PC6 is reset pin
+ HIGH_FUSES_MESSAGE = x0xxxxxx - WDT always on
+ HIGH_FUSES_MESSAGE = xx0xxxxx - serial programming enabled
+ HIGH_FUSES_MESSAGE = xxx0xxxx - CKOPT max, datasheet p24
+ HIGH_FUSES_MESSAGE = xxxx0xxx - eeprom not erased
+ HIGH_FUSES_MESSAGE = xxxxxBZx - boot size, datasheet p215
+ HIGH_FUSES_MESSAGE = xxxxxxx0 - reset at boot loader, p204
+ WRITE_EXTD_FUSES =
+ READ_EXTD_FUSES =
+ EXTD_FUSES_MESSAGE =
+ READ_CALIBRATION = llhh hlll llxx xxxx llll llll oooo oooo
+ CALIB_MESSAGE = four calibration bytes (datasheet p28 p29 p218)
+
+
+ An entry for the new Tiny2313 is no more difficult than the above,
+ but do note that use of the `debugwire' feature means you lose the
+ resetpin - so it can't be used when you depend on a serial mode
+ programmer like sp12. The entry in the current _sp12dev guards
+ accidental changes of the DWEN, SPIEN and RSTDISBL fuses:
+
+ WRITE_HIGH_FUSES = hlhl hhll hlhl hlll xxxx xxxx hili iiih
+
+ A new command introduced in the Tiny2313 is `poll rdy/bsy':
+
+ POLL_RDY_BSY = hhhh llll llll llll xxxx xxxx xxxx xxxo
+
+ When this command is part of an _sp12dev entry, the -o option
+ is ignored. And for devices which obey this new programming
+ command, -o must be ignored, as -o1 would cause errors.
+
+
+ I hope it will indeed prove easy to add entries to _sp12dev. Do
+ be sure to use the latest datasheets and errata when making them.
+ I had some trouble with an older sheet for the Mega163, which
+ contained a totally wrong `read lock bits' command...
+
diff --git a/sp12rc.txt b/sp12rc.txt
new file mode 100644
index 0000000..cb0fabe
--- /dev/null
+++ b/sp12rc.txt
@@ -0,0 +1,159 @@
+
+_SP12RC RUNTME CONFIGURATION FILE SETTINGS
+
+ PORT=<nnn>
+
+ Before creating _sp12rc, the programmer looks for available
+ parallel ports. If more than one address is found, or you know
+ about an address missed by sp12, you may want to edit the PORT=
+ line.
+
+ KANDA=<n>
+
+ Sp12 is compatible with three programming cables; the one as
+ used with previous versions - with or without Ken Huntington's
+ `dongle' - and the cable/dongles supplied with the Kanda
+ STK200/300 starter kits. The latter two are functionally
+ equivalent. To select a hardware mode, you edit the `KANDA' line
+ to read `KANDA=0' (original sp12 cable), `KANDA=1' (Kanda mode),
+ or `KANDA=3', to make sp12 behave according to how it is called.
+ A name with a `k' in it will cause Kanda mode, plain sp12 will be
+ just that. In Linux, this allows easy switching between the modes
+ when you make a symbolic link to the executable, like
+
+ ln -s /usr/local/bin/sp12 /usr/local/bin/sp12.kanda
+
+ This results in
+
+ -r-sr-xr-x 1 root root 53208 Jan 18 09:02 sp12*
+ lrwxrwxrwx 1 root root 19 Jan 1 11:15 sp12.kanda -> /usr/local/bin/sp12*
+
+ Creating a single executable with two names.
+
+ Note that the Kanda cable/dongle lacks some features, which means
+ that the port control option (see sp12.txt) is of limited use in
+ this mode.
+
+ LOGPATH=<path/logfile>
+
+ You can set a log path/file, where SP12 will log its write and
+ lock operations. The default is "sp12log.txt" in the current
+ directory, creating a separate log file for each project.
+ Adding a path combines everything in a single log file.
+
+ LOGGING=<n>
+
+ You can set LOGGING=1 (Default is 0.) When `logging' is set,
+ every write and lock operation will cause a single line to be
+ appended to the log.
+
+ QUERY=<n>
+
+ You can also set QUERY=1 (Default is 0). SP12 normally checks
+ each location (or ATmega page) right after writing; if the
+ content doesn't match what was written, SP12 retries a couple
+ of times before giving up. This procedure achieves correct
+ programming when conditions or memory cells are marginal, and
+ also catches the large majority of hard errors. But defects and
+ averse conditions may sometimes cause the content of one
+ address to change, while another is being written to. You can
+ catch these (extremely rare) errors by setting both `logging'
+ and `query'. After writing a file content into the designated
+ memory area, the flash or eeprom will then be read back and
+ compared with the file, address by address. When all is well, a
+ checksum is calculated and added to the log; else "readback
+ ERROR" is reported. For instance:
+
+ AT90S2313 -wpf diz_2.hex checksum cb46 Sat Sep 23 18:43:49 2000
+ AT90S2313 -wef diz_2.eep checksum 0f37 Sat Sep 23 18:43:53 2000
+ AT90S2313 -wea 00000052:0xaa verified Sat Sep 23 18:43:54 2000
+ AT90S2313 -wpa 00000006:0x5679 readback ERROR Sat Sep 23 19:30:24 2000
+ AT90S2313 -wpf diz_2.hex readback ERROR Fri Sep 23 19:33:02 2000
+
+ NOTE: The overlay option modifies the `query' behaviour; see
+ sp12.txt.
+ Lock operations are preceded by memory checksum calculations,
+ and results are logged like this:
+
+ ATmega8 -L3c flash 2451 eeprom 3d44 Sat Jan 18 09:49:40 2003
+
+ Note that the log command is written in hex, to save space.
+ So in the above case the command -wL111100 was used to read and
+ write protect the Mega8.
+ When logging is set but query is not, the address by address
+ comparison is not performed, and writes are logged like this:
+
+ AT90S2313 -wpf diz_2.hex not queried Fri Sep 29 14:42:21 2000
+ AT90S2313 -wef diz_2.eep not queried Fri Sep 29 14:42:22 2000
+
+ CHIPERASE=<nnn>
+
+ The default value of 120ms is demanded by for instance the old
+ Mega103. Many other devices can make do with 30 or 20ms. If you
+ feel the difference is significant, by all means edit this value,
+ but be sure to read the datasheets of your devices. There is
+ usually a table in the `serial downloading' section.
+
+ POWERON=<nnn>
+
+ The value of this time constant depends partly on the power supply
+ of your target, which may need time to reach a stable Vcc.
+ Note however that for values shorter than 100ms, it is necessary
+ to keep both reset and sck at gnd while the device powers up,
+ which isn't always possible. It's best to read the `serial
+ programming algorithm' in your device's datasheet before
+ experimenting with this setting.
+
+ CLOCKSPDDEFAULT=<n.n>
+
+ The default is 0.7MHz, which usually fits devices running on their
+ internal RC clock at Vcc > 4V. You can edit the value and/or
+ ask for something different by using the -M option on the command
+ line (see sp12.txt). For instance, with `-M4' you state that your
+ target is clocked at 4MHz. The minimum value is 0.1.
+
+ LOOPCOUNT=<n.ne+n>
+
+ The default is an autocalibrated number representing one second,
+ and used to calculate timing values as demanded by clockSpdDefault
+ and the -M option. Manual editing is recommended only if there is
+ no way to make autocalibration work well enough. (See the `bugs &
+ bother' section in readme.linux or readme.dos.)
+
+ PORTACCESSTIME=<n.ne-n>
+
+ The time your parallel port needs to respond to an outportb()
+ call. Don't edit. As this time is typically longer than 1us, this
+ is likely to limit the shortest timing to about 1.3us for an Sck
+ half cycle. Most AVR uCs need the Sck low and high phases to be
+ at least two clock cycles long; the AT89S1200 is an exception,
+ needing an Sck high phase of at least four clock cycles. So
+ while SP12 works correctly with very fast uCs, the time needed to
+ execute a command line is not likely to decrease for -M and
+ clockSpdDefault settings above 3MHz for the 1200, and 1.5MHz for
+ the other family members. SP12 reports the timing achieved.
+
+ BYTEWRITE=<nnn>
+ PAGEWRITE=<nnn>
+ PROGRAMENABLE=<nn>
+ RESETPULS=<nnn>
+
+ None of the above settings should be edited, with the possible
+ exceptiong of RESETPULS. The default number represents 50ms, and
+ is mostly determined by assumptions about the reset circuit of
+ your target. A very simple arrangement would consist of 10K
+ between the reset pin and Vcc, and a capacitor between that pin
+ and gnd. The constant must be (more than) long enough to allow
+ that cap to be (dis)charged. If your target has a rapid
+ (brown-out) reset circuit, a shorther value is possible.
+
+ NOTE: You may have written software which grabs the i/o lines
+ used for programming immediately after reset, and your device's
+ reset delay (CKSEL/SUT settings) may be shorter than 50ms.
+ This won't usually cause trouble. Sp12 either prevents the grab or
+ gently takes back control of the programming lines. You probably
+ won't even notice the grab attempt. But in rare cases, RESETPULS
+ may have to be reduced to a low value (divide the default by 500
+ or 1000) or zero. This has never happened to me (Steve), so I'd
+ be interested to hear the details of such cases.
+
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..5d37e14
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,691 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "sp12.h"
+
+
+/* Converts address or data string to number, automatically */
+/* selecting hex (0xNNN), oct (0NNN), binary (BNNN) or */
+/* dec (NNN) input. */
+
+unsigned int str2num(char *addressOrData) {
+
+ unsigned int number;
+
+ /*
+ * Determine format (hex, decimal or binary) by looking at prefix
+ * and convert data to unsigned int using base 2, 8, 10 or 16
+ */
+ if (addressOrData[1] == 'x')
+ number = (unsigned int) strtol(addressOrData, NULL, 16);
+ else if (addressOrData[0] == '0')
+ number = (unsigned int) strtol(addressOrData, NULL, 8);
+ else if (addressOrData[0] == 'B')
+ number = (unsigned int) strtol(&addressOrData[1], NULL, 2);
+ else
+ number = (unsigned int) strtol(addressOrData, NULL, 10);
+
+ return(number);
+}
+
+/* convert unsigned int to a string-representation of the */
+/* binary number (ascii `0' is 48, ascii `1' is 49) */
+
+void num2bin(unsigned char buffer, char *binary) {
+
+ int Bi;
+
+ for (Bi = 7; Bi >= 0; Bi--) {
+ binary[Bi] = (buffer & 0x01) + 48;
+ buffer = buffer >> 1;
+ }
+ binary[8] = '\0';
+}
+
+/* Reads program file in Atmel generic format (address:data) or */
+/* Intel HEX format; stores data into into flashBuf by address. */
+/* flashBuf by address. The two numbers in the generic format are */
+/* hex without `0x'. For example: 00000c:99e1 */
+/* Note: the 16-bit bufLimit is not suitable for Mega address space. */
+
+int readFlashFile(char flashPath[], unsigned int flashBuf[], long bufLimit) {
+
+ FILE *flashBufPtr;
+ char wordstring[WORDLEN];
+ long address;
+ unsigned int data;
+ char buffer[MAXLEN];
+ long offsetAddress = 0L;
+ int dataByteCount;
+ unsigned int lineAddress;
+ int recordType;
+ int idx;
+ int checksum;
+ int tmp;
+
+ if ((flashBufPtr = fopen(flashPath, "r")) == NULL) {
+ return(1);
+ } else {
+ if (fgets(wordstring, WORDLEN, flashBufPtr) != NULL) {
+ /*
+ * Try Atmel generic format (default of the Atmel assembler).
+ */
+ if (wordstring[FLASH_DATAPTR] == ':') {
+ fseek(flashBufPtr, 0, SEEK_SET);
+ while (fgets(wordstring, WORDLEN, flashBufPtr) != NULL) {
+ sscanf(wordstring, "%lx", &address);
+ if (wordstring[FLASH_DATAPTR] != ':') {
+ return(1);
+ }
+ sscanf(&wordstring[FLASH_DATAPTR + 1], "%x", &data);
+ if (address < bufLimit)
+ flashBuf[address] = data;
+ else
+ return(1);
+ }
+ fclose(flashBufPtr);
+ return(0);
+ }
+ /*
+ * Try Intel HEX format.
+ */
+ if (wordstring[0] == ':') {
+ fseek(flashBufPtr, 0, SEEK_SET);
+ while (fgets(buffer, MAXLEN, flashBufPtr) != NULL) {
+ checksum = 0;
+ sscanf(&buffer[1], "%2x", &dataByteCount);
+ checksum += dataByteCount;
+ sscanf(&buffer[3], "%4x", &lineAddress);
+ sscanf(&buffer[3], "%2x", &tmp);
+ checksum += tmp;
+ sscanf(&buffer[5], "%2x", &tmp);
+ checksum += tmp;
+ sscanf(&buffer[7], "%2x", &recordType);
+ checksum += recordType;
+ /*
+ * Record type 02 means update offset address
+ */
+ if (recordType == 2) {
+ sscanf(&buffer[9], "%4lx", &offsetAddress);
+ sscanf(&buffer[9], "%2x", &tmp);
+ checksum += tmp;
+ sscanf(&buffer[11], "%2x", &tmp);
+ checksum += tmp;
+ checksum = (unsigned char) (0x100 - (unsigned char) checksum);
+ sscanf(&buffer[13], "%2x", &tmp);
+ if (checksum != tmp)
+ return(1);
+ }
+ if (recordType == 0) {
+ for (idx = 9; idx < 9 + dataByteCount * 2; idx += 2) {
+ sscanf(&buffer[idx], "%2x", &data);
+ /*
+ * Use word addresses for the AT90 2-byte data format
+ */
+ address = lineAddress / 2;
+ address = address + (offsetAddress * 0x10) / 2;
+ if (address < bufLimit) {
+ if (lineAddress & 0x0001) /* is it an odd address? */
+ /* then set MSB of data */
+ flashBuf[address] &= (data << 8) | 0x00ff;
+ else /* else set LSB of data */
+ flashBuf[address] &= data | 0xff00;
+ } else {
+ return(1);
+ }
+ lineAddress++;
+ checksum += data;
+ }
+ checksum = (unsigned char) (0x100 - (unsigned char) checksum);
+ sscanf(&buffer[idx], "%2x", &tmp);
+ if (checksum != tmp)
+ return(1);
+ }
+ }
+ fclose(flashBufPtr);
+ return(0);
+ }
+ }
+ }
+ return(1);
+}
+
+/* Reads eeprom file in format address:data, stores data into */
+/* eepromBuf by address. Both numbers can be hexadecimal (0xC4), */
+/* decimal (196), octal (0304) or binary (B11000100). */
+
+int readEepromFile(char eepromPath[], unsigned int eepromBuf[], long bufLimit) {
+
+ FILE *eepromBufPtr;
+ char wordstring[WORDLEN];
+ long address;
+ unsigned int data;
+ char buffer[MAXLEN];
+ char *dataPtr;
+ long offsetAddress = 0L;
+ int dataByteCount;
+ unsigned int lineAddress;
+ int recordType;
+ int idx;
+ int checksum;
+ int tmp;
+
+ if ((eepromBufPtr = fopen(eepromPath, "r")) == NULL) {
+ return(1);
+ } else {
+ if (fgets(wordstring, WORDLEN, eepromBufPtr) != NULL) {
+ /*
+ * Try sp12 eeprom format.
+ */
+ if (strchr(wordstring, ':') != &wordstring[0]) {
+ fseek(eepromBufPtr, 0, SEEK_SET);
+ while (fgets(wordstring, WORDLEN, eepromBufPtr) != NULL) {
+ if ((dataPtr = strchr(wordstring, ':')) == NULL) {
+ return(1);
+ }
+ dataPtr[0] = '\0';
+ address =str2num(wordstring);
+ data = str2num(++dataPtr);
+ if (address < bufLimit)
+ eepromBuf[address] = data;
+ else
+ return(1);
+ }
+ fclose(eepromBufPtr);
+ return(0);
+ }
+ /*
+ * Try Intel HEX format.
+ */
+ if (strchr(wordstring, ':') == &wordstring[0]) {
+ fseek(eepromBufPtr, 0, SEEK_SET);
+ while (fgets(buffer, MAXLEN, eepromBufPtr) != NULL) {
+ checksum = 0;
+ sscanf(&buffer[1], "%2x", &dataByteCount);
+ checksum += dataByteCount;
+ sscanf(&buffer[3], "%4x", &lineAddress);
+ sscanf(&buffer[3], "%2x", &tmp);
+ checksum += tmp;
+ sscanf(&buffer[5], "%2x", &tmp);
+ checksum += tmp;
+ sscanf(&buffer[7], "%2x", &recordType);
+ checksum += recordType;
+ /*
+ * Record type 02 means update offset address
+ */
+ if (recordType == 2) {
+ sscanf(&buffer[9], "%4lx", &offsetAddress);
+ sscanf(&buffer[9], "%2x", &tmp);
+ checksum += tmp;
+ sscanf(&buffer[11], "%2x", &tmp);
+ checksum += tmp;
+ checksum = (unsigned char) (0x100 - (unsigned char) checksum);
+ sscanf(&buffer[13], "%2x", &tmp);
+ if (checksum != tmp)
+ return(1);
+ }
+ if (recordType == 0) {
+ address = lineAddress;
+ address = address + (offsetAddress * 0x10) / 2;
+ /*
+ * Use byte addresses for single byte eeprom data format.
+ */
+ for (idx = 9; idx < 9 + dataByteCount * 2; idx += 2) {
+ sscanf(&buffer[idx], "%2x", &data);
+ if (address < bufLimit)
+ eepromBuf[address] = data;
+ else
+ return(1);
+ address++;
+ checksum += data;
+ }
+ checksum = (unsigned char) (0x100 - (unsigned char) checksum);
+ sscanf(&buffer[idx], "%2x", &tmp);
+ if (checksum != tmp)
+ return(1);
+ }
+ }
+ fclose(eepromBufPtr);
+ return(0);
+ }
+ }
+ }
+ return(1);
+}
+
+/* Calculate checksum over buffer[]; int bufLimit is number of */
+/* elements in buffer. */
+
+unsigned int checksum(unsigned int buffer[], long bufLimit) {
+
+ long idx;
+ unsigned int chksum = 0;
+
+ /*
+ * cyclic right shift 1 of chksum + buffer element
+ */
+ for (idx = 0; idx < bufLimit; idx++) {
+ if (buffer[idx] == 0xfff)
+ buffer[idx] = 0xff;
+ chksum = ((chksum>>1) + ((chksum & 1) ?0x8000:0) + buffer[idx]) & 0xffff;
+ }
+ return(chksum);
+}
+
+/* Routines to write the flash or eeprom buffer into a file, */
+/* using Intel HEX format or as a hex dump with ascii translation. */
+
+#define BYTES_PER_LINE 16
+
+static int flash_intel_hex (FILE *filePtr, unsigned int *buffer,
+ long addr, long length) {
+
+ int line_cnt = 0; /* line byte count */
+ int line_len = 0; /* expected line length */
+ unsigned char checksum = 0;
+ unsigned char byt;
+
+ length *= 2;
+ while (length > 0) {
+ if (addr > 0xFFFF) { /* add record type 02 */
+ fprintf (filePtr, ":020000021000EC\n");
+ addr = 0x10000 - addr;
+ }
+ if (line_cnt == 0) { /* write line header */
+ line_len = (length > BYTES_PER_LINE) ? BYTES_PER_LINE : length;
+ fprintf (filePtr, ":%02X%04lX00", line_len, addr);
+ checksum = line_len;
+ checksum += addr & 0xff;
+ checksum += addr >> 8;
+ }
+
+ if (addr & 0x0001) { /* is it an odd address? */
+ byt = *buffer >> 8; /* write MSB */
+ buffer++;
+ } else {
+ byt = *buffer & 0x00ff; /* write LSB */
+ }
+ fprintf (filePtr, "%02X", byt);
+ checksum += byt;
+
+ if (++line_cnt == line_len) { /* write checksum */
+ fprintf (filePtr, "%02X\n", -checksum & 0xff);
+ line_cnt = 0;
+ }
+ addr++;
+ length--;
+ }
+ fprintf (filePtr, ":00000001FF\n"); /* write the terminator */
+ return (0);
+}
+
+static int eeprom_intel_hex (FILE *filePtr, unsigned int *buffer,
+ unsigned int addr, long length) {
+ int line_cnt = 0; /* line byte count */
+ int line_len = 0; /* expected line length */
+ unsigned char checksum = 0;
+
+ while (length > 0) {
+ if (line_cnt == 0) { /* write line header */
+ line_len = (length > BYTES_PER_LINE) ? BYTES_PER_LINE : length;
+ fprintf (filePtr, ":%02X%04X00", line_len, addr);
+ checksum = line_len;
+ checksum += addr & 0xff;
+ checksum += addr >> 8;
+ }
+ fprintf (filePtr, "%02X", *buffer);
+ checksum += *buffer;
+ if (++line_cnt == line_len) { /* write checksum */
+ fprintf (filePtr, "%02X\n", -checksum & 0xff);
+ line_cnt = 0;
+ }
+ buffer++;
+ addr++;
+ length--;
+ }
+ fprintf (filePtr, ":00000001FF\n"); /* write the terminator */
+ return (0);
+}
+
+int file_hex_ascii(FILE *filePtr, unsigned int buffer[],
+ int bufLimit, int twoByteFlag) {
+
+ unsigned long address;
+ char dataStr[MAXLEN];
+ char asciiStr[MAXLEN];
+ char lineBuf[MAXLEN];
+ unsigned char loByte, hiByte;
+ int addressPerLine = 0x10;
+
+ dataStr[0] = '\0';
+ asciiStr[0] = '\0';
+ for (address = 0; address < bufLimit; address++) {
+ if ((address > 0) && (address % addressPerLine) == 0) {
+ if ((fprintf(filePtr, "%06lx %s %s\n",
+ address - addressPerLine, dataStr, asciiStr)) == EOF)
+ return(1);
+ dataStr[0] = '\0';
+ asciiStr[0] = '\0';
+ }
+ if (twoByteFlag) {
+ addressPerLine = 0x08;
+ loByte = (unsigned char) buffer[address];
+ hiByte = (unsigned char) (buffer[address] >> 8);
+ sprintf(lineBuf, "%02x %02x ", hiByte, loByte);
+ strcat(dataStr, lineBuf);
+ if ((hiByte > 31) && (hiByte < 127))
+ sprintf(lineBuf, "%c", hiByte);
+ else
+ sprintf(lineBuf, ".");
+ strcat(asciiStr, lineBuf);
+ if ((loByte > 31) && (loByte < 127))
+ sprintf(lineBuf, "%c", loByte);
+ else
+ sprintf(lineBuf, ".");
+ strcat(asciiStr, lineBuf);
+ } else {
+ sprintf(lineBuf, "%02x ", buffer[address]);
+ strcat(dataStr, lineBuf);
+ if ((buffer[address] > 31) && (buffer[address] < 127))
+ sprintf(lineBuf, "%c", buffer[address]);
+ else
+ sprintf(lineBuf, ".");
+ strcat(asciiStr, lineBuf);
+ }
+ }
+ if ((fprintf(filePtr, "%06lx %s %s\n",
+ address - addressPerLine, dataStr, asciiStr)) == EOF)
+ return(1);
+ fprintf(filePtr, "Checksum: %04x\n",
+ checksum(buffer, bufLimit));
+ return(0);
+}
+
+/* Writes flashBuf[] into FILE *flashBufPtr using either Intel HEX */
+/* or the `native' format. */
+/* If write to file fails, return(1), else return(0) */
+
+int fileFlashBuf(unsigned int flashBuf[], long bufLimit,
+ char flashPath[], int intel_flag, int hex_ascii_flag) {
+
+ FILE *flashBufPtr;
+ long address;
+
+ if ((flashBufPtr = fopen(flashPath, "w")) == NULL)
+ return(1);
+
+ if (hex_ascii_flag) {
+ file_hex_ascii(flashBufPtr, flashBuf, bufLimit, 1);
+ } else if (intel_flag) {
+ flash_intel_hex(flashBufPtr, flashBuf, 0, bufLimit);
+ } else {
+ for (address = 0; address < bufLimit; address++) {
+ if ((fprintf(flashBufPtr, "%06lx:%04x\n",
+ address, flashBuf[address])) == EOF)
+ return(1);
+ }
+ }
+ fclose(flashBufPtr);
+ return(0);
+}
+
+/* Writes eepromBuf[] into FILE *eepromBufPtr; */
+/* If write to file fails, return(1), else return(0) */
+
+int fileEepromBuf(unsigned int eepromBuf[], long bufLimit,
+ char eepromPath[], int intel_flag, int hex_ascii_flag) {
+
+ FILE *eepromBufPtr;
+ long address;
+ char binary[9] = "76543210";
+
+ if ((eepromBufPtr = fopen(eepromPath, "w")) == NULL)
+ return(1);
+
+ if (hex_ascii_flag) {
+ file_hex_ascii(eepromBufPtr, eepromBuf, bufLimit, 0);
+ } else if (intel_flag) {
+ eeprom_intel_hex(eepromBufPtr, eepromBuf, 0, bufLimit);
+ } else {
+ if ((fprintf(eepromBufPtr,
+ "Address: Data in hex, dec, oct, bin\n")) == EOF)
+ return(1);
+ for (address = 0; address < bufLimit; address++) {
+ num2bin((unsigned char) eepromBuf[address], binary);
+ if ((fprintf(eepromBufPtr,
+ " %#06lx: %#04x %3d %#4o %s\n",
+ address, eepromBuf[address], eepromBuf[address],
+ eepromBuf[address], binary)) == EOF)
+ return(1);
+ }
+ }
+ fclose(eepromBufPtr);
+ return(0);
+}
+
+/* Writes buffer[] to stdout as a hex dump with ascii translation */
+
+void printBuffer(unsigned int buffer[], long bufLimit, int twoByteFlag) {
+
+ long address;
+ char dataStr[MAXLEN];
+ char asciiStr[MAXLEN];
+ char lineBuf[MAXLEN];
+ unsigned char loByte, hiByte;
+ int addressPerLine = 0x10;
+
+ dataStr[0] = '\0';
+ asciiStr[0] = '\0';
+ for (address = 0; address < bufLimit; address++) {
+ if ((address > 0) && (address % addressPerLine) == 0) {
+ printf("%06lx %s %s\n", address - addressPerLine, dataStr, asciiStr);
+ dataStr[0] = '\0';
+ asciiStr[0] = '\0';
+ }
+ if (twoByteFlag) {
+ addressPerLine = 0x08;
+ loByte = (unsigned char) buffer[address];
+ hiByte = (unsigned char) (buffer[address] >> 8);
+ sprintf(lineBuf, "%02x %02x ", hiByte, loByte);
+ strcat(dataStr, lineBuf);
+ if ((hiByte > 31) && (hiByte < 127))
+ sprintf(lineBuf, "%c", hiByte);
+ else
+ sprintf(lineBuf, ".");
+ strcat(asciiStr, lineBuf);
+ if ((loByte > 31) && (loByte < 127))
+ sprintf(lineBuf, "%c", loByte);
+ else
+ sprintf(lineBuf, ".");
+ strcat(asciiStr, lineBuf);
+ } else {
+ sprintf(lineBuf, "%02x ", buffer[address]);
+ strcat(dataStr, lineBuf);
+ if ((buffer[address] > 31) && (buffer[address] < 127))
+ sprintf(lineBuf, "%c", buffer[address]);
+ else
+ sprintf(lineBuf, ".");
+ strcat(asciiStr, lineBuf);
+ }
+ }
+ printf("%06lx %s %s\n", address - addressPerLine, dataStr, asciiStr);
+ printf("Checksum: %04x\n", checksum(buffer, bufLimit));
+}
+
+/* Add spaces until lenght or max is reached */
+/* Try to break line if necessary */
+
+void formatStr(char *logStr, int length, int max) {
+
+ int idx;
+ int limit;
+ int idxL = 0;
+
+ limit = length;
+ for (idx = 0; idx < limit; idx++) {
+ if (idx == max) {
+ logStr[idx] = '\0';
+ break;
+ }
+ if ((++idxL > length / 2) && logStr[idx] == ' ') {
+ logStr[idx] = '\n';
+ limit = limit + idxL;
+ idxL = 0;
+ }
+ if (logStr[idx] == '\0') {
+ logStr[idx] = ' ';
+ logStr[idx + 1] = '\0';
+ }
+ }
+}
+
+/* Add a line to the log about a write command */
+
+int logWrites(char *commandStr, unsigned int address, int data,
+ char *path, unsigned int buffer[], int overlayFlag, int *error) {
+
+ FILE *logPtr;
+ time_t curTime;
+ struct tm *locTime;
+ unsigned int areaChksum = 0;
+ unsigned int *queryBuf;
+ int idx;
+ long adrsCnt;
+ char deviceName[MAXLEN];
+ char fileName[MAXLEN];
+ char *fileNamePtr;
+
+ if (log.logging != 1)
+ return(0);
+
+ formatStr(commandStr, 6, MAXLEN);
+ strcpy(deviceName, device.name);
+ if (strcmp(deviceName, "AT90(L)S2343 or Tiny22(L)") == 0)
+ strcpy(deviceName, "2343/Tiny22");
+ formatStr(deviceName, 12, MAXLEN);
+ queryBuf = malloc(FLASHBUF_UPPERLIMIT * sizeof (unsigned int));
+ if (queryBuf == NULL) {
+ printf ("ERROR: No memory available for buffer!\n");
+ return(0);
+ }
+
+ curTime = time(NULL);
+ locTime = localtime(&curTime);
+
+ if ((logPtr = fopen(log.logPath, "a")) == NULL) {
+ free(queryBuf);
+ return(1);
+ }
+ fprintf(logPtr, "%s %s ", deviceName, commandStr);
+ if (strchr(commandStr, 'f') != NULL) {
+ strcpy(fileName, path);
+ fileNamePtr = fileName;
+ idx = strlen(fileName);
+ while (idx-- > 0 && fileName[idx] != '\\' && fileName[idx] != '/')
+ fileNamePtr = &fileName[idx];
+ formatStr(fileNamePtr, 14, MAXLEN - idx);
+ fprintf(logPtr, "%s ", fileNamePtr);
+ if (log.query) {
+ if (strchr(commandStr, 'p') != NULL) {
+ readFlashArea(queryBuf, device.flashLimit);
+ areaChksum = checksum(queryBuf, device.flashLimit);
+ *error = 0;
+ for (adrsCnt = 0; adrsCnt < device.flashLimit; adrsCnt++) {
+ if (overlayFlag && buffer[adrsCnt] == 0xffff)
+ continue;
+ if (queryBuf[adrsCnt] != buffer[adrsCnt]) {
+ *error = 1;
+ break;
+ }
+ }
+ } else {
+ readEepromArea(queryBuf, device.eepromLimit);
+ areaChksum = checksum(queryBuf, device.eepromLimit);
+ *error = 0;
+ for (adrsCnt = 0; adrsCnt < device.eepromLimit; adrsCnt++) {
+ if (overlayFlag && buffer[adrsCnt] > 0xFF)
+ continue;
+ if (queryBuf[adrsCnt] != (unsigned char) buffer[adrsCnt]) {
+ *error = 1;
+ break;
+ }
+ }
+ }
+ if (*error)
+ fprintf(logPtr, "readback ERROR %s", asctime(locTime));
+ else
+ fprintf(logPtr, "checksum %04x %s", areaChksum, asctime(locTime));
+ } else {
+ fprintf(logPtr, "not queried %s", asctime(locTime));
+ }
+ } else {
+ if (strchr(commandStr, 'p') != NULL)
+ fprintf(logPtr, "%08x:%#06x ", address, data);
+ else
+ fprintf(logPtr, "%08x:%#04x ", address, data);
+ if (*error)
+ fprintf(logPtr, "readback ERROR %s", asctime(locTime));
+ else
+ fprintf(logPtr, "verified %s", asctime(locTime));
+ }
+ fclose(logPtr);
+ free(queryBuf);
+ return(0);
+}
+
+/* Add a line to the log about a lock command */
+
+int logLocks(unsigned int buffer[], char *lockBits) {
+
+ FILE *logPtr;
+ time_t curTime;
+ struct tm *locTime;
+ unsigned int areaChksum = 0;
+ char deviceName[MAXLEN];
+ char lBits[MAXLEN] = "";
+
+ if (log.logging != 1)
+ return(0);
+
+ sprintf(lBits, "%02lx", strtol(lockBits, NULL, 2));
+
+ strcpy(deviceName, device.name);
+ formatStr(deviceName, 12, MAXLEN);
+ curTime = time(NULL);
+ locTime = localtime(&curTime);
+
+ if ((logPtr = fopen(log.logPath, "a")) == NULL)
+ return(1);
+ fprintf(logPtr, "%s -L%s ", deviceName, lBits);
+ readFlashArea(buffer, device.flashLimit);
+ areaChksum = checksum(buffer, device.flashLimit);
+ fprintf(logPtr, "flash %04x ", areaChksum);
+ readEepromArea(buffer, device.eepromLimit);
+ areaChksum = checksum(buffer, device.eepromLimit);
+ fprintf(logPtr, "eeprom %04x %s", areaChksum, asctime(locTime));
+ fclose(logPtr);
+ return(0);
+}
diff --git a/src/device.c b/src/device.c
new file mode 100644
index 0000000..53fe054
--- /dev/null
+++ b/src/device.c
@@ -0,0 +1,434 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */
+/* Artur Pundsack, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+/* Artur Pundsack can be reached by email: ap@pa-tec.de */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dos_cpt.h"
+#include "sp12.h"
+
+/* Delay by executing not quite empty loops */
+
+void loopDelay(unsigned long loops) {
+
+ unsigned long Ti;
+ float dummy;
+
+ for (Ti = 0; Ti < loops; Ti++) {
+ dummy = rand();
+ }
+}
+
+/* Assume the device connected to the Centronics port is powered, */
+/* but that device sck was not held low during power-up, so a */
+/* reset pulse is needed before the SPI can be enabled. */
+/* Assume also that power has yet to be switched on (for separate */
+/* programmer powered by parallel port, instead of in-circuit */
+/* programming. */
+/* If uC is 1200, emit just one PROGRAM_ENABLE command. */
+/* Else retry until the third byte read back by clockOutCommand() */
+/* is 0x53, or at least 32 retries have been unsuccessful. */
+
+int enableSPI(int uC) {
+
+ unsigned long readBack = 0;
+ int tries = 0;
+ /*
+ * Initialise programming lines.
+ */
+ bit_clear(outbyte, ENABLE | SCK | MOSI | RESET);
+ outportb(portAddress, outbyte);
+ /*
+ * Delay to make sure capacitor on separate programmer is charged.
+ */
+ delay(timeConst.powerOn);
+ /*
+ * If the resetPuls time constant > 0, then Hi pulse device reset
+ */
+ if (timeConst.resetPuls > 0) {
+ bit_set(outbyte, RESET);
+ outportb(portAddress, outbyte);
+ /*
+ * Delay to make sure that a capacitor
+ * from reset to gnd is (dis)charged
+ */
+ loopDelay(timeConst.resetPuls);
+ bit_clear(outbyte, RESET);
+ outportb(portAddress, outbyte);
+ /*
+ * Delay before program (SPI) enable command
+ */
+ delay(timeConst.programEnable);
+ }
+ /*
+ * Command program enable and check synchronization
+ */
+ while (tries < 33) {
+ tries++;
+ readBack = clockOutCommand(PROGRAM_ENABLE);
+ readBack = (readBack & 0x0000FF00L) >> 8;
+ if ((readBack == 0x53) || (uC == 1200)) {
+ break;
+ } else {
+ /*
+ * Pulse SCK lo-hi-lo
+ */
+ bit_clear(outbyte, SCK);
+ outportb(portAddress, outbyte);
+ loopDelay(timeConst.sckLO);
+ bit_set(outbyte, SCK);
+ outportb(portAddress, outbyte);
+ loopDelay(timeConst.sckHI);
+ bit_clear(outbyte, SCK);
+ outportb(portAddress, outbyte);
+ loopDelay(timeConst.sckLO);
+ }
+ }
+ if (tries > 1)
+ printf("Sp12 tried %d times to find a working device.\n", tries);
+ if ((readBack != 0x53) && (uC != 1200))
+ printf("No device connected.\n");
+/* printf("readBack: %#lx, tries: %d\n", readBack, tries); */
+ return(tries);
+}
+
+/* Adapt Sck timing to user's clock speed setting */
+/* (Init sets the timing equal to sck0.5M, and the flag will be */
+/* zero unless altered by the command line.) */
+
+float setSckTiming(float clkSpeed) {
+
+ float signal;
+
+ clkSpeed = (float) 2 / (clkSpeed * 1e6);
+ if (clkSpeed > timeConst.port)
+ timeConst.sckLO = (unsigned long) (timeConst.loop *
+ (clkSpeed - timeConst.port));
+ else
+ timeConst.sckLO = 1;
+ if (strcmp(device.name, "AT90S1200(A)") == 0
+ && (clkSpeed * 2) > timeConst.port)
+ timeConst.sckHI = (unsigned long) (timeConst.loop *
+ (clkSpeed * 2 - timeConst.port));
+ else
+ timeConst.sckHI = timeConst.sckLO;
+// printf("sckLO %ld, sckHI %ld\n", timeConst.sckLO, timeConst.sckHI);
+ signal = 1.8e-6 / clkSpeed;
+ if (strcmp(device.name, "AT90S1200(A)") == 0) {
+ if ((signal / 2) > (1.8e-6 / timeConst.port))
+ signal = 4.0e-6 / timeConst.port;
+ } else {
+ if (signal > (1.8e-6 / timeConst.port))
+ signal = 2.0e-6 / timeConst.port;
+ }
+ return(signal);
+}
+
+/* Before writing to the flash area, the device has to be erased. */
+/* Note: This command also erases the eeprom area (all to 0xFF). */
+/* There is no need for general erase before writing to the */
+/* eeprom area, since the device has an auto-erase built into */
+/* the eeprom write cycle. Thus you can alter one or more eeprom */
+/* addresses without disturbing the rest of the device. */
+
+void eraseDevice(void) {
+
+ clockOutCommand(CHIP_ERASE);
+ /*
+ * Delay before program (SPI) enable sequence
+ */
+ delay(timeConst.chipErase);
+ /*
+ * syncronisation must be ok, so just one PROGRAM_ENABLE
+ * command will be clocked out.
+ */
+ enableSPI(1200);
+}
+
+/* A routine to switch control the optional test bits on the */
+/* parallel port. */
+
+void portControl(int portFlag, int exitFlag) {
+
+ if (exitFlag) {
+ outbyte = (unsigned char) portFlag;
+ } else {
+ outbyte = (unsigned char) portFlag & PORTACTIVE;
+ delay(10);
+ }
+ outportb(portAddress, outbyte);
+}
+
+/* Reads flash and eeprom area's. Return 1 if a flash address does */
+/* not contain 0xFFFF, or 3 if an eeprom address also isn't blank; */
+/* return 2 if the flash is blank, but the eeprom isn't; */
+/* return 0 is both area's are blank. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: - Set the extended adress byte if necessary */
+
+int blankCheck(long flashLimit, long eepromLimit) {
+
+ long address, writeCmd;
+ int signal = 0;
+
+ if (flashLimit > 0x0000FFFF){
+ writeCmd = LOAD_EXT_ADDR;
+ clockOutCommand(writeCmd);
+ }
+
+ for (address = 0; address < flashLimit; address++) {
+ if (readCodeWord(address) != 0xffff) {
+ signal |= 0x01;
+ break; /* arrea is not blank; exit loop */
+ }
+ }
+ for (address = 0; address < eepromLimit; address++) {
+ if (readDataByte(address) != 0xff) {
+ signal |= 0x02;
+ break; /* arrea is not blank; exit loop */
+ }
+ }
+ return(signal);
+}
+
+
+/* Sends a lock or fuses string to the microcontroller. */
+/* Returns 9 if the writeCommand is zero (not available according */
+/* to _sp12dev). */
+/* The lock or fuses string may represent a binary or hex number. */
+/* If it's binary, the length of the string is compared with */
+/* W_FUSESLEN; a useful sanity check. The function returns 2 if */
+/* the length is wrong. A hex number is not checked, as there is no */
+/* way to know how many leading zeroes are intended. */
+/* Next, the block is ored into the writeCommand and uploaded to */
+/* the device. */
+/* Since (re)enabling brown-out detection usually causes the */
+/* AT90(L)S2333/4433 to hang, the fuses are only written, not */
+/* verified. */
+
+int writeFuses(unsigned long commandHM, unsigned long commandLM, \
+ char *fuses, int WfusesLsb, int WfusesLen) {
+
+ unsigned long fuseWord = 0;
+ int Bi;
+
+ if (!commandHM)
+ return(9);
+ if (fuses[1] == 'x')
+ fuseWord = strtoul(fuses, NULL, 16);
+ else if (strlen(fuses) != WfusesLen)
+ return(2);
+ else
+ fuseWord = strtoul(fuses, NULL, 2);
+ fuseWord = fuseWord << WfusesLsb;
+ fuseWord = fuseWord & commandHM;
+ fuseWord = fuseWord | commandLM;
+// printf("\nfuseword %04lx\n", fuseWord);
+ clockOutCommand(fuseWord);
+ /*
+ * Read back the fuses as a binary string
+ */
+ fuseWord = fuseWord >> WfusesLsb;
+ for (Bi = WfusesLen - 1; Bi >= 0; Bi--) {
+ fuses[Bi] = (fuseWord & 0x01L) + 48;
+ fuseWord = fuseWord >> 1;
+ }
+ fuses[WfusesLen] = '\0';
+ /*
+ * ByteWrite delay not long enough to allow reading back
+ * of true ATmega103/603 fuses directly after this
+ */
+ delay(timeConst.chipErase);
+ return(0);
+}
+
+
+/* Reads the lock or fuse bit block from the microcontroller. */
+/* Returns 9 if the readCommand is zero (not available according */
+/* to _sp12dev). */
+
+int readFuses(unsigned long readCommand, char *fuses, \
+ int RfusesLsb, int RfusesLen) {
+
+ unsigned long fuseWord = 0;
+ int Bi;
+
+ if (!readCommand)
+ return(9);
+
+ fuseWord = clockOutCommand(readCommand);
+ fuseWord = fuseWord >> RfusesLsb;
+ for (Bi = RfusesLen - 1; Bi >= 0; Bi--) {
+ fuses[Bi] = (fuseWord & 0x01L) + 48;
+ fuseWord = fuseWord >> 1;
+ }
+ fuses[RfusesLen] = '\0';
+ return(0);
+}
+
+
+/* Read the signature bits from the device attached to the */
+/* Centronics parallel port. */
+
+void readDeviceCode(void) {
+
+ unsigned long readCmd;
+
+ readCmd = READ_DEVICE | 0x0200L;
+ device.sigByte_2 = (unsigned char) clockOutCommand(readCmd);
+ readCmd = READ_DEVICE | 0x0100L;
+ device.sigByte_1 = (unsigned char) clockOutCommand(readCmd);
+ readCmd = READ_DEVICE | 0x0000L;
+ device.sigByte_0 = (unsigned char) clockOutCommand(readCmd);
+}
+
+
+/* Shifts the command highest bit first into unsigned char output, */
+/* which then is used to clock them out bit by bit through */
+/* Centronics data-7. */
+/* Reads back and returns whatever the uC clocks out on Miso */
+/* while the command is clocked in. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+unsigned long clockOutCommand(unsigned long command) {
+
+ unsigned long inBuf;
+ unsigned long readBack = 0x0L;
+ unsigned char inbyte; /* from Centronics status reg. */
+ int mostSigBit;
+ int i;
+
+ mostSigBit = 31;
+ /*
+ * Bits mostSigBit-0 to be clocked out
+ */
+ for (i = mostSigBit; i >= 0; i--) {
+ /*
+ * Bits mostSigBit-0 to be clocked out
+ */
+ if ((command >> i) & 0x01L)
+ bit_set(outbyte, MOSI);
+ else
+ bit_clear(outbyte, MOSI);
+ bit_clear(outbyte, SCK);
+ outportb(portAddress, outbyte);
+ /*
+ * Minimum delay SCK lo period
+ */
+ loopDelay(timeConst.sckLO);
+ /*
+ * Set bit-0 (SCK) hi, leave all other bits as they are
+ */
+ bit_set(outbyte, SCK);
+ outportb(portAddress, outbyte);
+ /*
+ * Minimum delay SCK hi period
+ */
+ loopDelay(timeConst.sckHI);
+ /*
+ * Fetch parallel port status register, clear all bits
+ * except 7 (MOSI), invert, shift and or into buffer
+ */
+ inbyte = inportb(portStatus);
+ inBuf = ((unsigned long) (inbyte ^ MISO_INV)) >> MISO_BITNR;
+ inBuf = (inBuf & 0x00000001L) << i;
+ readBack = readBack | inBuf;
+ }
+ /*
+ * return SCK to lo
+ */
+ bit_clear(outbyte, SCK);
+ outportb(portAddress, outbyte);
+ return(readBack);
+}
+
+/* Accepts a dataByte and a 16-bit address. Writes the byte into */
+/* the device connected to the Centronics port and verifies arrival. */
+/* Returns 1 if verify fails three times, else 0. */
+/* The time constant byteWrite is adjusted dynamically, */
+/* if the device is not a 1200(A) and/or optimizeFlag allows. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeByteVerified(unsigned long writeCommand,
+ unsigned long readCommand, int optimizeFlag) {
+
+ int idx;
+ unsigned char readBack;
+ int failure = 0;
+ unsigned char dataByte;
+ /*
+ * First check if the data isn't already in the uC
+ */
+ dataByte = (unsigned char) writeCommand;
+ readBack = (unsigned char) clockOutCommand(readCommand);
+ if (readBack == dataByte)
+ return(failure);
+ /*
+ * Else write the data into the uC
+ */
+ dataByte = (unsigned char) writeCommand;
+ clockOutCommand(writeCommand);
+ switch (dataByte) {
+ case 0xFF:
+ case 0x7F:
+ case 0x80:
+ case 0x00:
+ loopDelay(timeConst.byteWriteDefault);
+ readBack = (unsigned char) clockOutCommand(readCommand);
+ break;
+ default:
+ loopDelay(timeConst.byteWrite);
+ readBack = (unsigned char) clockOutCommand(readCommand);
+ if ((strcmp(device.name, "AT90S1200(A)") != 0 && optimizeFlag != 10)
+ || optimizeFlag == 11) {
+ if (readBack != dataByte) {
+ timeConst.byteWrite += timeConst.byteWriteDefault / 12;
+ timeConst.byteWriteAdjusted = 1;
+ loopDelay(timeConst.byteWrite);
+ readBack = (unsigned char) clockOutCommand(readCommand);
+ } else {
+ if (timeConst.byteWriteAdjusted == 0)
+ timeConst.byteWrite -= timeConst.byteWriteDefault / 12;
+ }
+ }
+ }
+ idx = 1;
+ if (readBack != dataByte) {
+ timeConst.byteWrite = timeConst.byteWriteDefault;
+ timeConst.byteWriteAdjusted = 0;
+ do {
+ clockOutCommand(writeCommand);
+ loopDelay(timeConst.byteWrite);
+ readBack = (unsigned char) clockOutCommand(readCommand);
+ } while (readBack != dataByte && ++idx < 4);
+ writeRetries += idx - 1;
+ if (readBack != dataByte)
+ failure = 1;
+ }
+ return(failure);
+}
+
diff --git a/src/dos_cpt.h b/src/dos_cpt.h
new file mode 100644
index 0000000..8cbfb80
--- /dev/null
+++ b/src/dos_cpt.h
@@ -0,0 +1,53 @@
+/* SP12: A serial programmer for working with Atmel AT90S uCs */
+/* Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+
+#ifdef LINUX
+
+#include <sys/io.h>
+#include <unistd.h>
+
+#define inportb(a) inb(a)
+#define outportb(a,b) outb(b,a)
+
+#define delay(a) usleep(a*1000)
+
+#else
+
+#ifdef WIN32
+
+// these functions are in winnt.c
+void win_giveio(void);
+void delay(int mseconds);
+inline unsigned char inportb (const unsigned short port);
+inline void outportb (unsigned short port, const unsigned char val);
+
+#else
+
+#include <dos.h>
+
+#endif // WIN32
+#endif // LINUX
+
+
+
+
+
diff --git a/src/eeprom.c b/src/eeprom.c
new file mode 100644
index 0000000..4e1513a
--- /dev/null
+++ b/src/eeprom.c
@@ -0,0 +1,125 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dos_cpt.h"
+#include "sp12.h"
+
+
+/* Accepts a 16-bit address. Reads the dataByte in two steps */
+/* from the device connected to the Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+unsigned char readDataByte(unsigned int address) {
+
+ unsigned int dataByte;
+ unsigned long readCmd;
+
+ readCmd = READ_EEPROM | ((long) address << 8);
+ dataByte = (unsigned char) clockOutCommand(readCmd);
+ return(dataByte);
+}
+
+/* Accepts a dataByte and a 16-bit address. Writes the code in two */
+/* steps into the device connected to the Centronics port and */
+/* verifies arrival. Returns 1 if verify fails three times, else 0. */
+/* The time constant byteWrite is adjusted dynamically, */
+/* if the device is not a 1200(A) and optimizeFlag allows. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeEepromVerified(unsigned int address, unsigned char dataByte,
+ int optimizeFlag) {
+
+ int failure;
+ unsigned long readCmd, writeCmd;
+
+ readCmd = READ_EEPROM | ((long) address << 8);
+ writeCmd = WRITE_EEPROM | ((long) address << 8);
+ writeCmd = writeCmd | dataByte;
+ failure = writeByteVerified(writeCmd, readCmd, optimizeFlag);
+ return(failure);
+}
+
+/* Expects eepromBuf[] to be filled with data. */
+/* executes writeEepromVerified() address by address; */
+/* if verify fails, stops and returns 1, else returns 0. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeEepromArea(unsigned int eepromBuf[], long bufLimit,
+ int optimizeFlag, int overlayFlag) {
+
+ long address, previous;
+
+ previous = 0;
+ printf("...............................................................\r");
+ /*
+ * If the overlayFlag is cleared, all addresses are written to
+ * since all data words (including 0xFF) can be valid.
+ * When the overlayFlag is set, buffer addresses containing
+ * the original 0xFF padding are skipped.
+ */
+ for (address = 0; address < bufLimit; address++) {
+ if (address >= (previous + bufLimit / 64)) {
+ putchar('o');
+ fflush(stdout);
+ previous = address;
+ }
+ if (overlayFlag && eepromBuf[address] > 0xFF)
+ continue;
+ if (writeEepromVerified (address, (unsigned char) eepromBuf[address],
+ optimizeFlag) == 1) {
+ printf("!!\n");
+ return (1);
+ }
+ }
+ printf("\n");
+ return (0);
+}
+
+/* (expects eepromBuf[] to be filled with 0xFF) */
+/* Loops readDataByte into eepromBuf[] */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+void readEepromArea(unsigned int eepromBuf[], long bufLimit) {
+
+ long address, previous;
+
+ previous = 0;
+ printf("...............................................................\r");
+
+ for (address = 0; address < bufLimit; address++) {
+ eepromBuf[address] = readDataByte(address);
+ if (address >= (previous + bufLimit / 64)) {
+ putchar('o');
+ fflush(stdout);
+ previous = address;
+ }
+ }
+ printf("\n");
+}
+
diff --git a/src/flash.c b/src/flash.c
new file mode 100644
index 0000000..f70dde1
--- /dev/null
+++ b/src/flash.c
@@ -0,0 +1,292 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */
+/* Artur Pundsack, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+/* Artur Pundsack can be reached by email: ap@pa-tec.de */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dos_cpt.h"
+#include "sp12.h"
+
+/* Accepts a 16-bit address. Reads the codeWord in two steps */
+/* from the device connected to the Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: - The adresswidth has been increased from */
+/* 16 to 32 bits (int -> long), */
+/* - Extended addressing support has been added */
+
+unsigned int readCodeWord(unsigned long address) {
+
+ unsigned char readByte;
+ unsigned int codeWord;
+ unsigned long readCmd;
+ unsigned long writeCmd;
+
+ /* For large ATMegas like ATMega2561 an extended address has to */
+ /* be set when crossing the 64k boundary. */
+ if (address > 0x0000FFFF) {
+ writeCmd = LOAD_EXT_ADDR | ((address & 0x00FF0000) >> 8);
+ clockOutCommand(writeCmd);
+ }
+
+ codeWord = 0;
+ readCmd = READ_PROG_HI | ((address & 0x0000FFFF) << 8);
+ readByte = (unsigned char) clockOutCommand(readCmd);
+ codeWord = codeWord | readByte;
+ readCmd = READ_PROG_LO | ((address & 0x0000FFFF) << 8);
+ readByte = (unsigned char) clockOutCommand(readCmd);
+ codeWord = (codeWord << 8) | readByte;
+ return(codeWord);
+}
+
+/* Accepts a 16-bit codeWord and a 32-bit address. Writes the code */
+/* in two steps with no delays into the ATMega device connected to */
+/* the Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: - The adresswidth has been increased from */
+/* 16 to 32 bits (int -> long), */
+/* - Extended addressing support has been added */
+void loadCodePage(unsigned long address, unsigned int codeWord) {
+
+ unsigned char loByte;
+ unsigned char hiByte;
+ unsigned long writeCmd;
+
+ loByte = (unsigned char) codeWord & 0x00FF;
+ hiByte = (unsigned char) ((codeWord & 0xFF00) >> 8);
+
+ /* For large ATMegas like ATMega2561 an extended address has to */
+ /* be set once for the first page and when crossing the 64k */
+ /* boundary. */
+ if ((ExtAddr != 1) && (address > 0x0000FFFF)) {
+ writeCmd = LOAD_EXT_ADDR | ((address & 0x00FF0000) >> 8);
+ clockOutCommand(writeCmd);
+ ExtAddr = 1; /* The 64k boundary has been detected */
+ }
+
+ writeCmd = LOAD_PAGE_LO | ((address & 0x000000FF) << 8);
+ writeCmd = writeCmd | loByte;
+ clockOutCommand(writeCmd);
+ writeCmd = LOAD_PAGE_HI | ((address & 0x000000FF) << 8);
+ writeCmd = writeCmd | hiByte;
+ clockOutCommand(writeCmd);
+}
+
+/* Accepts a 16-bit page number and programs it into the ATMega */
+/* device connected to the Centronics parallel port. */
+/* The page is read back and compared with the buffer; if all */
+/* is well, 0 is returned, else 1. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeCodePage(unsigned int flashBuf[], unsigned long address) {
+
+ unsigned long writeCmd;
+ unsigned int idx;
+ unsigned char readByte;
+ unsigned char testByte;
+
+ writeCmd = WRITE_PAGE | ((address & 0x0000FFFF) << 8);
+ clockOutCommand(writeCmd);
+ if (POLL_RDY_BSY) { /* time-out 64ms */
+ testByte = (unsigned char) ~POLL_RDY_BSY;
+ for (idx = 0; idx < 64; idx++) {
+ delay(1);
+ readByte = (unsigned char) clockOutCommand(POLL_RDY_BSY);
+ if ((readByte & testByte) == 0)
+ break;
+ }
+ } else {
+ loopDelay(timeConst.pageWrite);
+ }
+ for (idx = address + 1 - device.pageSize; idx <= address; idx++) {
+ if (flashBuf[idx] != 0xffff) {
+ if (readCodeWord(idx) != flashBuf[idx])
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/* Accepts a 16-bit codeWord and a 16-bit address. Writes the code */
+/* in two steps into the device connected to the Centronics port and */
+/* verifies arrival. Returns 1 if verify fails three times, else 0. */
+/* The time constant byteWrite is adjusted dynamically, */
+/* if the device is not a 1200(A) and optimizeFlag allows. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: This function is only available for non page mode!*/
+
+int writeFlashVerified(unsigned int address, unsigned int codeWord,
+ int optimizeFlag) {
+
+ unsigned char loByte;
+ unsigned char hiByte;
+ unsigned long readCmd, writeCmd;
+ int failure;
+
+ loByte = (unsigned char) codeWord & 0x00FF;
+ hiByte = (unsigned char) ((codeWord & 0xFF00) >> 8);
+
+ writeCmd = WRITE_PROG_HI | ((long) address << 8);
+ writeCmd = writeCmd | hiByte;
+ readCmd = READ_PROG_HI | ((long) address << 8);
+ failure = writeByteVerified(writeCmd, readCmd, optimizeFlag);
+ if (failure == 0) {
+ writeCmd = WRITE_PROG_LO | ((long) address << 8);
+ writeCmd = writeCmd | loByte;
+ readCmd = READ_PROG_LO | ((long) address << 8);
+ failure = writeByteVerified(writeCmd, readCmd, optimizeFlag);
+ }
+ return(failure);
+}
+
+/* Expects flashBuf[] to be filled with data. */
+/* If a (page) write fails, 1 is returned, else 0. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: - Added reset ext. address marker */
+/* - Set the extended adress byte if necessary */
+
+int writeFlashArea(unsigned int flashBuf[], long bufLimit,
+ int optimizeFlag) {
+
+ long address, previous, writeCmd;
+ int writeFlg = 0;
+ int idx = 1;
+
+ previous = 0;
+ printf("...............................................................\r");
+ if (optimizeFlag != 11)
+ timeConst.pageWriteAdjusted = 1;
+
+ /* AP, 15.01.2008: Added, Reset the extended address marker and */
+ /* set the extended adress byte if neccessary. */
+ ExtAddr = 0;
+ if (device.flashLimit > 0x0000FFFF){
+ writeCmd = LOAD_EXT_ADDR;
+ clockOutCommand(writeCmd);
+ }
+
+ for (address = 0; address < bufLimit; address++) {
+ if (device.pageMode) {
+ /*
+ * To speed things up: Skip locations containing 0xffff
+ * (The device has been erased before writing started)
+ */
+ if (flashBuf[address] != 0xffff) {
+ loadCodePage(address, flashBuf[address]);
+ writeFlg = 1;
+ }
+ if (writeFlg && (address > 0) &&
+ ((address & (device.pageSize - 1)) == device.pageSize - 1)) {
+ writeFlg = 0;
+ if (writeCodePage(flashBuf, address) == 1) {
+ if (++idx < 6) {
+ /*
+ * recalculate first address of the failed page
+ * once only. Note: The calculation below puts
+ * address at the last address value of the previous
+ * page. But address is incremented _after_ this
+ * calculation, _before_ loadCodePage is called
+ * again.
+ */
+ if (idx == 2) address = address - device.pageSize;
+ if (timeConst.pageWriteAdjusted == 1) writeRetries++;
+ } else {
+ printf("!!\n");
+ return (1);
+ }
+ if (optimizeFlag == 11) {
+ timeConst.pageWrite += timeConst.pageWrite / 2;
+ if (timeConst.pageWrite > 1.5 * timeConst.pageWriteDefault) {
+ printf("!!\n");
+ return (1);
+ }
+ timeConst.pageWriteAdjusted = 1;
+ }
+ } else {
+ if (optimizeFlag == 11 && timeConst.pageWriteAdjusted == 0) {
+ timeConst.pageWrite -= timeConst.pageWrite / 2;
+ }
+ idx = 1;
+ }
+ }
+ } else {
+ if (flashBuf[address] != 0xffff) {
+ if (writeFlashVerified((unsigned int) address,
+ flashBuf[address], optimizeFlag) == 1) {
+ printf("!!\n");
+ return (1);
+ }
+ }
+ }
+ if (address >= (previous + bufLimit / 64)) {
+ putchar('o');
+ fflush(stdout);
+ previous = address;
+ }
+ }
+
+ /*
+ * In page mode, a sequence like pageWrite reducing from 64ms
+ * to 32, 16, 8 and 4ms, then adjusting back upwards to 6ms
+ * and finally 9ms is valid; this would cause writeRetries
+ * to be incremented once. Therefore:
+ */
+ if (device.pageMode && writeRetries == 1)
+ writeRetries = 0;
+ printf("\n");
+ return (0);
+}
+
+/* (expects flashBuf[] to be filled with 0xFFFF) */
+/* Loops readCodeWord into flashBuf[] */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: - Set the extended adress byte if necessary */
+
+void readFlashArea(unsigned int flashBuf[], long bufLimit) {
+
+ long address, previous, writeCmd;
+
+ previous = 0;
+ printf("...............................................................\r");
+
+ if (device.flashLimit > 0x0000FFFF){
+ writeCmd = LOAD_EXT_ADDR;
+ clockOutCommand(writeCmd);
+ }
+
+ for (address = 0; address < bufLimit; address++) {
+ flashBuf[address] = readCodeWord(address);
+ if (address >= (previous + bufLimit / 64)) {
+ putchar('o');
+ fflush(stdout);
+ previous = address;
+ }
+ }
+ printf("\n");
+}
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 0000000..a9798a1
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,854 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */
+/* Artur Pundsack, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+/* Artur Pundsack can be reached by email: ap@pa-tec.de */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dos_cpt.h"
+#include <time.h>
+#include "sp12.h"
+
+
+const char RC_USAGE[] = {
+ "# SP12: A serial programmer for working with Atmel AVR uCs \n"
+ "# Copyright (C) 1997-2008 Ken Huntington, Kevin Towers,\n"
+ "# Artur Pundsack, Pitronics.\n"
+ "# \n"
+ "# This program is free software; you can redistribute it and/or \n"
+ "# modify it under the terms of the GNU General Public License \n"
+ "# as published by the Free Software Foundation; either version 2 \n"
+ "# of the License, or (at your option) any later version. \n"
+ "# \n"
+ "# This program is distributed in the hope that it will be useful, \n"
+ "# but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
+ "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n"
+ "# GNU General Public License for more details.\n"
+ "# \n"
+ "# You should have received a copy of the GNU General Public License \n"
+ "# along with this program; if not, write to the Free Software \n"
+ "# Foundation, Inc., 59 Temple Place - Suite 330, Boston, \n"
+ "# MA 02111-1307, USA. \n"
+ "# \n"
+ "# Pitronics can be reached by email: sbolt@xs4all.nl \n"
+ "# Kevin Towers can be reached by email: ktowers@omnexcontrols.com\n"
+ "# Ken Huntington can be reached by email: kenh@compmore.net \n"
+ "# \n"
+ "# Runtime configuration file to initialise time constants,\n"
+ "# parallel port, logging and port mode (sp12 native or Kanda \n"
+ "# compatible).\n"
+ "# Sp12 will make this file when first started; it will appear \n"
+ "# in the directory as defined by the environment variable SP12,\n"
+ "# or in the current directory if this variable is not set.\n"
+ "# The next time sp12 starts, time constants, port address, logging\n"
+ "# parameters and port mode will be read from this file.\n"
+ "# The primary parallel port address will be automatically selected.\n"
+ "# if you need to use, for instance, the secondary (0x278), then\n"
+ "# by all means edit this file manually, but don't change the *format*\n"
+ "# of the NNNN=ddd type statements, only the values. Note that\n"
+ "# BYTEWRITE is an upper limit; the value actually used is dynamically\n"
+ "# adjusted when sp12 runs. Check changes.doc for other details.\n"};
+
+/*--------------------- The global constants ------------------------*/
+
+unsigned long PROGRAM_ENABLE = 0xAC53FFFFL;
+unsigned long CHIP_ERASE = 0xAC80FFFFL;
+unsigned long READ_DEVICE = 0x30FF00FFL;
+unsigned long READ_PROG_LO = 0x200000FFL;
+unsigned long READ_PROG_HI = 0x280000FFL;
+unsigned long WRITE_PROG_LO = 0x40000000L;
+unsigned long WRITE_PROG_HI = 0x48000000L;
+unsigned long LOAD_PAGE_LO = 0x40000000L;
+unsigned long LOAD_PAGE_HI = 0x48000000L;
+unsigned long LOAD_EXT_ADDR = 0x4D000000L; /* AP, 15.01.2008: Added*/
+unsigned long WRITE_PAGE = 0x4C0000FFL;
+unsigned long READ_EEPROM = 0xA00000FFL;
+unsigned long WRITE_EEPROM = 0xC0000000L;
+unsigned long POLL_RDY_BSY = 0;
+unsigned long WRITE_LOCK_HM = 0;
+unsigned long WRITE_LOCK_LM = 0;
+unsigned long READ_LOCK = 0;
+unsigned long WRITE_FUSES_HM = 0;
+unsigned long WRITE_FUSES_LM = 0;
+unsigned long READ_FUSES = 0;
+unsigned long WRITE_HIGH_FUSES_HM = 0;
+unsigned long WRITE_HIGH_FUSES_LM = 0;
+unsigned long READ_HIGH_FUSES = 0;
+unsigned long WRITE_EXTD_FUSES_HM = 0;
+unsigned long WRITE_EXTD_FUSES_LM = 0;
+unsigned long READ_EXTD_FUSES = 0;
+unsigned long READ_CALIBRATION = 0;
+char CALIB_MESSAGE[MAXLEN] = "";
+char LOCK_MESSAGE[MAXLEN] = "";
+char FUSES_MESSAGE[MAXLEN] = "";
+char H_FUSES_MESSAGE[MAXLEN] = "";
+char X_FUSES_MESSAGE[MAXLEN] = "";
+int POLL_RBLSB = 0;
+int POLL_RBLEN = 0;
+int W_LOCKLSB = 0;
+int R_LOCKLSB = 0;
+int W_LOCKLEN = 0;
+int R_LOCKLEN = 0;
+int W_FUSESLSB = 0;
+int R_FUSESLSB = 0;
+int W_FUSESLEN = 0;
+int R_FUSESLEN = 0;
+int WH_FUSESLSB = 0;
+int RH_FUSESLSB = 0;
+int WH_FUSESLEN = 0;
+int RH_FUSESLEN = 0;
+int WX_FUSESLSB = 0;
+int RX_FUSESLSB = 0;
+int WX_FUSESLEN = 0;
+int RX_FUSESLEN = 0;
+int CALIBLSB = 0;
+int CALIBLEN = 0;
+
+/*------------------- No more global constants ----------------------*/
+
+/*---------------------- The global variables -----------------------*/
+
+unsigned char SCK;
+unsigned char MOSI;
+unsigned char MISO_BITNR;
+unsigned char MISO_INV;
+unsigned char RESET;
+unsigned char ENABLE;
+unsigned char PORTPOWER;
+unsigned char DEFAULT_EXIT_STATE;
+unsigned char PORTACTIVE;
+
+struct timeConsts timeConst;
+struct device_info device;
+struct logging log;
+
+int portAddress;
+int portStatus;
+int writeRetries;
+float clockSpdDefault;
+unsigned char outbyte;
+int KandaMode;
+int ExtAddr; /* AP, 15.01.2008: Added, Marker for crossing the 64k */
+ /* Flash boundary */
+
+/*-------------------- No more global variables ---------------------*/
+
+/* Look for available parallel ports, like the bios does, but */
+/* setting the data register to 0x80 and avoiding some rare */
+/* difficulties. The port address actually set will be the */
+/* last one available in the order 0x278, 0x378, 0x3BC, but */
+/* the status of all three will be reported in the rc file. */
+
+void checkParPort(FILE *rcPtr) {
+
+ printf("Looking for parallel ports...\n");
+
+ outportb(0x278, 0x80); /* Check secondary address, report */
+ /* status in rc file, set portAddress */
+ delay(1); /* Give port time to react */
+ if (inportb(0x278) == 0x80) {
+ portAddress = 0x278;
+ fprintf(rcPtr, "# Parallel port available at 0x278\n");
+ } else {
+ fprintf(rcPtr, "# NO parallel port at 0x278\n");
+ }
+
+ outportb(0x378, 0x80); /* Check primary address, report */
+ /* status in rc file, set portAddress */
+ delay(1); /* Give port time to react */
+ if (inportb(0x378) == 0x80) {
+ portAddress = 0x378;
+ fprintf(rcPtr, "# Parallel port available at 0x378\n");
+ } else {
+ fprintf(rcPtr, "# NO parallel port at 0x378\n");
+ }
+
+ outportb(0x3BC, 0x80); /* Check address on MDPA, report */
+ /* status in rc file, set portAddress */
+ delay(1); /* Give port time to react */
+ if (inportb(0x3BC) == 0x80) {
+ portAddress = 0x3BC;
+ fprintf(rcPtr, "# Parallel port available at 0x3BC\n");
+ } else {
+ fprintf(rcPtr, "# NO parallel port at 0x3BC\n");
+ }
+
+ fprintf(rcPtr, "# This port address will be used:\n");
+ fprintf(rcPtr, "PORT=%#x\n", portAddress);
+}
+
+/* Calibrate several time constants for delays that take care */
+/* of minimum pulse widths. portAddress must be valid. */
+
+void initTimeConst(FILE *rcPtr) {
+
+ clock_t start, end;
+ unsigned long reference;
+ unsigned long Ti; /* Timing loop counter */
+ unsigned long Ni; /* Temp. ref while calibrating */
+ /* timeConst.port */
+
+ printf("Calibrating delay loop. This may take some time...\n");
+
+ /*
+ * Measure time taken by timing loop,
+ * calibrate reference
+ */
+ reference = 1e6; /* 1e6 gives reasonable speed and */
+ /* accuracy in slow PCs like a 286 */
+ do {
+ start = clock();
+ loopDelay(reference);
+ end = clock();
+ /*
+ * Calculate elapsed time in seconds
+ */
+ timeConst.loop = ((double) (end - start)) / CLOCKS_PER_SEC;
+ if (timeConst.loop < 0.005) {
+ reference = reference * 4;
+ continue;
+ }
+ if (timeConst.loop < 1)
+ reference = (unsigned long) (reference * 1.2 / timeConst.loop);
+ } while (timeConst.loop < 1);
+
+ /*
+ * This line alters timeConst.loop as calculated by the loop
+ * above by a factor of two, when compiled by Linux gcc 2.7.
+ * Compiler magic...
+ */
+ timeConst.loop = ((double) (end - start)) / CLOCKS_PER_SEC;
+
+ /*
+ * Measure time taken by outportb() calls
+ */
+ Ni = 1e4;
+ do {
+ start = clock();
+ for (Ti = 0; Ti < Ni; Ti++) {
+ outportb(portAddress, 0x00);
+ }
+ end = clock();
+ /*
+ * Make timeConst.port equal to elapsed time in seconds
+ */
+ timeConst.port = ((double) (end - start)) / CLOCKS_PER_SEC;
+ if (timeConst.port < 0.005) {
+ Ni = Ni * 4;
+ continue;
+ }
+ if (timeConst.port < 1)
+ Ni = (unsigned long) (Ni * 1.2 / timeConst.port);
+ } while (timeConst.port < 1);
+ /*
+ * Set timeConst.port to time taken by 1 outportb() in seconds.
+ */
+ timeConst.port = (timeConst.port - Ni * timeConst.loop / reference) / Ni;
+ /*
+ * Set timeConst.loop to count for 1 second
+ */
+ timeConst.loop = reference / timeConst.loop;
+
+ /* All time constants set to 1 or larger; a check on time constants */
+ /* being zero is later used to estimate rc-file validity */
+
+ /* Calculate pageWrite for 64ms */
+ timeConst.pageWrite = timeConst.loop * 64e-3;
+ if (timeConst.pageWrite == 0)
+ timeConst.pageWrite = 1;
+
+ /* Calculate byteWrite for 12ms */
+ timeConst.byteWrite = timeConst.loop * 12e-3;
+ if (timeConst.byteWrite == 0)
+ timeConst.byteWrite = 1;
+
+ /* Calculate resetPuls for 50ms */
+ timeConst.resetPuls = timeConst.loop * 50e-3;
+ if (timeConst.resetPuls == 0)
+ timeConst.resetPuls = 1;
+
+ /* Set the other time constants in milliseconds */
+ timeConst.programEnable = 40;
+ timeConst.chipErase = 120; /* assume ATMega worst case */
+ timeConst.powerOn = 200;
+
+ /* Set the default uC clock speed in MHz */
+ clockSpdDefault = 0.7;
+
+ fprintf(rcPtr, "# Set KANDA=1 to adapt the parallel port pinout\n");
+ fprintf(rcPtr, "# to the cable/dongles supplied with the\n");
+ fprintf(rcPtr, "# Atmel/Kanda STK200/300 starter kits.\n");
+ fprintf(rcPtr, "# When KANDA=0 (default) the pinout conforms\n");
+ fprintf(rcPtr, "# to the original SP12 cable and Ken Huntington's\n");
+ fprintf(rcPtr, "# dongle.\n");
+ fprintf(rcPtr, "# If KANDA is removed or set to 3, sp12 will behave\n");
+ fprintf(rcPtr, "# according to the name by which it is called,\n");
+ fprintf(rcPtr, "# 'sp12' or 'sp12.kanda'.\n");
+ fprintf(rcPtr, "KANDA=%d\n", KandaMode);
+ fprintf(rcPtr, "# Set the log path/file to log writes and locks.\n");
+ fprintf(rcPtr, "# (less than 200 characters)\n");
+ fprintf(rcPtr, "LOGPATH=%s\n", log.logPath);
+ fprintf(rcPtr, "# Set logging=1 to activate logging:\n");
+ fprintf(rcPtr, "LOGGING=%d\n", log.logging);
+ fprintf(rcPtr, "# Set both logging and query=1 to always query writes:\n");
+ fprintf(rcPtr, "QUERY=%d\n", log.query);
+ fprintf(rcPtr, "# Chip erase delay, 120ms ATMega, 20ms others:\n");
+ fprintf(rcPtr, "CHIPERASE=%d\n", timeConst.chipErase);
+ fprintf(rcPtr, "# Time constant for 200ms will be:\n");
+ fprintf(rcPtr, "POWERON=%d\n", timeConst.powerOn);
+ fprintf(rcPtr, "# Set clockSpdDefault to a suitable value in MHz.\n");
+ fprintf(rcPtr, "CLOCKSPDDEFAULT=%.1f\n", clockSpdDefault);
+ fprintf(rcPtr, "# loopCount is a calibrated number which\n");
+ fprintf(rcPtr, "# represents about 1 second, and used to\n");
+ fprintf(rcPtr, "# calculate time constants as demanded by\n");
+ fprintf(rcPtr, "# clockSpdDefault and the -Mn.n clock speed\n");
+ fprintf(rcPtr, "# setting.\n");
+ fprintf(rcPtr, "LOOPCOUNT=%g\n", timeConst.loop);
+ fprintf(rcPtr, "# Do not change anything below this line.\n");
+ fprintf(rcPtr, "# ---------------------------------------\n");
+ fprintf(rcPtr, "PORTACCESSTIME=%g\n", timeConst.port);
+ fprintf(rcPtr, "BYTEWRITE=%ld\n", timeConst.byteWrite);
+ fprintf(rcPtr, "PAGEWRITE=%ld\n", timeConst.pageWrite);
+ fprintf(rcPtr, "PROGRAMENABLE=%d\n", timeConst.programEnable);
+ fprintf(rcPtr, "RESETPULS=%ld\n", timeConst.resetPuls);
+}
+
+/* Look for the rc file, using environment variable `SP12' (if */
+/* this variable has not been set, the current directory is used). */
+/* If the rc file exists, then read the time constants and the */
+/* parallel port address from this file. If the rc file is not */
+/* found, then calibrate the time constants, check for available */
+/* parallel ports, set (usually the primary) address, and write */
+/* it all into a new rc file. Afterwards check if the parallel */
+/* port is actually there (guarding against a corrupt rc file, and */
+/* setting the port data register to 0x80), and also check if the */
+/* time constants aren't 0. exit(1) if a check fails, else set */
+/* parallel port data register 0x00, and portStatus to */
+/* portAddress + 1 */
+/* Based on either the KANDA setting in _sp12rc or the name by */
+/* which the program is called (sp12 or sp12.kanda), the */
+/* parallel port pinout is adapted to the cable/dongles supplied */
+/* with the Atmel/Kanda STK200/300 starter kits, or to the */
+/* original SP12 cable and Ken Huntington's dongle. */
+
+void initSp12(char *howWeAreCalled) {
+
+ FILE *rcPtr;
+ char *sp12rc;
+ char rcPath[MAXLEN];
+ char rcLine[MAXLEN];
+
+ timeConst.sckLO = 0;
+ timeConst.sckHI = 0;
+ timeConst.resetPuls = 0;
+ timeConst.programEnable = 0;
+ timeConst.chipErase = 0;
+ timeConst.byteWrite = 0;
+ timeConst.powerOn = 0;
+
+ portAddress = 0;
+ portStatus = 0;
+ writeRetries = 0;
+ timeConst.byteWriteAdjusted = 0;
+ timeConst.pageWriteAdjusted = 0;
+ log.logging = 0;
+ log.query = 0;
+ strcpy(log.logPath, "sp12log.txt");
+ KandaMode = 3; /* if it remains 3 after reading _sp12rc, */
+ /* check how we were called */
+
+ if ((sp12rc = getenv("SP12")) != NULL) {
+ strcpy(rcPath, sp12rc);
+#ifdef LINUX
+ if (rcPath[strlen(rcPath)-1] != '/')
+ strcat (rcPath, "/");
+#else
+ if (rcPath[strlen(rcPath)-1] != '\\')
+ strcat (rcPath, "\\");
+#endif
+ printf("Path to _sp12rc and _sp12dev: %s\n", rcPath);
+ strcat(rcPath, "_sp12rc");
+ } else {
+ strcpy(rcPath, "_sp12rc");
+ printf("Path to _sp12rc and _sp12dev: Local directory\n");
+ }
+ if ((rcPtr = fopen(rcPath, "r")) != NULL) {
+ /*
+ * Read data from existing rc file, or...
+ */
+ while (fgets(rcLine, MAXLEN, rcPtr) != NULL) {
+ sscanf(rcLine, "PORT=%x", &portAddress);
+ sscanf(rcLine, "KANDA=%d", &KandaMode);
+ sscanf(rcLine, "LOGPATH=%s", log.logPath);
+ sscanf(rcLine, "LOGGING=%d", &log.logging);
+ sscanf(rcLine, "QUERY=%d", &log.query);
+ sscanf(rcLine, "RESETPULS=%ld", &timeConst.resetPuls);
+ sscanf(rcLine, "CHIPERASE=%d", &timeConst.chipErase);
+ sscanf(rcLine, "POWERON=%d", &timeConst.powerOn);
+ sscanf(rcLine, "CLOCKSPDDEFAULT=%f", &clockSpdDefault);
+ sscanf(rcLine, "LOOPCOUNT=%lg", &timeConst.loop);
+ sscanf(rcLine, "PORTACCESSTIME=%lg", &timeConst.port);
+ sscanf(rcLine, "BYTEWRITE=%ld", &timeConst.byteWrite);
+ sscanf(rcLine, "PAGEWRITE=%ld", &timeConst.pageWrite);
+ sscanf(rcLine, "PROGRAMENABLE=%d", &timeConst.programEnable);
+ }
+ } else {
+ /*
+ * Make a new rc file
+ */
+ delay(100); /* helps calibration to reach same values every time */
+ if ((rcPtr = fopen(rcPath, "w")) == NULL) {
+ fprintf(stderr, "Unable to open %s for writing.\n", rcPath);
+ exit(1);
+ }
+ if (strrchr(howWeAreCalled, '/') != NULL)
+ howWeAreCalled = (strrchr(howWeAreCalled, '/') + 1);
+ if (strrchr(howWeAreCalled, '\\') != NULL)
+ howWeAreCalled = (strrchr(howWeAreCalled, '\\') + 1);
+ if (strchr(howWeAreCalled, 'k') == NULL) {
+ KandaMode = 0; /* default is sp12 cable/dongle */
+ } else {
+ KandaMode = 1;
+ }
+ fprintf(rcPtr, "%s\n", RC_USAGE);
+ checkParPort(rcPtr);
+ if (portAddress) /* port must be valid, else segfault */
+ initTimeConst(rcPtr);
+ }
+ fclose(rcPtr);
+ if (!portAddress) /* no port found -> remove broken _sp12rc */
+ remove(rcPath);
+
+ /*
+ * Do check if the time constants aren't zero...
+ */
+ if (portAddress == 0 || timeConst.loop == 0 || timeConst.port == 0
+ || timeConst.programEnable == 0 || timeConst.chipErase == 0
+ || timeConst.byteWrite == 0 || timeConst.powerOn == 0
+ || timeConst.pageWrite == 0) {
+ fprintf(stderr, "Initialisation has failed (parallel port not found,\n");
+ fprintf(stderr, "or %s corrupt).\n", rcPath);
+ exit(1);
+ }
+ timeConst.byteWriteDefault = timeConst.byteWrite;
+ timeConst.pageWriteDefault = timeConst.pageWrite;
+ /*
+ * And if the port is actually there.
+ */
+ outportb(portAddress, 0x80);
+ if (inportb(portAddress) != 0x80) {
+ fprintf(stderr, "Initialisation has failed (parallel port not\n");
+ fprintf(stderr, "responding, or %s corrupt).\n", rcPath);
+ exit(1);
+ } else {
+ outportb(portAddress, 0x00);
+ portStatus = portAddress + 1;
+ }
+ /*
+ * Now set the parallel port pinout to match
+ * either the original sp12 cable and Ken's `dongle'
+ * or the cable/dongle as supplied with the
+ * Atmel/Kanda STK200/300 starter kits.
+ */
+ if (strrchr(howWeAreCalled, '/') != NULL)
+ howWeAreCalled = (strrchr(howWeAreCalled, '/') + 1);
+ if (strrchr(howWeAreCalled, '\\') != NULL)
+ howWeAreCalled = (strrchr(howWeAreCalled, '\\') + 1);
+ if (KandaMode == 0 || (KandaMode == 3 && strchr(howWeAreCalled, 'k') == NULL)) {
+ SCK = S_SCK;
+ MOSI = S_MOSI;
+ MISO_BITNR = S_MISO_BITNR;
+ MISO_INV = S_MISO_INV;
+ RESET = S_RESET;
+ ENABLE = S_ENABLE;
+ PORTPOWER = S_PORTPOWER;
+ DEFAULT_EXIT_STATE = S_DEFAULT_EXIT_STATE;
+ PORTACTIVE = S_PORTACTIVE;
+ printf("Running in SP12 cable/dongle compatible mode.\n");
+ } else if (KandaMode == 1 || \
+ (KandaMode == 3 && strchr(howWeAreCalled, 'k') != NULL)) {
+ SCK = K_SCK;
+ MOSI = K_MOSI;
+ MISO_BITNR = K_MISO_BITNR;
+ MISO_INV = K_MISO_INV;
+ RESET = K_RESET;
+ ENABLE = K_ENABLE;
+ PORTPOWER = K_PORTPOWER;
+ DEFAULT_EXIT_STATE = K_DEFAULT_EXIT_STATE;
+ PORTACTIVE = K_PORTACTIVE;
+ printf("Running in Kanda cable/dongle compatible mode.\n");
+ } else {
+ fprintf(stderr, "Call me 'sp12' or 'sp12.kanda', or set KANDA=0 or KANDA=1\n");
+ exit(1);
+ }
+ outbyte = PORTPOWER; /* Default: start with `port power' on */
+ /* (all zeroes when KANDA=1) */
+}
+
+
+/* Extract a lock or fuse command (read, write) from a rawLine */
+/* scanned from _sp12dev. Determine the lsb position and length */
+/* of the lock or fuses bit block, which is marked as something */
+/* like '6543' or 'iiiiii' or 'ooooooo' */
+
+int extractFuseCmnd(char *rawLine, unsigned long *commandHM, \
+ unsigned long *commandLM, int *fusesLsb, int *fusesLen) {
+
+ int idx = 0;
+ int idy = 0;
+ int chr = 0;
+ int fusesMsb = 0;
+ int firstBit = 0;
+ char procLine[MAXLEN];
+ char hiMask[MAXLEN] = "";
+ char loMask[MAXLEN] = "";
+
+ /*
+ * Command must be eight nibbles long, separated by spaces,
+ * containing only the characters we scanned for;
+ * but removing trailing spaces doesn't hurt.
+ */
+ for (idx = strlen(rawLine) - 1; idx > 0; idx--) {
+ if (rawLine[idx] != ' ')
+ break;
+ else
+ rawLine[idx] = '\0';
+ }
+// printf("len %i, raw %s\n", strlen(rawLine), rawLine);
+ if (strlen(rawLine) != 39)
+ return(1);
+ /*
+ * Remove the spaces
+ */
+ idy = 0;
+ for (idx = 0; idx < strlen(rawLine); idx++) {
+ if (rawLine[idx] != ' ') {
+ procLine[idy++] = rawLine[idx];
+ procLine[idy] = '\0';
+ }
+ }
+ /*
+ * Convert the characters into ones and zeroes,
+ * determine the position of the fuse lsb
+ */
+ firstBit = 0;
+ for (idx = 0; idx < strlen(procLine); idx++) {
+ chr = procLine[idx];
+ if (chr == 'h' || chr == 'x') {
+ hiMask[idx] = '1';
+ loMask[idx] = '1';
+ } else if (chr == 'l') {
+ hiMask[idx] = '0';
+ loMask[idx] = '0';
+ } else {
+ if (!firstBit) {
+ firstBit = 1;
+ fusesMsb = 31 - idx;
+ }
+ *fusesLsb = 31 - idx;
+ hiMask[idx] = '1';
+ loMask[idx] = '0';
+ }
+// printf("hiMask %s\n", hiMask);
+// printf("loMask %s\n", loMask);
+ }
+ *fusesLen = fusesMsb - *fusesLsb + 1;
+ *commandHM = strtoul(hiMask, NULL, 2);
+ *commandLM = strtoul(loMask, NULL, 2);
+ return(0);
+}
+
+
+/* Takes a devicecode (like 0392) or identifier ((-i)433) and sets */
+/* the device commands, messages and other parameters as found in */
+/* _sp12dev. */
+/* Returns 1 if _sp12dev not found; 2 if a line in _sp12dev is */
+/* corrupt; 3 if _sp12dev has no entry for the deviceCode or */
+/* identifier and the deviceCode (as an int) if all is well. */
+
+int setDevicePars(int initFlag, char *identifier) {
+
+ FILE *rcPtr;
+ char rcPath[MAXLEN];
+ char *sp12dev;
+ int deviceCode = 0;
+ char rcLine[MAXLEN] = "";
+ char rawLine[MAXLEN] = "";
+ char match[MAXLEN] = "";
+ int begin = 0; /* high when device code matches */
+ int found = 0; /* high when device was identified */
+ int iNum = 0;
+ int iFlag = 0; /* high inside ident ('begin') block */
+ int idx = 0;
+ int idy = 0;
+ int idz = 0;
+ unsigned long dummyHi = 0;
+
+
+ if ((sp12dev = getenv("SP12")) != NULL) {
+ strcpy(rcPath, sp12dev);
+#ifdef LINUX
+ if (rcPath[strlen(rcPath)-1] != '/')
+ strcat (rcPath, "/");
+#else
+ if (rcPath[strlen(rcPath)-1] != '\\')
+ strcat (rcPath, "\\");
+#endif
+ strcat(rcPath, "_sp12dev");
+ } else {
+ strcpy(rcPath, "_sp12dev");
+ }
+
+ if ((rcPtr = fopen(rcPath, "r")) == NULL) {
+ return(1);
+ }
+ /*
+ * Fetch commands
+ */
+ readDeviceCode();
+ deviceCode = deviceCode | device.sigByte_2;
+ deviceCode = deviceCode << 8;
+ deviceCode = deviceCode | device.sigByte_1;
+ switch (device.sigByte_0) {
+ case 0x1E:
+ strcpy(device.madeBy, "Atmel");
+ break;
+ default:
+ strcpy(device.madeBy, "an unknown manufacturer");
+ }
+ begin = 0;
+ iFlag = 0;
+ found = 0;
+ strcpy(LOCK_MESSAGE, "");
+ strcpy(FUSES_MESSAGE, "");
+ strcpy(device.name, "unknown device, or no device");
+ device.flashLimit = 0;
+ device.eepromLimit = 0;
+ device.pageMode = 0;
+ device.pageSize = 0;
+ while (fgets(rcLine, MAXLEN, rcPtr) != NULL) {
+ if (sscanf(rcLine, "begin %[0-9A-Fa-f]", rawLine)) {
+ if (!initFlag && strtol(rawLine, NULL, 16) == deviceCode) {
+ begin = 1;
+ found = 1;
+ } else if (!iFlag) {
+ begin = 0;
+ }
+ iFlag = 1;
+ } else if (sscanf(rcLine, "-i%[0-9a-zA-Z]", rawLine)) {
+ /*
+ * All defined characters must be there, in the right order
+ */
+ idy = 0;
+ idz = 0;
+ for (idx = 0; idx < strlen(identifier); idx++) {
+ if (identifier[idx] > 90) /* reduce a-z to A-Z */
+ identifier[idx] = identifier[idx] - 32;
+ if (identifier[idx] == rawLine[idy]) {
+ match[idz++] = identifier[idx];
+ if (++idy >= strlen(rawLine))
+ break;
+ } else if (idz && identifier[idx] < 58 && identifier[idx] > 47) {
+ break;
+ }
+ }
+ if (strcmp(match, rawLine) == 0) {
+ begin = 1;
+ found++;
+ } else if (iFlag && initFlag) {
+ begin = 0;
+ }
+ iFlag = 0;
+ }
+ if(found > 1) {
+ fprintf(stderr, "More than one ident: ");
+ return(2);
+ }
+
+ if (begin && sscanf(rcLine, "DEVICENAME = %[A-Z ()0-9a-z]", rawLine) == 1) {
+ strcpy(device.name, rawLine);
+ }
+ if (begin && sscanf(rcLine, "FLASHSIZE = %i", &iNum) == 1) {
+ device.flashLimit = iNum;
+ }
+ if (begin && sscanf(rcLine, "EEPROMSIZE = %i", &iNum) == 1) {
+ device.eepromLimit = iNum;
+ }
+ if (begin && sscanf(rcLine, "PAGEMODE = %i", &iNum) == 1) {
+ device.pageMode = iNum;
+ }
+ if (begin && sscanf(rcLine, "PAGESIZE = %i", &iNum) == 1) {
+ device.pageSize = iNum;
+ }
+ if (begin && sscanf(rcLine, "POLL_RDY_BSY = %[hlxo 0-9]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &dummyHi, &POLL_RDY_BSY, \
+ &POLL_RBLSB, &POLL_RBLEN)) {
+ fprintf(stderr, "_sp12dev line 'POLL_RDY_BSY' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "WRITE_LOCK = %[hlxi 0-9]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &WRITE_LOCK_HM, &WRITE_LOCK_LM, \
+ &W_LOCKLSB, &W_LOCKLEN)) {
+ fprintf(stderr, "_sp12dev line 'WRITE_LOCK' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "READ_LOCK = %[hlxo 0-9]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &dummyHi, &READ_LOCK, &R_LOCKLSB, \
+ &R_LOCKLEN)) {
+ fprintf(stderr, "_sp12dev line 'READ_LOCK' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "LOCK_MESSAGE = %[^][]", rawLine) == 1) {
+ strncat(LOCK_MESSAGE, rawLine, MAXLEN - strlen(LOCK_MESSAGE) - 2);
+ LOCK_MESSAGE[MAXLEN - 1] = '\0';
+ }
+ if (begin && sscanf(rcLine, "WRITE_FUSES = %[hlxi 0-9A-Z]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &WRITE_FUSES_HM, &WRITE_FUSES_LM,
+ &W_FUSESLSB, &W_FUSESLEN)) {
+ fprintf(stderr, "_sp12dev line 'WRITE_FUSES' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "READ_FUSES = %[hlxo 0-9A-Z]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &dummyHi, &READ_FUSES, &R_FUSESLSB, \
+ &R_FUSESLEN)) {
+ fprintf(stderr, "_sp12dev line 'READ_FUSES' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "FUSES_MESSAGE = %[^][]", rawLine) == 1) {
+ strncat(FUSES_MESSAGE, rawLine, MAXLEN - strlen(FUSES_MESSAGE) - 2);
+ FUSES_MESSAGE[MAXLEN - 1] = '\0';
+ }
+ if (begin && sscanf(rcLine, "WRITE_HIGH_FUSES = %[hlxi 0-9A-Z]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &WRITE_HIGH_FUSES_HM, &WRITE_HIGH_FUSES_LM,
+ &WH_FUSESLSB, &WH_FUSESLEN)) {
+ fprintf(stderr, "_sp12dev line 'WRITE_HIGH_FUSES' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "READ_HIGH_FUSES = %[hlxo 0-9A-Z]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &dummyHi, &READ_HIGH_FUSES, &RH_FUSESLSB,
+ &RH_FUSESLEN)) {
+ fprintf(stderr, "_sp12dev line 'READ_HIGH_FUSES' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "HIGH_FUSES_MESSAGE = %[^][]", rawLine) == 1) {
+ strncat(H_FUSES_MESSAGE, rawLine, MAXLEN - strlen(H_FUSES_MESSAGE) - 2);
+ H_FUSES_MESSAGE[MAXLEN - 1] = '\0';
+ }
+ if (begin && sscanf(rcLine, "WRITE_EXTD_FUSES = %[hlxi 0-9A-Z]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &WRITE_EXTD_FUSES_HM, &WRITE_EXTD_FUSES_LM,
+ &WX_FUSESLSB, &WX_FUSESLEN)) {
+ fprintf(stderr, "_sp12dev line 'WRITE_EXTD_FUSES' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "READ_EXTD_FUSES = %[hlxo 0-9A-Z]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &dummyHi, &READ_EXTD_FUSES, &RX_FUSESLSB,
+ &RX_FUSESLEN)) {
+ fprintf(stderr, "_sp12dev line 'READ_EXTD_FUSES' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "EXTD_FUSES_MESSAGE = %[^][]", rawLine) == 1) {
+ strncat(X_FUSES_MESSAGE, rawLine, MAXLEN - strlen(X_FUSES_MESSAGE) - 2);
+ X_FUSES_MESSAGE[MAXLEN - 1] = '\0';
+ }
+ if (begin && sscanf(rcLine, "READ_CALIBRATION = %[hlxo 0-9]", rawLine) == 1) {
+ if (extractFuseCmnd(rawLine, &dummyHi, &READ_CALIBRATION, &CALIBLSB,
+ &CALIBLEN)) {
+ fprintf(stderr, "_sp12dev line 'READ_CALIBRATION' corrupt\n");
+ return(2);
+ }
+ }
+ if (begin && sscanf(rcLine, "CALIB_MESSAGE = %[^][]", rawLine) == 1) {
+ strncat(CALIB_MESSAGE, rawLine, MAXLEN - strlen(CALIB_MESSAGE) - 2);
+ CALIB_MESSAGE[MAXLEN - 1] = '\0';
+ }
+ }
+ fclose(rcPtr);
+ if (!found)
+ return(3);
+ device.initPerformed = 1;
+ return(deviceCode);
+}
+
+/* Collects all device codes and names from _sp12dev, and shows */
+/* them on screen. */
+/* Returns 1 if _sp12dev not found, else zero. */
+
+int supported(void) {
+
+ FILE *rcPtr;
+ char rcPath[MAXLEN];
+ char *sp12dev;
+ char rcLine[MAXLEN];
+ char rawLine[MAXLEN];
+ int begin = 0;
+ int found = 0;
+
+ if ((sp12dev = getenv("SP12")) != NULL) {
+ strcpy(rcPath, sp12dev);
+#ifdef LINUX
+ if (rcPath[strlen(rcPath)-1] != '/')
+ strcat (rcPath, "/");
+#else
+ if (rcPath[strlen(rcPath)-1] != '\\')
+ strcat (rcPath, "\\");
+#endif
+ strcat(rcPath, "_sp12dev");
+ } else {
+ strcpy(rcPath, "_sp12dev");
+ }
+
+ if ((rcPtr = fopen(rcPath, "r")) == NULL) {
+ return(1);
+ }
+ /*
+ * Fetch and show codes and names
+ */
+ begin = 0;
+ printf("Supported devices:\n");
+ while (fgets(rcLine, MAXLEN, rcPtr) != NULL) {
+ if (sscanf(rcLine, "begin %[0-9A-Fa-f]", rawLine)) {
+ printf("%s, ", rawLine);
+ begin = 1;
+ found = 1;
+ }
+ if (begin && sscanf(rcLine, "DEVICENAME = %[A-Z ()0-9a-z]", rawLine) == 1) {
+ begin = 0;
+ printf("%s\n", rawLine);
+ }
+ }
+ fclose(rcPtr);
+ if (!found)
+ printf("No devices found.\n");
+ else
+ printf("\n");
+ return(0);
+}
diff --git a/src/makefile b/src/makefile
new file mode 100644
index 0000000..cc01f38
--- /dev/null
+++ b/src/makefile
@@ -0,0 +1,58 @@
+#
+# Makefile for the Free Software Foundations gcc compiler
+# Optimize flag = 1 to achieve correct timing
+#
+CC=gcc
+LINK=gcc
+#
+# LINUX FLAGS
+CFLAGS=-c -O1 -Wall -DLINUX
+LFLAGS=-s -o
+TARGET=sp12
+ERASE=rm -f
+OBJECTS=sp12.o init.o flash.o device.o buffer.o eeprom.o
+
+# DOS FLAGS
+#CFLAGS=-c -O1 -Wall
+#LFLAGS=-lemu -s -o
+#TARGET=sp12.exe
+#ERASE=del
+#OBJECTS=sp12.o init.o flash.o device.o buffer.o eeprom.o
+
+# Win FLAGS - MingW
+#CFLAGS=-c -O1 -Wall -mwindows -mconsole
+#LFLAGS=-s -o
+#TARGET=sp12.exe
+#ERASE=del
+#OBJECTS=sp12.o init.o flash.o device.o buffer.o eeprom.o winnt.o
+
+all: $(TARGET)
+
+sp12.o: sp12.c
+ $(CC) $(CFLAGS) sp12.c
+
+init.o: init.c
+ $(CC) $(CFLAGS) init.c
+
+flash.o: flash.c
+ $(CC) $(CFLAGS) flash.c
+
+device.o: device.c
+ $(CC) $(CFLAGS) device.c
+
+buffer.o: buffer.c
+ $(CC) $(CFLAGS) buffer.c
+
+eeprom.o: eeprom.c
+ $(CC) $(CFLAGS) eeprom.c
+
+winnt.o: winnt.c
+ $(CC) $(CFLAGS) winnt.c
+
+$(TARGET): makefile $(OBJECTS)
+ $(LINK) $(LFLAGS) $(TARGET) $(OBJECTS)
+
+clean:
+ $(ERASE) $(TARGET)
+ $(ERASE) *.o
+
diff --git a/src/sp12.c b/src/sp12.c
new file mode 100644
index 0000000..738f404
--- /dev/null
+++ b/src/sp12.c
@@ -0,0 +1,1136 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */
+/* Artur Pundsack, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+/* Artur Pundsack can be reached by email: ap@pa-tec.de */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dos_cpt.h"
+#include <time.h>
+#include "sp12.h"
+
+#define VERSION "2.1.1"
+
+
+const char USAGE[] = {
+ " SP12/32 version %s: A serial programmer for Atmel AVR uCs.\n"
+ " Copyright (C) 1997-2008 Ken Huntington, Kevin Towers,\n"
+ " Artur Pundsack, Pitronics.\n"
+ "SYNOPSIS\n"
+ " sp12 {-options} [filename or address(:data)] {-options} [filename...\n"
+ "OPTIONS\n"
+ " i[nnn] - init E - chip erase\n"
+ " e - eprom area B - blank check\n"
+ " p - program area C - calculate checksum\n"
+ " w - write to L[n...n] - lock fuses\n"
+ " r - read from F[n...n] - fuses\n"
+ " a - address(:data) next H[n...n] - high fuses\n"
+ " f - filename next X[n...n] - extended fuses\n"
+ " I - create Intel Hex file c[nn] - calibration byte(s)\n"
+ " h - hex dump with ascii M<n.n> - match Sck to uC clock\n"
+ " o0, o1 - optimization P<nnn> - parallel port control\n"
+ " s - show supported uCs t - timing check\n"
+ "EXAMPLES\n"
+ " sp12 -M4 -wF10011 -wpfC prog.hex -wefC eep.hex -wL00 (sets timing \n"
+ " for 4MHz, sets fuses, then writes prog.hex into the program area\n"
+ " and eep.hex into the eeprom, providing checksums for both; and\n"
+ " finally a read/write lock is set)\n"
+ " sp12 -rF -rH -rL -rc (reads fuses, locks and calibration if possible)\n"
+ " sp12 -wea 0x01:0x99 (Writes 0x99 into eeprom address 0x01)\n\n"};
+
+static int initFlag = 0; /* i<nn> on command line; flag set nn */
+static int flashFlag = 0; /* p on command line */
+static int eepromFlag = 0; /* e */
+static int writeFlag = 0; /* w */
+static int readFlag = 0; /* r */
+static int lockFlag = 0; /* L */
+static int fusesFlag = 0; /* F */
+static int highFFlag = 0; /* H */
+static int extdFFlag = 0; /* X */
+static int calibFlag = 0; /* c */
+static unsigned long calibAddress = 0;
+static int fileFlag = 0; /* d */
+static int addressFlag = 0; /* a */
+static int eraseFlag = 0; /* E */
+static int blankChkFlag = 0; /* B */
+static int checksumFlag = 0; /* C */
+static int testFlag = 0; /* T */
+static int portFlag = 0; /* P */
+static int optimizeFlag = 0; /* o, 0, 1 */
+static int overlayFlag = 0; /* O */
+static float clkSpeed = 0; /* M, value between 0.1 and 12 */
+static float prevClkSpeed = 0; /* previous clkSpeed */
+static int IntelFlag = 0; /* I */
+static int hexAsciiFlag = 0; /* h */
+static int addressAvailable = 0;
+static int pathAvailable = 0;
+static char flashPath[MAXLEN]; /* path/filename source or destination */
+static char eepromPath[MAXLEN]; /* path/filename source or destination */
+static char checksumPath[MAXLEN]; /* path/filename source */
+static char commandStr[MAXLEN]; /* stores commands for logging */
+static char fusesBits[MAXLEN] = "";
+static char lockBits[MAXLEN] = "";
+static char calibByte[MAXLEN] = "";
+static char identifier[MAXLEN] = "";
+static unsigned int flashAddress = 0;
+static unsigned int flashData = 0;
+static unsigned int eepromAddress = 0;
+static unsigned int eepromData = 0;
+static unsigned int *flashBuf; /* flash buffer */
+static unsigned int *eepromBuf; /* eeprom buffer */
+static clock_t sp12Start, sp12End;
+static double sp12Elapsed;
+
+
+void exitSp12(int exitState) {
+
+ char binary[9] = "76543210"; /* Stores conversion num to binary */
+
+ portControl(DEFAULT_EXIT_STATE, 1);
+ num2bin((unsigned char) DEFAULT_EXIT_STATE, binary);
+ printf("Writing %#04x (%d, B%s) ",
+ DEFAULT_EXIT_STATE, DEFAULT_EXIT_STATE, binary);
+ printf("to the parallel port data bits.\n");
+ sp12End = clock();
+ sp12Elapsed = ((double) (sp12End - sp12Start)) / CLOCKS_PER_SEC;
+ printf("Sp12 was active for %#3.2f seconds.\n", sp12Elapsed);
+ if (flashBuf)
+ free(flashBuf);
+ if (eepromBuf)
+ free(eepromBuf);
+ exit(exitState);
+}
+
+
+/* Merely check whether options -L, -E, -F, -R, -S, -K, D, V, */
+/* A or U was used, and say something about it. */
+
+void reportLEFHXcFlag(void) {
+
+ if (lockFlag) {
+ printf("You have selected option -L to read or write lock fuses,\n");
+ printf("which has had no effect. Use this option only in combination\n ");
+ printf("with -r and -w, like -rL or -wL00\n");
+ lockFlag = 0;
+ }
+ if (eraseFlag) {
+ printf("You have selected option -E for erase, which has had no\n");
+ printf("effect. Options -w, -p and -f together cause an automatic\n");
+ printf("erase; -E should be used on its own or together with B if\n");
+ printf("you want a blank check afterwards.\n");
+ eraseFlag = 0;
+ }
+ if (fusesFlag) {
+ printf("You have selected option -F to read or write fuse bits,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the commands -rF and -wF.\n");
+ fusesFlag = 0;
+ }
+ if (highFFlag) {
+ printf("You have selected option -H to read or write fuse bits,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the commands -rH and -wH.\n");
+ highFFlag = 0;
+ }
+ if (extdFFlag) {
+ printf("You have selected option -X to read or write extended fuses,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the commands -rX and -wX.\n");
+ extdFFlag = 0;
+ }
+ if (calibFlag) {
+ printf("You have selected option -c to read the calibration byte,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the command -rc.\n");
+ calibFlag = 0;
+ }
+}
+
+/* Merely check whether option -B was used, */
+/* and say something about it. */
+
+void reportBflag(void) {
+
+ if (blankChkFlag) {
+ printf("You have selected option -B for blank check, which has had \n");
+ printf("no effect. Options -w, -p and -f together cause an automatic\n");
+ printf("erase; if you also want a blank check before programming,\n");
+ printf("use -Bwpf. Use -EB if you just want an erase followed by a\n");
+ printf("blank check, or -B on its own for a blank check without a\n");
+ printf("preceding erase.\n");
+ blankChkFlag = 0;
+ }
+}
+
+/* Blank check the device. */
+
+int blank_check(void) {
+
+ int signal = 0;
+
+ printf("Performing blank check...\n");
+ signal = blankCheck(device.flashLimit, device.eepromLimit);
+ if (signal == 0)
+ printf("The program and eeprom area's are blank.\n");
+ if ((signal & 0x01) == 1)
+ printf("The program area is NOT blank.\n");
+ if ((signal & 0x02) == 2)
+ printf("The eeprom area is NOT blank.\n");
+ return(signal);
+}
+
+/* The command processor */
+
+void processCommand(void) {
+
+ unsigned long command;
+ long address;
+ int error; /* Storing return value */
+ int deviceCode = 0;
+ char binary[9] = "76543210"; /* Stores conversion num to binary */
+ int rFlag = 0;
+ int idx = 0;
+
+ /*
+ * If it hasn't been done yet, then set the device parameters
+ * according to device code and option -i[NN]
+ */
+ if (!device.initPerformed) {
+ printf("Enabling AVR serial reading/programming...\n");
+ /*
+ * First see if it's a 1200, which doesn't echo 0x53
+ * on the third byte of PROGRAM_ENABLE.
+ * Initiating contact at low speed
+ */
+ strcpy(device.name, "AT90S1200(A)");
+ setSckTiming(0.1);
+ enableSPI(1200);
+ deviceCode = setDevicePars(initFlag, identifier);
+ if (deviceCode == 1) {
+ fprintf(stderr, "_sp12dev not found\n");
+ exitSp12(2);
+ }
+ if (deviceCode == 2) {
+ fprintf(stderr, "_sp12dev corrupt.\n");
+ exitSp12(2);
+ }
+ if (deviceCode == 3) {
+ /*
+ * It doesn't look like a 1200. If a uC is connected,
+ * the SPI shiftregister is not in synch. We'll now fail
+ * if it is an out of synch 1200, but other uCs do
+ * echo 0x53 on the third byte of PROGRAM_ENABLE.
+ * So we'll try synch pulses for a while.
+ */
+ enableSPI(0);
+ deviceCode = setDevicePars(initFlag, identifier);
+ if (deviceCode == 1) {
+ fprintf(stderr, "_sp12dev not found\n");
+ exitSp12(2);
+ }
+ if (deviceCode == 2) {
+ fprintf(stderr, "_sp12dev corrupt.\n");
+ exitSp12(2);
+ }
+ if (device.sigByte_0 == 0 && device.sigByte_1 == 1
+ && device.sigByte_2 == 2) {
+ printf("WARNING: You have connected an unidentifiable\n");
+ printf(" device, which may be locked mode 3. \n");
+ printf(" Access to a supported, mode 3 locked \n");
+ printf(" device can be regained, but only by \n");
+ printf(" erasing it first.\n");
+ printf(" Check SP12.doc for details.\n\n");
+ }
+ }
+ if (initFlag == 0) {
+ printf("The device code bytes 0,1,2: %#x, %#x, %#x were read\n",
+ device.sigByte_0, device.sigByte_1, device.sigByte_2);
+ printf("from parallel port %#x and indicate the following:\n",
+ portAddress);
+ printf("You have connected an %s\n", device.name);
+ printf("The device was made by %s\n\n", device.madeBy);
+ }
+ if (device.flashLimit == 0 || device.eepromLimit == 0) {
+ printf("Nothing to do for sp12.\n");
+ exitSp12(1);
+ }
+ if (initFlag != 0 && device.flashLimit != 0) {
+ printf("Device code check OVERRULED! Assuming an %s\n\n",
+ device.name);
+ }
+ /*
+ * Continue with the Sck wave form for the now known uC,
+ * at the default speed.
+ */
+ setSckTiming(clockSpdDefault);
+ }
+ /*
+ * Do a few command sanity checks
+ */
+ error = flashFlag + eepromFlag + writeFlag + readFlag + lockFlag \
+ + fusesFlag + highFFlag + extdFFlag + calibFlag + fileFlag \
+ + addressFlag + eraseFlag + blankChkFlag + checksumFlag + testFlag \
+ + portFlag + optimizeFlag + overlayFlag;
+ if (((fusesFlag || highFFlag || extdFFlag || lockFlag || calibFlag) \
+ && error > 2) || (!readFlag && !writeFlag)) {
+ if (fusesFlag) {
+ printf("Use F only in the commands -rF or -wF<fuses>\n");
+ exitSp12(2);
+ }
+ if (highFFlag) {
+ printf("Use H only in the commands -rH or -wH<fuses>\n");
+ exitSp12(2);
+ }
+ if (extdFFlag) {
+ printf("Use X only in the commands -rX or -wX<fuses>\n");
+ exitSp12(2);
+ }
+ if (lockFlag) {
+ printf("Use L only in the commands -rL or -wL<fuses>\n");
+ exitSp12(2);
+ }
+ if (calibFlag) {
+ printf("Use c only in the command -rc[n]\n");
+ exitSp12(2);
+ }
+ }
+ if (flashFlag && eepromFlag) {
+ printf("Do not use options -p and -e in a single command.\n");
+ exitSp12(2);
+ }
+ if (checksumFlag && !eepromFlag && !flashFlag) {
+ printf("Use C only in commands like -Ce, -Cp, -Cef <file>\n");
+ exitSp12(2);
+ }
+ /*
+ * Inititalize buffers
+ */
+ for (address = 0; address < device.flashLimit; address++)
+ flashBuf[address] = 0xFFFF;
+ for (address = 0; address < device.eepromLimit; address++)
+ eepromBuf[address] = 0xFFF;
+ /*
+ * Set Sck timing to match the now known uC's wave form
+ * and clock speed asked for by an -Mn.n command.
+ */
+ if (clkSpeed && clkSpeed != prevClkSpeed) {
+ printf("Sck timing set for %.1f MHz or higher.\n",
+ setSckTiming(clkSpeed));
+ prevClkSpeed = clkSpeed;
+ }
+ clkSpeed = 0;
+ /*
+ * if r --> p || e || F || L
+ * rp --> rpf --> read program area; write to file
+ * rpa --> read program address to stdout
+ * rp --> read program area to stdout
+ * re --> ref --> read eeprom area; write to file
+ * rea --> read eeprom address to stdout
+ * re --> read eeprom area to stdout
+ * rF --> read the fuse bits, if possible
+ * rL --> read the lock bits, if possible
+ * check for C
+ * check for E, B, R, S, but just report them
+ */
+ if (readFlag && writeFlag) {
+ printf("Do not use options -w and -r in a single command.\n");
+ exitSp12(2);
+ }
+ if (readFlag) {
+ readFlag = 0;
+ if ((!pathAvailable || addressAvailable) && IntelFlag) {
+ printf("The Intel hex format is only available when writing\n");
+ printf("an entire memory area to file.\n");
+ exitSp12(2);
+ }
+ if (addressAvailable && hexAsciiFlag) {
+ printf("A hex dump with ascii translation is only possible\n");
+ printf("when writing an entire memory area to file.\n");
+ exitSp12(2);
+ }
+ if (IntelFlag && hexAsciiFlag) {
+ printf("Select either (I)ntel hex format or (h)ex dump with\n");
+ printf("ascii translation; not both at the same time\n");
+ exitSp12(2);
+ }
+ if (flashFlag) {
+ flashFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ flashData = readCodeWord(flashAddress);
+ printf("The word %#06x was read from program address %#08x\n",
+ flashData, flashAddress);
+ } else {
+ printf("Reading program area.\n");
+ readFlashArea(flashBuf, device.flashLimit);
+ if (pathAvailable) {
+ pathAvailable = 0;
+ printf("Writing program area content to %s\n", flashPath);
+ if (fileFlashBuf(flashBuf, device.flashLimit,
+ flashPath, IntelFlag, hexAsciiFlag) != 0) {
+ printf("%s %s\n", FILE_WRITE_ERROR, flashPath);
+ exitSp12(2);
+ }
+ IntelFlag = 0;
+ hexAsciiFlag = 0;
+ } else {
+ if (hexAsciiFlag) {
+ printBuffer(flashBuf, device.flashLimit, 1);
+ hexAsciiFlag = 0;
+ } else {
+ for (address = 0; address < device.flashLimit; address++)
+ printf("%06lx:%04x\n", address, flashBuf[address]);
+ }
+ }
+ }
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readFlashArea(flashBuf, device.flashLimit);
+ printf("Checksum program area: %04x\n",
+ checksum(flashBuf, device.flashLimit));
+ }
+ }
+ if (eepromFlag) {
+ eepromFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ eepromData = readDataByte(eepromAddress);
+ num2bin((unsigned char) eepromData, binary);
+ printf("The byte %#04x (%d, %#o, B%s) ", eepromData, eepromData,
+ eepromData, binary);
+ printf("was read from eeprom address %#06x\n", eepromAddress);
+ } else {
+ printf("Reading eeprom area.\n");
+ readEepromArea(eepromBuf, device.eepromLimit);
+ if (pathAvailable) {
+ pathAvailable = 0;
+ printf("Writing eeprom area content to %s\n", eepromPath);
+ if (fileEepromBuf(eepromBuf, device.eepromLimit,
+ eepromPath, IntelFlag, hexAsciiFlag) != 0) {
+ printf("%s %s\n", FILE_WRITE_ERROR, eepromPath);
+ exitSp12(2);
+ }
+ IntelFlag = 0;
+ hexAsciiFlag = 0;
+ } else {
+ if (hexAsciiFlag) {
+ printBuffer(eepromBuf, device.eepromLimit, 0);
+ hexAsciiFlag = 0;
+ } else {
+ printf("Address: Data in hex, dec, oct, bin\n");
+ for (address = 0; address < device.eepromLimit; address++) {
+ num2bin((unsigned char) eepromBuf[address], binary);
+ printf( " %#04lx: %#04x %3d %#4o %s\n",
+ address, eepromBuf[address], eepromBuf[address],
+ eepromBuf[address], binary);
+ }
+ }
+ }
+ }
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readEepromArea(eepromBuf, device.eepromLimit);
+ printf("Checksum eeprom area: %04x\n",
+ checksum(eepromBuf, device.eepromLimit));
+ }
+ }
+ if (fusesFlag) {
+ fusesFlag = 0;
+ rFlag = readFuses(READ_FUSES, fusesBits, R_FUSESLSB, R_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the fuse bits read from an %s\n",
+ fusesBits, device.name);
+ printf("%s\n", FUSES_MESSAGE);
+ }
+ }
+ if (highFFlag) {
+ highFFlag = 0;
+ rFlag = readFuses(READ_HIGH_FUSES, fusesBits, RH_FUSESLSB, RH_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_high_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the high fuse bits read from an %s\n",
+ fusesBits, device.name);
+ printf("%s\n", H_FUSES_MESSAGE);
+ }
+ }
+ if (extdFFlag) {
+ extdFFlag = 0;
+ rFlag = readFuses(READ_EXTD_FUSES, fusesBits, RX_FUSESLSB, RX_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_extd_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the extended fuse bits read from an %s\n",
+ fusesBits, device.name);
+ printf("%s\n", X_FUSES_MESSAGE);
+ }
+ }
+ if (lockFlag) {
+ lockFlag = 0;
+ rFlag = readFuses(READ_LOCK, lockBits, R_LOCKLSB, R_LOCKLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_locks not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the lock bits read from an %s\n", lockBits, device.name);
+ printf("%s\n", LOCK_MESSAGE);
+ }
+ }
+ if (calibFlag) {
+ calibFlag = 0;
+ command = READ_CALIBRATION | (calibAddress << 8);
+ rFlag = readFuses(command, calibByte, CALIBLSB, CALIBLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_calibration not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("0x%02lx is the calibration byte read from address 0x%02lx\n",
+ strtol(calibByte, NULL, 2), calibAddress);
+ printf("%s\n", CALIB_MESSAGE);
+ }
+ }
+
+ reportLEFHXcFlag();
+ reportBflag();
+ }
+ /*
+ * If w --> p || e
+ * wp --> f || a
+ * wpf --> chip erase;
+ * write file to program area
+ * wpa --> NO chip erase (warning);
+ * write address:data
+ * we --> f || a
+ * wef --> write file to eeprom area
+ * wpa --> write address:data
+ * wF --> write the fuse bits, if possible
+ * wL --> write the lock bits, if possible
+ * check for C; complete write before reading p || e
+ * back into array to compute the checksum
+ * check for E, R, S but just report them
+ */
+ if (writeFlag) {
+ writeFlag = 0;
+ timeConst.byteWrite = timeConst.byteWriteDefault;
+ timeConst.byteWriteAdjusted = 0;
+ timeConst.pageWrite = timeConst.pageWriteDefault;
+ timeConst.pageWriteAdjusted = 0;
+ writeRetries = 0;
+ if (flashFlag) {
+ flashFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ if (device.pageMode) {
+ printf ("ERROR: Single address flash programming "
+ "not available in page mode.\n");
+ exitSp12(2);
+ }
+ printf("WARNING: writing to single address in program area.\n");
+ printf(" Chip erase is not automatic; unless you \n");
+ printf(" used a separate -E command, it may not be \n");
+ printf(" possible to correctly write new data.\n");
+ printf("Writing %#06x into address %#08x in program area.\n",
+ flashData, flashAddress);
+ error = writeFlashVerified(flashAddress, flashData, optimizeFlag);
+ if (logWrites(commandStr, flashAddress, flashData, flashPath,
+ flashBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR at program address %#06x\n",
+ flashAddress);
+ exitSp12(3);
+ }
+
+ } else if (pathAvailable) { /* Write file to flash ////////////*/
+ pathAvailable = 0;
+ if (!overlayFlag) {
+ printf("Performing chip erase...\n");
+ eraseDevice();
+ }
+ if (blankChkFlag) {
+ blankChkFlag = 0;
+ if(blank_check())
+ exitSp12(3);
+ }
+ /* Read the HEX file */
+ printf("Writing content of %s into program area.\n", flashPath);
+ error = readFlashFile(flashPath, flashBuf, device.flashLimit);
+ if (error) {
+ printf("%s %s\n", flashPath, FILE_ERROR);
+ exitSp12(2);
+ }
+ /* Now copy file to flash */
+ error = writeFlashArea(flashBuf, device.flashLimit, optimizeFlag);
+ if (logWrites(commandStr, flashAddress, flashData, flashPath,
+ flashBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR after %d write retries.\n", writeRetries);
+ if (overlayFlag)
+ printf("The error may be due to an overlay conflict.\n");
+ exitSp12(3);
+ } else {
+ printf("%s written and verified.\n", flashPath);
+ printf("write retries: %d\n", writeRetries);
+ }
+ } /* Up to here the file to flash functions///////////////////*/
+
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readFlashArea(flashBuf, device.flashLimit);
+ printf("Checksum program area: %04x\n",
+ checksum(flashBuf, device.flashLimit));
+ }
+ }
+ if (eepromFlag) {
+ eepromFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ printf("Writing %#x into address %#x in eeprom area.\n",
+ eepromData, eepromAddress);
+ error=writeEepromVerified(eepromAddress, eepromData, optimizeFlag);
+ if (logWrites(commandStr, eepromAddress, eepromData, eepromPath,
+ eepromBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR at eeprom address %#04x\n",
+ eepromAddress);
+ exitSp12(3);
+ }
+ } else if (pathAvailable) {
+ pathAvailable = 0;
+ printf("Writing content of %s into eeprom area.\n", eepromPath);
+ error = readEepromFile(eepromPath, eepromBuf, device.eepromLimit);
+ if (error) {
+ printf("%s %s\n", eepromPath, FILE_ERROR);
+ exitSp12(2);
+ }
+ error = writeEepromArea(eepromBuf, device.eepromLimit,
+ optimizeFlag, overlayFlag);
+ if (logWrites(commandStr, eepromAddress, eepromData, eepromPath,
+ eepromBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR after %d write retries.\n", writeRetries);
+ exitSp12(3);
+ } else {
+ printf("%s written and verified.\n", eepromPath);
+ printf("write retries: %d, byteWrite: %ld percent of default\n",
+ writeRetries,
+ (timeConst.byteWrite * 100) / timeConst.byteWriteDefault);
+ }
+ }
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readEepromArea(eepromBuf, device.eepromLimit);
+ printf("Checksum eeprom area: %04x\n",
+ checksum(eepromBuf, device.eepromLimit));
+ }
+ reportBflag();
+ }
+ if (lockFlag) {
+ lockFlag = 0;
+ logLocks(flashBuf, lockBits);
+ rFlag = writeFuses(WRITE_LOCK_HM, WRITE_LOCK_LM, lockBits, \
+ W_LOCKLSB, W_LOCKLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_lock not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s: Wrong number of lock bits.\n", device.name);
+ } else {
+ for (idx = 0; idx < R_LOCKLEN - W_LOCKLEN; idx++)
+ printf(" ");
+ printf("%s are the lock bits written into an %s\n%s\n",
+ lockBits, device.name, LOCK_MESSAGE);
+ }
+ }
+ if (fusesFlag) {
+ fusesFlag = 0;
+ rFlag = writeFuses(WRITE_FUSES_HM, WRITE_FUSES_LM, fusesBits, \
+ W_FUSESLSB, W_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s; Wrong number of fuse bits.\n", device.name);
+ } else {
+ for (idx = 0; idx < (R_FUSESLEN - W_FUSESLEN) - W_FUSESLSB; idx++)
+ printf(" ");
+ printf("%s are the fuse bits written into an %s\n%s\n",
+ fusesBits, device.name, FUSES_MESSAGE);
+ }
+ }
+ if (highFFlag) {
+ highFFlag = 0;
+ rFlag = writeFuses(WRITE_HIGH_FUSES_HM, WRITE_HIGH_FUSES_LM, fusesBits, \
+ WH_FUSESLSB, WH_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_high_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s; Wrong number of high fuse bits.\n",
+ device.name);
+ } else {
+ for (idx = 0; idx < (RH_FUSESLEN - WH_FUSESLEN) - WH_FUSESLSB; idx++)
+ printf(" ");
+ printf("%s are the high fuse bits written into an %s\n%s\n",
+ fusesBits, device.name, H_FUSES_MESSAGE);
+ }
+ }
+ if (extdFFlag) {
+ extdFFlag = 0;
+ rFlag = writeFuses(WRITE_EXTD_FUSES_HM, WRITE_EXTD_FUSES_LM, fusesBits, \
+ WX_FUSESLSB, WX_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_extd_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s; Wrong number of high fuse bits.\n",
+ device.name);
+ } else {
+ for (idx = 0; idx < (RX_FUSESLEN - WX_FUSESLEN) - WX_FUSESLSB; idx++)
+ printf(" ");
+ printf("%s are the extended fuse bits written into an %s\n%s\n",
+ fusesBits, device.name, X_FUSES_MESSAGE);
+ }
+ }
+ reportLEFHXcFlag();
+ overlayFlag = 0;
+ }
+ /*
+ * if C --> (p || e) || ((p || e) && f)
+ * Cp(f) --> read program area (file) into
+ * device.flashLimit word array;
+ * calculate checksum for array
+ * Ce(f) --> read eeprom area (file) into
+ * device.eepromLimit byte array;
+ * calculate checksum for array
+ * check for L, E, B, F, R, S but just report them
+ */
+ if (checksumFlag) {
+ checksumFlag = 0;
+ if (eepromFlag) {
+ eepromFlag = 0;
+ if (pathAvailable) {
+ pathAvailable = 0;
+ if (readEepromFile(checksumPath, eepromBuf,
+ device.eepromLimit) != 0) {
+ printf("%s %s\n", checksumPath, FILE_ERROR);
+ exitSp12(2);
+ } else {
+ printf("Checksum eeprom file %s: %04x\n",
+ checksumPath, checksum(eepromBuf, device.eepromLimit));
+ }
+ } else {
+ readEepromArea(eepromBuf, device.eepromLimit);
+ printf("Checksum eeprom area: %04x\n",
+ checksum(eepromBuf, device.eepromLimit));
+ }
+ } else if (flashFlag) {
+ flashFlag = 0;
+ if (pathAvailable) {
+ pathAvailable = 0;
+ if (readFlashFile(checksumPath, flashBuf, device.flashLimit) != 0) {
+ printf("%s %s\n", checksumPath, FILE_ERROR);
+ exitSp12(2);
+ } else {
+ printf("Checksum program file %s: %04x\n",
+ checksumPath, checksum(flashBuf, device.flashLimit));
+ }
+ } else {
+ readFlashArea(flashBuf, device.flashLimit);
+ printf("Checksum program area: %04x\n",
+ checksum(flashBuf, device.flashLimit));
+ }
+ } else {
+ printf("you have selected option -C, but there is nothing\n");
+ printf("on the command line to calculate a checksum for.\n");
+ }
+ reportLEFHXcFlag();
+ reportBflag();
+ }
+ /*
+ * If E --> chip erase
+ */
+ if (eraseFlag) {
+ eraseFlag = 0;
+ printf("Performing chip erase...\n");
+ eraseDevice();
+ }
+ /*
+ * if B --> blank check
+ */
+ if (blankChkFlag) {
+ blankChkFlag = 0;
+ blank_check();
+ }
+ /*
+ * if i --> do nothing (init already done, device already reported)
+ * just clear initFlag
+ */
+ initFlag = 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ascii; /* characters on command line */
+ int idx = 0; /* index arguments on command line */
+ char *dataPtr; /* for separating address:data */
+ int exitFlag = 0;
+ char binary[9] = "76543210"; /* Stores conversion num to binary */
+
+ device.initPerformed = 0;
+ flashPath[0] = '\0';
+ eepromPath[0] = '\0';
+ checksumPath[0] = '\0';
+ sp12Start = clock();
+
+#ifdef LINUX
+ /*
+ * Take control of LPT I/O ports
+ */
+ if (ioperm(0x278,3,1)) {perror("ioperm error at 0x278");exit(1);}
+ if (ioperm(0x378,3,1)) {perror("ioperm error at 0x378");exit(1);}
+ if (ioperm(0x3BC,3,1)) {perror("ioperm error at 0x3BC");exit(1);}
+ /*
+ * Revoke setuid/setguid-root status
+ */
+ setgid(getgid());
+ setuid(getuid());
+#endif
+#ifdef WIN32
+ win_giveio (); // get access to I/O ports in Windows NT/2000/XP
+#endif
+
+ /*
+ * Check if something is on the command line, print usage message
+ * if not, else do init; if in sp12 mode, put power on the device
+ * (using Centronics data bits as power source), enable serial
+ * reading/programming
+ */
+ if (argc < 2) {
+ printf(USAGE, VERSION);
+ exit(0);
+ } else {
+ printf("SP12 version %s performing init...\n", VERSION);
+ initSp12(argv[0]);
+ }
+ /*
+ * allocate our memory buffers
+ */
+ flashBuf = malloc(FLASHBUF_UPPERLIMIT * sizeof (unsigned int));
+ if (flashBuf == NULL) {
+ printf ("ERROR: No memory available for buffer!\n");
+ exitSp12(2);
+ }
+ eepromBuf = malloc(EEPROMBUF_UPPERLIMIT * sizeof (unsigned int));
+ if (eepromBuf == NULL) {
+ printf ("ERROR: No memory available for buffer!\n");
+ exitSp12(2);
+ }
+ /*
+ * Dissect the command line, acting on commands from left to right.
+ */
+ idx = 0;
+ while (++idx < argc) {
+ if (*argv[idx] != '-' && fileFlag) {
+ fileFlag = 0;
+ if (addressFlag) {
+ printf("Do not use options -f and -a in a single command.\n");
+ exitSp12(2);
+ }
+ if (checksumFlag && !readFlag && !writeFlag) {
+ strcpy(checksumPath, argv[idx]);
+ pathAvailable = 1;
+ processCommand();
+ } else if (flashFlag) {
+ strcpy(flashPath, argv[idx]);
+ pathAvailable = 1;
+ processCommand();
+ } else if (eepromFlag) {
+ strcpy(eepromPath, argv[idx]);
+ pathAvailable = 1;
+ processCommand();
+ } else {
+ printf("Option -f must be combined with option -e, -p or -C\n");
+ exitSp12(2);
+ }
+ } else if (*argv[idx] != '-' && addressFlag) {
+ addressFlag = 0;
+ dataPtr = argv[idx];
+ if (writeFlag && (dataPtr = strchr(argv[idx], ':')) == NULL) {
+ printf("Option -wa must be followed by address:data\n");
+ exitSp12(2);
+ }
+ if (writeFlag)
+ dataPtr[0] = '\0';
+ if (flashFlag) {
+ flashAddress =str2num(argv[idx]);
+ if (writeFlag)
+ flashData = str2num(++dataPtr);
+ addressAvailable = 1;
+ processCommand();
+ } else if (eepromFlag) {
+ eepromAddress =str2num(argv[idx]);
+ if (writeFlag)
+ eepromData = str2num(++dataPtr);
+ addressAvailable = 1;
+ processCommand();
+ } else {
+ printf("Option -a must be combined with option -e or -p\n");
+ exitSp12(2);
+ }
+ } else if (*argv[idx] != '-') {
+ printf("No -a or -f option preceding argument `%s'\n", argv[idx]);
+ }
+ if (*argv[idx] == '-') {
+ if (strchr(argv[idx], 'w') != NULL)
+ strcpy(commandStr, argv[idx]);
+ while ((ascii = *++argv[idx]) != '\0') {
+ switch(ascii) {
+ case 'i':
+ if (strlen(argv[idx]) > 1) {
+ initFlag = 1;
+ strcpy(identifier, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ if (idx > 1) {
+ printf("WARNING: option -i[NN] has no effect unless\n");
+ printf(" it is first on the command line.\n");
+ }
+ break;
+ case 'T':
+ if (strlen(argv[idx]) > 1)
+ testFlag = atoi(++argv[idx]);
+ break;
+ case 'M':
+ if (strlen(argv[idx]) > 1) {
+ clkSpeed = atof(++argv[idx]);
+ if (clkSpeed <= 0.1)
+ clkSpeed = 0.1;
+ argv[idx][1] = '\0';
+ }
+ break;
+ case 'P':
+ if (strlen(argv[idx]) > 1) {
+ if (argv[idx][2] == 'x')
+ portFlag = (int) strtol(++argv[idx], NULL, 16);
+ else
+ portFlag = (int) strtol(++argv[idx], NULL, 10);
+ if ((idx + 1) == argc)
+ exitFlag = 1;
+ else
+ exitFlag = 0;
+ portControl(portFlag, exitFlag);
+ num2bin((unsigned char) portFlag, binary);
+ printf("Writing %#04x (%d, B%s) ",
+ portFlag, portFlag, binary);
+ printf("to the parallel port data bits.\n");
+ if ((idx + 1) < argc)
+ portFlag = 0;
+ argv[idx][1] = '\0';
+ }
+ break;
+ case 'p':
+ flashFlag = 1;
+ break;
+ case 'e':
+ eepromFlag = 1;
+ break;
+ case 'w':
+ writeFlag = 1;
+ break;
+ case 'r':
+ readFlag = 1;
+ break;
+ case 'L':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(lockBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ lockFlag = 1;
+ break;
+ case '0':
+ if (optimizeFlag)
+ optimizeFlag = 10;
+ break;
+ case '1':
+ if (optimizeFlag && !POLL_RDY_BSY)
+ optimizeFlag = 11;
+ break;
+ case '2':
+ break;
+ case '3':
+ break;
+ case '4':
+ break;
+ case '5':
+ break;
+ case '6':
+ break;
+ case '7':
+ break;
+ case '8':
+ break;
+ case '9':
+ break;
+ case 'f':
+ fileFlag = 1;
+ break;
+ case 'a':
+ addressFlag = 1;
+ break;
+ case 'E':
+ eraseFlag = 1;
+ break;
+ case 'B':
+ blankChkFlag = 1;
+ break;
+ case 'C':
+ checksumFlag = 1;
+ break;
+ case 'F':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(fusesBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ fusesFlag = 1;
+ break;
+ case 'H':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(fusesBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ highFFlag = 1;
+ break;
+ case 'X':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(fusesBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ extdFFlag = 1;
+ break;
+ case 'I':
+ IntelFlag = 1;
+ break;
+ case 'c':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ calibAddress = strtoul(++argv[idx], NULL, 2);
+ argv[idx][1] = '\0';
+ }
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) != '0' && *(argv[idx] + 1) != '1')) {
+ calibAddress = strtoul(++argv[idx], NULL, 10);
+ argv[idx][1] = '\0';
+ }
+ calibFlag = 1;
+ break;
+ case 'h':
+ hexAsciiFlag = 1;
+ break;
+ case 'o':
+ optimizeFlag = 1;
+ break;
+ case 's':
+ supported();
+ exitSp12(0);
+ break;
+ case 't':
+ idx = 0;
+ printf("(-t)iming check, about 10 seconds\n");
+ printf("..................................................\r");
+ for (idx = 0; idx < 50; idx++) {
+ loopDelay(timeConst.resetPuls * 4);
+ putchar('o');
+ fflush(stdout);
+ }
+ printf(" STOP\n");
+ exitSp12(0);
+ break;
+ case 'O':
+ overlayFlag = 1;
+ break;
+ default:
+ printf("The character `%c' ", ascii);
+ printf("is not a valid option.\n");
+ break;
+ }
+ }
+ if (!fileFlag && !addressFlag)
+ processCommand();
+ }
+ }
+ if (fileFlag) {
+ printf("Option f used, but no path on command line.\n");
+ printf("Nothing to do for sp12.\n");
+ exitSp12(2);
+ }
+ /*
+ * Exiting with the byte `portFlag' on the parallel port data bits.
+ * When the -Tnn option is not (also) used as the final option on
+ * the command line, this defaults to 0x00.
+ */
+ if (SCK == S_SCK && testFlag) {
+ switch(testFlag) {
+ case 1:
+ portFlag = RESET;
+ break;
+ case 2:
+ portFlag = RESET | PORTPOWER;
+ break;
+ default:
+ break;
+ }
+ } else if (testFlag) {
+ printf("Option -T is not available in Kanda compatible mode.\n");
+ }
+ if (!portFlag) {
+ portFlag = DEFAULT_EXIT_STATE;
+ num2bin((unsigned char) portFlag, binary);
+ printf("Writing %#04x (%d, B%s) ",
+ portFlag, portFlag, binary);
+ printf("to the parallel port data bits.\n");
+ }
+ portControl(portFlag, 1);
+ if (SCK == S_SCK) {
+ if (portFlag & 0x02)
+ printf("Reset was left high.\n");
+ if (portFlag & 0x7C)
+ printf("One or more `power' bits were left high.\n");
+ }
+ sp12End = clock();
+ sp12Elapsed = ((double) (sp12End - sp12Start)) / CLOCKS_PER_SEC;
+ printf("Sp12 was active for %#3.2f seconds.\n", sp12Elapsed);
+ return(0);
+}
diff --git a/src/sp12.h b/src/sp12.h
new file mode 100644
index 0000000..a75ef18
--- /dev/null
+++ b/src/sp12.h
@@ -0,0 +1,520 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */
+/* Artur Pundsack, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+/* Artur Pundsack can be reached by email: ap@pa-tec.de */
+
+#define WORDLEN 16
+#define DATALEN 5
+#define FLASH_DATAPTR 6
+#define MAXLEN 500
+#define FLASHBUF_UPPERLIMIT 1048576L
+#define EEPROMBUF_UPPERLIMIT 8192L
+#define FILE_ERROR "does not exist, wrong format,\n address > limit, or HEX file checksum failure."
+#define FILE_WRITE_ERROR "Unable to write to, or finish writing to"
+
+#define STK200TEST 0x02 /* data-1 connected to status-7 */
+#define STK200PRESENT 0x80
+#define STK300TEST 0x01 /* data-0 connected to status-5 */
+#define STK300PRESENT 0x20
+/*
+ * program control line definitions for sp12 cable/dongle
+ */
+#define S_SCK 0x01 /* SPI clock out */
+#define S_MOSI 0x80 /* SPI data out */
+#define S_MISO_BITNR 7 /* SPI data in bit number */
+#define S_MISO_INV 0xFF /* inverted */
+#define S_RESET 0x02 /* processor reset control */
+#define S_ENABLE 0 /* Dummy */
+#define S_PORTPOWER 0x7C /* `port power' bits */
+#define S_DEFAULT_EXIT_STATE 0
+#define S_PORTACTIVE 0x7C /* reserved for portControl() */
+/*
+ * program control line definitions for Kanda STK200 dongle
+ */
+#define K_SCK 0x10 /* SPI clock out */
+#define K_MOSI 0x20 /* SPI data out */
+#define K_MISO_BITNR 6 /* SPI data in bit number */
+#define K_MISO_INV 0x00 /* not inverted */
+#define K_RESET 0x80 /* processor reset control */
+#define K_ENABLE 0x0C /* ~enables Kanda `dongle' */
+#define K_PORTPOWER 0 /* Dummy */
+#define K_DEFAULT_EXIT_STATE 0x0C
+#define K_PORTACTIVE 0x43
+
+/*
+ * These macros perform various bit operations on scalar types using bit masks
+ */
+#define bit_set(value, bit) ((value) |= (bit))
+#define bit_clear(value, bit) ((value) &= ~(bit))
+#define bit_comp(value, bit) ((value) ^= (bit))
+#define bit_test(value, bit) (((value) & (bit)) != 0)
+
+/*---------------------- The global constants -----------------------*/
+/*----------------------- defined in init.c ------------------------*/
+
+extern unsigned long PROGRAM_ENABLE;
+extern unsigned long CHIP_ERASE;
+extern unsigned long READ_DEVICE;
+extern unsigned long READ_PROG_LO;
+extern unsigned long READ_PROG_HI;
+extern unsigned long WRITE_PROG_LO;
+extern unsigned long WRITE_PROG_HI;
+extern unsigned long LOAD_PAGE_HI;
+extern unsigned long LOAD_PAGE_LO;
+extern unsigned long LOAD_EXT_ADDR; /* AP, 15.01.2008: Added */
+extern unsigned long WRITE_PAGE;
+extern unsigned long READ_EEPROM;
+extern unsigned long WRITE_EEPROM;
+extern unsigned long POLL_RDY_BSY;
+extern unsigned long WRITE_LOCK_HM;
+extern unsigned long WRITE_LOCK_LM;
+extern unsigned long READ_LOCK;
+extern unsigned long WRITE_FUSES_HM;
+extern unsigned long WRITE_FUSES_LM;
+extern unsigned long READ_FUSES;
+extern unsigned long WRITE_HIGH_FUSES_HM;
+extern unsigned long WRITE_HIGH_FUSES_LM;
+extern unsigned long READ_HIGH_FUSES;
+extern unsigned long WRITE_EXTD_FUSES_HM;
+extern unsigned long WRITE_EXTD_FUSES_LM;
+extern unsigned long READ_EXTD_FUSES;
+extern unsigned long READ_CALIBRATION;
+extern char CALIB_MESSAGE[MAXLEN];
+extern char LOCK_MESSAGE[MAXLEN];
+extern char FUSES_MESSAGE[MAXLEN];
+extern char H_FUSES_MESSAGE[MAXLEN];
+extern char X_FUSES_MESSAGE[MAXLEN];
+extern int POLL_RBLSB;
+extern int POLL_RBLEN;
+extern int W_LOCKLSB;
+extern int R_LOCKLSB;
+extern int W_LOCKLEN;
+extern int R_LOCKLEN;
+extern int W_FUSESLSB;
+extern int R_FUSESLSB;
+extern int W_FUSESLEN;
+extern int R_FUSESLEN;
+extern int WH_FUSESLSB;
+extern int RH_FUSESLSB;
+extern int WH_FUSESLEN;
+extern int RH_FUSESLEN;
+extern int WX_FUSESLSB;
+extern int RX_FUSESLSB;
+extern int WX_FUSESLEN;
+extern int RX_FUSESLEN;
+extern int CALIBLSB;
+extern int CALIBLEN;
+
+/*-------------------- No more global constants ---------------------*/
+
+/*---------------------- The global variables -----------------------*/
+/*----------------------- defined in init.c ------------------------*/
+
+extern unsigned char SCK;
+extern unsigned char MOSI;
+extern unsigned char MISO_BITNR;
+extern unsigned char MISO_INV;
+extern unsigned char RESET;
+extern unsigned char ENABLE;
+extern unsigned char PORTPOWER;
+extern unsigned char DEFAULT_EXIT_STATE;
+extern unsigned char PORTACTIVE;
+
+struct timeConsts {
+ double loop;
+ double port; /* time taken by outportb() */
+ unsigned long sckLO;
+ unsigned long sckHI;
+ unsigned long resetPuls;
+ unsigned programEnable;
+ unsigned chipErase;
+ unsigned long byteWrite;
+ unsigned long byteWriteDefault;
+ int byteWriteAdjusted; /* a flag */
+ unsigned long pageWrite;
+ unsigned long pageWriteDefault;
+ int pageWriteAdjusted; /* a flag */
+ unsigned powerOn;
+};
+
+struct device_info {
+ unsigned char sigByte_0;
+ unsigned char sigByte_1;
+ unsigned char sigByte_2;
+ char name[30];
+ char madeBy[30];
+ long eepromLimit;
+ long flashLimit;
+ int initPerformed;
+ int pageMode; /* true if page programmed device */
+ int pageSize;
+ int fuseMode; /* 0: AT90S1200, 2313, 4414, 8515 */
+ /* 4: 2343 (lock +r, RCEN +rw) */
+ /* 5: 2323 4434, 8535 (lock +r, */
+ /* FSTRT +rw) */
+ /* 6: (ATmega103/603) */
+ /* 7: 2333, 4433 (lock +r, CKSELx3 +rw */
+ /* BODx2 +rw) */
+};
+
+struct logging {
+ char logPath[MAXLEN];
+ int logging;
+ int query;
+};
+
+extern struct timeConsts timeConst;
+extern struct device_info device;
+extern struct logging log;
+
+extern int portAddress;
+extern int portStatus;
+extern int writeRetries;
+extern float clockSpdDefault;
+extern int KandaMode; /* Cable/dongle Kanda or sp12 */
+extern int ExtAddr; /* AP, 15.01.2008: Added, Marker for crossing */
+ /* the 64k Flash boundary */
+
+extern unsigned char outbyte; /* current state of device */
+ /* control port */
+
+/*-------------------- No more global variables ---------------------*/
+
+/*
+ * A few prototypes.
+ */
+
+/* Look for the rc file, using environment variable `SP12' (if */
+/* this variable has not been set, the current directory is used). */
+/* If the rc file exists, then read the time constants and the */
+/* parallel port address from this file. If the rc file is not */
+/* found, then calibrate the time constants, check for available */
+/* parallel ports, set (usually the primary) address, and write */
+/* it all into a new rc file. Afterwards check if the parallel */
+/* port is actually there (guarding against a corrupt rc file, and */
+/* setting the port data register to 0xF0), and also check if the */
+/* time constants aren't 0. exit(1) if a check fails. */
+/* Based on either the KANDA setting in _sp12rc or the name by */
+/* which the program is called (sp12 or sp12.kanda), the */
+/* parallel port pinout is adapted to the cable/dongles supplied */
+/* with the Atmel/Kanda STK200/300 starter kits, or to the */
+/* original SP12 cable and Ken Huntington's dongle. */
+
+void initSp12(char *howWeAreCalled);
+
+
+/* Takes a devicecode (like 0392) or identifier ((-i)433) and sets */
+/* the device commands, messages and other parameters as found in */
+/* _sp12dev. */
+/* Returns 1 if _sp12dev not found; 2 if a line in _sp12dev is */
+/* corrupt; 3 if _sp12dev has no entry for the deviceCode or */
+/* identifier and the deviceCode (as an int) if all is well. */
+
+int setDevicePars(int initFlag, char *identifier);
+
+
+/* Collects all device codes and names from _sp12dev, and shows */
+/* them on screen. */
+/* Returns 1 if _sp12dev not found, else zero. */
+
+int supported(void);
+
+
+/* Delay by executing loops, not so empty as to be caught by */
+/* the compiler's optimization efforts. */
+
+void loopDelay(unsigned long loops);
+
+
+/* Determines the number of bits in command, and shifts them */
+/* highest bit first into unsigned char output, which then */
+/* is used to clock them out bit by bit through Centronics */
+/* data-7. */
+/* Reads back and returns whatever the uC clocks out on Miso */
+/* while the command is clocked in. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+unsigned long clockOutCommand(unsigned long command);
+
+
+/* Accepts a 32-bit address, and shifts it highest bit first */
+/* into unsigned char output, which then is used to clock the */
+/* bits out one by one hrough Centronics data-7 */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+void clockOutAddress(unsigned long address);
+
+
+/* Read one data byte from the status register of the */
+/* Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+unsigned char clockInByte(void);
+
+
+/* Accepts a 32-bit address. Reads the codeWord in two steps */
+/* from the device connected to the Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+unsigned int readCodeWord(unsigned long address);
+
+
+/* Accepts a 16-bit codeWord and a 7-bit address. Writes the code */
+/* in two steps with no delays into the ATMega device connected to */
+/* the Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+void loadCodePage(unsigned long address, unsigned int codeWord);
+
+
+/* Accepts a 32-bit page number and programs it into the ATMega */
+/* device connected to the Centronics parallel port. */
+/* The page is read back and compared with the buffer; if all */
+/* is well, 0 is returned, else 1. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeCodePage(unsigned int flashBuf[], unsigned long address);
+
+
+/* Accepts a 16-bit codeWord and a 16-bit address. Writes the code */
+/* in two steps into the device connected to the Centronics port and */
+/* verifies arrival. Returns 1 if verify fails three times, else 0. */
+/* The time constant byteWrite is adjusted dynamically, */
+/* if the device is not a 1200(A) and optimizeFlag allows. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+/* AP, 15.01.2008: This function is only available for non page mode!*/
+
+int writeFlashVerified(unsigned int address, unsigned int codeWord,
+ int optimizeFlag);
+
+
+/* Expects flashBuf[] to be filled with data. */
+/* If a (page) write fails, 1 is returned, else 0. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeFlashArea(unsigned int flashBuf[], long bufLimit,
+ int optimizeFlag);
+
+
+/* Assume the device connected to the Centronics port is powered, */
+/* but that device sck was not held low during power-up, so a */
+/* reset pulse is needed before the SPI can be enabled. */
+/* Assume also that power has yet to be switched on (for separate */
+/* programmer powered by parallel port, instead of in-circuit */
+/* programming. */
+/* If uC is 1200, emit just one PROGRAM_ENABLE command. */
+/* Else retry until the third byte read back by clockOutCommand() */
+/* is 0x53, or at least 32 retries have been unsuccessful. */
+
+int enableSPI(int uC);
+
+
+/* Adapt Sck timing to user's clock speed setting */
+/* (Init sets the timing equal to sck0.5M, and the flag will be */
+/* zero unless altered by the command line.) */
+
+float setSckTiming(float clkSpeed);
+
+
+/* Before writing to the flash area, the device has to be erased. */
+/* Note: This command also erases the eeprom area (all to 0xFF). */
+/* There is no need for general erase before writing to the */
+/* eeprom area, since the device has an auto-erase built into */
+/* the eeprom write cycle. Thus you can alter one or more eeprom */
+/* addresses without disturbing the rest of the device. */
+
+void eraseDevice(void);
+
+
+/* A routine to switch off the powerbits; useful only when the */
+/* separate programmer is used instead of in-circuit programming. */
+
+void portControl(int portFlag, int exitFlag);
+
+
+/* Sends a lock or fuses string to the microcontroller. */
+/* Returns 9 if the writeCommand is zero (not available according */
+/* to _sp12dev). */
+/* The lock or fuses string may represent a binary or hex number. */
+/* If it's binary, the length of the string is compared with */
+/* W_FUSESLEN; a useful sanity check. The function returns 2 if */
+/* the length is wrong. A hex number is not checked, as there is no */
+/* way to know how many leading zeroes are intended. */
+/* Next, the block is ored into the writeCommand and uploaded to */
+/* the device. */
+/* Since (re)enabling brown-out detection usually causes the */
+/* AT90(L)S2333/4433 to hang, the fuses are only written, not */
+/* verified. */
+
+int writeFuses(unsigned long commandHM, unsigned long commandLM, \
+ char *fuses, int WfusesLsb, int WfusesLen);
+
+
+/* Reads the lock or fuse bit block from the microcontroller. */
+/* Returns 9 if the readCommand is zero (not available according */
+/* to _sp12dev). */
+
+int readFuses(unsigned long readCommand, char *fuses, \
+ int RfusesLsb, int RfusesLen);
+
+void readDeviceCode(void);
+
+
+/* Converts address or data string to number, automatically */
+/* selecting hex (0xNNN), oct (0NNN), binary (BNNN) or */
+/* dec (NNN) input. */
+
+unsigned int str2num(char *addressOrData);
+
+
+/* convert unsigned int to a string-representation of the */
+/* binary number (ascii `0' is 48, ascii `1' is 49) */
+
+void num2bin(unsigned char buffer, char *binary);
+
+
+/* Reads program file in format address:data, stores data into */
+/* flashBuf by address. The two numbers must be hex without `0x' */
+/* for example: 00000c:99e1 */
+
+int readFlashFile(char flashPath[], unsigned int flashBuf[], long bufLimit);
+
+
+/* Reads program file in Atmel generic format (address:data) or */
+/* Intel HEX format; stores data into into flashBuf by address. */
+/* flashBuf by address. The two numbers in the generic format are */
+/* hex without `0x'. For example: 00000c:99e1 */
+
+int readEepromFile(char eepromPath[], unsigned int eepromBuf[], long bufLimit);
+
+
+/* Calculate checksum over buffer[]; bufLimit is number of */
+/* elements in buffer. */
+
+unsigned int checksum(unsigned int buffer[], long bufLimit);
+
+
+/* (expects flashBuf[] to be filled with 0xFFFF) */
+/* Loops readCodeWord into flashBuf[] */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+void readFlashArea(unsigned int flashBuf[], long bufLimit);
+
+
+/* Writes flashBuf[] into FILE *flashBufPtr; */
+/* If write to file fails, return(1), else return(0) */
+
+int fileFlashBuf(unsigned int flashBuf[], long bufLimit,
+ char flashPath[], int intel_flag, int hex_ascii_flag);
+
+
+/* Reads flash and eeprom area's. Return 1 if a flash address does */
+/* not contain 0xFFFF, or 3 if an eeprom address also isn't blank; */
+/* return 2 if the flash is blank, but the eeprom isn't; */
+/* return 0 is both area's are blank. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int blankCheck(long flashLimit, long eepromLimit);
+
+
+/* Accepts a dataByte and a 16-bit address. Writes the byte into */
+/* the device connected to the Centronics port and verifies arrival. */
+/* Returns 1 if verify fails three times, else 0. */
+/* The time constant byteWrite is adjusted dynamically, */
+/* if the device is not a 1200(A) and/or optimizeFlag allows. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeByteVerified(unsigned long writeCommand,
+ unsigned long readCommand, int optimizeFlag);
+
+
+/* Writes eepromBuf[] into FILE *eepromBufPtr; */
+/* If write to file fails, return(1), else return(0) */
+
+int fileEepromBuf(unsigned int eepromBuf[], long bufLimit,
+ char eepromPath[], int intel_flag, int hex_ascii_flag);
+
+
+/* Accepts a 16-bit address. Reads the dataByte in two steps */
+/* from the device connected to the Centronics port. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+unsigned char readDataByte(unsigned int address);
+
+
+/* Writes buffer[] to stdout as a hex dump with ascii translation */
+
+void printBuffer(unsigned int buffer[], long bufLimit, int twoByteFlag);
+
+
+/* Add a line to the log about a write command */
+
+int logWrites(char *commandStr, unsigned int address, int data,
+ char *path, unsigned int buffer[], int overlayFlag, int *error);
+
+
+/* Add a line to the log about a lock command */
+
+int logLocks(unsigned int buffer[], char *lockBits);
+
+
+/* Accepts a dataByte and a 16-bit address. Writes the code in two */
+/* steps into the device connected to the Centronics port and */
+/* verifies arrival. Returns 1 if verify fails three times, else 0. */
+/* The time constant byteWrite is adjusted dynamically, */
+/* if the device is not a 1200(A) and optimizeFlag allows. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeEepromVerified(unsigned int address, unsigned char dataByte,
+ int optimizeFlag);
+
+
+/* Expects eepromBuf[] to be filled with data. */
+/* executes writeEepromVerified() address by address; */
+/* if verify fails, stops and returns 1, else returns 0. */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+int writeEepromArea(unsigned int eepromBuf[], long bufLimit,
+ int optimizeFlag, int overlayFlag);
+
+
+/* (expects eepromBuf[] to be filled with 0xFF) */
+/* Loops readDataByte into eepromBuf[] */
+/* Power bits prior state assumed on; left on at return. */
+/* SCK prior state assumed lo; left lo at return. */
+
+void readEepromArea(unsigned int EepromBuf[], long bufLimit);
+
diff --git a/src/winnt.c b/src/winnt.c
new file mode 100644
index 0000000..30000ae
--- /dev/null
+++ b/src/winnt.c
@@ -0,0 +1,75 @@
+/* SP12: A serial programmer for working with Atmel AT90S uCs */
+/* Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program 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 General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+
+#ifdef WIN32
+
+#include <windows.h>
+#include <stdio.h>
+
+/*
+To install the device driver you need Dale Roberts' device driver giveio.sys
+(http://www.ddj.com/ftp/1996/1996.05/directio.zip) and the program instdrv.exe
+(instdrv.zip) from the device driver kit (DDK) for Windows NT.
+ Installation instructions
+
+ * Copy the driver giveio.sys from the archive directio.zip into %SystemRoot%\system32\drivers.
+ * Use command line to install the driver using instdrv:
+ instdrv giveio %SystemRoot%\system32\drivers\giveio.sys
+
+ * In order to start this driver at every reboot automatically, change the start up behaviour to automatic:
+ 2000/XP: start regedit and change the value of the key "Start" in
+ "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\giveio" to 2.
+ NT: Control Panel->Devices->giveio->Start Up->Automatic.
+
+*/
+
+void win_giveio(void)
+ {
+ HANDLE hDevice;
+
+ if(INVALID_HANDLE_VALUE==(hDevice=CreateFile("\\\\.\\giveio",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL))){
+ fprintf(stderr, "Couldn't access giveio device\n");
+ exit(1);
+ }
+ CloseHandle(hDevice);
+ }
+
+
+void delay(int mseconds)
+ {
+ Sleep((DWORD)mseconds);
+ }
+
+inline unsigned char inportb (const unsigned short port)
+ {
+ register unsigned char val;
+
+ __asm __volatile ("inb %%dx,%%al" : "=a" (val) : "d" (port));
+ return val;
+ }
+
+inline void outportb (unsigned short port, const unsigned char val)
+ {
+ __asm __volatile ("outb %%al,%%dx" :: "a" (val) , "d" (port));
+ }
+#endif
+