From 273d814d87242c5526dd03dc4530f605951fe0d4 Mon Sep 17 00:00:00 2001 From: Peter Henn Date: Thu, 21 Apr 2005 12:00:00 +0200 Subject: [PATCH] USBasp 2005.04.21. unmodified content from archive usbasp.2005-04-21.tar.gz --- .gitattributes | 9 + Readme.txt | 140 ++ bin/firmware/usbasp.2005-04-21.hex | 204 ++ bin/win-avrdude/avrdude.conf | 3317 ++++++++++++++++++++++++++++++ bin/win-avrdude/avrdude.exe | Bin 0 -> 169212 bytes bin/win-driver/libusb0.dll | Bin 0 -> 46592 bytes bin/win-driver/libusb0.sys | Bin 0 -> 33792 bytes bin/win-driver/usbasp.inf | 90 + circuit/usbasp_5V_circuit.pdf | Bin 0 -> 27608 bytes firmware/Makefile | 56 + firmware/clock.c | 23 + firmware/clock.h | 24 + firmware/isp.c | 274 +++ firmware/isp.h | 66 + firmware/main.c | 234 +++ firmware/usbconfig.h | 117 ++ firmware/usbdrv/Changelog.txt | 18 + firmware/usbdrv/License.txt | 457 ++++ firmware/usbdrv/oddebug.c | 51 + firmware/usbdrv/oddebug.h | 110 + firmware/usbdrv/oddebug.o | Bin 0 -> 661 bytes firmware/usbdrv/usbdrv.c | 429 ++++ firmware/usbdrv/usbdrv.h | 286 +++ firmware/usbdrv/usbdrv.o | Bin 0 -> 2996 bytes firmware/usbdrv/usbdrvasm.S | 648 ++++++ firmware/usbdrv/usbdrvasm.o | Bin 0 -> 4068 bytes software/avrdude_usbasp.2005-04-21.patch | 125 ++ software/usbasp.c | 329 +++ software/usbasp.h | 28 + 29 files changed, 7035 insertions(+) create mode 100644 .gitattributes create mode 100644 Readme.txt create mode 100644 bin/firmware/usbasp.2005-04-21.hex create mode 100644 bin/win-avrdude/avrdude.conf create mode 100755 bin/win-avrdude/avrdude.exe create mode 100755 bin/win-driver/libusb0.dll create mode 100755 bin/win-driver/libusb0.sys create mode 100644 bin/win-driver/usbasp.inf create mode 100644 circuit/usbasp_5V_circuit.pdf create mode 100644 firmware/Makefile create mode 100644 firmware/clock.c create mode 100644 firmware/clock.h create mode 100644 firmware/isp.c create mode 100644 firmware/isp.h create mode 100644 firmware/main.c create mode 100644 firmware/usbconfig.h create mode 100644 firmware/usbdrv/Changelog.txt create mode 100644 firmware/usbdrv/License.txt create mode 100644 firmware/usbdrv/oddebug.c create mode 100644 firmware/usbdrv/oddebug.h create mode 100644 firmware/usbdrv/oddebug.o create mode 100644 firmware/usbdrv/usbdrv.c create mode 100644 firmware/usbdrv/usbdrv.h create mode 100644 firmware/usbdrv/usbdrv.o create mode 100644 firmware/usbdrv/usbdrvasm.S create mode 100644 firmware/usbdrv/usbdrvasm.o create mode 100644 software/avrdude_usbasp.2005-04-21.patch create mode 100644 software/usbasp.c create mode 100644 software/usbasp.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..9803a03eb --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# Declare files that will always have CRLF line endings on checkout. +*.inf text eol=crlf + +# Declare pathc and diff files allow trailing whitespace +*.diff text=auto -whitespace +*.patch text=auto -whitespace + +# ignore .git +.git* text export-ignore diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 000000000..a3ef94043 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,140 @@ +This is the README file for USBasp. + +USBasp is a USB in-circuit programmer for Atmel AVR controllers. It simply +consists of an ATMega8 and a couple of passive components. The programmer +uses a firmware-only USB driver, no special USB controller is needed. + +Features: +- Works under multiple platforms. Linux, Mac OS X and Windows are tested. +- No special controllers or smd components are needed. +- Programming speed is up to 5kBytes/sec. +- SCK option to support targets with low clock speed (< 1,5MHz). +- Planned: serial interface to target (e.g. for debugging). + + +LICENSE + +The project is built with AVR USB driver by Objective Development, which is +published under a proprietary Open Source license. To conform with this +license, USBasp is distributed under the same license conditions. See the +file "firmware/usbdrv/License.txt" for details. + + +LIMITATIONS + +Hardware: +"circuit/usbasp_5V_circuit.pdf" shows a simple circuit. It doesn't meet the +voltage range on the data lines specified in USB 1.1. Also this circuit can +only be used for programming 5V target systems. For other systems a level +converter is needed. + +Firmware: +The firmware dosn't support USB Suspend Mode. A bidirectional serial +interface to slave exists in hardware but the firmware doesn't support it yet. + + +USE PRECOMPILED VERSION + +Firmware: +Flash "bin/firmware/usbasp.xxxx-xx-xx.hex" to the ATMega8 with a working +programmer (e.g. with avrdude, uisp, ...). Set jumper J2 to activate +USBasp firmware update function. + +Windows: +Start Windows and connect USBasp to the system. When Windows asks for a +driver, choose "bin/win-driver". On Win2k and WinXP systems, Windows will +warn that the driver is is not 'digitally signed'. Ignore this message and +continue with the installation. +Now you can run the precompiled version of avrdude: change in command line +mode to "bin/win-avrdude" and start the program. Consult the documentation +of avrdude for details. Examples: +1. Enter terminal mode with an AT90S2313 connected to the programmer: + avrdude -c usbasp -p at90s2313 -t +2. Write main.hex to the flash of an ATmega8: + avrdude -c usbasp -p atmega8 -U flash:w:main.hex + +Setting jumpers: +J1 Power target + Supply target with 5V (USB voltage). Be careful with this option, the + circuit isn't protected against short circuit! +J2 Jumper for firmware upgrade (not self-upgradable) + Set this jumper for flashing the ATMega8 of USBasp with another working + programmer. +J3 SCK option + If the target clock is lower than 1,5 MHz, you have to set this jumper. + Then SCK is scaled down from 375 kHz to about 8 kHz. + + +BUILDING AND INSTALLING FROM SOURCE CODE + +Firmware: +To compile the firmware +1. install the GNU toolchain for AVR microcontrollers (avr-gcc, avr-libc), +2. change directory to firmware/ +3. run "make" +4. flash "main.hex" to the ATMega8. E.g. with uisp or avrdude (check +the Makefile option "make avrdude"). To flash the firmware you have +to set jumper J2 and connect USBasp to a working programmer. + +Software (avrdude): +An extension to avrdude (http://www.nongnu.org/avrdude/) was written. +To compile the software: +1. install libusb: http://libusb.sourceforge.net/ +2. get the csv version of avrdude: + export CVS_RSH="ssh" + cvs -z3 -d:ext:anoncvs@savannah.nongnu.org:/cvsroot/avrdude co avrdude +3. cp usbasp/software/usbasp.* avrdude/ +4. cd avrdude +5. apply the patch: + patch < ../usbasp/software/avrdude_usbasp.xxxx-xx-xx.patch +6. configure to your environment: + ./bootstrap (I had to comment out the two if-blocks which verify the + installed versions of autoconf and automake) + ./configure +7. compile and install it: + make + make install + +Notes on Windows (Cygwin): +Download libusb-win32-device-bin-x.x.x.x.tar.gz from +http://libusb-win32.sourceforge.net/ and unpack it. +-> copy lib/gcc/libusb.a to lib-path +-> copy include/usb.h to include-path +cd avrdude +./configure LDFLAGS="-static" --enable-versioned-doc=no +make + +Notes on Darwin/MacOS X: +after "./configure" I had to edit Makefile: +change "avrdude_CPPFLAGS" to "AM_CPPFLAGS" +(why is this needed only on mac? bug in configure.ac?) + + +FILES IN THE DISTRIBUTION + +Readme.txt ...................... The file you are currently reading +firmware ........................ Source code of the controller firmware +firmware/usbdrv ................. AVR USB driver by Objective Development +firmware/usbdrv/License.txt ..... Public license for AVR USB driver and USBasp +software ........................ Source code of the host software +circuit ......................... Circuit diagram in PDF +bin ............................. Precompiled programs +bin/win-driver .................. Windows driver +bin/win-avrdude ................. avrdude compiled for Windows + + +MORE INFORMATION + +For more information on USBasp and it's components please visit the +following URLs: + +USBasp .......................... http://www.fischl.de/usbasp/ + +Firmware-only AVR USB driver .... http://www.obdev.at/products/avrusb/ +avrdude ......................... http://www.nongnu.org/avrdude/ +libusb .......................... http://libusb.sourceforge.net/ +libusb-win32 .................... http://libusb-win32.sourceforge.net/ + + +2005-04-21 Thomas Fischl +http://www.fischl.de diff --git a/bin/firmware/usbasp.2005-04-21.hex b/bin/firmware/usbasp.2005-04-21.hex new file mode 100644 index 000000000..eeb499c80 --- /dev/null +++ b/bin/firmware/usbasp.2005-04-21.hex @@ -0,0 +1,204 @@ +:100000003BC072C153C052C051C050C04FC04EC05F +:100010004DC04CC04BC04AC049C048C047C046C094 +:1000200045C044C043C00E03550053004200610068 +:10003000730070001C037700770077002E006600C5 +:1000400069007300630068006C002E00610074009A +:1000500004030904090212000101008019090400C7 +:1000600000000000000012010101FF000008EB0386 +:10007000B4C700010102000111241FBECFE5D4E086 +:10008000DEBFCDBF10E0A0E6B0E0EAE9FCE002C0D0 +:1000900005900D92A436B107D9F710E0A4E6B0E0C0 +:1000A00001C01D92A23AB107E1F7E2C5A9CF1F93A3 +:1000B000CF93FC0180919B008D3269F080917A0092 +:1000C00087FD04C0CF0145D58F3F71F010926300CA +:1000D00010927A0066C0C0E010E8683061F0C0930A +:1000E000630010937A005DC08EE180938D0082E002 +:1000F0008093620056C080818076F9F426E930E072 +:10010000C093960081818823A1F08530E9F0863084 +:10011000F9F0883061F18A3071F130939D002093BD +:100120009C0087818823D9F686818C17C0F6C82F5A +:10013000D6CFC0939700C2E0F0CFC681CF01FCD3E9 +:100140008F3FA9F710E0CBCF828180937B00E5CF72 +:1001500010EC8381813089F0823099F08330E9F6A8 +:100160008281882391F4C4E020E530E0D6CFC1E05D +:10017000C0939600D2CFC1E0D0CFC2E126E630E0F6 +:10018000CCCFC2E124E530E0C8CF813031F08230FD +:1001900021F6CEE026E230E0C0CFCCE124E330E02F +:1001A000BCCFCF911F910895CF9360919E0066239D +:1001B00051F0635067FD05C0809199009927019621 +:1001C00076DF10929E008091620087FD1AC086B390 +:1001D000837019F010927C0077C080917C00882396 +:1001E00009F072C094E686B3837009F06DC0915037 +:1001F000D1F781E080937C009093980090937B00EE +:1002000063C0809163008F3F31F12BE490917A00BD +:1002100090FD23EC9F5F90937A0020938D00682FD0 +:10022000893008F068E0861B80936300AEE8B0E098 +:1002300097FD30C0662349F560E070E0C62F693055 +:10024000A0F08EE180938D0092E08FEF80936300A9 +:1002500090936200BCCF80917B00882309F4B7CFD4 +:100260008093980010927B00B2CF8EE890E0B9D1D5 +:10027000EC2FFF27E357FF4F818392839C2F9C5FD6 +:10028000C83018F390936200A2CFCD0125D4682F17 +:100290007727D4CFE0919C00F0919D0096FF0DC090 +:1002A000962F03C084918D9331969150D8F7F09397 +:1002B0009D00E0939C007727C1CF962F02C08191CB +:1002C0008D939150E0F7F3CFCF91089584E690E0BD +:1002D00080939A000B968093990085B7836085BFC1 +:1002E0008BB780648BBF08950F930FB70F9305E012 +:1002F000B09BFECF0A95B099E9F71F933F932F93D8 +:1003000031E012E006B3102710FD32E0102F3A95CD +:10031000C9F700FDE0C006B3102717952FE7279512 +:10032000DF9316B3012707952795CF93C0919A00C5 +:1003300006B31027179527953BE0DD274F9316B39B +:100340000127079527954FEF000051C005E0B09BAE +:10035000FECF0A95B099E9F7DF9100C0D1CF16B36F +:10036000137079F1407C2C6F13C006B3037049F110 +:1003700041782C6F15C0037021F1102F2C6F06B33C +:1003800019C006B30370E9F04E7F2C6F18C038F324 +:1003900006B30370B1F0102717952795243028F382 +:1003A00016B3012707952795422749934FEF06B3C8 +:1003B000243008F3102717952795243010F316B32F +:1003C0001370E1F10127079527952430F0F006B36B +:1003D0000370A1F11027179527952430E0F016B38C +:1003E0000127079527953A9541F12430D0F006B3BF +:1003F000037021F11027179527952430C0F016B30C +:100400000127079527952430C2CF16B31370B1F09A +:100410004C7F2C6FDCCF06B3037081F0487F2C6FCC +:10042000DECF16B3137051F0407F2C6FE0CF06B3D0 +:10043000037021F0407E2C6FE2CF3AC03C2FC09178 +:100440009A003C1B00E433300ABF90F10881198107 +:10045000412F1F77209198000D3271F1013E61F11B +:100460000936B9F0033C11F00B3411F510919F00DF +:100470001123F1F000919E000030B1F530939E0001 +:1004800010939B0000919900C093990000939A00EB +:100490002EC0121769F4309162003F3F29F10FEF2F +:1004A00000936200CDE8D0E025C0002700939F00B4 +:1004B0004F91CF91DF910FC01217B9F700939F00B2 +:1004C0000FEF00936300009362004F91CF910AB742 +:1004D00006FD3CCFDF9100E40ABF2F913F911F91B1 +:1004E0000F910FBF0F911895C0E6D0E002C0C1E692 +:1004F000D0E032E05F9308B30C7F016008BB53E0AB +:1005000017B3136017BB20E80FC0052710E008BB26 +:1005100010C0052710E0089408BB13C0052710E0A1 +:1005200015C0052710E019C020FF052708BB279537 +:1005300017951C3F50F720FF0527279508BB1795F7 +:100540001C3F38F720FF05272795179508BB1C3F50 +:1005500028F720FF0527279517951C3F08BB08F7AC +:1005600000C0499120FF052708BB279517951C3F20 +:1005700048F520FF0527279508BB17951C3F30F548 +:1005800020FF05272795179508BB1C3F20F520FF66 +:100590000527279517951C3F08BB00F5242F3A9592 +:1005A00019F60C7F5F9108BB34E03A95F1F70160D2 +:1005B00017B31C7F08BB0C7F4F91CF9117BB08BBB3 +:1005C000DF9189CF052710E008BBD1CF052710E0C8 +:1005D000089408BBD4CF052710E0D6CF052710E03C +:1005E000DACFA82FB92F8FEF9FEF41E050EA61508B +:1005F00070F02D9138E0722F782796958795269583 +:1006000070FF02C0842795273A95A9F7F0CF80950F +:100610009095089582E58DB981E08EB9089588237B +:1006200039F480E493E09093A1008093A0000895B2 +:100630008DE593E09093A1008093A000089592B778 +:1006400082B7891B8C30E0F3089587B38C6287BB37 +:10065000C298C598F4DFC29AF2DFC2988091A000D8 +:100660009091A1008D55934009F00895D3DF08952E +:1006700087B3837D87BB88B3837D88BB1DB808950E +:100680000F931F93CF93C82F00E017E00CC0C398BF +:10069000CC0F000FB4990F5FC59AD1DFC598CFDF9B +:1006A000115017FD04C0C7FFF2CFC39AF1CF802FBE +:1006B0009927CF911F910F9108958FB9779BFECF06 +:1006C0008FB1992708951F93CF93CFE103C0C150F5 +:1006D000CF3F51F1E091A000F091A1008CEA099583 +:1006E000E091A000F091A10083E50995E091A000C0 +:1006F000F091A10080E00995182FE091A000F09101 +:10070000A10080E00995133591F01DB8C59A97DFD7 +:10071000C59895DF8091A0009091A1008D559340E0 +:10072000B1F678DFC150B0F681E090E002C080E021 +:1007300090E0CF911F9108950F931F938C018170CA +:10074000880F880F880FE091A000F091A1008062CF +:100750000995C801892F99278695E091A000F0910D +:10076000A100099516950795E091A000F091A100D0 +:10077000802F0995E091A000F091A10080E00995FB +:1007800099271F910F9108950F931F93CF93DF9394 +:10079000EC01062F142F8170880F880F880FE091CD +:1007A000A000F091A10080640995CE01892F9927BE +:1007B0008695E091A000F091A1000995CE01969553 +:1007C0008795E091A000F091A1000995E091A0002B +:1007D000F091A100802F09951123A9F00F3789F01E +:1007E0001EE102B7CE01A8DF8F3769F482B7801B04 +:1007F0008D3310F002B711501123A1F781E090E082 +:1008000004C08FE08CD080E090E0DF91CF911F9109 +:100810000F9108950F931F93CF93DF93EC01162F41 +:10082000E091A000F091A1008CE40995CE01892F00 +:1008300099278695E091A000F091A1000995CE013D +:1008400096958795E091A000F091A1000995E0911F +:10085000A000F091A10080E009951F3F89F01EE102 +:1008600002B7CE0169DF8F3F69F482B7801B8D33F9 +:1008700010F002B711501123A1F781E090E004C0FD +:100880008FE04DD080E090E0DF91CF911F910F91EC +:1008900008950F931F938C01E091A000F091A100A7 +:1008A00080EA0995812F9927E091A000F091A1009D +:1008B0000995E091A000F091A100802F0995E091A9 +:1008C000A000F091A10080E0099599271F910F9158 +:1008D0000895FF920F931F938C01F62EE091A000D4 +:1008E000F091A10080EC0995812F9927E091A0005B +:1008F000F091A1000995E091A000F091A100802F56 +:100900000995E091A000F091A1008F2D09958EE14D +:1009100006D080E090E01F910F91FF900895382F4E +:1009200020E0231740F492B782B7891B8C33E0F3A1 +:100930002F5F2317C0F308951F93CF93DF93EC012C +:1009400010E089818130A1F0823009F472C08330D7 +:1009500009F472C0843091F0873009F450C08530BA +:1009600009F4AAC0863039F1883009F0A9C086C0E0 +:100970009A9B812F54DE69DEA998A2C08B819927AA +:10098000982F88272A813327822B932B90938900D5 +:10099000809388008F819927982F88272E8133276D +:1009A000822B932B90937E0080937D0082E0809336 +:1009B0007F001FEF85C08B819927982F88272A8178 +:1009C0003327822B932B90938900809388009C81FE +:1009D00090938A008D8180938B0080FF02C090935A +:1009E0008C008F819927982F88272E813327822B7F +:1009F000932B90937E0080937D0081E0D8CF8B81F4 +:100A00009927982F88272A813327822B932B90931D +:100A10008900809388008F819927982F88272E81BD +:100A20003327822B932B90937E0080937D0083E06D +:100A3000BECF1EDEA99A44C0E091A000F091A100B3 +:100A40008A81099580938000E091A000F091A10037 +:100A50008B81099580938100E091A000F091A10025 +:100A60008C81099580938200E091A000F091A10013 +:100A70008D8109958093830014E022C08B81992792 +:100A8000982F88272A813327822B932B90938900D4 +:100A90008093880010938A0010938B008F81992790 +:100AA000982F88272E813327822B932B90937E00BB +:100AB00080937D0084E07BCF06DE8093800011E090 +:100AC00080E890E090939D0080939C00812F99276F +:100AD000DF91CF911F910895EF92FF921F93CF93D3 +:100AE0007C01162F90917F00892F8250823050F523 +:100AF000C0E0C617C0F01FC08091880090918900A7 +:100B0000C8DEF701EC0FF11D808380918800909181 +:100B1000890001969093890080938800CF5FC11768 +:100B200050F490917F00923039F780918800909135 +:100B3000890002DEE6CF183010F410927F00812F7A +:100B4000992702C08FEF90E0CF911F91FF90EF9017 +:100B50000895CF92DF92EF92FF920F931F93CF935E +:100B6000DF936C01062F40917F00413019F0443033 +:100B700009F073C010E01017F0F16CC080918A008A +:100B8000882309F046C0C12FDD27FE01EC0DFD1DB5 +:100B900060818091880090918900F6DD80917D00D0 +:100BA00090917E00019790937E0080937D00892B29 +:100BB000A1F410927F0080918B0081FF0EC0909174 +:100BC0008C0080918A00981741F0CC0DDD1D688162 +:100BD00080918800909189001DDE8091880090911D +:100BE0008900019690938900809388001F5F1017F9 +:100BF00088F540917F00413009F2C12FDD27FE01C9 +:100C0000EC0DFD1D6081809188009091890061DE6E +:100C1000C5CFC12FDD277E01EC0CFD1C40E0F701A4 +:100C200060818091880090918900AEDD80918C0078 +:100C3000815080938C00882309F0B0CFF701608148 +:100C40008091880090918900E5DD80918A008093F1 +:100C50008C00A4CF80E090E002C08FEF90E0DF91A5 +:100C6000CF911F910F91FF90EF90DF90CF9008955B +:100C7000CFE5D4E0DEBFCDBF12BA18BA8BEF81BB8F +:100C800017BA93E094BB8EEF85BB93BF81E0C7DCBE +:0A0C90001DDB789489DA88DAFDCFC5 +:040C9A005AD2FFFF2C +:00000001FF diff --git a/bin/win-avrdude/avrdude.conf b/bin/win-avrdude/avrdude.conf new file mode 100644 index 000000000..a74de19e2 --- /dev/null +++ b/bin/win-avrdude/avrdude.conf @@ -0,0 +1,3317 @@ +# $Id: avrdude.conf.in,v 1.36 2004/12/22 01:30:30 bdean Exp $ +# +# AVRDUDE Configuration File +# +# This file contains configuration data used by AVRDUDE which describes +# the programming hardware pinouts and also provides part definitions. +# AVRDUDE's "-C" command line option specifies the location of the +# configuration file. The "-c" option names the programmer configuration +# which must match one of the entry's "id" parameter. The "-p" option +# identifies which part AVRDUDE is going to be programming and must match +# one of the parts' "id" parameter. +# +# Possible entry formats are: +# +# programmer +# id = [, [, ] ...] ; # are quoted strings +# desc = ; # quoted string +# type = par | stk500 | avr910; # programmer type +# baudrate = ; # baudrate for avr910-programmer +# vcc = [, ... ] ; # pin number(s) +# reset = ; # pin number +# sck = ; # pin number +# mosi = ; # pin number +# miso = ; # pin number +# errled = ; # pin number +# rdyled = ; # pin number +# pgmled = ; # pin number +# vfyled = ; # pin number +# ; +# +# part +# id = ; # quoted string +# desc = ; # quoted string +# devicecode = ; # deprecated, use stk500_devcode +# stk500_devcode = ; # numeric +# avr910_devcode = ; # numeric +# chip_erase_delay = ; # micro-seconds +# pagel = ; # pin name in hex, i.e., 0xD7 +# bs2 = ; # pin name in hex, i.e., 0xA0 +# reset = dedicated | io; +# retry_pulse = reset | sck; +# pgm_enable = ; +# chip_erase = ; +# memory +# paged = ; # yes / no +# size = ; # bytes +# page_size = ; # bytes +# num_pages = ; # numeric +# min_write_delay = ; # micro-seconds +# max_write_delay = ; # micro-seconds +# readback_p1 = ; # byte value +# readback_p2 = ; # byte value +# pwroff_after_write = ; # yes / no +# read = ; +# write = ; +# read_lo = ; +# read_hi = ; +# write_lo = ; +# write_hi = ; +# loadpage_lo = ; +# loadpage_hi = ; +# writepage = ; +# ; +# ; +# +# If any of the above parameters are not specified, the default value +# of 0 is used for numerics or the empty string ("") for string +# values. If a required parameter is left empty, AVRDUDE will +# complain. +# +# NOTES: +# * 'devicecode' is the device code used by the STK500 (see codes +# listed below) +# * Not all memory types will implement all instructions. +# * AVR Fuse bits and Lock bits are implemented as a type of memory. +# * Example memory types are: +# "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high +# fuse), "signature", "calibration", "lock" +# * The memory type specified on the avrdude command line must match +# one of the memory types defined for the specified chip. +# * The pwroff_after_write flag causes avrdude to attempt to +# power the device off and back on after an unsuccessful write to +# the affected memory area if VCC programmer pins are defined. If +# VCC pins are not defined for the programmer, a message +# indicating that the device needs a power-cycle is printed out. +# This flag was added to work around a problem with the +# at90s4433/2333's; see the at90s4433 errata at: +# +# http://www.atmel.com/atmel/acrobat/doc1280.pdf +# +# INSTRUCTION FORMATS +# +# Instruction formats are specified as a comma seperated list of +# string values containing information (bit specifiers) about each +# of the 32 bits of the instruction. Bit specifiers may be one of +# the following formats: +# +# '1' = the bit is always set on input as well as output +# +# '0' = the bit is always clear on input as well as output +# +# 'x' = the bit is ignored on input and output +# +# 'a' = the bit is an address bit, the bit-number matches this bit +# specifier's position within the current instruction byte +# +# 'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12 +# is address bit 12 on input, a0 is address bit 0. +# +# 'i' = the bit is an input data bit +# +# 'o' = the bit is an output data bit +# +# Each instruction must be composed of 32 bit specifiers. The +# instruction specification closely follows the instruction data +# provided in Atmel's data sheets for their parts. +# +# See below for some examples. +# +# +# The following are STK500 part device codes to use for the +# "devicecode" field of the part. These came from Atmel's software +# section avr061.zip which accompanies the application note +# AVR061 available from: +# +# http://www.atmel.com/atmel/acrobat/doc2525.pdf +# + +#define ATTINY10 0x10 +#define ATTINY11 0x11 +#define ATTINY12 0x12 +#define ATTINY15 0x13 +#define ATTINY13 0x14 + +#define ATTINY22 0x20 +#define ATTINY26 0x21 +#define ATTINY28 0x22 +#define ATTINY2313 0x23 + +#define AT90S1200 0x33 + +#define AT90S2313 0x40 +#define AT90S2323 0x41 +#define AT90S2333 0x42 +#define AT90S2343 0x43 + +#define AT90S4414 0x50 +#define AT90S4433 0x51 +#define AT90S4434 0x52 +#define ATMEGA48 0x59 + +#define AT90S8515 0x60 +#define AT90S8535 0x61 +#define AT90C8534 0x62 +#define ATMEGA8515 0x63 +#define ATMEGA8535 0x64 + +#define ATMEGA8 0x70 +#define ATMEGA88 0x73 + +#define ATMEGA161 0x80 +#define ATMEGA163 0x81 +#define ATMEGA16 0x82 +#define ATMEGA162 0x83 +#define ATMEGA169 0x84 + +#define ATMEGA323 0x90 +#define ATMEGA32 0x91 + +#define ATMEGA64 0xA0 + +#define ATMEGA103 0xB1 +#define ATMEGA128 0xB2 +#define AT90CAN128 0xB3 + +#define AT86RF401 0xD0 + +#define AT89START 0xE0 +#define AT89S51 0xE0 +#define AT89S52 0xE1 + + +# +# Overall avrdude defaults +# +default_parallel = "/dev/parport0"; +default_serial = "/dev/ttyS0"; + + +# +# PROGRAMMER DEFINITIONS +# + +programmer + id = "bsd"; + desc = "Brian Dean's Programmer, http://www.bsdhome.com/avrdude/"; + type = par; + vcc = 2, 3, 4, 5; + reset = 7; + sck = 8; + mosi = 9; + miso = 10; +; + +programmer + id = "avrisp"; + desc = "Atmel AVR ISP"; + type = stk500; +; + +programmer + id = "usbasp"; + desc = "usbasp"; + type = usbasp; +; + +programmer + id = "stk500"; + desc = "Atmel STK500"; + type = stk500; +; + +programmer + id = "avr910"; + desc = "Atmel Low Cost Serial Programmer"; + type = avr910; +; + +programmer + id = "butterfly"; + desc = "Atmel Butterfly Development Board"; + type = butterfly; +; + +programmer + id = "pavr"; + desc = "Jason Kyle's pAVR Serial Programmer"; + type = avr910; +; + +programmer + id = "stk200"; + desc = "STK200"; + type = par; + buff = 4, 5; + sck = 6; + mosi = 7; + reset = 9; + miso = 10; +; + +# The programming dongle used by the popular Ponyprog +# utility. It is almost similar to the STK200 one, +# except that there is a LED indicating that the +# programming is currently in progress. + +programmer + id = "pony-stk200"; + desc = "Pony Prog STK200"; + type = par; + buff = 4, 5; + sck = 6; + mosi = 7; + reset = 9; + miso = 10; + pgmled = 8; +; + +programmer + id = "dt006"; + desc = "Dontronics DT006"; + type = par; + reset = 4; + sck = 5; + mosi = 2; + miso = 11; +; + +programmer + id = "bascom"; + desc = "Bascom SAMPLE programming cable"; + type = par; + reset = 4; + sck = 5; + mosi = 2; + miso = 11; +; + +programmer + id = "alf"; + desc = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/"; + type = par; + vcc = 2, 3, 4, 5; + buff = 6; + reset = 7; + sck = 8; + mosi = 9; + miso = 10; + errled = 1; + rdyled = 14; + pgmled = 16; + vfyled = 17; +; + +programmer + id = "sp12"; + desc = "Steve Bolt's Programmer"; + type = par; + vcc = 4,5,6,7,8; + reset = 3; + sck = 2; + mosi = 9; + miso = 11; +; + +programmer + id = "picoweb"; + desc = "Picoweb Programming Cable, http://www.picoweb.net/"; + type = par; + reset = 2; + sck = 3; + mosi = 4; + miso = 13; +; + +programmer + id = "abcmini"; + desc = "ABCmini Board, aka Dick Smith HOTCHIP"; + type = par; + reset = 4; + sck = 3; + mosi = 2; + miso = 10; +; + +programmer + id = "futurlec"; + desc = "Futurlec.com programming cable."; + type = par; + reset = 3; + sck = 2; + mosi = 1; + miso = 10; +; + + +# From the contributor of the "xil" jtag cable: +# The "vcc" definition isn't really vcc (the cable gets its power from +# the programming circuit) but is necessary to switch one of the +# buffer lines (trying to add it to the "buff" lines doesn't work). +# With this, TMS connects to RESET, TDI to MOSI, TDO to MISO and TCK +# to SCK (plus vcc/gnd of course) +programmer + id = "xil"; + desc = "Xilinx JTAG cable"; + type = par; + mosi = 2; + sck = 3; + reset = 4; + buff = 5; + miso = 13; + vcc = 6; +; + + +# +# PART DEFINITIONS +# + +#------------------------------------------------------------ +# ATtiny12 +#------------------------------------------------------------ + +part + id = "t12"; + desc = "ATtiny12"; + stk500_devcode = 0x12; + avr910_devcode = 0x55; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 64; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + + memory "flash" + size = 1024; + min_write_delay = 4500; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "fuse" + size = 1; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", + "x x x x x x x x i i i i i i i i"; + ; +; + +#------------------------------------------------------------ +# ATtiny13 +#------------------------------------------------------------ + +part + id = "t13"; + desc = "ATtiny13"; + stk500_devcode = 0x14; + chip_erase_delay = 4000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 64; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 1024; + page_size = 32; + num_pages = 32; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 0 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 0 0 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 0 0 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATtiny15 +#------------------------------------------------------------ + +part + id = "t15"; + desc = "ATtiny15"; + stk500_devcode = 0x13; + avr910_devcode = 0x56; + chip_erase_delay = 8200; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 64; + min_write_delay = 8200; + max_write_delay = 8200; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + + memory "flash" + size = 1024; + min_write_delay = 4100; + max_write_delay = 4100; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "fuse" + size = 1; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x o o o o x x o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", + "x x x x x x x x i i i i 1 1 i i"; + ; +; + + +#------------------------------------------------------------ +# AT90s1200 +#------------------------------------------------------------ + +part + id = "1200"; + desc = "AT90S1200"; + stk500_devcode = 0x33; + avr910_devcode = 0x13; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 64; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x x a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 1024; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s4414 +#------------------------------------------------------------ + +part + id = "4414"; + desc = "AT90S4414"; + stk500_devcode = 0x50; + avr910_devcode = 0x28; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 256; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 4096; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x7f; + readback_p2 = 0x7f; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90s2313 +#------------------------------------------------------------ + +part + id = "2313"; + desc = "AT90S2313"; + stk500_devcode = 0x40; + avr910_devcode = 0x20; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 128; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 2048; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x7f; + readback_p2 = 0x7f; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x i i x", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s2333 +#------------------------------------------------------------ + +part + id = "2333"; + desc = "AT90S2333"; + stk500_devcode = 0x42; + avr910_devcode = 0x34; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 128; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 2048; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + pwroff_after_write = yes; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + + +#------------------------------------------------------------ +# AT90s2343 +#------------------------------------------------------------ + +part + id = "2343"; + desc = "AT90S2343"; + stk500_devcode = 0x43; + avr910_devcode = 0x4c; + chip_erase_delay = 18000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 128; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 2048; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o o x x x x o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o o x x x x o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + + +#------------------------------------------------------------ +# AT90s4433 +#------------------------------------------------------------ + +part + id = "4433"; + desc = "AT90S4433"; + stk500_devcode = 0x51; + avr910_devcode = 0x30; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 256; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 4096; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + pwroff_after_write = yes; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s4434 +#------------------------------------------------------------ + +part + id = "4434"; + desc = "AT90S4434"; + stk500_devcode = 0x52; + avr910_devcode = 0x6c; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 256; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x x", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 4096; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x x a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 i i i i i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + min_write_delay = 9000; + max_write_delay = 20000; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s8515 +#------------------------------------------------------------ + +part + id = "8515"; + desc = "AT90S8515"; + stk500_devcode = 0x60; + avr910_devcode = 0x38; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 8192; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x7f; + readback_p2 = 0x7f; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x x o"; + write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o x x x x x x"; + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# AT90s8535 +#------------------------------------------------------------ + +part + id = "8535"; + desc = "AT90S8535"; + stk500_devcode = 0x61; + avr910_devcode = 0x68; + chip_erase_delay = 20000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0 x x x x x x x a8", + "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + size = 8192; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write_lo = " 0 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + write_hi = " 0 1 0 0 1 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "fuse" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x x o"; + write = "1 0 1 0 1 1 0 0 1 0 1 1 1 1 1 i", + "x x x x x x x x x x x x x x x x"; + ; + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x o o x x x x x x"; + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + ; + +#------------------------------------------------------------ +# ATmega103 +#------------------------------------------------------------ + +part + id = "m103"; + desc = "ATMEGA103"; + stk500_devcode = 0xB1; + avr910_devcode = 0x41; + chip_erase_delay = 112000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 4096; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 22000; + max_write_delay = 56000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + ; + + memory "fuse" + size = 1; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x x o x o 1 o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 1 i 1 i i", + "x x x x x x x x x x x x x x x x"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x o o x"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 i i 1", + "x x x x x x x x x x x x x x x x"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega64 +#------------------------------------------------------------ + +part + id = "m64"; + desc = "ATMEGA64"; + stk500_devcode = 0xA0; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 2048; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 65536; + page_size = 256; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + + +#------------------------------------------------------------ +# ATmega128 +#------------------------------------------------------------ + +part + id = "m128"; + desc = "ATMEGA128"; + stk500_devcode = 0xB2; + avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# AT90CAN128 +#------------------------------------------------------------ + +part + id = "c128"; + desc = "AT90CAN128"; + stk500_devcode = 0xB3; +# avr910_devcode = 0x43; + chip_erase_delay = 9000; + pagel = 0xD7; + bs2 = 0xA0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 8; /* for parallel programming */ + size = 4096; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 131072; + page_size = 256; + num_pages = 512; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + "a15 a14 a13 a12 a11 a10 a9 a8", + " a7 x x x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega16 +#------------------------------------------------------------ + +part + id = "m16"; + desc = "ATMEGA16"; + stk500_devcode = 0x82; + avr910_devcode = 0x74; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "lfuse" + size = 1; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega162 +#------------------------------------------------------------ + +part + id = "m162"; + desc = "ATMEGA162"; + stk500_devcode = 0x83; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + ; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x 1 1 1 i i i i 1"; + ; + + memory "lock" + size = 1; + min_write_delay = 16000; + max_write_delay = 16000; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + + read = "0 0 1 1 0 0 0 0 0 0 x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; +; + + + +#------------------------------------------------------------ +# ATmega163 +#------------------------------------------------------------ + +part + id = "m163"; + desc = "ATMEGA163"; + stk500_devcode = 0x81; + avr910_devcode = 0x64; + chip_erase_delay = 32000; + pagel = 0xd7; + bs2 = 0xa0; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + memory "eeprom" + size = 512; + min_write_delay = 4000; + max_write_delay = 4000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 16000; + max_write_delay = 16000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o x x o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i 1 1 i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x x 1 o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x 1 1 1 1 1 i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x 0 x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega169 +#------------------------------------------------------------ + +part + id = "m169"; + desc = "ATMEGA169"; + stk500_devcode = 0x85; + avr910_devcode = 0x75; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x i i i x"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega32 +#------------------------------------------------------------ + +part + id = "m32"; + desc = "ATMEGA32"; + stk500_devcode = 0x91; + avr910_devcode = 0x72; + chip_erase_delay = 9000; + pagel = 0xd7; + bs2 = 0xa0; + reset = dedicated; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + memory "eeprom" + paged = no; /* leave this "no" */ + page_size = 4; /* for parallel programming */ + size = 1024; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 32768; + page_size = 128; + num_pages = 256; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 a13 a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + ; + +#------------------------------------------------------------ +# ATmega161 +#------------------------------------------------------------ + +part + id = "m161"; + desc = "ATMEGA161"; + stk500_devcode = 0x80; + avr910_devcode = 0x60; + chip_erase_delay = 28000; + pagel = 0xd7; + bs2 = 0xa0; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 0 0 0 0 0", + "x x x x x x x x x x x x x x x x"; + memory "eeprom" + size = 512; + min_write_delay = 3400; + max_write_delay = 3400; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " x x x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 16384; + page_size = 128; + num_pages = 128; + min_write_delay = 14000; + max_write_delay = 14000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x a12 a11 a10 a9 a8", + " a7 a6 x x x x x x", + " x x x x x x x x"; + ; + + memory "fuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 x x x x x x x x", + "x x x x x x x x x o x o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 x x x x x", + "x x x x x x x x 1 i 1 i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega8 +#------------------------------------------------------------ + +part + id = "m8"; + desc = "ATMEGA8"; + stk500_devcode = 0x70; + avr910_devcode = 0x76; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + +#------------------------------------------------------------ +# ATmega8515 +#------------------------------------------------------------ + +part + id = "m8515"; + desc = "ATMEGA8515"; + stk500_devcode = 0x63; + avr910_devcode = 0x3A; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + + + +#------------------------------------------------------------ +# ATmega8535 +#------------------------------------------------------------ + +part + id = "m8535"; + desc = "ATMEGA8535"; + stk500_devcode = 0x64; + pagel = 0xd7; + bs2 = 0xa0; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 x x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 0 x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 2000; + max_write_delay = 2000; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 x x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATtiny26 +#------------------------------------------------------------ + +part + id = "t26"; + desc = "ATTINY26"; + stk500_devcode = 0x21; + avr910_devcode = 0x5e; + pagel = 0xb3; + bs2 = 0xb2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 128; + min_write_delay = 9000; + max_write_delay = 9000; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 x x x x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " x x x x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " x x x x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " x x x x x x a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + + memory "lock" + size = 1; + read = "0 1 0 1 1 0 0 0 x x x x x x x x", + "x x x x x x x x x x x x x x o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 1 1 1 i i", + "x x x x x x x x x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x x x x i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x x x x o o o o o"; + ; + + memory "calibration" + size = 4; + read = "0 0 1 1 1 0 0 0 x x x x x x x x", + "0 0 0 0 0 0 a1 a0 o o o o o o o o"; + ; + +; + + +#------------------------------------------------------------ +# ATmega48 +#------------------------------------------------------------ + +part + id = "m48"; + desc = "ATMEGA48"; + stk500_devcode = 0x59; +# avr910_devcode = 0x; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 256; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x x x", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "flash" + paged = yes; + size = 4096; + page_size = 64; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATmega88 +#------------------------------------------------------------ + +part + id = "m88"; + desc = "ATMEGA88"; + stk500_devcode = 0x73; +# avr910_devcode = 0x; + pagel = 0xd7; + bs2 = 0xc2; + chip_erase_delay = 9000; + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 512; + min_write_delay = 3600; + max_write_delay = 3600; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = " 1 0 1 0 0 0 0 0", + " 0 0 0 x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + write = " 1 1 0 0 0 0 0 0", + " 0 0 0 x x x x a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " i i i i i i i i"; + ; + memory "flash" + paged = yes; + size = 8192; + page_size = 64; + num_pages = 128; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x a4 a3 a2 a1 a0", + " i i i i i i i i"; + + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 a11 a10 a9 a8", + " a7 a6 a5 x x x x x", + " x x x x x x x x"; + ; + + memory "lfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "hfuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "efuse" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x i i i i i i i i"; + ; + + memory "lock" + size = 1; + min_write_delay = 4500; + max_write_delay = 4500; + read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x x x o o o o o o"; + + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "calibration" + size = 1; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 0 o o o o o o o o"; + ; + + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + ; + + +#------------------------------------------------------------ +# ATtiny2313 +#------------------------------------------------------------ + +part + id = "t2313"; + desc = "ATtiny2313"; + stk500_devcode = 0x23; +## avr910_devcode = ?; +## Try the AT90S2313 devcode: + avr910_devcode = 0x20; + pagel = 0xD4; + bs2 = 0xD6; + reset = io; + chip_erase_delay = 9000; + + pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", + "x x x x x x x x x x x x x x x x"; + + chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", + "x x x x x x x x x x x x x x x x"; + + memory "eeprom" + size = 128; + min_write_delay = 4000; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read = "1 0 1 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 o o o o o o o o"; + + write = "1 1 0 0 0 0 0 0 0 0 0 x x x x x", + "x a6 a5 a4 a3 a2 a1 a0 i i i i i i i i"; + ; + memory "flash" + paged = yes; + size = 2048; + page_size = 32; + num_pages = 64; + min_write_delay = 4500; + max_write_delay = 4500; + readback_p1 = 0xff; + readback_p2 = 0xff; + read_lo = " 0 0 1 0 0 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + + read_hi = " 0 0 1 0 1 0 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 a3 a2 a1 a0", + " o o o o o o o o"; + +# The information in the data sheet of April/2004 is wrong, this works: + loadpage_lo = " 0 1 0 0 0 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + +# The information in the data sheet of April/2004 is wrong, this works: + loadpage_hi = " 0 1 0 0 1 0 0 0", + " 0 0 0 x x x x x", + " x x x x a3 a2 a1 a0", + " i i i i i i i i"; + +# The information in the data sheet of April/2004 is wrong, this works: + writepage = " 0 1 0 0 1 1 0 0", + " 0 0 0 0 0 0 a9 a8", + " a7 a6 a5 a4 x x x x", + " x x x x x x x x"; + ; +# ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A. + memory "signature" + size = 3; + read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x", + "x x x x x x a1 a0 o o o o o o o o"; + ; + memory "lock" + size = 1; + write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x", + "x x x x x x x x 1 1 i i i i i i"; + ; + + memory "lfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "hfuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0", + "x x x x x x x x i i i i i i i i"; + + read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; + + memory "efuse" + size = 1; + write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0", + "x x x x x x x x x x x x x x x i"; + + read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0", + "x x x x x x x x o o o o o o o o"; + ; +# The Tiny2313 has calibration data for both 4 MHz and 8 MHz. +# The information in the data sheet of April/2004 is wrong, this works: + + memory "calibration" + size = 2; + read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x", + "0 0 0 0 0 0 0 a0 o o o o o o o o"; + ; + ; diff --git a/bin/win-avrdude/avrdude.exe b/bin/win-avrdude/avrdude.exe new file mode 100755 index 0000000000000000000000000000000000000000..a56404844989f5e8106dead7dfd5f575d739d504 GIT binary patch literal 169212 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

