From 09381c6097773b08622c810428a84840b5b08070 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 6 Jan 2010 17:55:16 +0000 Subject: AVR SP12 programmer --- COPYING.txt | 351 ++++++++++++++++++ _sp12dev | 1067 +++++++++++++++++++++++++++++++++++++++++++++++++++++ changes.txt | 1085 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ dongle.gif | Bin 0 -> 10037 bytes dongle.txt | 27 ++ hardware.txt | 65 ++++ icp_intr.gif | Bin 0 -> 7545 bytes progrmmr.gif | Bin 0 -> 8373 bytes readme.dos | 130 +++++++ readme.linux | 152 ++++++++ readme.win | 163 +++++++++ sp12 | Bin 0 -> 54800 bytes sp12.txt | 1045 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sp12dev.txt | 218 +++++++++++ sp12rc.txt | 159 ++++++++ src/buffer.c | 691 +++++++++++++++++++++++++++++++++++ src/device.c | 434 ++++++++++++++++++++++ src/dos_cpt.h | 53 +++ src/eeprom.c | 125 +++++++ src/flash.c | 292 +++++++++++++++ src/init.c | 854 +++++++++++++++++++++++++++++++++++++++++++ src/makefile | 58 +++ src/sp12.c | 1136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sp12.h | 520 ++++++++++++++++++++++++++ src/winnt.c | 75 ++++ 25 files changed, 8700 insertions(+) create mode 100644 COPYING.txt create mode 100644 _sp12dev create mode 100644 changes.txt create mode 100644 dongle.gif create mode 100644 dongle.txt create mode 100644 hardware.txt create mode 100644 icp_intr.gif create mode 100644 progrmmr.gif create mode 100644 readme.dos create mode 100644 readme.linux create mode 100644 readme.win create mode 100755 sp12 create mode 100644 sp12.txt create mode 100644 sp12dev.txt create mode 100644 sp12rc.txt create mode 100644 src/buffer.c create mode 100644 src/device.c create mode 100644 src/dos_cpt.h create mode 100644 src/eeprom.c create mode 100644 src/flash.c create mode 100644 src/init.c create mode 100644 src/makefile create mode 100644 src/sp12.c create mode 100644 src/sp12.h create mode 100644 src/winnt.c 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. 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 Binary files /dev/null and b/dongle.gif 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 Binary files /dev/null and b/icp_intr.gif differ diff --git a/progrmmr.gif b/progrmmr.gif new file mode 100644 index 0000000..bd17e4a Binary files /dev/null and b/progrmmr.gif 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= + + 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// + + 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= + + 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= + + 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 Binary files /dev/null and b/sp12 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 - [filename or address(:data)] - [filename... + +OPTION SUMMARY + + i - 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' 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. 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. 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 [] [] + 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 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. 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 + 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= + + 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= + + 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= + + 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= + + 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= + + 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= + + 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= + + 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= + + 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= + + 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= + + 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= + PAGEWRITE= + PROGRAMENABLE= + RESETPULS= + + 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 +#include +#include +#include +#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 +#include +#include +#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 +#include + +#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 + +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#include "dos_cpt.h" +#include +#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 +#include +#include +#include "dos_cpt.h" +#include +#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 - match Sck to uC clock\n" + " o0, o1 - optimization P - 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 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\n"); + exitSp12(2); + } + if (highFFlag) { + printf("Use H only in the commands -rH or -wH\n"); + exitSp12(2); + } + if (extdFFlag) { + printf("Use X only in the commands -rX or -wX\n"); + exitSp12(2); + } + if (lockFlag) { + printf("Use L only in the commands -rL or -wL\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 \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 +#include + +/* +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 + -- cgit v1.2.3