m9IXj8ic?9YobP|hO^;uXBt2rH@cxCS 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 literal 0 HcmV?d00001 diff --git a/bin/win-driver/libusb0.sys b/bin/win-driver/libusb0.sys new file mode 100755 index 0000000000000000000000000000000000000000..3d369667a13573450e265d7aa75590487db61b23 GIT binary patch literal 33792 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 literal 0 HcmV?d00001 diff --git a/bin/win-driver/usbasp.inf b/bin/win-driver/usbasp.inf new file mode 100644 index 000000000..82ca9e1c7 --- /dev/null +++ b/bin/win-driver/usbasp.inf @@ -0,0 +1,90 @@ +[Version] +Signature = "$Chicago$" +provider = %manufacturer% +DriverVer = 03/09/2005,0.1.10.1 +CatalogFile = usbasp.cat + +Class = LibUsbDevices +ClassGUID = {EB781AAF-9C70-4523-A5DF-642A87ECA567} + +[ClassInstall] +AddReg=ClassInstall.AddReg + +[ClassInstall32] +AddReg=ClassInstall.AddReg + +[ClassInstall.AddReg] +HKR,,,,"LibUSB-Win32 Devices" +HKR,,Icon,,"-20" + +[Manufacturer] +%manufacturer%=Devices + +;-------------------------------------------------------------------------- +; Files +;-------------------------------------------------------------------------- + +[SourceDisksNames] +1 = "Libusb-Win32 Driver Installation Disk",, + +[SourceDisksFiles] +libusb0.sys = 1,, +libusb0.dll = 1,, + +[DestinationDirs] +LIBUSB.Files.Sys = 10,System32\Drivers +LIBUSB.Files.Dll = 10,System32 + +[LIBUSB.Files.Sys] +libusb0.sys + +[LIBUSB.Files.Dll] +libusb0.dll + +;-------------------------------------------------------------------------- +; Device driver +;-------------------------------------------------------------------------- + +[LIBUSB_DEV] +CopyFiles = LIBUSB.Files.Sys, LIBUSB.Files.Dll +AddReg = LIBUSB_DEV.AddReg + +[LIBUSB_DEV.NT] +CopyFiles = LIBUSB.Files.Sys, LIBUSB.Files.Dll + +[LIBUSB_DEV.HW] +DelReg = LIBUSB_DEV.DelReg.HW + +[LIBUSB_DEV.NT.HW] +DelReg = LIBUSB_DEV.DelReg.HW + +[LIBUSB_DEV.NT.Services] +AddService = libusb0, 0x00000002, LIBUSB.AddService + +[LIBUSB_DEV.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,libusb0.sys + +[LIBUSB_DEV.DelReg.HW] +HKR,,"LowerFilters" + +;-------------------------------------------------------------------------- +; Services +;-------------------------------------------------------------------------- + +[LIBUSB.AddService] +DisplayName = "LibUsb-Win32 - Kernel Driver 03/09/2005, 0.1.10.1" +ServiceType = 1 +StartType = 3 +ErrorControl = 0 +ServiceBinary = %12%\libusb0.sys + +;-------------------------------------------------------------------------- +; Devices +;-------------------------------------------------------------------------- + +[Devices] +"USBasp"=LIBUSB_DEV, USB\VID_03eb&PID_c7b4 + +[Strings] +manufacturer = "www.fischl.de" diff --git a/circuit/usbasp_5V_circuit.pdf b/circuit/usbasp_5V_circuit.pdf new file mode 100644 index 0000000000000000000000000000000000000000..76a220e7d1874e032d89f2d2d534614ecb89ffd0 GIT binary patch literal 27608 zcmZs?by!qy)HN(!!q7;KbeA~5PZ)A&1cokYP#TdOx=Y$2q=zmk38h78fuTg{F3F*! z8 zd$(6!4lEMDC%VGQjxJvIZ&-wtU97$A742=^?d)Y_h&{dD*ju|2`{gDEsWl2dt6hK^ zrSgA@x1t)Qg}nPqIjJxDeuiF^;r8I|&T8y`mqWwD7-kD!Y+SWayZWo;5O>*|WyU-0 z`#y!MKkD}X zeJZSdb!mBjGW+-A(YzR4ovYFPv!nA_TTY7v*~5Z>OX}X%186X9@MgokOQKE&hG6=y zXF_`8-$v%}>tD4#q-mY*H{(j#dHg3_9ibmC;5kZvm9zE%V+QW8p3Gcd5?$cZ+EMq0a%6pOlA=JG5bNUgK3C;8`8$~^q0xk5y5e*NPVoog8Jd9#|qNX85)Gep`vQA>hx6}iB-d`aC+-5G8e&MDTTc0SrWn8-3`m}MX{VlBHVkIeDujQX`sW7Tl zPW0Q1bm>fAmHc7nWl$;mG}(2>#Jr~39_*GZo~ceueT=Jg0nNQa98;H?HeGqDPAgi- zlfHEyde=E_8)%pV7(`HFMX@9qAB*(9hZ`9dUS(x zmJ%`PM+QTJC<4>Cq5=X^HYWuv(x3q2FS?>mj(*+Y97?uBc61$1TFNSey%p1k1?EN2 zdUEOv1%_A>7%M3?i0T1}COM0hbrzw=>ECBnc>-RMTZ1tDM_34+C;M?wrAk^Iu|cZo zC&5BBavSm+q+zNNs*l=mNJOmhSiggQ2hMwue!Rzlb6fRlGfKfM;$kuz*W1bnW`P zNU|P_f=3rKe`mvcU~#>-P``@1C*E&#{P4UpUBk?c$ySR#FG8) z&Jly3v@IcXH#LVAFA?U`8M0BhC+i(j@9$2nthFxHM^<5uL&-VIJ z4%JE$$THp#xk@^X_-;glOh_&BLRLv2{hR!o>!VPaF6gB}z>C6^n0zbJi59Y;4jrlM zAL)h~$mi1bZV-l;+Ko*QIFg&evwK>CjWl3tXD@+-^rNYD@c}w7^8aq&wH~m6H+ugz zP`$mMih~#Z&Fr3D(3hvj;iDyvop~1)ZFsM)DvpOWPf6ICHMSLs2pd=6kvu1rgYZb{ zRG9qmkiSMoc|=qKwgp(GWQ~>7-~SP@ajXed=2QOs(UK;IO}XoE`FDly6^hI8EN=Te zMhhlBcB7F4pUUsOuK7(KLce(IKj}gT7r+N2epY`Uk09vUHr|rOq&&ct+^G+vMaOsC zyaE$S+T_|x3dsKSp&o>0`EyZYi1+@|*9Si28M(*nxBpyw$Jn^iRwkxkQCQ_E-3 z9LnD}cGX{_ZS3I&Z}Yvmup3r@8xuRS2tAB~yw3gi^y?4F>(Si!s?ykY_G5ym&`fjq zB$MN>WlqKiBv0P@aEB1k!c8GoEb^55{*tQ}vSJmTkm(Vh^!Tj-EQL3n-j z)Qn8&!DNbPcJ#2q*P7_&U%faV6eq?b@KHRd&}bA-jTJ9_sr)8U8g(q`nY7Io9QP3^ zUA6P(vxYQss%UIlLXxMfB-3O#4@gLXME`<@h~b>h(3b{_goQ?vNxL}mqORUL=gu-b z1pg9qQuj`rqvsZ6*+<+;ZqqF4Nogpsg4(vBLiZKydB%E9nQ7zmp7z1L+cAi`)mOU& z*%y^fFFHL#j3@&txp zV6QO_azrc!h-bWL;IZ3chEnnGpv9pC_@oF`oQSq9x$7-q!>11QnyPwT-{ZG^b_d)q zNpHXf{NDD@P$>jBgh1ix2+x+?@o$vV>+Qy3{SaFAp^RO#Gs{VxL=I1E%BjtXfoB7C z$V!30JBQ0?cu5&a*=;t6%A{XBnm#s+d@_J4NWT<&Xy;pxJ>y34V*wMJJk$fD{>+sX z&9AL9>~h;W9#PISV?)}9Pe^SFp5b`T_2rmHZG_{Y2uh-neDkj4SikgL3t4Aq(bLbw zHmmO963j&}L!-a2H#Q>mWjv?dxb0YZ-e5CaD~=CQzR}uB1s5Vy{YxrnSiAe?&--KzWq&;|7x%oY0>^-;K z1Iq6D{?rRBO2=5!E%coTfT`OjQ{3 zZsip!XG1%FJa1ZLnE=X{)YvDXIhx!T*s4gkXBn)AWGre}@WCnEAyX;O5xzh$v78o) zYLeQ^PFj|iv)IdWnS?KW{9+Mr*k>9`{cG5=_CRP2Ndqy-z+2rgh%Psa-Y#<{_S^J7vYRvf)r0L0fSPXNla;i6M zM}5Y^T~6Izr%3@Qj|mZmp!5=ZPEr#DDhps^oB>dsJ; zf62HVXf2}>c@=m#U3c}a6`x)Cg+{l;okEhp_nrI}crpaN8*Sjf*)#od&;y9A%ZJdrq3a6Hhe!YOGmrUTsvbvH=tB^suBOqfdiImL6ml?Q~`_;#5q>&LZO6o zZ1^48a7dekGOiHWOU(Je~*-^7?C~T3nr0;^wHQ&tLb8+%(LnXRS5L;sBMeM~UXGEpnIo zG`6g>B{lo!4ZrOejiyU?=@sp&wKj+vgT{%%WTbI)ovqUNo(QFiC;4Zp8l&Z{zwF2d z{j7abX#M!`FM`H6YwD3KvsNt;sTZY~EQt1EMGlKJ$NgsyP`z@_{*kZJi=0EhKl-#j zW8xLOfqWz-QGzr$E&6!axHW7Cw;7{vWxnVTE}u}OU$7Bq_OqCX;Ilg^>oh!jCHM?2 zla6a!gG_xEB{13%_d5}St8@|;jVZE8jZWg7Bg9x$yw~X&iTJ@m?zo}{^R~k3cYVN= zLeu}9Nng?lPu2ME1J;ALP35U+H)Xqf!vP%WTA@Dt}>_ zZKwhc0<2F=YGA3UtxT+{$M5i-iqIjJxSbu;^tW;Kx(3j>F&^j5DDl;P4VVokVlJ^+8Fqzu?ErHs{;KX85j&dv8Z zqrrQkml?jw>ol2Wfsu=fp06vQWmW|rSp*g%yvckhOB z^V4TVU)It-SlgC=S0nj&@3|PPAmXtYY~(ST7P{#>y*EK+bC8pH{-inJ*X$>rqF?2@&v*jTl_ z*=+u1KyDR5lfUJi>3@b!b=79)bD#oazp-$33ZetH*IUPOWR4w#lQmy`OuRSE-Uobf zr!4J~1oa&L0gb=3;0YzEEzxq(>dhaTO7iKx(fV<>v-PAT;-HMTSI1! zaj^)WBZ;D*$D=3q`ploW0zJx4q6YLPFL^y>trb*Ch55FI*WRkHhDjy5n@7bUu6#fC z!a8rMUI3qr@~p@YXlDSauA6xhuKu|FyILQ2LoZG%&GI*55NDeKGoGP=VDAOc=p9JS zm|3{{V}V{+RSnR^^+gZmy{uNYFr4S~eO;bvv>I0YoW~m!svDE3(}NR(JW~LF>Zw;; zWvwdkf2_HRQao~uim^X4+_8TyIN+@baBM~Q>Zq7Gl^i(>dBlyvQo(T6{47;7Cd;zB zvMuM*T;*`fvXu__Yccq6Yf47Occm+NTrXJZbB=cV-9lx%qVMj&mc;6J`@1_i>SGZ* z!qd|g8vR-3?5LQq%_c$jC?ohHHVLLa!CH93nx2Z-uObNGK=RT}qe8vu%)Uf-CV3_JX*$21j{8#Lt`cc_YQbP7==~T zKHA&aoSQcGks~Y#t9{P1dJ4sK1P1}bqq5!k-=17D#b|t& z-nM1m@>>s$F29Wzz0B2){K=rK+LTT>sG&UNkzI=J;qG&!Enyu5eWYd>{P>YGDk?jM zMwDa=j~++B_#=^rDvt1bY64TNU#p=CFobi3hnJ!&?^y*Uzv==VAvM^P6%|Tw@i0u4 z-(Y{Isqw6WJ&1m_n=EbjM*u}0MQ^4&S|d+7BAC6u+HPi+Yr&MjLM4vEF3 z$A!GM8Y0X{)7iVSfbZJHUCm7lvfCxc@tialGyDH+J%$(MOzZqAsZ#vO?5I@89PB@| zr^#O!CZ+BDhppaNq%X>4YEZ+u&5kUUwNW8^jGrrSORL#7N!Dz7ArRF&1e;{dJ~zULq#Bjpin;HJ4+!e-+OAmiWw>z??1F$cl#X!L$e=G!L$ea9V%o0 z(aIVbc;*M+F5p;6ipsQpVZ_BT@Qar`cW7bO6$XS6%3#&bW8&c?1RYrYjD0=o5-%zv zb-13x==Tgct$9%_t=bz3L0u(^)EJ)b)I#7%EZyLKj|e)eQlqU!(PbVVv09HGF5K^slPOfcSBD8Dx=6>gw6~L#v z6fvJDhuE%e?rdmt*S197dR}RXydCnm$%qnZyB=`cZ^&Y*=#9v#{HHMJWG_^?#PfE9 zH!{Wn6{GgaiX41F?d$=~h#U{-gT+B%D%UT49R8n3; z`!NRza$wwwPw1*+5#jF1s$;mYgyO0-#n%^uu+9Z?1__-j#t)lB&$zvhwc$GIN=CAf3^&oA$u@lE@m1_o1A2XxKm7|n8WZ<`Bb8GUY7gpfo!^i_@0{j2o#0A4#R)gee<_nKJJ1qpQ^Mz`h zmPE`9Vy1^Iwr1W~NPZs!_;Z-ADBmQSGe#%OQ0~LNJ$??~ljreG!YoZBb9_ku1_jK4 zN-^i57qg?R)~?#Fr0!+6&tpdv>!7f`Qg&#<&Sg7oc9A|oH-F19L~C%*Tp3GSr;$7h z==h4&c#@%tpJjQV>HnR&jso1d`EuUIQqbL0@s0%qliRT8txN!8_gW0XklO}+k9eWN z+Czxl+ZDX@)5$COY51yj{V@X{RMA935JJ79ti-Sf_K^d+CsgPqXVJIBRa%{;0%;Kt zy*74M>uBbknO*Dv#rNbb0#X4{+^XXq&jBjpD1rvId^iuV`2mY0AkJ(1dmxt#TyQ8j z&-|MsuW#*$&eKA5%L@Ru)?X#%=;uE3L;qC9&TlXBqH_C?{9<#LayK|3e94+fOthAEcrFQh59(z#@FH7?S>r?>ehobo{Z26&i zQ}S^#p!^%%O8S7=n&r8i$@Z5U8YUzmKWmN`29_OWGCKy3JnuN;di0R{4+#OBtElJ0 zz-=1&j^%Fbgg1Eis#;XQreZ)me%PC%%a>Zb`EJPU9NU_#3rlPrfPsY_kXrvV(wPlYZxQ z3<(73o7p*~4x5?(>lym#roo=gTC~#YuyGt30Xd@ke&;hh6j*VzeTqE$UUy?~#F?ZH zdY+S^6MUH4#v55lT}ij6Wbzv-Q7XjF`MhafH<0!#%>JICYipH;QB|n-i!-MVknYA3d(4B=ypjmQBY`g+_!%KZ()$ zEI&w5Z8eBGs_SB*ha^N=k7d?CC8ME*)}cNKRT%syl_QVvJ`n^i{hru?{3{iqql0#4 z45X>NItdax$~w-ji|rUY%2H@e2q`5dwRPjcYr>v8kYk*L=byh<_}UQDN+)co-w0v_ zngE`01_KmoZz47MdLEdlhP)33%~-pOHoCr}WOy;hS*2mM{vX zopUFmMB5=sNe}#Lr$RNJ4S5HRIgQ(?Na2YcOk#4rsBehQfcYm0Dix)tCl0UA=UW9I zfUqaUYAA_8rwoP%Q8E5;wLlKQbb;391&;xS?8&ZryVPimg>zL`1jqpFe^I}uVX<}a zQE^4ShvbkH4kIFhM+`6lKpJbRa<=pnF^M;HsAa_HmS^eod?nlx+u*g1lTi8G zu|qnK65GrvhWfPIPUXgy6c)cA3yesno<)?q4(uKOgS?bTV8(^U%lEPS00=TG%CAak z!ld#SDSt?n{lv>F`F-Yu=NV_M;~6^;>pIrP&Qcs2LuQm!Ku}jW)(8V}WYfCwm(ZYh zrO2O>YCJkmfCyLvkK_#s0|LD&fOh9)a2D%tGH*aW>*`}(W^?3~Fh`odVp{s0OV=qB z_}BaQNn-EUPoAK>DO&KB_dLZ_FHWcaEU^9_+`un^(_|>~S6HWH;Fl@YD&Nk_;$rfp zYOd2V15P<8{2uANuvum0tBHpqvucQ;XqjIm2y$P_|GhE{zIHeW;~94K#>jzWKu&x( z{`Dd%=81q4BO)@*z~mz2e3PmW)iV=xo=#C{zxYuzwTwqdTbUK)%7C33BksMJ%2jw%IP&|Q z66k$y*ax95jVI2WydesCjIsmS-&Zs{B@XiQZ6d^-i*MWrDwrCVcRA^mT(7sH{vrcC zpMuX4BDxR>lTX-ZD~@}zQZr|s6z&A?fz^MFKh(Kl_!j&!mciH3Hp}^z-u_)}@5p)1 z^k2LZKCCFL+r$0Wk@w$Ix?cKUQrR@C8|C`)AYo}-`EP&U@V)&zy5+#|Y<{2mJ+V`{ z?RvFMxsWprxM;^en+t&cZ=+fiwE2b4-;(yZdZ6n+V9h4brqN$t>IFoQs6PzL?dWE4 zPT)|C>P#(P!w=d;z&1^v&=eUi?Yo*Peqhl)Z@c1G_L9&(iApy}xEm(xVI9KyPkq*7 z|JB}{m!)7;V(*gzIH3c!Q^bH8SAt>vAR}5yR~&*o%_mcPc-7972pJ=w$6HfTN#)?7 zIwYpEkiSx=!_>cUE9(7P1Z33z>K%JP8g>T_3;=2-?Gq&57bW`o!|-zaEK^tGYk$kW z+k#v$3a1DP&tEQhKZOw>+x>8l+M*(Pd|yPxtaY^0fcXv#jQotRBeC;0#GXxNVd3W$ zL{ENrJxey&r^{qxg8S{wP&gR^JcJ9ZH%hwrRjs~CsVOt$V9ql^0II~?VVJU?2>s3v zyiD^G$3g|H3RAc>C@!BFG2d=mF6|oMsB20v^`9 zEy1r>$^|5C_kXvAgQp_!Ns@lX@VFzRe$Q%rmBiL-#|1JX;B#L95QdjPOa4mIV;D|Zwr-iX5Ma5g747fuG59`M+D?=*T0||c__uf=CQgl#~IQ&w5 zDRR-BzV|kJbEW$OkxD#7Zd{(RV&s@>-}JxUrfH^nriI8(DzlSLP`TkNAvTfskz-?K zq2(J~<#~fg7aF|f37BTaBpQTYQXR8F2=}WM!h^m1i2IlHL-YyGN_oe4{UvsDFaja#5MfMO|LIa0XY01 z16emu?LjIejU>QQkmfcBS%8ly!-P7*B*?pWlxY!twI}KBf&yaig+bQTXpcE1C7T1H==q8cugwb>)_|2 zZ@vrf-qrE0u4wNZ&Ps;Bh{n0QKYEHqe%2cK67nu~->jW<6oT_vSW0p5X#WMXwffw# zaHc|T^)rt4b}6P;FC@W-tiT8yE73BPIf?7AC5gp_51J3*bi9rbY`?4Vu3ypYvl z5Pzq)cgs~phPXO3djEYLM5!`=iI5mHk_qp@nSrrPlIt6cuPuC=AuN10{dHSDLgrAL zsstG!BNuSL$Di%`>P+q~Px3Q+6DWY}Z;pM5#nO1rn5QxshD>cRWw|nwK%uz_hz-f; zw1)8R+cnR`v$D6ovohXN#+zS$#vFz?`5tZ!!;l@ir-)-X+v0d+h2J7qQ@w;aA80{a z;hzEK5WxP|erkX;iR|jqLGXCY)IctJVFw_@vyw?PIo7ZM#4#4fu#$O}$#JEsSVb|u z>6PcZA4{XD%E=-|zX`qjfG}$Tukz02OB1*r34INSbY3N#nS9gpCbpGUf`YmCg@W7O z*@sthUr&+CI+BrtqoG|A=j;;DYbP%ydFq+qqzp!jRo3BltADEBSQIc=WfKU4%1@Lb zaIrMyVPIdPFgd-Hxo1GPRMboM&nlz`ScPGek-*tkibT`!o`fp`HOPQPJElv)yjr%^2eZGVW=Q^7z>-e=1^I;}|3tKk% z={2R?DYdQ6@%=Vertfk0+7RvSi$9)Ryj{-2r9SqO4tWjL-`f5XVQ}xm+@hP@5xyr| z(Se4qIK910tT+V!AyODAY*whIlWGzpEJbMkY;rY!Y@SFdIs9R>f}c_oKA8GdNK1^2N0e<%+DH)^ z#}d86Ch_(Ue{=Iu>GeH6HE)Z4*~rdy)BxSw9b<}cA7gLEo*==!>vAZYQrC(f8F0n^ zj|9tXFGX4DR_G?ra%f=s&u*+=#ylZ^3l~iV?E-a&AH&;%!It)tdD9k-?^+(5{-{wk zVGthp6s-Mb^_^@+!CAXbK;!bgfO5BkB4w=D_<|?dg_)hmS6zHfXEp+24U_-BewzXH zJH_0n*2~A?;@1WSr4=)qSDO7hu#1p~3=N@(a zGHI1=OCM7b5ht#pVaBztWe?9@Wld5}lPOC`y$`J~sazq{Gxh9Ih~?B~AbqJJbTDV& zqNsfm7Wbq3LW`G?w3^y$JNr&QJ5(qsU-=g55Un95x-#z;)N zmy$P|UM~2z=mf3|q)1bIE*_hvoM9m_GpL%;)Ih!izi#8&SqhpxU@*o6gq!gDH*^p~ zB_&Sm^ycU_iAIZFlzZ0R;IWkO?iHy&1)}CO`iuI*MQ&XLUMb^Seh_CgYsw{QRGGYI zlm!U(&2NFfO1sn81(EkooXmvSaGL>~DBb!qL3E3%lsD90{dvWmOhp6QOcwHTqF|KF zSmpM`y6RH<(_QbBemDb}mPX2Vp2x$rBM*D1f}_0J674bBzG68$Pcvg|s7A(%Z|K%* z3aXyg@jm$__Jf*cyto_TqW6Q){BJ{_l-*_D_Dd{0sL}_KwQoSYvFNN7`tDMvJ3h#6 zQVFzMOwZUH4H#zdEe*m#nNJg^Wgz`cS!a7Y?;#Fcw#6gP0!pGZ@G1c-B4q?9h3ml% zuMnzt^ypHiv|IeMmQ}am&vt^Q_1{}JhTNT@Uq8%JiAK9WF#q5^n1~a_$pUM$^HvCSK8~8S@XRb}*4ZQY@g%Tf@$B^Iji9MX;%S(;ui`Y+E*1m=}utv}N+>~*h#j-bPHaohQ!ykXj&8&ZJ zfY43dZs_=_{Py)W!#G;A>vFI1emkTF6=)jtG0H~r@`?SBoSy0SR}q11t&2tTmY2+8 zQ(W&`0+#IpP~E!gyeGktbx)@ru17Lc%_^5W+jid0;U|83!FreXV}u!1y_z5K*O1<^ zGj~hcGx_{YHvOhK{k7DGOoHCC9{?642j%+1coM-EFVrJDWgJPS9X!l9AdU3aWN@Zh`Nr|jv7PleWKn9^fdXkI90TF zjd{R8y8_15m>xrEAF6-*qm4+7ZbPZNO-@{e=;`- z@b^NY{Ab@?-At{U3ZbS-=F^sRPP)SPP`~gZXF^}}Z^1gf46=8M8vg?Eos;w>}~Ynpe=P?j+w`kUsZJun!m|^83r}y z1i!MS$yY^IKh!ubJ^kX?oK3(>yN%i&1&Eu4|2iCnI(%8BpqE0;Ei#Dh*#==jiNTJZPrhF$iOo8I z{1JNHGzHzQwrHWk;ELe~+~_}XM@)?Mhf#)=^L(yhYsFn*hd zV`#ogjSU#E?ig8S#zGZ$+k?}iu@B6<6<~{BO;z=f8QcKv&54%VKxvx$mJm67_IReZ z)8Ezxt3c!kHnPIn9_ID#id~eqvKk?i2!n9>0@NoW@?Q_YvwbePJbr zlW#c4(dZ0TGK7Q1ETiK?3^+i1#A!Qi;O&>7c0X;^lH1>Pd2?U-RMdRtP%I?UQbK1X zSUqnz{9g=r2^gyf+bmAr*1s-sX$_juh=}@eK16c`Or{|Esju)e6tK&GHFTtkAl?Sr z6UB0|a%}%_KM8ne?t>?`NgROqxqrGsPOD*L#@2K6?DEe_QGX%6~|D`DU41UJGitbI!=nM>q|kS10W9Aw5;XgHI} z&sRqyZ{{Q{>Q9SrZh}wThE%bZpdt1L^N)m z@Ats{R}H!8cX`Ch3QgoicbLDvWIUbRo@*FN8og^#BMN%4Z5HeHIO@P_OOZC?{C#@5 z=ugQ+x76wQGUuloBCds@s}X+G^ww0~ zw>4Tzo4*89bSAyIaw8*tW!f?|OD#jK&~D>xHB?}9WtuOPn*V8oItx{^G6c-xKkib9YbW1vUTBz)my5@b=&6EbrvFU7LnL|CsV=QcNSO zIiwB*H`0j!16(tgH=VmcL6=ggaBGl#nC-lMvj5m#TDy#%A>?}z6+zRgj>b>-XZ{ob z4^h2bCppn`oZ~hi_-A#Z(Vu!|vx@2w-^>cy43bA#_ZXsP-qQS(Dw5}9&8#~S;zIAz zp-bJ!O&IL8z-%!SAxcrYgH+Ul&PSn*$OOq|U6?P-J}x@GW9*e}y-Ze<(Reha*yt%A zAT+4q<`?;ZDL4*hRm0g{Ps$_{9-7H$&bPkQRx?{#+}hWT-vD~j!%TqIzUj%F@W_2a?s>i zQrBIZN_WI>e4KNgRjPVvQk&54JzqQ0mw{249*gLAy&TUH&IY%;B-KZXO$Qu))N7`_ zMjAcP^w!X!!GD}y_G>GQucqGyh4KZP;1K(TGe|8a7X1$eGFY2@rx0Z*cYUi-8U}4s zzg0|;y~kiHv=a_aDpb<(qkXC4dFOO7;%}!e+;ANhrk5<`9b@}Ge$2~`I%N2@`)%+G z@2FH@vHJu5@ej`0LXbQR&k2L%e8{-^`w?m`2R6vcVB?X0z4<$Na{{LuN>b+oO(Y<_cQIH4Avz z*QM$ZO=YqBs_Z=;dw8Ha$Qy^VUrlj!r9gFJZYHy)Z zv;Y~x65hvQQfXHfgVpQS8kmuQ1T&I1f3sabILro3tFm}`TC9FzHtK3){qP2zw3H!A zbnu9r!=A+6V-S$7@p;pomHm+g{n}0Y-HDZ0Y0ByQvz&b@6}iefr+<>t8n%6gZF|zo zJWW0$Wy3^C_$9t!k;tQ-O{xdx&G!9vd_oOa+ib&Z*CpB~jje_am18jk(#kE{Jazx} z{KxM)7?#n@0ComO@)5jq(n`)dMnv`Z&x7yQOJ1rv$3IQ!pHOEPk&)hsKjQf}n+N-n z)D^lw-~e{82mPCRO;xZ$M$i49L?${||5u;68XAFlZFMinRLGo5_n#~S!4b1`W9IZSC`9iaG@S)Vk-YecaF@ZGO@<_vnBqF`}*CGc`%g25>X!f;8voz(vqO8nAjo zN_a<2P@~hTeKl9iF7K}^^}iGb5Pq*3vc{h9rkVhsbye7+^lP972*s&~DddkaZiD(s zOFARs&Eu7%vAeTYjU8w6%o59b>Q^2GMuj+m2$*x7eu9}c4^YRr_RrlxQRNk8fL;i^ z^M)+x=IHe3O>4%aeN@~Cf}va+Eq+(gz#WpBpkEHoyf(bM3)uYxRJ`Vz1b+X_kh@IHX-EEvG071AAu}AG z3*~HVG?Tk#D4e4)ZoC`Sef|9@!-rY{?>{Xxoqt2?uqLcmaYokvOmi{^r>z6O(8XwuOri2MOeU;5nXyMi7f`(|(EGzU6< zw{*q_vqR|uf`|T4DQoqPYbifO$=q&EUs7}Mhn?lrlj`SG@NLf&;HcB+UXi(&4s@K? zQRa_;@0jCR%qJS9mN1q=qIe5e`p%kiq!YtmqSRSQjg{PmnJ00T zIvwnU7eO)$X`Nm&;?@?O^NBf!GwsWth*Vmqk1ot>aS4TIBp6>sE|UW8Mqy&Wr-b5m zi?Q@20!;0+tSK>+Ifu*@&;+%cLxS<9gn;|^rLkBF48#iuRl2|wxqV-OrzZUKEnCU= zYrT^T{@gt(F*4%Q42&SUX{-DRBnsa#I9dUxpNf1M=aseE2ST#t3 zBLC}51$-WvlmHtfgaBjlvt4T<&%J|4Di+2$62wl!{4O^`Xbh@Mo6)L6_3U=wCCJGR%Q||-cE0pP+>;A4;iN%)#CPfGE6OzIR;~$C%UB}|X9@7YQ z$~0GY!cy1kdM@?nP>B#eZKTmO$Wj>g)_uTDW){$V!z`FN4>U@;CogPt(#2VIty^EV zdoIMGpOnKuIanYaZugQaATUI?vYjkeywb~gCW`W||LAUpk$mS_36s*KOeLs&<_K6N zlxEnpbt0HYNcPm}Mzh&zH9|giI#P&5LcPjUGs`wav-veH6u@nA5*^1|0_wRsZFG=-eA1Fb0! zm&s`G|4fALy8#S6Ar1~)IQ?|1PN0c0dSO#G0@%U?i(62~AQOSD9mG(V_JG*$P|Cp_o)!zOcLELs#HRh*_2y3FY$3(^ub(j9cmk-5vbO|h z3fddi7MjbrwNU1I$G`1euU;VF$zgm@SE`&pW#;Y#!Vri5tc6OfwcM^0a6S~#l4xu2 zP*q1Nfaf5HlnfEViET)Gccw+RLemNoOF|>Bm@hW{K83y{Gm$fek0l4O3xmNap zb^rJ0lMHoAiyGSR$sSs_(bUU`y(I=PuQGrypU!%%5;-Y#9*l7bLQ@`j?^MtoP!S_| zCY-Lts>@B~rYL>lep^h{VbI|Tk|hMMa!f5OW;lJDaR6~{DO2ZbcH&O4qhxtXq+}`j zS8sjho1hkvHGAu>stCCYNFDcW{KRLXU#7CK-pI8glySM)kLYM&P5ND||Cq^CtX-rR zNY*|5L`Nc74;;1{S|bKb=&?D@3vQnaP04^LA0l>9IcCMGDa0l1A$XL-jo~y5Rhqse z7A%5vmL!ZUC9LtapF4U~i8g=9>ZD<7JhaxdR2t`D=2o$YiaBUm_9~@MRsoqjdW#fy zg@OfJm%X+bw!0hf=x)nw3$x{RHXrQzY^0ZhWzQomSt03%>sf|KI?io`>RrI_gx2!w zbfkV>nYrY))A%R2TiiwrRokI0F{j`557)xC(t-F`ns5SHlq0~u%XtiJ63evYS?dbV zg2RS!;=K6YOWSM$pyY^a?}(cHO8!}#OmZsKETI{urZe!;2BpHcRg1rI}qNmzD%&}{i;}N*u5<5?n zZ`jn(Tnv!)V`qf^=!j&pt;)^Jt+-q;VQADpd3&*E=OG7!^D(34EE=gXa_4s58vK3u-{Vq3wVg}ONxG+Ac~N6-8g0P zX&VTQGVX1dhuOG**MI) z?0%=N^KmE`r1X$*%~u;eeNS8x ziV!7vPVY)(;-KN46IC|xv9h4m)UhLzy1G;w(aTkZ=fFU7by566*xlsdwoxyG0D?!F zKg)pto)QUiWD$N(j3^BF6xj>xBR6oej1~X~!0H7c)t!Mffp(FZ*GfnoQfNCRZClkM z44=a57qxi?o zEQJLewCr6JRWDo9@LrKsqYcEQuF+8uEb)qk6r}to9oS>@*VLFU8W6%VvGCmGAj>kZJfmfov?#UlMc9E%iC%x;!LK(=FqvwX zTei)$yc4w7i5W#TW1PTp=n)<`zVrY#`QhTrr{lyQ=ysY~egKFgH^;h^l{ z)%8EzeU1+|5v1LseDEbb641G+w0w(2fcoBfEuO@Du7OiY?QNxY6-{<1L-!sLOQB=+ zE=E0Oh#%r&y40Q$&2nS`92zKMr33GP&C8E_9s*YSdItbOYrX=0+SoTR>LrOdkf&0U zv{WbE#J$^D3CB?~2Kn}|qI39D%-p!~`a9)1p5q%3H}j$8lSy5|kjdU-2F@nu*{7bs zF}SKz-=6e(X<6o|Dh-0J`$fGSp8-RO>lmAA3!gn%R7XiHrI%cQr6X)$rtI6Z+bvT6 zl6qIc2;fvkQ_!pb0Iv9CIQ^02Tm@9|+{_Ihn1ra(6|k!N0UaMC0Rx%+?HIdmVf*>5 zTqDsgARRwYQ@UHl&xw%zl9~%MVojzo-_m?p-2SJOndzNdP0^gJS7|fm(dP5(w!ol~ zk@vRmj1KugoId8T4^ZWk2*Fp%K)rLA?fFhg0-Ty};eBCp(+fi)cL2t!*y^;3x^SBT ze6LNZH0P#N+r@iI?i_^{z*&Nwt$Q3eV9(jI@kt<_!Z`M>+adAVg09%?A~ z`l%z#XU>q}rMLTJ6x-%8-V)pZTrtF>b`}1{llkj~)Kt#%g-SB|)+t6?J!SeB(jjSI zi#bV8K;>$;_@?JL3631R@5E}lk%m_3S*76WAl;fQDK0?nf38Gg@-w&FeQj2za(vA+ z+GjVc3PjS(@S1PJgAjS&|1-*UmskuO`K*Pp+Fs6EVxO3r<6eAF|2Y2waa_`pWY3-! zw0rPiV|(tJzsSLJrHa`!|NoTrOZFn$P}zwjWvq$DzCHbpp6B~{zMt>UA9&q+?wxb*J@?Ex@9m`2J&~sy zJW}?O%^1P;El-A4lJuXxX+K3moAoEta68Zi>~BJEs1>5HS(SIb-g$9RawR*~I_Nqb z6i9?%8S;h_%{PY%@6H-F6^)1KS98a|o?;x!r=NE)8!H7T7M_(H{orNl<@surZ;tZ) zXOVa-XD1gFBB^Si`n9xmk?{MD<)CS2JK)>Fe;uSP45wPswCz724pGrl|Piz2#}M^E6%T z^}-*Oh9xDGSj0f&LH_Q^hFEPtq&loB0kRDsaf6DC1zmN&gkx)LI~AflD*n0g=kGrw}P4py{}d8k%t=X$nCj);#P@< z*mGxD&dAI~+)7jKys&7qIGeb>s=eLpm6o_{-AO-%V590$)6{n_i@nxGd@yQe7OlC8 zjb2PAj6x0{KQ^(*Hp|~qYfNXKK9MZaxF&B*#W}$FZff*tv$l?0Br6d7nY#@Vb)w3S z$P5iYVp7&Yq*gn|mJ6lW(RM18!FdA2RYcHLnpXQ5MYqpQCmxfyp0;ct-HhQG*-a-t z+ajBP?#4B;wmc|bA1Nj}b&NMr8wC+;bMf6SK1Vksn1MEEYUX!3 zOIEB|ou2&@rJ8oYE;-8U3bNa37er_`Jf5};)ko8)?s$yd zHSy`xf?a5Ek~LntezlRsyV_nTg5~aTL1O9&sdw$!+C1^uok1-=CF+RbTL;ot4^6M~ zccHHOc&7oG!aM7=E>W~OOYdt>p}7EewJdhev8S;JJMO1#fViKX13 zu-B8mJ(E6DALyW5R;( zwOj>b&)SE@5lA!RL*#jk08i_^{&AsoulaboVs*Fx=(j1O562hJ6hUM2&-w?k^+RXa zacYg~boai@XAJ!cms-Ge1zbtHgi)27RELx02NW>p?eiF;TPYB>cH7@va3pB72D6f% zlxH4VVB!FUaAS1)zMj%aX$-e`1|W9|+%rg7g>D|7@wNNGQ>%-uzkVL!2OYuynQAcF zx^%j7xn+1KK}6$mJ$(S~;Gk7q7m=>#b%h)`Q@V1%T-WArMmuZyI6?{W~y>D z@uVQ7Ev^0-R5v;CS;}6oR2^Qi+wRB;rniJ(gUkH++QC5XU3lB;7>6O)Y6By}&3QnL zP(*W3F`MA-oZ%|}5=`7?H-vLe_fv7x;wOC!8(6in0#}R|)3mg7!W-2K1;niA(;uN) z6T)`-`M%-S@}}rE#a&C3RChaCi{1=Z`>!jDMEr&iC&$g+3;b}Y^B&HZ^i$=p4a-#Q zY^Z!PhU2XF}Ea`xrqE^$0(w*rOeBlTr5IpyEux!7JZ6BUB!?OG? zwY_}LQlneFb?Ev>-)T(G%b?F>MW15_g=O7G?B=l(h?^e;&_;>5<;I=GhSgd!WprCP|%ryKx>q$WtqdWDMn&URS6TSL^5%U$ZH0&>E zbk2{NveTFQK%^NhD@9Z z+o8P^n48W!-L1KcgQS!V3x0!U4@SGYLe8$H(3kgw5G^Z=qwV3Pt&;*}HFc zHu!F5CjlEkJ}ZBqQ{B^IGNKCT98=6CvVct9{CVsfowA{9j+&#EDd=Y{zWTcts?=*V z_}=SJF|+lZ1}Cs~2C`jZEljJ zzvH>|EwZ1(7{EQ9&Q}{HPks2HY@Fc4mF&raePHn)DTut?7nsV&qFZSq&3&ZG=Z@af zUZu^YzEiBX1~y+EX03&1ZkBdqdEcE@ebu^X*->bDSI1T(tdNkEa?(!^uvCO+3ff3L zjhIKcC`v7uO-ttm8d3R{Au&JnUw6y27wd9*^7c@A0uPaUdCQc3P&K6W(sNtH97^N=wrt#Ws$qt?==H9Cx@q(k-HO!+7MW z=E#WB?9HKPlh3Qnn{n1zG@?}(Upd}RZQRFyE-E>UOT_--De)}T>)uGREh&wTFjJU* zB|6yoXim~3>c=eRB_-lbUkqh$2{#fMYS0RNuf)4xSb2FTB?4%BiVb5p?aNB|$i%cO zNB&J|hk)xPZzAelkCeE*vl&?4;1w>o5GW2|pgQkUY7v zD;=G`EwlvQwN z(UuKe3+j^k>c&^} zj~{aiZZjqNc7K5jeA+xyc!1t=f{1^tE?*>$1hNK$dnmcVvkYa>Yqd2Q=kAtr1MYi4-v&gr zxYcfCb=pJ7R(l!lBEb8>U?kixpR~|*QGR5a8ounBM@0;-cnJ<$PL|L>CM7f%l znlS~W3o9L7W2Uy!d@7`?KH+tX8`PfM$GjdX)A83mkdLKnIH)jQ~+GFYzT}l4c;6 z>2E{UBQglI@%fv)tZT^o!pavpe`N?Ck!#g> zMdzQeCI7`?nYT?gYljtW@MJYm8s~g2 zS5NYYN813;H?K(g4keCDuDOPnx4DnpQeRN8C(2Y-CHfCz-c3mSz3^6Cj@a<4h%==8 zWD9qjb{=wOQ*H_n?Rrvj@{qz4DR;dDzJ>-^FIryYB8KU49SL z$5^X$)A2mz93!2IcBakpX=_Z5y4ibszSPevSsT3I-$ucY;c=gdtAW58w0OV58!q|_ z@$DvA%9E70ZLT+mh51bI;}@KDf6Cp7>KW$l^Pxup@PrT^7ibhi3+ObFNc9oTbjZJ% zGyG!+k9hT^WHO_CZKloz(VD1mO><-e2{39w5n{EOV0Jmx3JkX6H^AibiwG0YUAVN< z0PRr`2_!I`8kw_gdbJHC%Kue}O)>!_j2)Y+Tv#HuK`DU`7h^A;f42K`X*fFQ7OtwM zAgnmo5{cpfF$6kR9uexb%@=(qN#B8ct&h8dna$|5Gd0?-U5k$m_EYsC7?vzQ59anT zQeVXfbQ6Js45hBMM%-4@aDDxkfNgSHYi84RMIVPq`Wt)LzM}{A*VHsJU)8sLCw(>m zLrb$m(zy2qF{S_h)5-&t4Y^p|@w$M?g+*F)@Ja*ey9^(-{{YEZwMK7W33#UU6tWo|ncuLJYZ zMKVooUxwH*i_qub4HQh#yy_{yy2obTUF;Z(e?-;t0RN~lI2a~hqXXV(MWC7L*q51R zHlZQ+1-g7B#V@WtQ+({BR3e7q8nKSWu7||x9jF^b`rWu-!eznoA#df3fzANao?mX> zfW@c$OAyAs6vVGnwXF6A+9Q^$5+AIB>?lSasqR|w(#2p0@+XdVUTVLZGaQeos>@}J zwYf6fy`h=h>6g4iW6zY=1&@zew-3}%orN-z`v1ITJ3oZ18nNBOi=-;KGGWF{%aW&! zDxzkF5IEL_kNl4sp5=%_Il4&q{uG9xs$Ja>=_WI*(?;e>T8FMZLHT5y#m1L zL>|5u%C?h5JCT=>i5IZFEt5}LyNO$gDeYd_xB%#CK#6$pv6D%Z&|7A81^{s8Q;jx% zVYmh#$evSb#PqS&3@_|YO+9FaM??hTPtl%2SRn-5rTeSfp6fu&VJXfu7P z>!X=l)FI1mPpvcdS*m?LnMT(~TK+Pn8KSsTL5R+pe;$P@2d^Xoyd=^6d>i?q@p`>6 zf&0#3+S$2_Cq;+8HKPu0k^Xi{od#6cpQ1_0kzXuZ;Rg>V>$BVfp)g~^RdGNkw4dVS zD_^Z5xJG4tc=_RGRlAPWBB*@Drxh_mjN22!_*=Q5MQtRLk-fkZ^NL^8{*1b2 z#W#x{c;Kh*fOtlsFX~SWO!C($NT!v59J+XctaYFTAg7wk0HLAa%Bou*K>nlvy#V>E z$FWlP@S<%B5O58KnSu$#{T<0ugFwOs!cHEj?!{VGdf@`TOKj;dGfi9on7mA`3Iqyo zUU8*kB5OW7Ljb`FLSo{&J=*;FkC0F7uwv%zCg^)bLIcDRzd>ZTZv`cL1uDYgDXYcdZFIq}%O|y)k$KB~D zjb)Tp4;8+YRFBZ5>_H!QeCag&De8PVSYWZn>y5+?4VBGcZzmXI8KN*P~S+LmadA*>L|#l2VQ zItbthrh`_f+i z$<|Cfge${vHkhxwVEj6fbIGiyvgKFWJ2PFg!$Ip;vVcqMn{eT$cQPu zFI!&;T|U58yyn}qM&O!?oAW(t2IQE8G&k~@hnh;l+;es$&oipik}cS>YV`SowqvQl zufkNre%x~}Bkc1V51OSy7!6YROSamA_3C)5;tMK2&X>bG z?XCm;ls)hq8kGGRLxGF2RtEN@6RLx;Hgvd4=3kC<2yTpPK1Ld(%MVtpW{k@5Ck){;6pR`iF5K2{bRTR)-GB62WxKz-uN!w zap*@x|7v20Ucxv1-Q7^RX#Vj09t!*bjc(Pe;YrHrbKPb@XIHR@tocL<`kYmZc0Blg zN$0$&v!hLo=T8zBx-XCGZ~Rq|a3R)o=Et@0rU0aKu3)gUEETuwJDDpdnGVa06LHGHbFOW0XDJ`oj(5}SF&x8L;DA|hr$3m&OMIa z;6R4JtZ$H__5rhD`h_Yjc_`^benwZ{E$@EzB$cNlGdq6NxYv#akIpelygT<{myl9a z>r{H_sCu|z&~$=N%ivU!(}&7q37gH(=ZYIG#Np2c^LSb#S_V4;h!N!uvsl7+5kfxw z)Yhp$e~%0C%oE|$W&msth|V8{)~C6H{o=W$n}*vV zL!h1qJcHu4lsx5g4w+c}^!@Sd1-Be}lPvcIHlhF<`m4*+WkBlLQ38j!M6~*VhTg9T zdN%{Hxsa#3*Chf7U%WmC&zJXif_y}ws$lV912aQi`PBJG@eifd+pZ5?g;(OPT{%}B zT_Y+MdXPO+`RyOo=e~0}2St(*)>x5d{MUh1cQJ)Apn z)wYI5 zR4Q%eNKPT*vBT4?Io}9d z<+3M>yZxnZKpPOvR;tc9zO}bVJb0w-#Xua=u1X~z*o%g`hXgi^#E&0MK^HnDb%ST6 zcJNh`YVUr6vCLOk;@zBNqF#3Xrk-yTPX)QgS}C+cpdd_COp_u9n0w$(x#j8uR%HS^ z?zeEPLPoFm1mXkvn=d}C&|Rp2x*R^^`k?c({L1NTSmsPq;5I^%Bxf4!J!lI>FJ5FJ z>F(iE`%)`HdtwwmS>;2+!cu7G8{tSB&2bj;i^wUF;HZmhX1ahE9Kmi(hnRmnS(yJz zz9sAB;0;w$GF~fd|4BXh9n0B`DAgm&+wYHs&dW)ULY>dWub){I`KYC&`Qy!w(M)yX z0(995S{6F20Vz8e6ht37*O_3w-&jy6z?!^T*MnpY&4>eioMuVI(wBdZRa|EK`2(Ki+_xt3NEpL@zX1)w-$sUJdSKXQqTXJ+@ z+lfhGu?jPnBmEd8pYXteOsFbf;#Pw$|~~;4y7}va4cx1dP$u@$r8U#k6D+Ppj>&< zPIGmhS_}EgTOmY(-v;WOJR*-(Z^ctwS+|vZkdwUD*>sEQB_>M{SYqwz~I z#I(5%)^3~~EhP!G0SIURfy$}tX#KZecK>=xD-E|a4J}iYRYw21B(!eUUPia?ZuxP- zjzSh+(%=hnnCyt2%Z9E-G z2rUoEGf5Wf>NU+;2iOUdE(J};S83n-D75q6z2p^Q^W0qU-Tx`*^=SNcKzwOYd0zDD z?VJ7zjyPDmvtKMzdy5)z%160=B(%jOgL#v4k{2`Dx~_%NH;kvq##}NUXDds&-9u;T z@rDgA)WhJp?uG3-C`<};NZObzO5F^)%L~Qu4M#jVq!orf8xQG0khxIr1^=+X9}$UE)3(x*3sKX$;@M#Y#Hl> zsBE1EJ>Gs@k4TRtF}}tS{^r>9@zA~oJALN^@0i5{-(NR`%#w;+lbVH%lbt-Iape$` zYelR$ig(UF{oU<5vaV#WTYe0JGM7`cV02LSgEWDdfS#9lBdU<|V#dAUd3GUpgS+1k zvo@Bza<^Kx__7F6IC`ned?kuokAB^qRwmvv55lusT-l+|U%>EO$@8xASWQtrn~5bOPu~5(RENLZ>MS3B zX(};z%@^M7)9op9_|U7+m9s)iNz0yi){_-`yM|miN|gNOBW5^QXR@QV?vAl{6_clE zu<7CGm+gpx$aWx;cy$zY8Z5HOk5nHAhL|ykH@oWY2xJrX4NY&+*Y+@ptqGksxr}Sg z?A8W>IRPO<#pIFtU*Rmr0Ks#PP1U$vMG%Q^{-$61J$1N*p7X=>PYj!9{F{vS=Js}z zQcIfi%DpcLEYAy<#jKTHuJ!1ql~0S2>Q+a5)n)OTBSOIt@I3&5mvJw|0348ncB!=l zA)q`b(S+bIyvT}LNKd6?eaCchW~x!+%x35(7O}Y{hrzG#%XVcz%Dxv|e=pf%uL)$N z;EwY!Y>yei{MeqSyV?O`r%G=X^6a)O$L=iih%XO`QjHJ7tR%{MxR67u8iGG%x z1`?6M^pUqQ~9M$olouojbCo?m!9;?J$N~sVINgMqC3y$LhJ}@n zuwInEjLm?lkAO_+TiKPys{V667|FNOOv|VJX2U>Mn{0T2JmEZ!wd^%Ky}Vx?SuUR@ zcB^({I4p;as$@Bjgj$S>5XrSXy1#Q7#6LRT&AZ=>;6oE|xnUv@@h1vt?H3`IV6}}8 z86J5qdsN^a#H5&*NfU}(Yq_aAvI_i=Rv#m^v#$i$f?)WFLNwY=zWW)L0tq0b)R*fR zrqDh~Hehzhw_>h3U+7|Eeiy4stIspaXW z9IqTo;$F9}rzG<7I6L_AUb z)rzG$tS@o3s`@Ugk6InSDjJjlU?zog(mX>HoWeBRH#~?KZRSGST4u-h8Y5`CdNI(! zZe2<^H9%7%e>&k{0WN4&l2u0iO7*;dZ{UpT&&Xy8l4O;ZJ<`10bR#>Vz^&xT>ji6s zRqoAlgIz%Bbs4NVv%hskgbNE^5}RQc;I3j!0;Qxd&`A4Y@TjUA)?m@Cb62 z&zhI`D#3=tNK9gw22OHc-H>#@X|Ne2S1$|T_tF}MK!Cw%hC?NQHs*pLhJ!h|29*A)r7{jcdz)_{a!5Z8grm!EA;w(YHZf z%1%6lnlR8WS_5*;Pp1j04o|SIcF49SDAbv>WS|s0^2cv4y`CxKi9dA=!9Mo_FVh@= z0~^;7*8wl`587&wajl38Uuu0EQf6E9_kAtnisyyeOJ1MTt=1wn6W|cwK%5-M2%zf@_oNNcWRnULuk9tmgr(+-DEK&_xg|NJerlMkzH#>ce(PNQftQ}i8N3L)Z zShVHO|C|ee#2kWBl#9f7VYPvJi#YM_iuz41fD(UiBI>k&o&s*(D#q^d%vy|1p6aN6 ztL-=aBJun>%G>pym5;!G$EzhBuaR{8S5{G3QJ(3ajSBxRrDTP@je;Ru+)*$Slq=dr z+b0O(C=GTi%E&^LRAil*U=}_Yu&@$D8kF)wd1D}QV6O$(jPmyh@VkNX2kS8*{CsX$ zqA-pyuwoN9LN^GbZ~5mSqI@A1$7+9o3dp4I=^CMyG;`G0RyR8jiBIr;zpb7hslHU3XI zjGqhoCdv;i!Ucg@qH!pQ3IsF|AMjj`Zwmxw=^v=`u_t|82`io literal 0 HcmV?d00001 diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 000000000..02bbbca5e --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,56 @@ +SERIAL = `echo /dev/tty.USA19QI*` +UISP = uisp -dprog=avr910 -dserial=$(SERIAL) -dpart=auto +TARGET = atmega8 +#TARGET = at90s2313 +# The two lines above are for "uisp" and the AVR910 serial programmer connected +# to a Keyspan USB to serial converter to a Mac running Mac OS X. +# Choose your favorite programmer and interface. + +COMPILE = avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=$(TARGET) # -DDEBUG_LEVEL=2 + +OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o isp.o clock.o main.o + + +# symbolic targets: +all: main.hex + +.c.o: + $(COMPILE) -c $< -o $@ +#-Wa,-ahlms=$<.lst + +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +.c.s: + $(COMPILE) -S $< -o $@ + +clean: + rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o main.s usbdrv.s + +# file targets: +main.bin: $(OBJECTS) + $(COMPILE) -o main.bin $(OBJECTS) -Wl,-Map,main.map + +main.hex: main.bin + rm -f main.hex main.eep.hex + avr-objcopy -j .text -j .data -O ihex main.bin main.hex +# ./checksize main.bin +# do the checksize script as our last action to allow successful compilation +# on Windows with WinAVR where the Unix commands will fail. + +disasm: main.bin + avr-objdump -d main.bin + +cpp: + $(COMPILE) -E main.c + +avrdude: + avrdude -c butterfly -p $(TARGET) -U flash:w:main.hex + +uisp: all + $(UISP) --erase + $(UISP) --upload --verify if=main.hex diff --git a/firmware/clock.c b/firmware/clock.c new file mode 100644 index 000000000..139749320 --- /dev/null +++ b/firmware/clock.c @@ -0,0 +1,23 @@ +/* + clock.c - part of USBasp + + Autor..........: Thomas Fischl + Description....: Provides functions for timing/waiting + Licence........: Free under certain conditions. See Documentation. + Creation Date..: 2005-02-23 + Last change....: 2005-04-20 +*/ + +#include +#include +#include "clock.h" + +/* wait time * 320 us */ +void clockWait(uint8_t time) { + + uint8_t i; + for (i = 0; i < time; i++) { + uint8_t starttime = TIMERVALUE; + while ((uint8_t) (TIMERVALUE - starttime) < CLOCK_T_320us) {} + } +} diff --git a/firmware/clock.h b/firmware/clock.h new file mode 100644 index 000000000..89eb868d8 --- /dev/null +++ b/firmware/clock.h @@ -0,0 +1,24 @@ +/* + clock.h - part of USBasp + + Autor..........: Thomas Fischl + Description....: Provides functions for timing/waiting + Licence........: Free under certain conditions. See Documentation. + Creation Date..: 2005-02-23 + Last change....: 2005-04-20 +*/ + +#ifndef __clock_h_included__ +#define __clock_h_included__ + +#define F_CPU 12000000L /* 12MHz */ +#define TIMERVALUE TCNT0 +#define CLOCK_T_320us 60 + +/* set prescaler to 64 */ +#define clockInit() TCCR0 = (1 << CS01) | (1 << CS00); + +/* wait time * 320 us */ +void clockWait(uint8_t time); + +#endif /* __clock_h_included__ */ diff --git a/firmware/isp.c b/firmware/isp.c new file mode 100644 index 000000000..1bd41d338 --- /dev/null +++ b/firmware/isp.c @@ -0,0 +1,274 @@ +/* + isp.c - part of USBasp + + Autor..........: Thomas Fischl + Description....: Provides functions for communication/programming + over ISP interface + Licence........: Free under certain conditions. See Documentation. + Creation Date..: 2005-02-23 + Last change....: 2005-04-20 +*/ + +#include +#include "isp.h" +#include "clock.h" + +#define spiHWdisable() SPCR = 0 + +void spiHWenable() { + + /* enable SPI, master, 375kHz SCK */ + SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1); + SPSR = (1 << SPI2X); +} + +void ispSetSCKOption(uchar option) { + + if (option == 0) { + + /* use software spi */ + ispTransmit = ispTransmit_sw; + // spiHWdisable(); + + } else { + + /* use hardware spi */ + ispTransmit = ispTransmit_hw; + + } +} + +void ispDelay() { + + uint8_t starttime = TIMERVALUE; + while ((uint8_t) (TIMERVALUE - starttime) < 12) { } +} + +void ispConnect() { + + /* all ISP pins are inputs before */ + /* now set output pins */ + ISP_DDR |= (1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI); + + /* reset device */ + ISP_OUT &= ~(1 << ISP_RST); /* RST low */ + ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */ + + /* positive reset pulse > 2 SCK (target) */ + ispDelay(); + ISP_OUT |= (1 << ISP_RST); /* RST high */ + ispDelay(); + ISP_OUT &= ~(1 << ISP_RST); /* RST low */ + + if (ispTransmit == ispTransmit_hw) { + spiHWenable(); + } +} + +void ispDisconnect() { + + /* set all ISP pins inputs */ + ISP_DDR &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI)); + /* switch pullups off */ + ISP_OUT &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI)); + + /* disable hardware SPI */ + spiHWdisable(); +} + +uchar ispTransmit_sw(uchar send_byte) { + + uchar rec_byte = 0; + uchar i; + for (i = 0; i < 8; i++) { + + /* set MSB to MOSI-pin */ + if ((send_byte & 0x80) != 0) { + ISP_OUT |= (1 << ISP_MOSI); /* MOSI high */ + } else { + ISP_OUT &= ~(1 << ISP_MOSI); /* MOSI low */ + } + /* shift to next bit */ + send_byte = send_byte << 1; + + /* receive data */ + rec_byte = rec_byte << 1; + if ((ISP_IN & (1 << ISP_MISO)) != 0) { + rec_byte++; + } + + /* pulse SCK */ + ISP_OUT |= (1 << ISP_SCK); /* SCK high */ + ispDelay(); + ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */ + ispDelay(); + } + + return rec_byte; +} + +uchar ispTransmit_hw(uchar send_byte) { + SPDR = send_byte; + + while (!(SPSR & (1 << SPIF))); + return SPDR; +} + +uchar ispEnterProgrammingMode() { + uchar check; + uchar count = 32; + + while (count--) { + ispTransmit(0xAC); + ispTransmit(0x53); + check = ispTransmit(0); + ispTransmit(0); + + if (check == 0x53) { + return 0; + } + + spiHWdisable(); + + /* pulse SCK */ + ISP_OUT |= (1 << ISP_SCK); /* SCK high */ + ispDelay(); + ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */ + ispDelay(); + + if (ispTransmit == ispTransmit_hw) { + spiHWenable(); + } + + } + + return 1; /* error: device dosn't answer */ +} + +uchar ispReadFlash(unsigned int address) { + ispTransmit(0x20 | ((address & 1) << 3)); + ispTransmit(address >> 9); + ispTransmit(address >> 1); + return ispTransmit(0); +} + + +uchar ispWriteFlash(unsigned int address, uchar data, uchar pollmode) { + + /* 0xFF is value after chip erase, so skip programming + if (data == 0xFF) { + return 0; + } + */ + + ispTransmit(0x40 | ((address & 1) << 3)); + ispTransmit(address >> 9); + ispTransmit(address >> 1); + ispTransmit(data); + + if (pollmode == 0) + return 0; + + if (data == 0x7F) { + clockWait(15); /* wait 4,8 ms */ + return 0; + } else { + + /* polling flash */ + uchar retries = 30; + uint8_t starttime = TIMERVALUE; + while (retries != 0) { + if (ispReadFlash(address) != 0x7F) { + return 0; + }; + + if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { + starttime = TIMERVALUE; + retries --; + } + + } + return 1; /* error */ + } + +} + + +uchar ispFlushPage(unsigned int address, uchar pollvalue) { + ispTransmit(0x4C); + ispTransmit(address >> 9); + ispTransmit(address >> 1); + ispTransmit(0); + + + if (pollvalue == 0xFF) { + clockWait(15); + return 0; + } else { + + /* polling flash */ + uchar retries = 30; + uint8_t starttime = TIMERVALUE; + + while (retries != 0) { + if (ispReadFlash(address) != 0xFF) { + return 0; + }; + + if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { + starttime = TIMERVALUE; + retries --; + } + + } + + return 1; /* error */ + } + +} + + +uchar ispReadEEPROM(unsigned int address) { + ispTransmit(0xA0); + ispTransmit(address >> 8); + ispTransmit(address); + return ispTransmit(0); +} + + +uchar ispWriteEEPROM(unsigned int address, uchar data) { + + ispTransmit(0xC0); + ispTransmit(address >> 8); + ispTransmit(address); + ispTransmit(data); + + clockWait(30); // wait 9,6 ms + + return 0; + /* + if (data == 0xFF) { + clockWait(30); // wait 9,6 ms + return 0; + } else { + + // polling eeprom + uchar retries = 30; // about 9,6 ms + uint8_t starttime = TIMERVALUE; + + while (retries != 0) { + if (ispReadEEPROM(address) != 0xFF) { + return 0; + }; + + if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { + starttime = TIMERVALUE; + retries --; + } + + } + return 1; // error + } + */ + +} diff --git a/firmware/isp.h b/firmware/isp.h new file mode 100644 index 000000000..7b832016a --- /dev/null +++ b/firmware/isp.h @@ -0,0 +1,66 @@ +/* + isp.h - part of USBasp + + Autor..........: Thomas Fischl + Description....: Provides functions for communication/programming + over ISP interface + Licence........: Free under certain conditions. See Documentation. + Creation Date..: 2005-02-23 + Last change....: 2005-04-20 +*/ + +#ifndef __isp_h_included__ +#define __isp_h_included__ + +#ifndef uchar +#define uchar unsigned char +#endif + +#define ISP_OUT PORTB +#define ISP_IN PINB +#define ISP_DDR DDRB +#define ISP_RST PB2 +#define ISP_MOSI PB3 +#define ISP_MISO PB4 +#define ISP_SCK PB5 + +#define ISP_DELAY 1 +#define ISP_SCK_SLOW 0 +#define ISP_SCK_FAST 1 + +/* Prepare connection to target device */ +void ispConnect(); + +/* Close connection to target device */ +void ispDisconnect(); + +/* read an write a byte from isp using software (slow) */ +uchar ispTransmit_sw(uchar send_byte); + +/* read an write a byte from isp using hardware (fast) */ +uchar ispTransmit_hw(uchar send_byte); + +/* enter programming mode */ +uchar ispEnterProgrammingMode(); + +/* read byte from eeprom at given address */ +uchar ispReadEEPROM(unsigned int address); + +/* write byte to flash at given address */ +uchar ispWriteFlash(unsigned int address, uchar data, uchar pollmode); + +uchar ispFlushPage(unsigned int address, uchar pollvalue); + +/* read byte from flash at given address */ +uchar ispReadFlash(unsigned int address); + +/* write byte to eeprom at given address */ +uchar ispWriteEEPROM(unsigned int address, uchar data); + +/* pointer to sw or hw transmit function */ +uchar (*ispTransmit)(uchar); + +/* set SCK speed. call before ispConnect! */ +void ispSetSCKOption(uchar sckoption); + +#endif /* __isp_h_included__ */ diff --git a/firmware/main.c b/firmware/main.c new file mode 100644 index 000000000..9d79354bd --- /dev/null +++ b/firmware/main.c @@ -0,0 +1,234 @@ +/* + USBasp - USB in-circuit programmer for Atmel AVR controllers + + Thomas Fischl + + License: + The project is built with AVR USB driver by Objective Development, which is + published under an own licence based on the GNU General Public License (GPL). + USBasp is also distributed under this enhanced licence. See Documentation. + + Target.........: ATMega8 at 12 MHz + Creation Date..: 2005-02-20 + Last change....: 2005-04-20 + + PC2 SCK speed option. GND -> slow (8khz SCK), + open -> fast (375kHz SCK) +*/ + +#include +#include +#include +#include +#include + +#include "usbdrv.h" +#include "isp.h" +#include "clock.h" + +#define USBASP_FUNC_CONNECT 1 +#define USBASP_FUNC_DISCONNECT 2 +#define USBASP_FUNC_TRANSMIT 3 +#define USBASP_FUNC_READFLASH 4 +#define USBASP_FUNC_ENABLEPROG 5 +#define USBASP_FUNC_WRITEFLASH 6 +#define USBASP_FUNC_READEEPROM 7 +#define USBASP_FUNC_WRITEEEPROM 8 + +#define PROG_STATE_IDLE 0 +#define PROG_STATE_WRITEFLASH 1 +#define PROG_STATE_READFLASH 2 +#define PROG_STATE_READEEPROM 3 +#define PROG_STATE_WRITEEEPROM 4 + +#define PROG_BLOCKFLAG_FIRST 1 +#define PROG_BLOCKFLAG_LAST 2 + +#define ledRedOn() PORTC &= ~(1 << PC1) +#define ledRedOff() PORTC |= (1 << PC1) +#define ledGreenOn() PORTC &= ~(1 << PC0) +#define ledGreenOff() PORTC |= (1 << PC0) + +static uchar replyBuffer[8]; + +static uchar prog_state = PROG_STATE_IDLE; + +static unsigned int prog_address; +static unsigned int prog_nbytes = 0; +static uchar prog_pagesize; +static uchar prog_blockflags; +static uchar prog_pagecounter; + + +uchar usbFunctionSetup(uchar data[8]) { + + uchar len = 0; + + if(data[1] == USBASP_FUNC_CONNECT){ + + /* set SCK speed */ + if ((PINC & (1 << PC2)) == 0) { + ispSetSCKOption(ISP_SCK_SLOW); + } else { + ispSetSCKOption(ISP_SCK_FAST); + } + + ispConnect(); + ledRedOn(); + + } else if (data[1] == USBASP_FUNC_DISCONNECT) { + ispDisconnect(); + ledRedOff(); + + } else if (data[1] == USBASP_FUNC_TRANSMIT) { + replyBuffer[0] = ispTransmit(data[2]); + replyBuffer[1] = ispTransmit(data[3]); + replyBuffer[2] = ispTransmit(data[4]); + replyBuffer[3] = ispTransmit(data[5]); + len = 4; + + } else if (data[1] == USBASP_FUNC_READFLASH) { + prog_address = (data[3] << 8) | data[2]; + prog_nbytes = (data[7] << 8) | data[6]; + prog_state = PROG_STATE_READFLASH; + len = 0xff; /* multiple in */ + + } else if (data[1] == USBASP_FUNC_READEEPROM) { + prog_address = (data[3] << 8) | data[2]; + prog_nbytes = (data[7] << 8) | data[6]; + prog_state = PROG_STATE_READEEPROM; + len = 0xff; /* multiple in */ + + } else if (data[1] == USBASP_FUNC_ENABLEPROG) { + replyBuffer[0] = ispEnterProgrammingMode();; + len = 1; + + } else if (data[1] == USBASP_FUNC_WRITEFLASH) { + prog_address = (data[3] << 8) | data[2]; + prog_pagesize = data[4]; + prog_blockflags = data[5]; + if (prog_blockflags & PROG_BLOCKFLAG_FIRST) { + prog_pagecounter = prog_pagesize; + } + prog_nbytes = (data[7] << 8) | data[6]; + prog_state = PROG_STATE_WRITEFLASH; + len = 0xff; /* multiple out */ + + } else if (data[1] == USBASP_FUNC_WRITEEEPROM) { + prog_address = (data[3] << 8) | data[2]; + prog_pagesize = 0; + prog_blockflags = 0; + prog_nbytes = (data[7] << 8) | data[6]; + prog_state = PROG_STATE_WRITEEEPROM; + len = 0xff; /* multiple out */ + } + + usbMsgPtr = replyBuffer; + + return len; +} + + +uchar usbFunctionRead(uchar *data, uchar len) { + + uchar i; + + /* check if programmer is in correct read state */ + if ((prog_state != PROG_STATE_READFLASH) && + (prog_state != PROG_STATE_READEEPROM)) { + return 0xff; + } + + /* fill packet */ + for (i = 0; i < len; i++) { + if (prog_state == PROG_STATE_READFLASH) { + data[i] = ispReadFlash(prog_address); + } else { + data[i] = ispReadEEPROM(prog_address); + } + prog_address++; + } + + /* last packet? */ + if (len < 8) { + prog_state = PROG_STATE_IDLE; + } + + return len; +} + + +uchar usbFunctionWrite(uchar *data, uchar len) { + + uchar i; + + /* check if programmer is in correct write state */ + if ((prog_state != PROG_STATE_WRITEFLASH) && + (prog_state != PROG_STATE_WRITEEEPROM)) { + return 0xff; + } + + + for (i = 0; i < len; i++) { + + if (prog_state == PROG_STATE_WRITEFLASH) { + /* Flash */ + + if (prog_pagesize == 0) { + /* not paged */ + ispWriteFlash(prog_address, data[i], 1); + } else { + /* paged */ + ispWriteFlash(prog_address, data[i], 0); + prog_pagecounter --; + if (prog_pagecounter == 0) { + ispFlushPage(prog_address, data[i]); + prog_pagecounter = prog_pagesize; + } + } + + } else { + /* EEPROM */ + ispWriteEEPROM(prog_address, data[i]); + } + + prog_nbytes --; + + if (prog_nbytes == 0) { + prog_state = PROG_STATE_IDLE; + if ((prog_blockflags & PROG_BLOCKFLAG_LAST) && + (prog_pagecounter != prog_pagesize)) { + + /* last block and page flush pending, so flush it now */ + ispFlushPage(prog_address, data[i]); + } + } + + prog_address ++; + } + + return 0; +} + + +int main(void) +{ + PORTD = 0; + PORTB = 0; /* no pullups on USB and ISP pins */ + DDRD = ~(1 << 2); /* all outputs except PD2 = INT0 */ + DDRB = 0; /* all USB and ISP pins inputs */ + + DDRC = 0x03; /* all inputs except PC0, PC1 */ + PORTC = 0xfe; + + clockInit(); /* init timer */ + + ispSetSCKOption(ISP_SCK_FAST); + + usbInit(); + sei(); + for(;;){ /* main event loop */ + usbPoll(); + } + return 0; +} diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h new file mode 100644 index 000000000..04b974995 --- /dev/null +++ b/firmware/usbconfig.h @@ -0,0 +1,117 @@ +/* Name: usbconfig.h + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2005-04-01 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usbconfig.h 43 2005-04-10 21:04:36Z cs $ + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + +/* +General Description: +This file contains parts of the USB driver which can be configured and can or +must be adapted to your hardware. +*/ + +/* ---------------------------- Hardware Config ---------------------------- */ + +#define USB_CFG_IOPORT PORTB +/* This is the port where the USB bus is connected. When you configure it to + * "PORTB", the registers PORTB, PINB (=PORTB+2) and DDRB (=PORTB+1) will be + * used. + */ +#define USB_CFG_DMINUS_BIT 0 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This MUST be bit 0. All other values will result in a compile error! + */ +#define USB_CFG_DPLUS_BIT 1 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port. Please note that D+ must also be connected + * to interrupt pin INT0! + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 0 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint 1. + */ +#define USB_CFG_INTR_POLL_INTERVAL 10 +/* If you compile a version with endpoint 1 (interrupt-in), this is the poll + * interval. The value is in milliseconds and must not be less than 10 ms for + * low speed devices. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* Define this to 1 if the device has its own power supply. Set it to 0 if the + * device is powered from the USB bus. + */ +#define USB_CFG_MAX_BUS_POWER 50 +/* Set this variable to the maximum USB bus power consumption of your device. + * The value is in milliamperes. [It will be divided by two since USB + * communicates power requirements in units of 2 mA.] + */ +#define USB_CFG_SAMPLE_EXACT 0 +/* This variable affects Sampling Jitter for USB receiving. When it is 0, the + * driver guarantees a sampling window of 1/2 bit. The USB spec requires + * that the receiver has at most 1/4 bit sampling window. The 1/2 bit window + * should still work reliably enough because we work at low speed. If you want + * to meet the spec, set this value to 1. This will unroll a loop which + * results in bigger code size. + * If you have problems with long cables, try setting this value to 1. + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 1 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 1 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * usbFunctionSetup(). This saves a couple of bytes. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID 0xeb, 0x03 +/* USB vendor ID for the device, low byte first. 0xeb, 0x03 is Atmel's vendor + * ID. Don't use it for hardware you sell or publish! + */ +#define USB_CFG_DEVICE_ID 0xb4, 0xc7 +/* This is the ID of the device, low byte first. It is interpreted in the + * scope of the vendor ID. The only requirement is that no two devices may + * share the same product and vendor IDs. Not even if the devices are never + * on the same bus together! + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 'w', 'w', 'w', '.', 'f', 'i', 's', 'c', 'h', 'l', '.', 'a', 't' +#define USB_CFG_VENDOR_NAME_LEN 13 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + */ +#define USB_CFG_DEVICE_NAME 'U', 'S', 'B', 'a', 's', 'p' +#define USB_CFG_DEVICE_NAME_LEN 6 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. + */ +#define USB_CFG_DEVICE_CLASS 0xff +#define USB_CFG_DEVICE_SUBCLASS 0 +/* See USB specification if you want to conform to an existing device class. + */ +#define USB_CFG_INTERFACE_CLASS 0 +#define USB_CFG_INTERFACE_SUBCLASS 0 +#define USB_CFG_INTERFACE_PROTOCOL 0 +/* See USB specification if you want to conform to an existing device class or + * protocol. + */ + + +#endif /* __usbconfig_h_included__ */ diff --git a/firmware/usbdrv/Changelog.txt b/firmware/usbdrv/Changelog.txt new file mode 100644 index 000000000..3b641d298 --- /dev/null +++ b/firmware/usbdrv/Changelog.txt @@ -0,0 +1,18 @@ +This file documents changes in the software, firmware and hardware of the +"Remote Sensor" device. New entries are always appended to the end of the file. +Scroll down to the bottom to see the most recent changes. + +2005-04-01: + - Implemented endpoint 1 as interrupt-in endpoint. + - Moved all configuration options to usbconfig.h which is not part of the + driver. + - Changed interface for usbVendorSetup(). + - Fixed compatibility with ATMega8 device. + - Various minor optimizations. + +2005-04-11: + - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead() + and usbFunctionWrite() now. Added configuration options to choose which + of these functions to compile in. + - Assembler module delivers receive data non-inverted now. + - Made register and bit names compatible with more AVR devices. diff --git a/firmware/usbdrv/License.txt b/firmware/usbdrv/License.txt new file mode 100644 index 000000000..93432eebb --- /dev/null +++ b/firmware/usbdrv/License.txt @@ -0,0 +1,457 @@ +PREFACE + +Conceiving and understanding a new license is not an easy task. To make things +easier for both, the author and the licensee, we have decided to base our +license for the USB driver on an existing license with well-understood +properties. + +Our favorite choice for the base license was the GNU General Public License +(GPL). However, we cannot use the GNU GPL directly for the following reasons: + +(1) It was not intended for projects involving hardware -- we must extend the + term "source code" to at least the circuit diagram. +(2) The GNU GPL does not require publication. Only if a binary is published, + it requires that the source is published as well. This is reasonable for + software because unpublished software is of little relevance. For projects + involving hardware, we want to REQUIRE publication. More than that, we + even want to define HOW the publication must be done (files contained, + file formats etc). +(3) As the author of the software, we can distribute it under more than one + license. For people who don't want to meet the obligations of the GNU GPL, + we want to offer pay-by-unit business licenses. To avoid a split in + revisions of the driver, we need special privileges to distribute + contributed modifications under other licenses. + +We can not simply modify the GNU GPL and incorporate our changes because the +Free Software Foundation (FSF) who holds the copyright for the text of the +GNU GPL does not allow modifications. We therefore set up our own small +license which incorporates the GNU GPL by reference: + + + +LICENSE FOR PROJECTS BUILT WITH "OBJECTIVE DEVELOPMENT'S +FIRMWARE-ONLY USB-DRIVER FOR ATMEL'S AVR MICROCONTROLLERS" +Version 2005-02 + + +I. Definitions + +"OBDEV" shall mean OBJECTIVE DEVELOPMENT Software GmbH or any legal successor +thereof. + +"Software Source Code" shall mean the preferred form of the software for +making modifications to it. + +"USB Driver" shall mean the Software Source Code for OBDEV's firmware-only +USB-driver for Atmel's AVR microcontrollers. + +"Function" shall mean the Software Source Code for all software executed on +the microcontroller except the USB Driver. + +"Host Software" shall mean the Software Source Code for all software required +to control the USB device from the USB host running any operating system. + +"Project" shall mean the USB Driver, the Function, the Host Software, circuit +diagrams of the controller based hardware and accompanying documentation. + +"source code" shall have the same meaning as the term "Project" above. + +"Web Site" shall mean a collection of text and multimedia documents accessible +worldwide over internet through the HyperText Transfer Protocol (HTTP) on +TCP port 80 (standard HTTP port). + + +II. General License Terms +The general terms of this license consist of the GNU General Public License +Version 2 (GNU GPL2) which is hereby incorporated into this section as though +it were fully set forth here. A copy of the GNU GPL2 is included for your +convenience in appendix A of this license. + +The term "source code" in the GNU GPL2 is to be understood as defined in +section I above. If any term or definition in section I, III, IV or V +conflicts with the GNU GPL2, the term or definition in section I, III, IV or +V has precedence of the GNU GPL2. + + +III. Distribution of the Project +The distributed form of a Project must contain at least the following files: +(a) Software Source Code files for the USB Driver, the Function and the Host + Software. +(b) Circuit diagrams for the hardware in PDF, PNG or GIF image file format. +(c) A file with name "Readme.txt" in ASCII format with at least the following + content (in English language): + - An explanation what the Project does. + - What to do with the distributed files (installation procedure etc.). + - A reference to Objective Development's USB driver. + - Your (author's) name and contact information. E-mail and/or URL is + sufficient. +(d) Optionally a text file with a description of the circuit diagram, an + explanation of special (software) techniques used etc. +(e) A copy of this license in a file with the name "License.txt". + + +IV. Requirement for Publication +All modifications and derived work (Projects using the USB Driver) MUST be +distributed (published) as described in section III above on a Web Site. The +main page must reproduce at least a description of the Project (e.g. as +contained in the "Readme.txt" file distributed) and a download link for the +entire Project. The URL of the main page must be submitted to OBDEV. OBDEV +will provide a mechanism for submitting Project URLs and for publishing +Projects on their Web Site. The Project must remain available for at least +twelve (12) months after the initial publication or at least six (6) months +after a subsequent version of that particular Project has been published. + + +V. Author Privileges +OBDEV reserves the right to distribute the USB Driver and all modified +versions under other (proprietary) licenses. If you modify the USB Driver +under the grants of this license, you therefore grant OBDEV (in addition to +the grants of the GNU GPL2) a worldwide, perpetual, irrevocable royalty free +license for your modifications. OBDEV shall not automatically gain rights +other than those of the GNU GPL2 in the other parts of the Project. This +section V overrides possibly contradicting terms in the GNU GPL2 referenced +in section II. + + +APPENDIX A + + 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. + + GNU GENERAL PUBLIC LICENSE + 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. + + + Copyright (C) + + 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) year 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. + + , 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/firmware/usbdrv/oddebug.c b/firmware/usbdrv/oddebug.c new file mode 100644 index 000000000..5c5e7b1bf --- /dev/null +++ b/firmware/usbdrv/oddebug.c @@ -0,0 +1,51 @@ +/* Name: oddebug.c + * Project: AVR library + * Author: Christian Starkjohann + * Creation Date: 2005-01-16 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: oddebug.c 52 2005-04-12 16:57:29Z cs $ + */ + +#include +#include "oddebug.h" + +#if DEBUG_LEVEL > 0 + +static void uartPutc(char c) +{ + while(!(ODDBG_USR & (1 << UDRE))); /* wait for data register empty */ + ODDBG_UDR = c; +} + +static uchar hexAscii(uchar h) +{ + h &= 0xf; + if(h < 10){ + h += '0'; + }else{ + h += 'a' - (uchar)10; + } + return h; +} + +static void printHex(uchar c) +{ + uartPutc(hexAscii(c >> 4)); + uartPutc(hexAscii(c)); +} + +void odDebug(uchar prefix, uchar *data, uchar len) +{ + printHex(prefix); + uartPutc(':'); + while(len--){ + uartPutc(' '); + printHex(*data++); + } + uartPutc('\r'); + uartPutc('\n'); +} + +#endif diff --git a/firmware/usbdrv/oddebug.h b/firmware/usbdrv/oddebug.h new file mode 100644 index 000000000..28d5f947b --- /dev/null +++ b/firmware/usbdrv/oddebug.h @@ -0,0 +1,110 @@ +/* Name: oddebug.h + * Project: AVR library + * Author: Christian Starkjohann + * Creation Date: 2005-01-16 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: oddebug.h 52 2005-04-12 16:57:29Z cs $ + */ + +#ifndef __oddebug_h_included__ +#define __oddebug_h_included__ + +#include + +/* +General Description: +This module implements a function for debug logs on the serial line of the +AVR microcontroller. Debugging can be configured with the define +'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging +calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is +2, DBG1 and DBG2 logs will be printed. + +A debug log consists of a label ('prefix') to indicate which debug log created +the output and a memory block to dump in hex ('data' and 'len'). +*/ + + +#ifndef F_CPU +# define F_CPU 12000000 /* 12 MHz */ +#endif + +#ifndef uchar +# define uchar unsigned char +#endif + +#if DEBUG_LEVEL > 0 && !defined TXEN /* no UART in device */ +# warning "Debugging disabled because device has no UART" +# undef DEBUG_LEVEL +#endif + +#ifndef DEBUG_LEVEL +# define DEBUG_LEVEL 0 +#endif + +/* ------------------------------------------------------------------------- */ + +#if DEBUG_LEVEL > 0 +# define DBG1(prefix, data, len) odDebug(prefix, data, len) +#else +# define DBG1(prefix, data, len) +#endif + +#if DEBUG_LEVEL > 1 +# define DBG2(prefix, data, len) odDebug(prefix, data, len) +#else +# define DBG2(prefix, data, len) +#endif + +/* ------------------------------------------------------------------------- */ + +#if DEBUG_LEVEL > 0 +extern void odDebug(uchar prefix, uchar *data, uchar len); + +/* Try to find our control registers; ATMEL likes to rename these */ + +#if defined UBRR +# define ODDBG_UBRR UBRR +#elif defined UBRRL +# define ODDBG_UBRR UBRRL +#elif defined UBRR1 +# define ODDBG_UBRR UBRR1 +#elif defined UBRR1L +# define ODDBG_UBRR UBRR1L +#endif + +#if defined UCR +# define ODDBG_UCR UCR +#elif defined UCSRB +# define ODDBG_UCR UCSRB +#elif defined UCSR1B +# define ODDBG_UCR UCSR1B +#endif + +#if defined USR +# define ODDBG_USR USR +#elif defined UCSRA +# define ODDBG_USR UCSRA +#elif defined UCSR1A +# define ODDBG_USR UCSR1A +#endif + +#if defined UDR +# define ODDBG_UDR UDR +#elif defined UDR1 +# define ODDBG_UDR UDR1 +#endif + +static inline void odDebugInit(void) +{ + ODDBG_UCR |= (1<wZ3`fsF5Rk5bX4EmFcO3L!cTR9k2g0Iav$SynZ}ZxJD6(d4DN17- zQFv+3}KS-^x}6^tCP%N6Hl;qbS~vzDY8 T&$HEr-BV!}`f1{v< +#include +#include "usbdrv.h" +#include "oddebug.h" + +/* +General Description: +This module implements the C-part of the USB driver. See usbdrv.h for a +documentation of the entire driver. +*/ + +/* ------------------------------------------------------------------------- */ + +/* raw USB registers / interface to assembler code: */ +/* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */ +static char usbRxBuf[2][USB_BUFSIZE];/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */ +uchar usbDeviceId; /* assigned during enumeration, defaults to 0 */ +uchar usbInputBuf; /* ptr to raw buffer used for receiving */ +uchar usbAppBuf; /* ptr to raw buffer passed to app for processing */ +volatile char usbRxLen; /* = 0; number of bytes in usbAppBuf; 0 means free */ +uchar usbCurrentTok; /* last token received */ +uchar usbRxToken; /* token for data we received */ +uchar usbMsgLen = 0xff; /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */ +volatile char usbTxLen = -1; /* number of bytes to transmit with next IN token */ +uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT +/* uchar usbRxEndp; endpoint which was addressed (1 bit in MSB) [not impl] */ +volatile char usbTxLen1 = -1; /* TX count for endpoint 1 */ +uchar usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */ +#endif +uchar usbAckBuf[1] = {USBPID_ACK}; /* transmit buffer for ack tokens */ +uchar usbNakBuf[1] = {USBPID_NAK}; /* transmit buffer for nak tokens */ + +/* USB status registers / not shared with asm code */ +uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */ +static uchar usbMsgFlags; /* flag values see below */ +static uchar usbNewDeviceId; /* = 0; device ID which should be set after status phase */ +static uchar usbIsReset; /* = 0; USB bus is in reset phase */ + +#define USB_FLG_TX_PACKET (1<<0) +/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */ +#define USB_FLG_MSGPTR_IS_ROM (1<<6) +#define USB_FLG_USE_DEFAULT_RW (1<<7) + +/* +optimizing hints: +- do not post/pre inc/dec integer values in operations +- assign value of PRG_RDB() to register variables and don't use side effects in arg +- use narrow scope for variables which should be in X/Y/Z register +- assign char sized expressions to variables to force 8 bit arithmetics +*/ + +/* ------------------------------------------------------------------------- */ + +static char usbDescrDevice[] PROGMEM = { /* USB device descriptor */ + 18, /* sizeof(usbDescrDevice): length of descriptor in bytes */ + 1, /* descriptor type */ + 0x01, 0x01, /* USB version supported */ + USB_CFG_DEVICE_CLASS, + USB_CFG_DEVICE_SUBCLASS, + 0, /* protocol */ + 8, /* max packet size */ + USB_CFG_VENDOR_ID, /* 2 bytes */ + USB_CFG_DEVICE_ID, /* 2 bytes */ + USB_CFG_DEVICE_VERSION, /* 2 bytes */ +#if USB_CFG_VENDOR_NAME_LEN + 1, /* manufacturer string index */ +#else + 0, /* manufacturer string index */ +#endif +#if USB_CFG_DEVICE_NAME_LEN + 2, /* product string index */ +#else + 0, /* product string index */ +#endif + 0, /* serial number string index */ + 1, /* number of configurations */ +}; + +static char usbDescrConfig[] PROGMEM = { /* USB configuration descriptor */ + 9, /* sizeof(usbDescrConfig): length of descriptor in bytes */ + 2, /* descriptor type */ + (18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT), 0, /* total length of data returned (including inlined descriptors) */ + 1, /* number of interfaces in this configuration */ + 1, /* index of this configuration */ + 0, /* configuration name string index */ +#if USB_CFG_IS_SELF_POWERED + USBATTR_SELFPOWER, /* attributes */ +#else + USBATTR_BUSPOWER, /* attributes */ +#endif + USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ +/* interface descriptor follows inline: */ + 9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ + 4, /* descriptor type */ + 0, /* index of this interface */ + 0, /* alternate setting for this interface */ + USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ + USB_CFG_INTERFACE_CLASS, + USB_CFG_INTERFACE_SUBCLASS, + USB_CFG_INTERFACE_PROTOCOL, + 0, /* string index for interface */ +#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ + 7, /* sizeof(usbDescrEndpoint) */ + 5, /* descriptor type = endpoint */ + 0x81, /* IN endpoint number 1 */ + 0x03, /* attrib: Interrupt endpoint */ + 8, 0, /* maximum packet size */ + USB_CFG_INTR_POLL_INTERVAL, /* in ms */ +#endif +}; + +static char usbDescrString0[] PROGMEM = { /* language descriptor */ + 4, /* sizeof(usbDescrString0): length of descriptor in bytes */ + 3, /* descriptor type */ + 0x09, 0x04, /* language index (0x0409 = US-English) */ +}; + +#if USB_CFG_VENDOR_NAME_LEN +static int usbDescrString1[] PROGMEM = { + (2 * USB_CFG_VENDOR_NAME_LEN + 2) | (3<<8), /* length of descriptor in bytes | descriptor type */ + USB_CFG_VENDOR_NAME +}; +#endif +#if USB_CFG_DEVICE_NAME_LEN +static int usbDescrString2[] PROGMEM = { + (2 * USB_CFG_DEVICE_NAME_LEN + 2) | (3<<8), /* length of descriptor in bytes | descriptor type */ + USB_CFG_DEVICE_NAME +}; +#endif + +/* We don't use prog_int or prog_int16_t for compatibility with various libc + * versions. Here's an other compatibility hack: + */ +#ifndef PRG_RDB +#define PRG_RDB(addr) pgm_read_byte(addr) +#endif + +typedef union{ + unsigned word; + uchar *ptr; + uchar bytes[2]; +}converter_t; +/* We use this union to do type conversions. This is better optimized than + * type casts in gcc 3.4.3 and much better than using bit shifts to build + * ints from chars. Byte ordering is not a problem on an 8 bit platform. + */ + +/* ------------------------------------------------------------------------- */ + +#if USB_CFG_HAVE_INTRIN_ENDPOINT +static uchar usbTxPacketCnt1; + +void usbSetInterrupt(uchar *data, uchar len) +{ +uchar *p, i; +converter_t crc; + + if(len > 7) + len = 7; + i = USBPID_DATA1; + if(usbTxPacketCnt1 & 1) + i = USBPID_DATA0; + if(usbTxLen1 < 0){ /* packet buffer was empty */ + usbTxPacketCnt1++; + }else{ + usbTxLen1 = -1; /* avoid sending incomplete interrupt data */ + } + p = usbTxBuf1; + *p++ = i; + for(i=len;i--;) + *p++ = *data++; + crc.word = usbCrc16(&usbTxBuf1[1], len); + usbTxBuf1[len + 1] = crc.bytes[0]; + usbTxBuf1[len + 2] = crc.bytes[1]; + usbTxLen1 = len + 4; /* len must be given including sync byte */ +} +#endif + +static void usbWrite(uchar *data, uchar len) +{ +#if USB_CFG_IMPLEMENT_FN_WRITE + if(!(usbMsgFlags & USB_FLG_USE_DEFAULT_RW)){ + if(usbFunctionWrite(data, len) == 0xff){ /* an error occurred */ + /* usbMsgLen = 0xff; cancel potentially pending ACK [has been done by ASM module when OUT token arrived] */ + usbTxBuf[0] = USBPID_STALL; + usbTxLen = 2; /* length including sync byte */ + return; + } + } +#endif + usbMsgLen = 0; /* send zero-sized block as ACK */ + usbMsgFlags = 0; /* start with a DATA1 package */ +} + +static uchar usbRead(uchar *data, uchar len) +{ +#if USB_CFG_IMPLEMENT_FN_READ + if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){ +#endif + uchar i = len, *r = usbMsgPtr; + if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */ + while(i--){ + char c = PRG_RDB(r); /* assign to char size variable to enforce byte ops */ + *data++ = c; + r++; + } + }else{ /* RAM data */ + while(i--) + *data++ = *r++; + } + usbMsgPtr = r; + return len; +#if USB_CFG_IMPLEMENT_FN_READ + }else{ + if(len != 0) /* don't bother app with 0 sized reads */ + return usbFunctionRead(data, len); + return 0; + } +#endif +} + +/* Don't make this function static to avoid inlining. + * The entire function would become too large and exceed the range of + * relative jumps. + */ +void usbProcessRx(uchar *data, uchar len) +{ +/* We use if() cascades because the compare is done byte-wise while switch() + * is int-based. The if() cascades are therefore more efficient. + */ + DBG2(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, len); + if(usbRxToken == (uchar)USBPID_SETUP){ + uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW; + if(len == 8){ /* Setup size must be always 8 bytes. Ignore otherwise. */ + uchar type = data[0] & (3 << 5); + if(type == USBRQ_TYPE_STANDARD << 5){ + uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */ + replyData[0] = 0; + if(data[1] == 0){/* GET_STATUS */ +#if USB_CFG_IS_SELF_POWERED + uchar recipient = data[0] & 0x1f; /* assign arith ops to variables to enforce byte size */ + if(recipient == USBRQ_RCPT_DEVICE) + replyData[0] = USB_CFG_IS_SELF_POWERED; +#endif + replyData[1] = 0; + replyLen = 2; + }else if(data[1] == 5){ /* SET_ADDRESS */ + usbNewDeviceId = data[2]; + }else if(data[1] == 6){ /* GET_DESCRIPTOR */ + flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW; + if(data[3] == 1){ /* descriptor type requested */ + replyLen = sizeof(usbDescrDevice); + replyData = (uchar *)usbDescrDevice; + }else if(data[3] == 2){ + replyLen = sizeof(usbDescrConfig); + replyData = (uchar *)usbDescrConfig; + }else if(data[3] == 3){ /* string descriptor */ + if(data[2] == 0){ /* descriptor index */ + replyLen = sizeof(usbDescrString0); + replyData = (uchar *)usbDescrString0; +#if USB_CFG_VENDOR_NAME_LEN + }else if(data[2] == 1){ + replyLen = sizeof(usbDescrString1); + replyData = (uchar *)usbDescrString1; +#endif +#if USB_CFG_DEVICE_NAME_LEN + }else if(data[2] == 2){ + replyLen = sizeof(usbDescrString2); + replyData = (uchar *)usbDescrString2; +#endif + } + } + }else if(data[1] == 8){ /* GET_CONFIGURATION */ + replyLen = 1; + replyData[0] = 1; /* config is always 1, no setConfig required */ + }else if(data[1] == 10){ /* GET_INTERFACE */ + replyLen = 1; +#if USB_CFG_HAVE_INTRIN_ENDPOINT + }else if(data[1] == 11){ /* SET_INTERFACE */ + usbTxPacketCnt1 = 0; /* reset data toggling for interrupt socket */ +#endif + }else{ + /* the following requests can be ignored, send default reply */ + /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */ + /* 9: SET_CONFIGURATION, 11: SET_INTERFACE, 12: SYNCH_FRAME */ + } + usbMsgPtr = replyData; + if(!data[7] && replyLen > data[6]) /* max length is in data[7]:data[6] */ + replyLen = data[6]; + }else{ /* not a standard request -- must be vendor or class request */ +#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE + uchar len; + replyLen = data[6]; /* if this is an OUT operation, the next token will reset usbMsgLen */ + if((len = usbFunctionSetup(data)) != 0xff){ + replyLen = len; + }else{ + flags = 0; /* we have no valid msg, use read/write functions */ + } +#else + replyLen = usbFunctionSetup(data); +#endif + } + } + usbMsgLen = replyLen; + usbMsgFlags = flags; + }else{ /* out request */ + usbWrite(data, len); + } +} + +/* ------------------------------------------------------------------------- */ + +static void usbBuildTxBlock(void) +{ +uchar wantLen, len, txLen, x; +converter_t crc; + + x = USBPID_DATA1; + if(usbMsgFlags & USB_FLG_TX_PACKET) + x = USBPID_DATA0; + usbMsgFlags++; + usbTxBuf[0] = x; + wantLen = usbMsgLen; + if(wantLen > 8) + wantLen = 8; + usbMsgLen -= wantLen; + len = usbRead(usbTxBuf + 1, wantLen); + if(len <= 8){ /* valid data packet */ + crc.word = usbCrc16(&usbTxBuf[1], len); + usbTxBuf[len + 1] = crc.bytes[0]; + usbTxBuf[len + 2] = crc.bytes[1]; + txLen = len + 4; /* length including sync byte */ + if(len < 8) /* a partial package identifies end of message */ + usbMsgLen = 0xff; + }else{ + usbTxBuf[0] = USBPID_STALL; + txLen = 2; /* length including sync byte */ + usbMsgLen = 0xff; + } + usbTxLen = txLen; + DBG2(0x20, usbTxBuf, txLen-1); +} + +static inline uchar isNotSE0(void) +{ +uchar rval; +/* We want to do + * return (USBIN & USBMASK); + * here, but the compiler does int-expansion acrobatics. + * We can avoid this by assigning to a char-sized variable. + */ + rval = USBIN & USBMASK; + return rval; +} + +/* ------------------------------------------------------------------------- */ + +void usbPoll(void) +{ +uchar len; + + if((len = usbRxLen) > 0){ +/* We could check CRC16 here -- but ACK has already been sent anyway. If you + * need data integrity checks with this driver, check the CRC in your app + * code and report errors back to the host. Since the ACK was already sent, + * retries must be handled on application level. + * unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3); + */ + len -= 3; /* remove PID and CRC */ + if(len < 128){ + usbProcessRx((uchar *)(unsigned)(usbAppBuf + 1), len); + } + usbRxLen = 0; /* mark rx buffer as available */ + } + if(usbTxLen < 0){ /* TX system is idle */ + if(usbMsgLen != 0xff){ + usbBuildTxBlock(); + }else if(usbNewDeviceId){ + usbDeviceId = usbNewDeviceId; + DBG1(1, &usbNewDeviceId, 1); + usbNewDeviceId = 0; + } + } + if(isNotSE0()){ /* SE0 state */ + usbIsReset = 0; + }else{ + /* check whether SE0 lasts for more than 2.5us (3.75 bit times) */ + if(!usbIsReset){ + uchar i; + for(i=100;i;i--){ + if(isNotSE0()) + goto notUsbReset; + } + usbIsReset = 1; + usbDeviceId = 0; + usbNewDeviceId = 0; + DBG1(0xff, 0, 0); +notUsbReset:; + } + } +} + +/* ------------------------------------------------------------------------- */ + +void usbInit(void) +{ + usbInputBuf = (uchar)usbRxBuf[0]; + usbAppBuf = (uchar)usbRxBuf[1]; +#if USB_INTR_CFG_SET != 0 + USB_INTR_CFG |= USB_INTR_CFG_SET; +#endif +#if USB_INTR_CFG_CLR != 0 + USB_INTR_CFG &= ~(USB_INTR_CFG_CLR); +#endif + USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); +} + +/* ------------------------------------------------------------------------- */ diff --git a/firmware/usbdrv/usbdrv.h b/firmware/usbdrv/usbdrv.h new file mode 100644 index 000000000..66be5ed2e --- /dev/null +++ b/firmware/usbdrv/usbdrv.h @@ -0,0 +1,286 @@ +/* Name: usbdrv.h + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usbdrv.h 52 2005-04-12 16:57:29Z cs $ + */ + +#ifndef __usbdrv_h_included__ +#define __usbdrv_h_included__ +#include "usbconfig.h" + +/* +Hardware Prerequisites: +======================= +USB lines D+ and D- MUST be wired to the same I/O port. Line D- MUST be wired +to bit number 0. D+ must also be connected to INT0. D- requires a pullup of +1.5k to +3.5V (and the device must be powered at 3.5V) to identify as +low-speed USB device. A pullup of 1M SHOULD be connected from D+ to +3.5V to +prevent interference when no USB master is connected. We use D+ as interrupt +source and not D- because it does not trigger on keep-alive and RESET states. + +Please adapt the values in usbconfig.h according to your hardware! + +The device MUST be clocked at 12 MHz. This is more than the 10 MHz allowed by +an AT90S2313 powered at 4.5V. However, if the supply voltage to maximum clock +relation is interpolated linearly, an ATtiny2313 meets the requirement by +specification. In practice, the AT90S2313 can be overclocked and works well. + + +Limitations: +============ +Compiling: +The bss segment of the driver must be in the first 256 bytes of the address +space because byte wide variables are used as pointers for efficiency reasons. +This is not a problem on devices with 128 byte RAM since the entire RAM +meets this condition. For larger devices please link usbdrv first. + +Robustness with respect to communication errors: +The driver assumes error-free communication. It DOES check for errors in +the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte, +token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due +to timing constraints: We must start sending a reply within 7 bit times. +Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU +performance does not permit that. The driver does not check Data0/Data1 +toggling, but application software can implement the check. + +Sampling jitter: +The driver guarantees a sampling window of 1/2 bit. The USB spec requires +that the receiver has at most 1/4 bit sampling window. The 1/2 bit window +should still work reliably enough because we work at low speed. If you want +to meet the spec, define the macro "USB_CFG_SAMPLE_EXACT" to 1 in usbconfig.h. +This will unroll a loop which results in bigger code size. + +Input characteristics: +Since no differential receiver circuit is used, electrical interference +robustness may suffer. The driver samples only one of the data lines with +an ordinary I/O pin's input characteristics. However, since this is only a +low speed USB implementation and the specification allows for 8 times the +bit rate over the same hardware, we should be on the safe side. Even the spec +requires detection of asymmetric states at high bit rate for SE0 detection. + +Number of endpoints: +The driver supports up to two endpoints: One control endpoint (endpoint 0) and +one interrupt-in endpoint (endpoint 1) where the device can send interrupt +data to the host. Endpoint 1 is only compiled in if +USB_CFG_HAVE_INTRIN_ENDPOINT is defined to 1 in usbconfig.h. + +Maximum data payload: +Data payload of control in and out transfers may be up to 255 bytes. In order +to accept payload data of out transfers, you need to implement +'usbFunctionWrite()'. + +USB Suspend Mode supply current: +The USB standard limits power consumption to 500uA when the bus is in suspend +mode. This is not a problem for self-powered devices since they don't need +bus power anyway. Bus-powered devices can achieve this only by putting the +CPU in sleep mode. The driver does not implement suspend handling by itself. +However, the application may implement activity monitoring and wakeup from +sleep. The host sends regular SE0 states on the bus to keep it active. These +SE0 states can be detected by wiring the INT1 pin to D+. It is not necessary +to enable the interrupt, checking the interrupt pending flag should suffice. +Before entering sleep mode, the application should enable INT1 for a wakeup +on the next bus activity. + +Operation without an USB master: +The driver behaves neutral without connection to an USB master if D- reads +as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M) +pullup resistor on D+. If D- becomes statically 0, the driver may block in +the interrupt routine. + +Interrupt latency: +The application must ensure that the USB interrupt is not disabled for more +than 20 cycles. + +Maximum interrupt duration / CPU cycle consumption: +The driver handles all USB communication during the interrupt service +routine. The routine will not return before an entire USB message is received +and the reply is sent. This may be up to ca. 1200 cycles = 100us if the host +conforms to the standard. The driver will consume CPU cycles for all USB +messages, even if they address an other (low-speed) device on the same bus. + +*/ + +/* ------------------------------------------------------------------------- */ +/* --------------------------- Module Interface ---------------------------- */ +/* ------------------------------------------------------------------------- */ + +#ifndef __ASSEMBLER__ + +#ifndef uchar +#define uchar unsigned char +#endif + +#if USB_CFG_HAVE_INTRIN_ENDPOINT +void usbSetInterrupt(uchar *data, uchar len); +/* This function sets the message which will be sent during the next interrupt + * IN transfer. The message is copied to an internal buffer and must not exceed + * a length of 7 bytes. The message may be 0 bytes long just to indicate the + * interrupt status to the host. + * If you need to transfer more bytes, use a control read after the interrupt. + */ +#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */ + +extern void usbInit(void); +/* This function must be called before interrupts are enabled and the main + * loop is entered. + */ +extern void usbPoll(void); +/* This function must be called at regular intervals from the main loop. + * Maximum delay between calls is somewhat less than 50ms (USB timeout between + * packages of a message). + */ +extern uchar *usbMsgPtr; +/* This variable may be used to pass transmit data to the driver from the + * implementation of usbFunctionWrite(). It is also used internally by the + * driver for standard control requests. + */ +extern uchar usbFunctionSetup(uchar data[8]); +/* This function is called for all setup requests which are not of type + * "Standard" (in practice: class and vendor requests). The 8 bytes setup + * data is passed in 'data'. Data for control-out transfers is passed to the + * application in separate calls to usbFunctionWrite() (unless you have turned + * this option off). You should store the setup context in global/static + * variables to have it available in usbFunctionWrite(). Data for control-in + * transfers can be provided in two ways: (1) immediately as a result of + * usbFunctionSetup() or (2) on demand of the driver in calls to the separate + * function usbFunctionRead() (if enabled). For (1) write the data to a static + * buffer, set the global variable 'usbMsgPtr' to this buffer and return the + * data length (may be 0). To implement (2), simply return 0xff (== -1) in + * usbFunctionSetup(). The driver will call usbFunctionRead() when data is + * needed. You may use 'usbMsgPtr' to save your own status in this case. + * The data passed in 'data' has the following content (see USB 1.1 spec): + * struct usbControlData{ + * uchar requestType; //[0] + * uchar request; //[1] + * unsigned value; //[2], [3] + * unsigned index; //[4], [5] + * unsigned length; //[6], [7] + * }; + */ +#if USB_CFG_IMPLEMENT_FN_WRITE +extern uchar usbFunctionWrite(uchar *data, uchar len); +/* This function is called by the driver to provide a control transfer's + * payload data (control-out). It is called in chunks of up to 8 bytes. The + * total count provided in the current control transfer can be obtained from + * the 'length' property in the setup data. If an error occurred during + * processing, return 0xff (== -1). The driver will answer the entire transfer + * with a STALL token in this case. Otherwise return any number which is not + * 0xff. NOTE: Only the return value of the LAST usbFunctionWrite() call + * (the one immediately before the status phase) is used. + */ +#endif /* USB_CFG_IMPLEMENT_FN_WRITE */ +#if USB_CFG_IMPLEMENT_FN_READ +extern uchar usbFunctionRead(uchar *data, uchar len); +/* This function is called by the driver to ask the application for a control + * transfer's payload data (control-in). You should supply up to 'len' bytes of + * data in this chunk. 'len' will be 8 bytes for all but the last chunk. If + * you return less than 8 bytes, the control transfer ends. If you return an + * invalid value (e.g. -1), the driver sends a STALL token. + */ +#endif /* USB_CFG_IMPLEMENT_FN_READ */ +extern unsigned usbCrc16(uchar *data, uchar len); +/* This function calculates the binary complement of the data CRC used in + * USB data packets. The value is used to build raw transmit packets. + * You may want to use this function for data checksums. + */ + +#endif /* __ASSEMBLER__ */ + +/* ------------------------------------------------------------------------- */ +/* ------------------------- Constant definitions -------------------------- */ +/* ------------------------------------------------------------------------- */ + +/* I/O definitions for assembler module */ +#define USBOUT USB_CFG_IOPORT /* output port for USB bits */ +#ifdef __ASSEMBLER__ +#define USBIN (USB_CFG_IOPORT - 2) /* input port for USB bits */ +#define USBDDR (USB_CFG_IOPORT - 1) /* data direction for USB bits */ +#else +#define USBIN (*(&USB_CFG_IOPORT - 2)) /* input port for USB bits */ +#define USBDDR (*(&USB_CFG_IOPORT - 1)) /* data direction for USB bits */ +#endif +#if USB_CFG_DMINUS_BIT != 0 +# error "USB_CFG_DMINUS_BIT MUST be 0!" +#endif +#define USBMINUS 0 /* D- MUST be on bit 0 */ +#define USBIDLE 0x01 /* value representing J state */ +#define USBMASK ((1<-yb+Q@)>1Grk?pdbwkz%KGP`ZTh<2$I z5RjHig@h;=6CZyxNP^Ku211Z1GDr-8KRQGu5UWlBTQTDLeKU93al;Q!d+zzpx!*na z%zf=EODmUoJRaeQN30gZ9->|$d@zq%gxR7{v1EYWg{= zzgO40rgs(W*Sl-*wRI)Wn2})p-CT{|ez4Tj)A9qq*j|arTE{2tiAmNvv|5ZEC55J{ zy>X54LbFNh3Vu77w$`8%)lwrCZ}0r_{<%MOB4_8_lD@Y??BTaJlk96n@=d z<74B^y8*4PWW^sfM#4B#77ZLW?UmhU?ERe_j_lQ059YpoTxX0G9@X27PD5PiE6bD` zL32U6eP8>bvO}S>fr+;`<{kYT>|#S%Yw35ofzc+kCo@{>Df4QtcJ1jd@97F&9yGx; zpsl4R^`5dEEsdV8pfPw0t5mR`GjP63J zj;lYpxhWN151UeL+u$HoX$<>Q%BGa?uTLh0KcU9!o0KMhZ8#OS^ZmcJ7&P9CJW1z$ zcsxfsFwUKs0_;@E-uDZH7==5OFFEWR1${*N=&~e+T<&pBzK76@6ugF(sNhYKn8xAF zmDnkXysCTf#vp{%tCS_pOL`x6WFky8}R?Bt&D$BnjedZsF75Wj@p3C-sh0pzT`UilyZ;o#P_>a2~2BJsrLkoAb!Zle-bLwwiGpf8q9l`5o9xup z@eMX(S#vCsipFEls?n5HT(vc=JvNw9Nq0D_l~i+rfndC`(as~YFH9t45$=y!tVYV` zxf4_=Vf!m%QR@>|#1hRZIdE~asw%M*3bWrGA0Jl;_uq$$$GgEhTKQB28U@t()A-)9VSiUuvp^Ot>lW`bv9m+W6 zHz@gIU`;6F#Q#8jGtfXr;cob5+IT#%j87((YciV{^>e-bF1*}@D~U_&JV6=f_pT*I z9{h_M8Ry=;;KDIttQ+Me7yo5o?gfl!L&LowK7hvIA10Rh-<6pA_#v@e^JB!awohI0 zUSKEx7r;(_4cI#iNg!u{3uSF*fk#Mu8Q58$@5z@xGS?Z$*`V}E3?p(-lyheCBqoRN XRvzl46a(i=Jd2!CJ3fbarj7pvq$)Gr literal 0 HcmV?d00001 diff --git a/firmware/usbdrv/usbdrvasm.S b/firmware/usbdrv/usbdrvasm.S new file mode 100644 index 000000000..d46ef92eb --- /dev/null +++ b/firmware/usbdrv/usbdrvasm.S @@ -0,0 +1,648 @@ +/* Name: usbdrvasm.S + * Project: AVR USB driver + * Author: Christian Starkjohann + * Creation Date: 2004-12-29 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: Proprietary, free under certain conditions. See Documentation. + * This Revision: $Id: usbdrvasm.S 52 2005-04-12 16:57:29Z cs $ + */ + +/* +General Description: +This module implements the assembler part of the USB driver. See usbdrv.h +for a description of the entire driver. +Since almost all of this code is timing critical, don't change unless you +really know what you are doing! Many parts require not only a maximum number +of CPU cycles, but even an exact number of cycles! +*/ + +/* configs for io.h */ +#define __SFR_OFFSET 0 +#define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ + +#include /* for CPU I/O register definitions and vectors */ +#include "usbdrv.h" /* for common defs */ + + +/* register names */ +#define x1 r16 +#define x2 r17 +#define shift r18 +#define cnt r19 +#define x3 r20 +#define x4 r21 + +#define nop2 rjmp .+0 /* jump to next instruction */ + +.text + +.global SIG_INTERRUPT0 + .type SIG_INTERRUPT0, @function +SIG_INTERRUPT0: +;Software-receiver engine. Strict timing! Don't change unless you can preserve timing! +;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled +;max allowable interrupt latency: 32 cycles -> max 25 cycles interrupt disable +;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes +usbInterrupt: +;order of registers pushed: +;x1, SREG, x2, cnt, shift, [YH, YL, x3] + push x1 ;2 push only what is necessary to sync with edge ASAP + in x1, SREG ;1 + push x1 ;2 +;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] +;sync up with J to K edge during sync pattern -- use fastest possible loops +;first part has no timeout because it waits for IDLE or SE1 (== disconnected) +#if !USB_CFG_SAMPLE_EXACT + ldi x1, 5 ;1 setup a timeout for waitForK +#endif +waitForJ: + sbis USBIN, USBMINUS ;1 wait for D- == 1 + rjmp waitForJ ;2 +#if USB_CFG_SAMPLE_EXACT +;The following code represents the unrolled loop in the else branch. It +;results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + sbis USBIN, USBMINUS + rjmp foundK + nop + nop2 +foundK: +#else +waitForK: + dec x1 ;1 + sbic USBIN, USBMINUS ;1 wait for D- == 0 + brne waitForK ;2 +#endif +;{2, 6} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] +;we have 1 bit time for setup purposes, then sample again: + push x2 ;2 + push cnt ;2 + push shift ;2 +shortcutEntry: + ldi cnt, 1 ;1 pre-init bit counter (-1 because no dec follows, -1 because 1 bit already sampled) + ldi x2, 1< 8 edge sync ended with D- == 0 +;now wait until SYNC byte is over. Wait for either 2 bits low (success) or 2 bits high (failure) +waitNoChange: + in x1, USBIN ;1 <-- sample, timing: edge + {2, 6} cycles + eor x2, x1 ;1 + sbrc x2, 0 ;1 | 2 + ldi cnt, 2 ;1 | 0 cnt = numBits - 1 (because dec follows) + mov x2, x1 ;1 + dec cnt ;1 + brne waitNoChange ;2 | 1 + sbrc x1, USBMINUS ;2 + rjmp sofError ;0 two consecutive "1" bits -> framing error +;start reading data, but don't check for bitstuffing because these are the +;first bits. Use the cycles for initialization instead. Note that we read and +;store the binary complement of the data stream because eor results in 1 for +;a change and 0 for no change. + in x1, USBIN ;1 <-- sample bit 0, timing: edge + {3, 7} cycles + eor x2, x1 ;1 + ror x2 ;1 + ldi shift, 0x7f ;1 The last bit of the sync pattern was a "no change" + ror shift ;1 + push YH ;2 -> 7 + in x2, USBIN ;1 <-- sample bit 1, timing: edge + {2, 6} cycles + eor x1, x2 ;1 + ror x1 ;1 + ror shift ;1 + push YL ;2 + lds YL, usbInputBuf ;2 -> 8 + in x1, USBIN ;1 <-- sample bit 2, timing: edge + {2, 6} cycles + eor x2, x1 ;1 + ror x2 ;1 + ror shift ;1 + ldi cnt, USB_BUFSIZE;1 + clr YH ;1 + push x3 ;2 -> 8 + in x2, USBIN ;1 <-- sample bit 3, timing: edge + {2, 6} cycles + eor x1, x2 ;1 + ror x1 ;1 + ror shift ;1 + ser x3 ;1 + nop ;1 + rjmp rxbit4 ;2 -> 8 + +shortcutToStart: ;{,43} into next frame: max 5.5 sync bits missed +#if !USB_CFG_SAMPLE_EXACT + ldi x1, 5 ;2 setup timeout +#endif +waitForJ1: + sbis USBIN, USBMINUS ;1 wait for D- == 1 + rjmp waitForJ1 ;2 +#if USB_CFG_SAMPLE_EXACT +;The following code represents the unrolled loop in the else branch. It +;results in a sampling window of 1/4 bit which meets the spec. + sbis USBIN, USBMINUS + rjmp foundK1 + sbis USBIN, USBMINUS + rjmp foundK1 + sbis USBIN, USBMINUS + rjmp foundK1 + nop + nop2 +foundK1: +#else +waitForK1: + dec x1 ;1 + sbic USBIN, USBMINUS ;1 wait for D- == 0 + brne waitForK1 ;2 +#endif + pop YH ;2 correct stack alignment + nop2 ;2 delay for the same time as the pushes in the original code + rjmp shortcutEntry ;2 + +; ################# receiver loop ################# +; extra jobs done during bit interval: +; bit 6: se0 check +; bit 7: or, store, clear +; bit 0: recover from delay [SE0 is unreliable here due to bit dribbling in hubs] +; bit 1: se0 check +; bit 2: se0 check +; bit 3: overflow check +; bit 4: se0 check +; bit 5: rjmp + +; stuffed* helpers have the functionality of a subroutine, but we can't afford +; the overhead of a call. We therefore need a separate routine for each caller +; which jumps back appropriately. + +stuffed5: ;1 for branch taken + in x2, USBIN ;1 <-- sample @ +1 + andi x2, USBMASK ;1 + breq se0a ;1 + andi x3, 0xc0 ;1 (0xff03 >> 2) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit6 ;2 + +stuffed6: ;1 for branch taken + in x1, USBIN ;1 <-- sample @ +1 + andi x1, USBMASK ;1 + breq se0a ;1 + andi x3, 0x81 ;1 (0xff03 >> 1) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit7 ;2 + +; This is somewhat special because it has to compensate for the delay in bit 7 +stuffed7: ;1 for branch taken + andi x1, USBMASK ;1 already sampled by caller + breq se0a ;1 + mov x2, x1 ;1 ensure correct NRZI sequence [we can save andi x3 here] + ori shift, 0xfc ;1 + in x1, USBIN ;1 <-- sample bit 0 + rjmp unstuffed7 ;2 + +stuffed0: ;1 for branch taken + in x1, USBIN ;1 <-- sample @ +1 + andi x1, USBMASK ;1 + breq se0a ;1 + andi x3, 0xfe ;1 (0xff03 >> 7) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit1 ;2 + +;----------------------------- +rxLoop: + brlo stuffed5 ;1 +rxbit6: + in x1, USBIN ;1 <-- sample bit 6 + andi x1, USBMASK ;1 + breq se0a ;1 + eor x2, x1 ;1 + ror x2 ;1 + ror shift ;1 + cpi shift, 4 ;1 + brlo stuffed6 ;1 +rxbit7: + in x2, USBIN ;1 <-- sample bit 7 + eor x1, x2 ;1 + ror x1 ;1 + ror shift ;1 + eor x3, shift ;1 x3 is 0 at bit locations we changed, 1 at others + st y+, x3 ;2 the eor above reconstructed modified bits and inverted rx data + ser x3 ;1 +rxbit0: + in x1, USBIN ;1 <-- sample bit 0 + cpi shift, 4 ;1 + brlo stuffed7 ;1 +unstuffed7: + eor x2, x1 ;1 + ror x2 ;1 + ror shift ;1 + cpi shift, 4 ;1 + brlo stuffed0 ;1 +rxbit1: + in x2, USBIN ;1 <-- sample bit 1 + andi x2, USBMASK ;1 +se0a: ; enlarge jump range to SE0 + breq se0 ;1 check for SE0 more often close to start of byte + eor x1, x2 ;1 + ror x1 ;1 + ror shift ;1 + cpi shift, 4 ;1 + brlo stuffed1 ;1 +rxbit2: + in x1, USBIN ;1 <-- sample bit 2 + andi x1, USBMASK ;1 + breq se0 ;1 + eor x2, x1 ;1 + ror x2 ;1 + ror shift ;1 + cpi shift, 4 ;1 + brlo stuffed2 ;1 +rxbit3: + in x2, USBIN ;1 <-- sample bit 3 + eor x1, x2 ;1 + ror x1 ;1 + ror shift ;1 + dec cnt ;1 check for buffer overflow + breq overflow ;1 + cpi shift, 4 ;1 + brlo stuffed3 ;1 +rxbit4: + in x1, USBIN ;1 <-- sample bit 4 + andi x1, USBMASK ;1 + breq se0 ;1 + eor x2, x1 ;1 + ror x2 ;1 + ror shift ;1 + cpi shift, 4 ;1 + brlo stuffed4 ;1 +rxbit5: + in x2, USBIN ;1 <-- sample bit 5 + eor x1, x2 ;1 + ror x1 ;1 + ror shift ;1 + cpi shift, 4 ;1 + rjmp rxLoop ;2 +;----------------------------- + +stuffed1: ;1 for branch taken + in x2, USBIN ;1 <-- sample @ +1 + andi x2, USBMASK ;1 + breq se0 ;1 + andi x3, 0xfc ;1 (0xff03 >> 6) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit2 ;2 + +stuffed2: ;1 for branch taken + in x1, USBIN ;1 <-- sample @ +1 + andi x1, USBMASK ;1 + breq se0 ;1 + andi x3, 0xf8 ;1 (0xff03 >> 5) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit3 ;2 + +stuffed3: ;1 for branch taken + in x2, USBIN ;1 <-- sample @ +1 + andi x2, USBMASK ;1 + breq se0 ;1 + andi x3, 0xf0 ;1 (0xff03 >> 4) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit4 ;2 + +stuffed4: ;1 for branch taken + in x1, USBIN ;1 <-- sample @ +1 + andi x1, USBMASK ;1 + breq se0 ;1 + andi x3, 0xe0 ;1 (0xff03 >> 3) & 0xff + ori shift, 0xfc ;1 + rjmp rxbit5 ;2 + +;################ end receiver loop ############### + +overflow: ; ignore package if buffer overflow + rjmp rxDoReturn ; enlarge jump range + +;This is the only non-error exit point for the software receiver loop +;{4, 20} cycles after start of SE0, typically {10, 18} after SE0 start = {-6, 2} from end of SE0 +;next sync starts {16,} cycles after SE0 -> worst case start: +4 from next sync start +;we don't check any CRCs here because there is no time left. +se0: ;{-6, 2} from end of SE0 / {,4} into next frame + mov cnt, YL ;1 assume buffer in lower 256 bytes of memory + lds YL, usbInputBuf ;2 reposition to buffer start + sub cnt, YL ;1 length of message + ldi x1, 1< 19 = {13, 21} from SE0 end + cpi x1, USBPID_OUT ;1 + breq isSetupOrOut ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame + cpi x1, USBPID_IN ;1 + breq handleIn ;1 + cpi x1, USBPID_DATA0 ;1 + breq isData ;1 + cpi x1, USBPID_DATA1 ;1 + brne rxDoReturn ;1 ignore all other PIDs +isData: + lds x2, usbCurrentTok ;2 + tst x2 ;1 + breq rxDoReturn ;1 for other device or spontaneous data -- ignore + lds x1, usbRxLen ;2 + cpi x1, 0 ;1 + brne sendNakAndReti ;1 no buffer space available / {30, 38} from SE0 end + sts usbRxLen, cnt ;2 store received data, swap buffers + sts usbRxToken, x2 ;2 + lds x1, usbAppBuf ;2 + sts usbAppBuf, YL ;2 + sts usbInputBuf, x1 ;2 buffers now swapped + rjmp sendAckAndReti ;2 -> {42, 50} from SE0 end + +handleIn: ; {18, 26} from SE0 end + cp x2, shift ;1 shift contains our device ID + brne rxDoReturn ;1 other device +#if USB_CFG_HAVE_INTRIN_ENDPOINT + sbrc x3, 7 ;2 + rjmp handleIn1 ;0 +#endif + lds cnt, usbTxLen ;2 + cpi cnt, -1 ;1 + breq sendNakAndReti ;1 -> {27, 35} from SE0 end + ldi x1, -1 ;1 + sts usbTxLen, x1 ;2 buffer is now free + ldi YL, lo8(usbTxBuf) ;1 + ldi YH, hi8(usbTxBuf) ;1 + rjmp usbSendAndReti ;2 -> {34, 43} from SE0 end + +; Comment about when to set usbTxLen to -1: +; We should set it back to -1 when we receive the ACK from the host. This would +; be simple to implement: One static variable which stores whether the last +; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the +; ACK. However, we set it back to -1 immediately when we send the package, +; assuming that no error occurs and the host sends an ACK. We save one byte +; RAM this way and avoid potential problems with endless retries. The rest of +; the driver assumes error-free transfers anyway. + +otherOutOrSetup: + clr x1 + sts usbCurrentTok, x1 +rxDoReturn: + pop x3 ;2 + pop YL ;2 + pop YH ;2 + rjmp sofError ;2 + +isSetupOrOut: ; we must be fast here -- a data package may follow / {,24} into next frame + cp x2, shift ;1 shift contains our device ID + brne otherOutOrSetup ;1 other device -- ignore + sts usbCurrentTok, x1 ;2 +#if 0 /* we implement only one rx endpoint */ + sts usbRxEndp, x3 ;2 only stored if we may have to distinguish endpoints +#endif +;A transmission can still have data in the output buffer while we receive a +;SETUP package with an IN phase. To avoid that the old data is sent as a reply, +;we abort transmission. ### This mechanism assumes that NO OUT OR SETUP package +;is ever sent to endpoint 1. We would abort transmission for endpoint 0 +;in this case. + ldi x1, -1 ;1 + sts usbMsgLen, x1 ;2 + sts usbTxLen, x1 ;2 abort transmission + pop x3 ;2 + pop YL ;2 + in x1, USB_INTR_PENDING;1 + sbrc x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame + rjmp shortcutToStart ;2 save the pops and pushes -- a new interrupt is aready pending +;If the jump above was not taken, we can be at {,2} into the next frame here + pop YH ;2 +sofError: ; error in start of frame -- ignore frame + ldi x1, 1< {,21} into next frame -> up to 3 sync bits missed + + +sendNakAndReti: ; 21 cycles until SOP + ldi YL, lo8(usbNakBuf) ;1 + ldi YH, hi8(usbNakBuf) ;1 + rjmp usbSendToken ;2 + +sendAckAndReti: ; 19 cycles until SOP + ldi YL, lo8(usbAckBuf) ;1 + ldi YH, hi8(usbAckBuf) ;1 +usbSendToken: + ldi cnt, 2 ;1 +;;;;rjmp usbSendAndReti fallthrough + +; USB spec says: +; idle = J +; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 +; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 +; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) + +;usbSend: +;pointer to data in 'Y' +;number of bytes in 'cnt' +;uses: x1...x4, shift, cnt, Y +usbSendAndReti: ; SOP starts 16 cycles after call + push x4 ;2 + in x1, USBOUT ;1 + cbr x1, USBMASK ;1 mask out data bits + ori x1, USBIDLE ;1 idle + out USBOUT, x1 ;1 prepare idle state + ldi x4, USBMASK ;1 exor mask + in x2, USBDDR ;1 + ori x2, USBMASK ;1 set both pins to output + out USBDDR, x2 ;1 <-- acquire bus now +; need not init x2 (bitstuff history) because sync starts with 0 + ldi shift, 0x80 ;1 sync byte is first byte sent + rjmp txLoop ;2 -> 13 + 3 = 16 cycles until SOP + +#if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */ +handleIn1: + lds cnt, usbTxLen1 + cpi cnt, -1 + breq sendNakAndReti + ldi x1, -1 + sts usbTxLen1, x1 + ldi YL, lo8(usbTxBuf1) + ldi YH, hi8(usbTxBuf1) + rjmp usbSendAndReti +#endif + +bitstuff0: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + out USBOUT, x1 ;1 <-- out + rjmp didStuff0 ;2 branch back 2 cycles earlier +bitstuff1: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + sec ;1 set carry so that brsh will not jump + out USBOUT, x1 ;1 <-- out + rjmp didStuff1 ;2 jump back 1 cycle earler +bitstuff2: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + rjmp didStuff2 ;2 jump back 3 cycles earlier and do out +bitstuff3: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + rjmp didStuff3 ;2 jump back earlier + +txLoop: + sbrs shift, 0 ;1 + eor x1, x4 ;1 + out USBOUT, x1 ;1 <-- out + ror shift ;1 + ror x2 ;1 +didStuff0: + cpi x2, 0xfc ;1 + brsh bitstuff0 ;1 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + ror shift ;1 + out USBOUT, x1 ;1 <-- out + ror x2 ;1 + cpi x2, 0xfc ;1 +didStuff1: + brsh bitstuff1 ;1 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + ror shift ;1 + ror x2 ;1 +didStuff2: + out USBOUT, x1 ;1 <-- out + cpi x2, 0xfc ;1 + brsh bitstuff2 ;1 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + ror shift ;1 + ror x2 ;1 +didStuff3: + cpi x2, 0xfc ;1 + out USBOUT, x1 ;1 <-- out + brsh bitstuff3 ;1 + nop2 ;2 + ld x3, y+ ;2 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + out USBOUT, x1 ;1 <-- out + ror shift ;1 + ror x2 ;1 +didStuff4: + cpi x2, 0xfc ;1 + brsh bitstuff4 ;1 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + ror shift ;1 + out USBOUT, x1 ;1 <-- out + ror x2 ;1 + cpi x2, 0xfc ;1 +didStuff5: + brsh bitstuff5 ;1 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + ror shift ;1 + ror x2 ;1 +didStuff6: + out USBOUT, x1 ;1 <-- out + cpi x2, 0xfc ;1 + brsh bitstuff6 ;1 + sbrs shift, 0 ;1 + eor x1, x4 ;1 + ror shift ;1 + ror x2 ;1 +didStuff7: + cpi x2, 0xfc ;1 + out USBOUT, x1 ;1 <-- out + brsh bitstuff7 ;1 + mov shift, x3 ;1 + dec cnt ;1 + brne txLoop ;2 | 1 + cbr x1, USBMASK ;1 prepare SE0 + pop x4 ;2 + out USBOUT, x1 ;1 <-- out SE0 + ldi cnt, 4 ;1 two bits = 16 cycles +se0Delay: + dec cnt ;1 + brne se0Delay ;2 | 1 + ori x1, USBIDLE ;1 + in x2, USBDDR ;1 + cbr x2, USBMASK ;1 set both pins to input + out USBOUT, x1 ;1 <-- out J (idle) + cbr x1, USBMASK ;1 configure no pullup on both pins + pop x3 ;2 + pop YL ;2 + out USBDDR, x2 ;1 <-- release bus now + out USBOUT, x1 ;1 set pullup state + pop YH ;2 + rjmp sofError ;2 [we want to jump to rxDoReturn, but this saves cycles] + +bitstuff4: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + out USBOUT, x1 ;1 <-- out + rjmp didStuff4 ;2 jump back 2 cycles earlier +bitstuff5: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + sec ;1 set carry so that brsh is not taken + out USBOUT, x1 ;1 <-- out + rjmp didStuff5 ;2 jump back 1 cycle earlier +bitstuff6: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + rjmp didStuff6 ;2 jump back 3 cycles earlier and do out there +bitstuff7: ;1 (for branch taken) + eor x1, x4 ;1 + ldi x2, 0 ;1 + rjmp didStuff7 ;2 jump back 4 cycles earlier + +; ######################## utility functions ######################## + +; extern unsigned usbCrc16(unsigned char *data, unsigned char len); +; data: r24/25 +; len: r22 +; temp variables: +; r18: data byte +; r19: bit counter +; r20/21: polynomial +; r23: scratch +; r24/25: crc-sum +; r26/27=X: ptr +.global usbCrc16 +usbCrc16: + mov XL, r24 + mov XH, r25 + ldi r24, 0xff + ldi r25, 0xff + ldi r20, lo8(0xa001) + ldi r21, hi8(0xa001) +crcByteLoop: + subi r22, 1 + brcs crcReady + ld r18, x+ + ldi r19, 8 +crcBitLoop: + mov r23, r18 + eor r23, r24 + lsr r25 + ror r24 + lsr r18 + sbrs r23, 0 + rjmp crcNoXor + eor r24, r20 + eor r25, r21 +crcNoXor: + dec r19 + brne crcBitLoop + rjmp crcByteLoop +crcReady: + com r24 + com r25 + ret diff --git a/firmware/usbdrv/usbdrvasm.o b/firmware/usbdrv/usbdrvasm.o new file mode 100644 index 0000000000000000000000000000000000000000..9b0215d39eb89fe5483deb8762bbdf8e045b4e4c GIT binary patch literal 4068 zcmbW34Qw0b8OPsi8|Mfab{pEXB3c7vb%ug{cHFeeqNeFbL`q58B#f>gC60Y=4w5@_ zKIcQ)mK6{Pi7(5&qJcC%gb-sAYL!W)cv_E6>NaWMRzlTOmGwa7YnmEcr42&ry63s~ z-pk8Lh^en~e*eG!^SsZ!_xSGOxt+Uv1wkNe2xN#X5g~_`6S4w=2`8bIh@^%Di@{^T zVvT*|<^PuJ%p<@3YH@wByBICT>{WJPJ`@gJi`$`Sr}_6qa?Q5TX*8o>gv|@ZHSV;=#qA1P-D&nzTcp!Y9M0@kx4d|Zbkf=D(aLVv$N4hWIas*|^uHW` zZ)GcJ+wpI&Z2fhc_G!7(>WX4Vx^5#E+oie_FI2^Y>kjrr*H1Tt`=j`yRbflAdQ->o z%JQz2m75bQuY|x~d1tjkU?$ShD^ih=5FE%B&TvGmRgKEm5;)!6KdlBA(6j8*_D?Jl zMm>op}VlY5G({w1Pg0Ttg+0(&$vBO6zA*b zgi*0HWH-(?j5d~0vHXf}24Swsq(VhL%p zOO3!y-K`!qb&Dl&kyw2Ne(gP1__dNtbZxUoxRzXLf%|dY)%v-Sf>=t}oo01W7;T(y zniEU)bJ&N*l32P>c)Cn?eumDl^N$>L*7-bFek*!B`uxHx3qAIpe<$~3D|Z(*+j?{+ zeAs--++b#}FSDKqo8eCL_luSCZ_F1=(Ik=F?4*$#gW1sOJkFFZPb4FTJY$eZI%ySq-@P_>8u}^U4N$j&B14pJ6u6-$IB8L0pG97^{b4gUhVMC==l0 zVD;KSi*T^;_vNkRazGNyi=l7_tB3P4X2SdtY{;%5q!#pEIBtc z3&Z+1fHNGw1N<<@?*dP8{66qGj!yx<#qkHgk8yk!_+5@a27Zp?&w>BJaTWL_j=u#y z%dr4A@0%Qpz^6D40uRF)It0=HdqWG5iZ^ae3gs00}pcXF5pg%cLMiv z+z-5l-{yD<7{5b01oA83r3Y3Z&j1I|bA~`(23^nb+n`T!>)!*e zy_Mq+LEpjgKSA%}_*2k#ar__9`#HV}I>9mC;%ScSfIB(96+j>BH*ow6=vz2`5p*-h zuX>u0Rd9d(fn$8H9`o^Ee0;{o=Y0H`j~9IWjgJNHosH+e*~hDWydL;lw;v(cKgs9D z()v`CPRZP4WaztAWSm4Wn$pyaasVi*WsPWZN{>z`W6=Ytl%v}tiAZ}i5?T7g3`I>% zS4x|lOseVT2}PB+kgl=3GGW}U zs9UgWeX1erdOmBA>7-)xYWglF?j^Z#xQJBV*r^)&tYi0U+sBjY0h#2q%uZd`bfV9U zDMrFe9oB}7q`p)v=2eT4oRQCDhDbO;hyR5Qk9tTLcG6|vtK9@ZX_RbtSqfc-ibDv`93 z9>Nw$gn2Q~i+Nt$^WvV@?s-cp;YAZ(bff2O^t=ww>+rlyo(IjBr5*4?b(W;`)V5he zc3Ka5P)??)sTj=b*Y?3JF)}hGrwmOWiP0M@n>V)QGpKjSQ%XwiOQYVN*L7JnpchDk zGrOTBj-cHE*^|w>>xNl$c*b?^%N=kRz?b2A@IAO{yPk@5kY0GVtQe$k&3*9NU|K~z zMExgG4^#ad>iela%;}d<|D5{2L;V2NuXFlM)b6>Cpx#Gw-sAM2KnH$7{Xc`Qb@eIC qarc0~O_)B9dOyv#QM)zqe{bMH>MsLb>uUTT9C(QO_#33w)&B!}l|_*N literal 0 HcmV?d00001 diff --git a/software/avrdude_usbasp.2005-04-21.patch b/software/avrdude_usbasp.2005-04-21.patch new file mode 100644 index 000000000..ebe923d29 --- /dev/null +++ b/software/avrdude_usbasp.2005-04-21.patch @@ -0,0 +1,125 @@ +? usbasp.c +? usbasp.h +Index: Makefile.am +=================================================================== +RCS file: /cvsroot/avrdude/avrdude/Makefile.am,v +retrieving revision 1.23 +diff -u -r1.23 Makefile.am +--- Makefile.am 10 Feb 2005 14:54:57 -0000 1.23 ++++ Makefile.am 9 Apr 2005 09:04:02 -0000 +@@ -85,6 +85,8 @@ + stk500.c \ + stk500.h \ + stk500_private.h \ ++ usbasp.c \ ++ usbasp.h \ + term.c \ + term.h + +Index: avrdude.conf.in +=================================================================== +RCS file: /cvsroot/avrdude/avrdude/avrdude.conf.in,v +retrieving revision 1.36 +diff -u -r1.36 avrdude.conf.in +--- avrdude.conf.in 22 Dec 2004 01:30:30 -0000 1.36 ++++ avrdude.conf.in 9 Apr 2005 09:04:10 -0000 +@@ -243,6 +243,12 @@ + miso = 10; + ; + ++programmer ++ id = "usbasp"; ++ desc = "usbasp"; ++ type = usbasp; ++; ++ + # The programming dongle used by the popular Ponyprog + # utility. It is almost similar to the STK200 one, + # except that there is a LED indicating that the +@@ -337,7 +343,6 @@ + miso = 10; + ; + +- + # From the contributor of the "xil" jtag cable: + # The "vcc" definition isn't really vcc (the cable gets its power from + # the programming circuit) but is necessary to switch one of the +Index: config_gram.y +=================================================================== +RCS file: /cvsroot/avrdude/avrdude/config_gram.y,v +retrieving revision 1.39 +diff -u -r1.39 config_gram.y +--- config_gram.y 22 Dec 2004 01:52:45 -0000 1.39 ++++ config_gram.y 9 Apr 2005 09:04:11 -0000 +@@ -34,6 +34,7 @@ + #include "pgm.h" + #include "stk500.h" + #include "avr910.h" ++#include "usbasp.h" + #include "butterfly.h" + #include "avr.h" + +@@ -112,6 +113,7 @@ + %token K_SIZE + %token K_STK500 + %token K_AVR910 ++%token K_USBASP + %token K_BUTTERFLY + %token K_TYPE + %token K_VCC +@@ -302,6 +304,11 @@ + } + } | + ++ K_TYPE TKN_EQUAL K_USBASP { ++ { ++ usbasp_initpgm(current_prog); ++ } ++ } | + K_TYPE TKN_EQUAL K_BUTTERFLY { + { + butterfly_initpgm(current_prog); +Index: configure.ac +=================================================================== +RCS file: /cvsroot/avrdude/avrdude/configure.ac,v +retrieving revision 1.22 +diff -u -r1.22 configure.ac +--- configure.ac 10 Feb 2005 15:39:42 -0000 1.22 ++++ configure.ac 9 Apr 2005 09:04:11 -0000 +@@ -104,6 +104,21 @@ + AC_SUBST(SUBDIRS_AC, $SUBDIRS_AC) + AC_SUBST(DIST_SUBDIRS_AC, $DIST_SUBDIRS_AC) + ++# USB stuff ++AH_TEMPLATE([HAVE_LIBUSB], ++ [Define if USB support is enabled via libusb]) ++AC_CHECK_LIB(usb, main, have_libusb=yes) ++if test x$have_libusb = xyes; then ++ case $target in ++ *-*-darwin*) ++ LIBS="$LIBS -lusb -framework CoreFoundation -framework IOKit" ++ ;; ++ *) ++ LIBS="$LIBS -lusb" ++ ;; ++ esac ++ AC_DEFINE([HAVE_LIBUSB]) ++fi + + # Find the parallel serial device files based on target system + # If a system doesn't have a PC style parallel, mark it as unknown. +Index: lexer.l +=================================================================== +RCS file: /cvsroot/avrdude/avrdude/lexer.l,v +retrieving revision 1.30 +diff -u -r1.30 lexer.l +--- lexer.l 22 Dec 2004 01:52:45 -0000 1.30 ++++ lexer.l 9 Apr 2005 09:04:12 -0000 +@@ -156,6 +156,7 @@ + size { yylval=NULL; return K_SIZE; } + stk500 { yylval=NULL; return K_STK500; } + avr910 { yylval=NULL; return K_AVR910; } ++usbasp { yylval=NULL; return K_USBASP; } + butterfly { yylval=NULL; return K_BUTTERFLY; } + type { yylval=NULL; return K_TYPE; } + vcc { yylval=NULL; return K_VCC; } diff --git a/software/usbasp.c b/software/usbasp.c new file mode 100644 index 000000000..439fa3b5c --- /dev/null +++ b/software/usbasp.c @@ -0,0 +1,329 @@ +#include "ac_cfg.h" + +#include +#include +#include +#include +#include +#include + +#include "avr.h" +#include "pgm.h" +#include "usbasp.h" + +#ifdef HAVE_LIBUSB +#include /* this is libusb, see http://libusb.sourceforge.net/ */ + +extern char * progname; +extern int do_cycles; + +static usb_dev_handle *usbhandle; + +/* + * wrapper for usb_control_msg call + */ +static int usbasp_transmit(unsigned char receive, unsigned char functionid, + unsigned char send[4], unsigned char * buffer, int buffersize) +{ + int nbytes; + nbytes = usb_control_msg(usbhandle, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | (receive << 7), + functionid, + (send[1] << 8) | send[0], + (send[3] << 8) | send[2], + buffer, buffersize, + 5000); + if(nbytes < 0){ + fprintf(stderr, "%s: error: usbasp_transmit: %s\n", progname, usb_strerror()); + exit(1); + } + + return nbytes; +} + +static int usbasp_open(PROGRAMMER * pgm, char * port) +{ + struct usb_bus *bus; + struct usb_device *dev = 0; + + usb_init(); + usb_find_busses(); + usb_find_devices(); + for(bus=usb_busses; bus; bus=bus->next){ + for(dev=bus->devices; dev; dev=dev->next){ + if(dev->descriptor.idVendor == USBDEV_VENDOR && dev->descriptor.idProduct == USBDEV_PRODUCT) + break; + } + if(dev) + break; + } + if(!dev){ + fprintf(stderr, "%s: error: could not find USB device vendor=0x%x product=0x%x\n", + progname, USBDEV_VENDOR, USBDEV_PRODUCT); + exit(1); + } + + usbhandle = usb_open(dev); + if(!usbhandle){ + fprintf(stderr, "%s: error: opening usb device: %s\n", + progname, usb_strerror()); + exit(1); + } + + return 0; +} + + +static void usbasp_close(PROGRAMMER * pgm) +{ + unsigned char temp[4]; + memset(temp, 0, sizeof(temp)); + usbasp_transmit(1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp)); + + usb_close(usbhandle); +} + + +static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p) +{ + + unsigned char temp[4]; + memset(temp, 0, sizeof(temp)); + usbasp_transmit(1, USBASP_FUNC_CONNECT, temp, temp, sizeof(temp)); + + usleep(100000); + + pgm->program_enable(pgm, p); + return 0; +} + +static void usbasp_disable(PROGRAMMER * pgm) +{ + /* Do nothing. */ + + return; +} + +static void usbasp_enable(PROGRAMMER * pgm) +{ + /* Do nothing. */ + + return; +} + +static void usbasp_display(PROGRAMMER * pgm, char * p) +{ + return; +} + + +static int usbasp_cmd(PROGRAMMER * pgm, unsigned char cmd[4], + unsigned char res[4]) +{ + int nbytes = + usbasp_transmit(1, USBASP_FUNC_TRANSMIT, cmd, res, sizeof(res)); + + if(nbytes != 4){ + fprintf(stderr, "%s: error: wrong responds size\n", + progname); + return -1; + } + + return 0; +} + + +static int usbasp_program_enable(PROGRAMMER * pgm, AVRPART * p) +{ + unsigned char res[4]; + unsigned char cmd[4]; + memset(cmd, 0, sizeof(cmd)); + memset(res, 0, sizeof(res)); + + cmd[0] = 0; + + int nbytes = + usbasp_transmit(1, USBASP_FUNC_ENABLEPROG, cmd, res, sizeof(res)); + + if ((nbytes != 1) | (res[0] != 0)) { + fprintf(stderr, "%s: error: programm enable: target doesn't answer. %x \n", + progname, res[0]); + return -1; + } + + return 0; +} + + +static int usbasp_chip_erase(PROGRAMMER * pgm, AVRPART * p) +{ + unsigned char cmd[4]; + unsigned char res[4]; + + if (p->op[AVR_OP_CHIP_ERASE] == NULL) { + fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n", + p->desc); + return -1; + } + + memset(cmd, 0, sizeof(cmd)); + + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); + pgm->cmd(pgm, cmd, res); + usleep(p->chip_erase_delay); + pgm->initialize(pgm, p); + + return 0; +} + + +static int usbasp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int n_bytes) +{ + int n; + unsigned char cmd[4]; + int address = 0; + int wbytes = n_bytes; + int blocksize; + unsigned char * buffer = m->buf; + int function; + + if (strcmp(m->desc, "flash") == 0) { + function = USBASP_FUNC_READFLASH; + } else if (strcmp(m->desc, "eeprom") == 0) { + function = USBASP_FUNC_READEEPROM; + } else { + return -2; + } + + while (wbytes) { + if (wbytes > USBASP_READBLOCKSIZE) { + blocksize = USBASP_READBLOCKSIZE; + wbytes -= USBASP_READBLOCKSIZE; + } else { + blocksize = wbytes; + wbytes = 0; + } + + cmd[0] = address & 0xFF; + cmd[1] = address >> 8; + + n = usbasp_transmit(1, function, cmd, buffer, blocksize); + + if (n != blocksize) { + fprintf(stderr, "%s: error: wrong reading bytes %x\n", + progname, n); + exit(1); + } + + buffer += blocksize; + address += blocksize; + + report_progress (address, n_bytes, NULL); + } + + return n_bytes; +} + +static int usbasp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, + int page_size, int n_bytes) +{ + int n; + unsigned char cmd[4]; + int address = 0; + int wbytes = n_bytes; + int blocksize; + unsigned char * buffer = m->buf; + unsigned char blockflags = USBASP_BLOCKFLAG_FIRST; + int function; + + if (strcmp(m->desc, "flash") == 0) { + function = USBASP_FUNC_WRITEFLASH; + } else if (strcmp(m->desc, "eeprom") == 0) { + function = USBASP_FUNC_WRITEEEPROM; + } else { + return -2; + } + + while (wbytes) { + if (wbytes > USBASP_WRITEBLOCKSIZE) { + blocksize = USBASP_WRITEBLOCKSIZE; + wbytes -= USBASP_WRITEBLOCKSIZE; + } else { + blocksize = wbytes; + wbytes = 0; + blockflags |= USBASP_BLOCKFLAG_LAST; + } + + cmd[0] = address & 0xFF; + cmd[1] = address >> 8; + cmd[2] = page_size & 0xFF; + cmd[3] = blockflags; + blockflags = 0; + + n = usbasp_transmit(0, function, cmd, buffer, blocksize); + + if (n != blocksize) { + fprintf(stderr, "%s: error: wrong count at writing %x\n", + progname, n); + exit(1); + } + + + buffer += blocksize; + address += blocksize; + + report_progress (address, n_bytes, NULL); + } + + return n_bytes; +} + +void usbasp_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "usbasp"); + + /* + * mandatory functions + */ + + pgm->initialize = usbasp_initialize; + pgm->display = usbasp_display; + pgm->enable = usbasp_enable; + pgm->disable = usbasp_disable; + pgm->program_enable = usbasp_program_enable; + pgm->chip_erase = usbasp_chip_erase; + pgm->cmd = usbasp_cmd; + pgm->open = usbasp_open; + pgm->close = usbasp_close; + + /* + * optional functions + */ + + pgm->paged_write = usbasp_paged_write; + pgm->paged_load = usbasp_paged_load; + +} + + +#else /* HAVE_LIBUSB */ + +extern char * progname; + +static int usbasp_nousb_open (struct programmer_t *pgm, char * name) +{ + fprintf(stderr, "%s: error: no usb support. please compile again with libusb installed.\n", + progname); + + exit(1); +} + +void usbasp_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "usbasp"); + + pgm->open = usbasp_nousb_open; +} + +#endif /* HAVE_LIBUSB */ diff --git a/software/usbasp.h b/software/usbasp.h new file mode 100644 index 000000000..0592d5bce --- /dev/null +++ b/software/usbasp.h @@ -0,0 +1,28 @@ +#ifndef __usbasp_h__ +#define __usbasp_h__ + +#include "avrpart.h" + + +#define USBDEV_VENDOR 0x03eb /* ATMEL */ +#define USBDEV_PRODUCT 0xc7B4 /* USBasp */ + +#define USBASP_FUNC_CONNECT 1 +#define USBASP_FUNC_DISCONNECT 2 +#define USBASP_FUNC_TRANSMIT 3 +#define USBASP_FUNC_READFLASH 4 +#define USBASP_FUNC_ENABLEPROG 5 +#define USBASP_FUNC_WRITEFLASH 6 +#define USBASP_FUNC_READEEPROM 7 +#define USBASP_FUNC_WRITEEEPROM 8 + +#define USBASP_BLOCKFLAG_FIRST 1 +#define USBASP_BLOCKFLAG_LAST 2 + +#define USBASP_READBLOCKSIZE 200 +#define USBASP_WRITEBLOCKSIZE 200 + + +void usbasp_initpgm (PROGRAMMER * pgm); + +#endif /* __usbasp_h__ */ -- 2.11.0