├── Changelog.txt ├── LICENSE ├── README.md ├── README_nerdralph.md ├── Readme.txt ├── circuit ├── USBasp.sch └── USBasp_schematics.pdf ├── firmware ├── Makefile ├── cbuf.h ├── clock.c ├── clock.h ├── isp.c ├── isp.h ├── main.c ├── serialnumber.c ├── serialnumber.h ├── tpi.S ├── tpi.h ├── tpi_defs.h ├── uart.c ├── uart.h ├── usb_descriptors.h ├── usbasp.h ├── usbconfig.h └── usbdrv │ ├── Changelog.txt │ ├── CommercialLicense.txt │ ├── License.txt │ ├── Readme.txt │ ├── USB-ID-FAQ.txt │ ├── USB-IDs-for-free.txt │ ├── asmcommon.inc │ ├── oddebug.c │ ├── oddebug.h │ ├── usbconfig-prototype.h │ ├── usbdrv.c │ ├── usbdrv.h │ ├── usbdrvasm.S │ ├── usbdrvasm.asm │ ├── usbdrvasm12.inc │ ├── usbdrvasm128.inc │ ├── usbdrvasm15.inc │ ├── usbdrvasm16.inc │ ├── usbdrvasm165.inc │ ├── usbdrvasm18-crc.inc │ ├── usbdrvasm18.inc │ ├── usbdrvasm20.inc │ └── usbportability.h └── utility └── USBaspHIDUART ├── USBaspHIDUART.lpi ├── USBaspHIDUART.pas ├── hidapi.pas ├── hidapi.inc ├── hidapi.pas └── hidapi_static.pas ├── spscringbuffer.pas ├── usbasp_hid.pas └── usbasp_threads.pas /Changelog.txt: -------------------------------------------------------------------------------- 1 | usbasp.2011-05-28 (v1.4) 2 | ------------------------ 3 | - added TPI support for ATTiny4/5/6/10 (by Slawomir Fraś) 4 | - added support for controllers with flash >128kb (by Slawomir Fraś) 5 | - fixed resync after program enable signal to pulse RST (based on patch by Marco S) 6 | - updated usb driver to V-USB Release 2010-07-15 7 | 8 | 9 | usbasp.2009-02-28 (v1.3) 10 | ------------------------ 11 | - added support for software control of ISP speed (based on patch by Jurgis Brigmanis) 12 | - included new AVRUSB driver version (Release 2008-11-26) 13 | - added libusb 0.1.12.1 windows drivers (needed for WinAVR version 20080512 or greater) 14 | 15 | usbasp.2007-10-23 (v1.2) 16 | ------------------------ 17 | - red LED turns on before connecting to target device: this signal can be used to control external tri-state buffers (by Pawel Szramowski) 18 | 19 | usbasp.2007-07-23 20 | ----------------- 21 | - changed licence to GNU GPL v2 22 | - included new AVRUSB driver version (Release 2007-07-07); AVRUSB licence was changed to GNU GPL v2 23 | - fixed long addressing for Mega128 (by BoskiDialer) 24 | 25 | usbasp.2006-12-29 26 | ----------------- 27 | - fixed returnvalue in usbWriteFunction (by Jeroen Koeter) 28 | - changed clock.h: adaptation for newer MCUs like ATMega48 (by Hanns-Konrad Unger) 29 | - improved Makefile to select target (by Hanns-Konrad Unger) 30 | - circuit diagram: added zener diodes to USB data lines 31 | 32 | usbasp.2006-09-16 33 | ----------------- 34 | - add usb reset on startup 35 | - included new AVRUSB driver version (Release 2006-07-18) 36 | - changed VID and PID to OBDEV's shared IDs to meet new licence conditions 37 | - removed avrdude patch from this package. USBasp is supported in latest avrdude CVS version 38 | 39 | usbasp.2005-11-14 40 | ----------------- 41 | - fixed blocksize restriction (programming the Mega128 now works) 42 | by Thomas Pfeifer (TP) 43 | - update patch for avrdude-5.0 44 | 45 | usbasp.2005-07-03 46 | ----------------- 47 | - set USB_CFG_SAMPLE_EXACT in usbconfig.h to reduce problems with long cables 48 | - corrected vendor string 49 | - added notes on setting fuse bits 50 | 51 | usbasp.2005-04-21 52 | ----------------- 53 | - first public version 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # usbasp improved 2 | ### _WCID compliant_, _HID UART support_ 3 | 4 | This USBasp firmware is based on [a fork by Ralph Doncaster]. Original fork readme can be found at README_nerdralph.md. 5 | 6 | ### Features 7 | - From version 1.07 a default SCK clock of 1.5Mhz and automatic SCK slowing if target does not respond. PORTD is left as input, so this firmware also works [with USBISP modules]. ( nerdralph ) 8 | - From version 1.08 the firmware is [WCID] compliant, meaning it should work on Windows without any driver or .inf install. 9 | - From version 1.09 a ( reliable at 9600 Baud, with 120ms - 160ms intervals for higher speeds see note at UART HID protocol ) UART HID implementation is added for debugging purposes. USBasp will appear as a composite device with a WINUSB interface and a HID interface. 10 | - From version 1.10 USBasp WCID switch to Microsoft OS 2.0 Descriptors. It seems that it play better with USB 3.0 ports. 11 | - From version 1.11 USBasp supports updating it's serial number ( see [USBaspHIDUART utility] ) and also adds support for the AT89S51/2 ICs. 12 | 13 | ### Avrdude 14 | 15 | > Note: Windows only . 16 | 17 | Windows MSVC builds of [avrdude], uses libwinusb instead of libusb, which doesn't support composite devices as this firmware implements. Please use a MINGW build ( i.e. avrdude-v8.0-windows_mingw-x64.zip ) . 18 | 19 | ### UART GUI Client 20 | 21 | From release v0.7.0, the [libUSBUARTTerminal] supports this firmware's HID UART implementation. 22 | 23 | ### UART HID protocol 24 | 25 | > Note: There is a small 128 byte ring buffer for both Tx and Rx. That means you can use higher baud rates ( i.e. 115200 ) if the message length is smaller than 128 bytes and the transmit / receive interval is 160 ms or higher. 26 | 27 | ##### _Serial Data_ 28 | 29 | V-USB implementation uses 8 byte size input and output interrupt reports. 30 | 31 | The last byte ( 8th ) has special meaning. Its serial data or its the serial bytes count. If its value is greater than 7 then its serial data. If the value is 7 or smaller then its the serial data count and the remaining bytes are ignored. 32 | 33 | _Input Reports ( USBasp -> USB PC )_ or _Output Reports ( USB PC -> USBasp)_ 34 | 35 | i.e. 36 | 37 | ```sh 38 | 0x55,0x34,0x00,0x00,0x00,0x00,0x00,0x02 -> Actual serial bytes 2 : 0x55,0x34 39 | 40 | 0x00,0x34,0x00,0x66,0x32,0x36,0x00,0x04 -> Actual serial bytes 4 : 0x00,0x34,0x00,0x66 41 | 42 | 0x00,0xC3,0x34,0x55,0x32,0xF3,0x00,0xAB -> Actual serial bytes 8 ( 8th byte > 7 ) : 0x00,0xC3,0x34,0x55,0x32,0xF3,0x00,0xAB 43 | ``` 44 | 45 | ##### _UART Configuration_ 46 | 47 | The USBasp's UART configuration uses an 8 byte size feature report, with the following format. 48 | 49 | | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 - 7 RO | 50 | | -------- | --------- | -------- | -------- | -------- | 51 | | Prescaler Low Byte | Prescaler High Byte | See [UART Flags] | Unused | USBasp Capabilities | 52 | 53 | To setup and enable the UART, send a feature set report, with the prescaler in the first two bytes and the parity, data bit, stop bit flags at the third byte ( see [UART Flags] ). The fourth byte is ignored. 54 | 55 | To disable the UART, send a feature set report, with the prescaler bytes as zero. 56 | 57 | > Note: The UART is disabled by default, if read or write is detected for do to not interfere with those functions. 58 | 59 | ### USBaspHIDUART utility 60 | 61 | The USBaspHIDUART is a simple console utility, used for testing the HID UART implementation. 62 | 63 | This is the help page ( USBaspHIDUART.exe -h ) : 64 | 65 | ```sh 66 | 67 | USBaspHIDUART -h 68 | 69 | USBasp HIDUART Test App 70 | 71 | -l List USBasp HID devices 72 | -i Select USBasp index ( default 0 ) 73 | -b Set Baud ( default 9600 ) 74 | -c Set USBasp Crystal Hz ( default 12 MHz or 12000000 Hz ) 75 | -s Select USBasp with serial number. 76 | 4 Digits numeric only i.e. 3456, 2222, etc ). 77 | -u Serial Number to update ( 4 Digits numeric only i.e. 3456, 2222, etc ). 78 | Use with index -i when more than one USBasp are connected. 79 | -r Continuous read input 80 | -w Interactive send output 81 | 82 | examples 83 | 84 | Read from USBasp at index 0 with 4800 baud 85 | USBaspHIDUART -b 4800 -r 86 | 87 | Interactive write to USBasp at index 1 with 9600 baud 88 | USBaspHIDUART -i 1 -w 89 | 90 | Interactive write to USBasp with serial number 1111 with 9600 baud 91 | USBaspHIDUART -s 1111 -w 92 | 93 | Read from USBasp with 20 MHz crystal at index 1 with 19200 baud 94 | USBaspHIDUART -i 1 -b 19200 -c 20000000 -r 95 | 96 | Read from USBasp with 20 MHz crystal and with serial number 2345 with 19200 baud 97 | USBaspHIDUART -s 2345 -b 19200 -c 20000000 -r 98 | 99 | Update the first found USBasp's serial number with 3456 100 | USBaspHIDUART -u 3456 101 | 102 | Update the USBasp's at index 3 serial number with 3456 103 | USBaspHIDUART -i 3 -u 3456 104 | ``` 105 | 106 | ##### _Build from source_ 107 | 108 | Building USBaspHIDUART from source is very straightforward : 109 | 110 | > Note: You'll need [FreePascal] 3.0.4 and higher installed. 111 | 112 | ( it's always better to build in another directory ) 113 | 114 | Windows 115 | 116 | ``` 117 | \utility\USBaspHIDUART>mkdir build 118 | \utility\USBaspHIDUART>cd build 119 | \utility\USBaspHIDUART\build>fpc.exe -MObjFPC -FU. -Fu..\hidapi.pas ..\USBaspHIDUART.pas -o.\USBaspHIDUART.exe 120 | ``` 121 | 122 | Linux \ FreeBSD 123 | 124 | ``` 125 | \utility\USBaspHIDUART>mkdir build 126 | \utility\USBaspHIDUART>cd build 127 | \utility\USBaspHIDUART\build>fpc -MObjFPC -FU. -Fu../ -Fu../hidapi.pas -dUseCThreads ../USBaspHIDUART.pas -o./USBaspHIDUART 128 | ``` 129 | 130 | 131 | [a fork by Ralph Doncaster]: 132 | [with USBISP modules]: 133 | [WCID]: 134 | [MSYS2]: 135 | [avr8-gnu-toolchain (3.6.2.17778)]: 136 | [UART Flags]: 137 | [avrdude]: 138 | [avrdudes/avrdude]: 139 | [libUSBUARTTerminal]: 140 | [USBaspHIDUART utility]: 141 | [FreePascal]: 142 | -------------------------------------------------------------------------------- /README_nerdralph.md: -------------------------------------------------------------------------------- 1 | # usbasp improved 2 | 3 | USBasp firmware based on a fork by Bill Perry and the latest v-usb. 4 | 5 | Firmware version 1.06 (2020-09-14) features a default SCK clock of 1.5Mhz and automatic SCK slowing if target does not respond. PORTD is left as input, so this firmware also works with USBISP modules. 6 | 7 | Thanks to patches from Dimitrios, the USBasp firmware 1.08 is WCID compliant, meaning it should work on Windows without any driver or .inf install. 8 | 9 | A pre-built hex file for the mega8 (main.hex) is in the firmware directory, along with m88.hex for the mega88. 10 | 11 | ## development plans 12 | Recognize when the target device is in debugWIRE mode, and send the dW command to enter ISP mode. 13 | 14 | -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | This is the README file for USBasp. 2 | 3 | USBasp is a USB in-circuit programmer for Atmel AVR controllers. It simply 4 | consists of an ATMega88 or an ATMega8 and a couple of passive components. 5 | The programmer uses a firmware-only USB driver, no special USB controller 6 | is needed. 7 | 8 | Features: 9 | - Works under multiple platforms. Linux, Mac OS X and Windows are tested. 10 | - No special controllers or smd components are needed. 11 | - Programming speed is up to 5kBytes/sec. 12 | - SCK option to support targets with low clock speed (< 1,5MHz). 13 | - Planned: serial interface to target (e.g. for debugging). 14 | 15 | 16 | LICENSE 17 | 18 | USBasp is distributed under the terms and conditions of the GNU GPL version 19 | 2 (see "firmware/usbdrv/License.txt" for details). 20 | 21 | USBasp is built with V-USB driver by OBJECTIVE DEVELOPMENT GmbH. See 22 | "firmware/usbdrv/" for further information. 23 | 24 | 25 | LIMITATIONS 26 | 27 | Hardware: 28 | This package includes a circuit diagram. This circuit can only be used for 29 | programming 5V target systems. For other systems a level converter is needed. 30 | 31 | Firmware: 32 | The firmware dosn't support USB Suspend Mode. A bidirectional serial 33 | interface to slave exists in hardware but the firmware doesn't support it yet. 34 | 35 | 36 | USE PRECOMPILED VERSION 37 | 38 | Firmware: 39 | Flash "bin/firmware/usbasp.atmega88.xxxx-xx-xx.hex" or 40 | "bin/firmware/usbasp.atmega8.xxxx-xx-xx.hex" to the used controller with a 41 | working programmer (e.g. with avrdude, uisp, ...). Set jumper J2 to activate 42 | USBasp firmware update function. 43 | You have to change the fuse bits for external crystal (see "make fuses"). 44 | # TARGET=atmega8 HFUSE=0xc9 LFUSE=0xef 45 | # TARGET=atmega48 HFUSE=0xdd LFUSE=0xff 46 | # TARGET=atmega88 HFUSE=0xdd LFUSE=0xff 47 | 48 | Windows: 49 | Start Windows and connect USBasp to the system. When Windows asks for a 50 | driver, choose "bin/win-driver". On Win2k and WinXP systems, Windows will 51 | warn that the driver is is not 'digitally signed'. Ignore this message and 52 | continue with the installation. 53 | Now you can run avrdude. Examples: 54 | 1. Enter terminal mode with an AT90S2313 connected to the programmer: 55 | avrdude -c usbasp -p at90s2313 -t 56 | 2. Write main.hex to the flash of an ATmega8: 57 | avrdude -c usbasp -p atmega8 -U flash:w:main.hex 58 | 59 | Setting jumpers: 60 | J1 Power target 61 | Supply target with 5V (USB voltage). Be careful with this option, the 62 | circuit isn't protected against short circuit! 63 | J2 Jumper for firmware upgrade (not self-upgradable) 64 | Set this jumper for flashing the ATMega(4)8 of USBasp with another working 65 | programmer. 66 | J3 SCK option 67 | If the target clock is lower than 1,5 MHz, you have to set this jumper. 68 | Then SCK is scaled down from 375 kHz to about 8 kHz. 69 | 70 | 71 | BUILDING AND INSTALLING FROM SOURCE CODE 72 | 73 | Firmware: 74 | To compile the firmware 75 | 1. install the GNU toolchain for AVR microcontrollers (avr-gcc, avr-libc), 76 | 2. change directory to firmware/ 77 | 3. run "make main.hex" 78 | 4. flash "main.hex" to the ATMega(4)8. E.g. with uisp or avrdude (check 79 | the Makefile option "make flash"). To flash the firmware you have 80 | to set jumper J2 and connect USBasp to a working programmer. 81 | You have to change the fuse bits for external crystal, (check the Makefile 82 | option "make fuses"). 83 | 84 | Software (avrdude): 85 | AVRDUDE supports USBasp since version 5.2. 86 | 1. install libusb: http://libusb.sourceforge.net/ 87 | 2. get latest avrdude release: http://download.savannah.gnu.org/releases/avrdude/ 88 | 3. cd avrdude-X.X.X 89 | 5. configure to your environment: 90 | ./bootstrap (I had to comment out the two if-blocks which verify the 91 | installed versions of autoconf and automake) 92 | ./configure 93 | 6. compile and install it: 94 | make 95 | make install 96 | 97 | Notes on Windows (Cygwin): 98 | Download libusb-win32-device-bin-x.x.x.x.tar.gz from 99 | http://libusb-win32.sourceforge.net/ and unpack it. 100 | -> copy lib/gcc/libusb.a to lib-path 101 | -> copy include/usb.h to include-path 102 | cd avrdude 103 | ./configure LDFLAGS="-static" --enable-versioned-doc=no 104 | make 105 | 106 | Notes on Darwin/MacOS X: 107 | after "./configure" I had to edit Makefile: 108 | change "avrdude_CPPFLAGS" to "AM_CPPFLAGS" 109 | (why is this needed only on mac? bug in configure.ac?) 110 | 111 | Notes on Linux: 112 | To use USBasp as non-root, you have to define some device rules. See 113 | bin/linux-nonroot for an example. 114 | 115 | FILES IN THE DISTRIBUTION 116 | 117 | Readme.txt ...................... The file you are currently reading 118 | firmware ........................ Source code of the controller firmware 119 | firmware/usbdrv ................. AVR USB driver by Objective Development 120 | firmware/usbdrv/License.txt ..... Public license for AVR USB driver and USBasp 121 | circuit ......................... Circuit diagram in PDF and EAGLE format 122 | bin ............................. Precompiled programs 123 | bin/win-driver .................. Windows driver 124 | bin/firmware .................... Precompiled firmware 125 | bin/linux-nonroot ............... Linux device rule file 126 | 127 | 128 | MORE INFORMATION 129 | 130 | For more information on USBasp and it's components please visit the 131 | following URLs: 132 | 133 | USBasp .......................... http://www.fischl.de/usbasp/ 134 | 135 | Firmware-only V-USB driver ...... http://www.obdev.at/products/vusb/ 136 | avrdude ......................... http://www.nongnu.org/avrdude/ 137 | libusb .......................... http://libusb.sourceforge.net/ 138 | libusb-win32 .................... http://libusb-win32.sourceforge.net/ 139 | 140 | 141 | 2011-05-28 Thomas Fischl 142 | http://www.fischl.de 143 | -------------------------------------------------------------------------------- /circuit/USBasp.sch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dioannidis/usbasp/1255367ea0469b52e0694993bbd8a4bf96a97556/circuit/USBasp.sch -------------------------------------------------------------------------------- /circuit/USBasp_schematics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dioannidis/usbasp/1255367ea0469b52e0694993bbd8a4bf96a97556/circuit/USBasp_schematics.pdf -------------------------------------------------------------------------------- /firmware/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for usbasp 3 | # 20061119 Thomas Fischl original 4 | # 20061120 Hanns-Konrad Unger help: and TARGET=atmega48 added 5 | # 6 | 7 | # TARGET=atmega8 HFUSE=0xc9 LFUSE=0xef 8 | # TARGET=atmega48 HFUSE=0xdd LFUSE=0xff 9 | # TARGET=at90s2313 10 | TARGET ?= atmega8 11 | # TARGET ?= atmega88 12 | # C9 DF = full swing xtal, 4ms SUT 13 | HFUSE=0xC9 14 | LFUSE=0xDF 15 | CLOCK=12000000 16 | TPI= 17 | HIDUART= 18 | 19 | # ISP=ponyser PORT=/dev/ttyS1 20 | # ISP=stk500 PORT=/dev/ttyS1 21 | # ISP=stk500v2 PORT=/dev/ttyUSB0 22 | ISP=snap_isp 23 | PORT=usb 24 | 25 | help: 26 | @echo "Usage: make same as make help" 27 | @echo " make help same as make" 28 | @echo " make main.hex create main.hex" 29 | @echo " make clean remove redundant data" 30 | @echo " make disasm disasm main" 31 | @echo " make flash upload main.hex into flash" 32 | @echo " make fuses program fuses" 33 | @echo " make avrdude test avrdude" 34 | @echo "Current values:" 35 | @echo " TARGET=${TARGET}" 36 | @echo " LFUSE=${LFUSE}" 37 | @echo " HFUSE=${HFUSE}" 38 | @echo " CLOCK=${CLOCK}" 39 | @echo " TPI=$(if ifeq (${TPI},),Off,On)" 40 | @echo " HIDUART=$(if ifeq (${HIDUART},),Off,On)" 41 | @echo " ISP=${ISP}" 42 | @echo " PORT=${PORT}" 43 | 44 | COMPILE = avr-gcc -Wall -Wextra -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -Os -Iusbdrv -I. -mmcu=$(TARGET) -DF_CPU=$(CLOCK) # -DDEBUG_LEVEL=1 45 | 46 | OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o isp.o clock.o main.o 47 | 48 | ifneq ($(TPI),) 49 | COMPILE += -D__TPI__ 50 | OBJECTS += tpi.o 51 | endif 52 | 53 | ifneq ($(HIDUART),) 54 | COMPILE += -D__HIDUART__ 55 | OBJECTS += uart.o serialnumber.o 56 | endif 57 | 58 | .c.o: 59 | $(COMPILE) -c $< -o $@ 60 | #-Wa,-ahlms=$<.lst 61 | 62 | .S.o: 63 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 64 | # "-x assembler-with-cpp" should not be necessary since this is the default 65 | # file type for the .S (with capital S) extension. However, upper case 66 | # characters are not always preserved on Windows. To ensure WinAVR 67 | # compatibility define the file type manually. 68 | 69 | .c.s: 70 | $(COMPILE) -S $< -o $@ 71 | 72 | clean: 73 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o main.s usbdrv/*.o 74 | 75 | # file targets: 76 | main.bin: $(OBJECTS) 77 | $(COMPILE) -o main.bin $(OBJECTS) -Wl,-Map,main.map 78 | 79 | main.hex: main.bin 80 | rm -f main.hex main.eep.hex 81 | avr-objcopy -j .text -j .data -O ihex main.bin main.hex 82 | avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex main.bin main.eep.hex 83 | # ./checksize main.bin 84 | # do the checksize script as our last action to allow successful compilation 85 | # on Windows with WinAVR where the Unix commands will fail. 86 | 87 | disasm: main.bin 88 | avr-objdump -d main.bin 89 | 90 | cpp: 91 | $(COMPILE) -E main.c 92 | 93 | flash: 94 | avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -U flash:w:main.hex:i -U eeprom:w:main.eep.hex:i 95 | 96 | fuses: 97 | avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -u -U hfuse:w:$(HFUSE):m -U lfuse:w:$(LFUSE):m 98 | 99 | avrdude: 100 | avrdude -c ${ISP} -p ${TARGET} -P ${PORT} -v 101 | 102 | # Fuse atmega8 high byte HFUSE: 103 | # 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000) 104 | # ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 105 | # | | | | | +-------- BOOTSZ1 106 | # | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) 107 | # | | | +-------------- CKOPT (full output swing) 108 | # | | +---------------- SPIEN (allow serial programming) 109 | # | +------------------ WDTON (WDT not always on) 110 | # +-------------------- RSTDISBL (reset pin is enabled) 111 | # Fuse atmega8 low byte LFUSE: 112 | # 0x9f = 1 0 0 1 1 1 1 1 113 | # ^ ^ \ / \--+--/ 114 | # | | | +------- CKSEL 3..0 (external >8M crystal) 115 | # | | +--------------- SUT 1..0 (crystal osc, BOD enabled) 116 | # | +------------------ BODEN (BrownOut Detector enabled) 117 | # +-------------------- BODLEVEL (2.7V) 118 | # 119 | # Fuse atmega48 high byte hfuse: 120 | # 0xdf = 1 1 0 1 1 1 1 1 factory setting 121 | # ^ ^ ^ ^ ^ \-+-/ 122 | # | | | | | +------ BODLEVEL (Brown out disabled) 123 | # | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) 124 | # | | | +-------------- WDTON (WDT not always on) 125 | # | | +---------------- SPIEN (allow serial programming) 126 | # | +------------------ DWEN (debug wire is disabled) 127 | # +-------------------- RSTDISBL (reset pin is enabled) 128 | # 0xdd = ext.reset, no DW, SPI, no watchdog, no save eeprom, BOD 2.7V 129 | # Fuse atmega48 low byte lfuse: 130 | # 0x62 = 0 1 1 0 0 0 1 0 factory setting 131 | # ^ ^ \ / \--+--/ 132 | # | | | +------- CKSEL 3..0 (internal 8Mhz Oszillator) 133 | # | | +--------------- SUT 1..0 (start-up time) 134 | # | +------------------ CKOUT (no clock output) 135 | # +-------------------- CKDIV8 (divide clock by 8) 136 | # 0xdc = divide/1,no clock output,fast raising power,low Pw Oszil. 3..8 Mhz 137 | # 0xe0 = divide/1,no clock output,fast raising power,external Oszil. 138 | # 0xff = divide/1,no clock output,slow raising power,low Pw Oszil 8.. Mhz 139 | 140 | 141 | SERIAL = `echo /dev/tty.USA19QI*` 142 | UISP = uisp -dprog=$S -dserial=$(SERIAL) -dpart=auto 143 | # The two lines above are for "uisp" and the AVR910 serial programmer connected 144 | # to a Keyspan USB to serial converter to a Mac running Mac OS X. 145 | # Choose your favorite programmer and interface. 146 | 147 | uisp: all 148 | $(UISP) --erase 149 | $(UISP) --upload --verify if=main.hex 150 | 151 | -------------------------------------------------------------------------------- /firmware/cbuf.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * 3 | * Since this code originated from code which is public domain, I 4 | * hereby declare this code to be public domain as well. 5 | * 6 | * Dave Hylands - dhylands@gmail.com 7 | * 8 | ****************************************************************************/ 9 | /** 10 | * 11 | * @file CBUF.h 12 | * 13 | * @defgroup CBUF Circular Buffer 14 | * @{ 15 | * 16 | * @brief A simple and efficient set of circular buffer manipulations. 17 | * 18 | * These macros implement a circular buffer which employs get and put 19 | * pointers, in such a way that mutual exclusion is not required 20 | * (assumes one reader & one writer). 21 | * 22 | * It requires that the circular buffer size be a power of two, and the 23 | * size of the buffer needs to smaller than the index. So an 8 bit index 24 | * supports a circular buffer upto ( 1 << 7 ) = 128 entries, and a 16 bit index 25 | * supports a circular buffer upto ( 1 << 15 ) = 32768 entries. 26 | * 27 | * The basis for these routines came from an article in Jack Ganssle's 28 | * Embedded Muse: http://www.ganssle.com/tem/tem110.pdf 29 | * 30 | * In order to offer the most amount of flexibility for embedded environments 31 | * you need to define a macro for the size. 32 | * 33 | * First, you need to name your circular buffer. For this example, we'll 34 | * call it @c myQ. 35 | * 36 | * The size macro that needs to be defined will be the name of the 37 | * circular buffer followed by @c _SIZE. The size must be a power of two 38 | * and it needs to fit in the get/put indicies. i.e. if you use an 39 | * 8 bit index, then the maximum supported size would be 128. 40 | * 41 | * The structure which defines the circular buffer needs to have 3 members 42 | * m_getIdx, m_putIdx, and @c m_entry. 43 | * 44 | * @c m_getIdx and @c m_putIdx need to be unsigned integers of the same size. 45 | * 46 | * @c m_entry needs to be an array of @c xxx_SIZE entries, or a pointer to an 47 | * array of @c xxx_SIZE entries. The type of each entry is entirely up to the 48 | * caller. 49 | * 50 | * @code 51 | * #define myQ_SIZE 64 52 | * 53 | * volatile struct 54 | * { 55 | * uint8_t m_getIdx; 56 | * uint8_t m_putIdx; 57 | * uint8_t m_entry[ myQ_SIZE ]; 58 | * 59 | * } myQ; 60 | * @endcode 61 | * 62 | * You could then use CBUF_Push to add a character to the circular buffer: 63 | * 64 | * @code 65 | * CBUF_Push( myQ, 'x' ); 66 | * @endcode 67 | * 68 | * And CBUF_Pop to retrieve an element from the buffer: 69 | * 70 | * @code 71 | * ch = CBUF_Pop( myQ ); 72 | * @endcode 73 | * 74 | * If you happen to prefer to use C++ instead, there is a templatized 75 | * version which requires no macros. You just declare 3 template parameters: 76 | * 77 | * - The type that should be used for the index 78 | * - The size of the circular buffer 79 | * - The type that should be used for the entry 80 | * 81 | * For example: 82 | * @code 83 | * CBUF< uint8_t, 64, char > myQ; 84 | * @endcode 85 | * 86 | ****************************************************************************/ 87 | 88 | #if !defined( CBUF_H ) 89 | #define CBUF_H /**< Include Guard */ 90 | 91 | /* ---- Include Files ---------------------------------------------------- */ 92 | 93 | /* ---- Constants and Types ---------------------------------------------- */ 94 | 95 | /** 96 | * Initializes the circular buffer for use. 97 | */ 98 | 99 | #define CBUF_Init( cbuf ) cbuf.m_getIdx = cbuf.m_putIdx = 0 100 | 101 | /** 102 | * Returns the number of elements which are currently 103 | * contained in the circular buffer. 104 | */ 105 | 106 | #define CBUF_Len( cbuf ) ((typeof( cbuf.m_putIdx ))(( cbuf.m_putIdx ) - ( cbuf.m_getIdx ))) 107 | 108 | /** 109 | * Appends an element to the end of the circular buffer. The 110 | * element is expected to be of the same type as the @c m_entry 111 | * member. 112 | */ 113 | 114 | #define CBUF_Push( cbuf, elem ) do { \ 115 | (cbuf.m_entry)[ cbuf.m_putIdx & (( cbuf##_SIZE ) - 1 )] = (elem); \ 116 | cbuf.m_putIdx++; \ 117 | } while(0) 118 | 119 | /** 120 | * Retrieves an element from the beginning of the circular buffer 121 | */ 122 | 123 | #define CBUF_Pop( cbuf ) ({ \ 124 | __typeof__(cbuf.m_entry[0]) _elem = (cbuf.m_entry)[ cbuf.m_getIdx & (( cbuf##_SIZE ) - 1 )]; \ 125 | cbuf.m_getIdx++; \ 126 | _elem; }) 127 | 128 | /** 129 | * Returns a pointer to the last spot that was pushed. 130 | */ 131 | 132 | #define CBUF_GetLastEntryPtr( cbuf ) &(cbuf.m_entry)[ ( cbuf.m_putIdx - 1 ) & (( cbuf##_SIZE ) - 1 )] 133 | 134 | /** 135 | * Returns a pointer to the next spot to push. This can be used 136 | * in conjunction with CBUF_AdvancePushIdx to fill out an entry 137 | * before indicating that it's available. It is the caller's 138 | * responsibility to enure that space is available, and that no 139 | * other items are pushed to overwrite the entry returned. 140 | */ 141 | 142 | #define CBUF_GetPushEntryPtr( cbuf ) &(cbuf.m_entry)[ cbuf.m_putIdx & (( cbuf##_SIZE ) - 1 )] 143 | 144 | /** 145 | * Advances the put index. This is useful if you need to 146 | * reserve space for an item but can't fill in the contents 147 | * yet. CBUG_GetLastEntryPtr can be used to get a pointer to 148 | * the item. It is the caller's responsibility to ensure that 149 | * the item isn't popped before the contents are filled in. 150 | */ 151 | 152 | #define CBUF_AdvancePushIdx( cbuf ) cbuf.m_putIdx++ 153 | 154 | /** 155 | * Advances the get index. This is slightly more efficient than 156 | * popping and tossing the result. 157 | */ 158 | 159 | #define CBUF_AdvancePopIdx( cbuf ) cbuf.m_getIdx++ 160 | 161 | /** 162 | * Retrieves the idx'th element from the beginning of 163 | * the circular buffer 164 | */ 165 | 166 | #define CBUF_Get( cbuf, idx ) (cbuf.m_entry)[( cbuf.m_getIdx + idx ) & (( cbuf##_SIZE ) - 1 )] 167 | 168 | /** 169 | * Retrieves the idx'th element from the end of the 170 | * circular buffer. 171 | */ 172 | 173 | #define CBUF_GetEnd( cbuf, idx ) (cbuf.m_entry)[( cbuf.m_putIdx - idx - 1 ) & (( cbuf##_SIZE ) - 1 )] 174 | 175 | /** 176 | * Returns a pointer to the next spot to push. 177 | */ 178 | 179 | #define CBUF_GetPopEntryPtr( cbuf ) &(cbuf.m_entry)[ cbuf.m_getIdx & (( cbuf##_SIZE ) - 1 )] 180 | 181 | /** 182 | * Determines if the circular buffer is empty. 183 | */ 184 | 185 | #define CBUF_IsEmpty( cbuf ) ( CBUF_Len( cbuf ) == 0 ) 186 | 187 | /** 188 | * Determines if the circular buffer is full. 189 | */ 190 | 191 | #define CBUF_IsFull( cbuf ) ( CBUF_Len( cbuf ) == ( cbuf##_SIZE )) 192 | 193 | /** 194 | * Determines if the circular buffer is currenly overflowed or underflowed. 195 | */ 196 | 197 | #define CBUF_Error( cbuf ) ( CBUF_Len( cbuf ) > cbuf##_SIZE ) 198 | 199 | #if defined( __cplusplus ) 200 | 201 | template < class IndexType, unsigned Size, class EntryType > 202 | class CBUF 203 | { 204 | public: 205 | 206 | CBUF() 207 | { 208 | m_getIdx = m_putIdx = 0; 209 | } 210 | 211 | IndexType Len() const { return m_putIdx - m_getIdx; } 212 | 213 | bool IsEmpty() const { return Len() == 0; } 214 | bool IsFull() const { return Len() == Size; } 215 | bool Error() const { return Len() > Size; } 216 | 217 | void Push( EntryType val ) 218 | { 219 | m_entry[ m_putIdx & ( Size - 1 )] = val; 220 | m_putIdx++; 221 | } 222 | 223 | EntryType Pop() 224 | { 225 | EntryType item = m_entry[ m_getIdx & ( Size - 1 )]; 226 | m_getIdx++; 227 | return item; 228 | } 229 | 230 | private: 231 | 232 | volatile IndexType m_getIdx; 233 | volatile IndexType m_putIdx; 234 | EntryType m_entry[ Size ]; 235 | 236 | }; 237 | 238 | #endif // __cplusplus 239 | 240 | /* ---- Variable Externs ------------------------------------------------- */ 241 | /* ---- Function Prototypes ---------------------------------------------- */ 242 | 243 | /** @} */ 244 | 245 | #endif // CBUF_H 246 | -------------------------------------------------------------------------------- /firmware/clock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * clock.c - part of USBasp 3 | * 4 | * Autor..........: Thomas Fischl 5 | * Description....: Provides functions for timing/waiting 6 | * Licence........: GNU GPL v2 (see Readme.txt) 7 | * Creation Date..: 2005-02-23 8 | * Last change....: 2005-04-20 9 | */ 10 | 11 | #include 12 | #include 13 | #include "clock.h" 14 | 15 | /* wait time * 320 us */ 16 | void clockWait(uint8_t time) { 17 | 18 | //uint8_t i; 19 | //for (i = 0; i < time; i++) { 20 | do { 21 | uint8_t starttime = TIMERVALUE; 22 | while ((uint8_t) (TIMERVALUE - starttime) < CLOCK_T_320us); 23 | } while (--time); 24 | } 25 | -------------------------------------------------------------------------------- /firmware/clock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * clock.h - part of USBasp 3 | * 4 | * Autor..........: Thomas Fischl 5 | * Description....: Provides functions for timing/waiting 6 | * Licence........: GNU GPL v2 (see Readme.txt) 7 | * Creation Date..: 2005-02-23 8 | * Last change....: 2006-11-16 9 | */ 10 | 11 | #ifndef __clock_h_included__ 12 | #define __clock_h_included__ 13 | 14 | #define TIMERVALUE TCNT0 15 | 16 | #if F_CPU == 12000000L 17 | # define CLOCK_T_320us 60 18 | #elif F_CPU == 16000000L /* ATmega8 max speed */ 19 | # define CLOCK_T_320us 80 20 | #elif F_CPU == 18000000L 21 | # define CLOCK_T_320us 90 22 | #elif F_CPU == 20000000L 23 | # define CLOCK_T_320us 100 24 | #endif 25 | 26 | #if (defined __AVR_ATmega8__) || (defined __AVR_ATmega8A__) 27 | #define TCCR0B TCCR0 28 | #endif 29 | 30 | /* set prescaler to 64 */ 31 | #define clockInit() TCCR0B = (1 << CS01) | (1 << CS00); 32 | 33 | /* wait time * 320 us */ 34 | void clockWait(uint8_t time); 35 | 36 | #endif /* __clock_h_included__ */ 37 | -------------------------------------------------------------------------------- /firmware/isp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * isp.c - part of USBasp 3 | * 4 | * Autor..........: Thomas Fischl 5 | * Ralph Doncaster at gmail dot com 6 | * Description....: Provides functions for communication/programming 7 | * over ISP interface 8 | * Licence........: GNU GPL v2 (see Readme.txt) 9 | * Creation Date..: 2005-02-23 10 | * Last change....: 2020-09-14 11 | */ 12 | 13 | #include 14 | #include "isp.h" 15 | #include "clock.h" 16 | #include "usbasp.h" 17 | 18 | uchar sck_sw_delay; 19 | uchar isp_hiaddr; 20 | 21 | static inline void spiHWenable() { 22 | /* enable SPI, master */ 23 | SPCR |= (1 << SPE) | (1 << MSTR); 24 | } 25 | 26 | static inline void spiHWdisable() { 27 | SPCR = 0; 28 | } 29 | 30 | void ispSetSCKOption(uchar option) { 31 | 32 | if (option == USBASP_ISP_SCK_AUTO) 33 | option = USBASP_ISP_SCK_1500; 34 | 35 | if (option >= USBASP_ISP_SCK_93_75) { 36 | ispTransmit = ispTransmit_hw; 37 | SPSR = 0; 38 | sck_sw_delay = 1; /* force RST#/SCK pulse for 320us */ 39 | 40 | switch (option) { 41 | 42 | case USBASP_ISP_SCK_3000: 43 | /* 3MHz, XTAL/4 */ 44 | SPCR = 0; 45 | break; 46 | case USBASP_ISP_SCK_1500: 47 | default: 48 | /* 1.5MHz, XTAL/8 */ 49 | SPSR = (1 << SPI2X); 50 | // fall through 51 | case USBASP_ISP_SCK_750: 52 | /* 750kHz, XTAL/16 */ 53 | SPCR = (1 << SPR0); 54 | break; 55 | case USBASP_ISP_SCK_375: 56 | /* 375kHz, XTAL/32 (default) */ 57 | SPSR = (1 << SPI2X); 58 | // fall through 59 | case USBASP_ISP_SCK_187_5: 60 | /* 187.5kHz XTAL/64 */ 61 | SPCR = (1 << SPR1); 62 | break; 63 | case USBASP_ISP_SCK_93_75: 64 | /* 93.75kHz XTAL/128 */ 65 | SPCR = (1 << SPR1) | (1 << SPR0); 66 | break; 67 | } 68 | 69 | } else { 70 | ispTransmit = ispTransmit_sw; 71 | #if 0 72 | switch (option) { 73 | 74 | case USBASP_ISP_SCK_32: 75 | sck_sw_delay = 3; break; 76 | case USBASP_ISP_SCK_16: 77 | sck_sw_delay = 6; break; 78 | case USBASP_ISP_SCK_8: 79 | sck_sw_delay = 12; break; 80 | case USBASP_ISP_SCK_4: 81 | sck_sw_delay = 24; break; 82 | case USBASP_ISP_SCK_2: 83 | sck_sw_delay = 48; break; 84 | case USBASP_ISP_SCK_1: 85 | sck_sw_delay = 96; break; 86 | case USBASP_ISP_SCK_0_5: 87 | sck_sw_delay = 192; break; 88 | } 89 | #endif 90 | /* more efficient than switch */ 91 | sck_sw_delay = 3 << (USBASP_ISP_SCK_32 - option); 92 | } 93 | } 94 | 95 | void ispDelay() { 96 | 97 | uint8_t starttime = TIMERVALUE; 98 | while ((uint8_t) (TIMERVALUE - starttime) < sck_sw_delay) { 99 | } 100 | } 101 | 102 | void ispConnect() { 103 | 104 | /* all ISP pins were inputs before, now set output pins 105 | * V-USB modifies DDR, so set only one at a time for atomic sbi */ 106 | ISP_DDR |= (1 << ISP_SCK); 107 | ISP_DDR |= (1 << ISP_MOSI); 108 | ISP_DDR |= (1 << ISP_RST); 109 | 110 | /* enable pullup on MISO for improved noise immunity */ 111 | ISP_OUT |= (1 << ISP_MISO); 112 | 113 | /* positive pulse on RST for at least 2 target clock cycles */ 114 | // ISP_OUT |= (1 << ISP_RST); 115 | // clockWait(1); /* 320us */ 116 | // ISP_OUT &= ~(1 << ISP_RST); 117 | 118 | /* Initial extended address value */ 119 | isp_hiaddr = 0xff; /* ensure that even 0x00000 causes a write of the extended address byte */ 120 | } 121 | 122 | void ispDisconnect() { 123 | 124 | /* set all ISP pins inputs */ 125 | ISP_DDR &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI)); 126 | /* switch pullups off */ 127 | ISP_OUT &= ~(1 << ISP_MISO); 128 | ISP_OUT &= ~(1 << ISP_MOSI); 129 | 130 | /* disable hardware SPI */ 131 | spiHWdisable(); 132 | 133 | prog_sck = USBASP_ISP_SCK_AUTO; 134 | } 135 | 136 | // todo: make ispTransmit function that checks mode and branches 137 | uchar ispTransmit_sw(uchar send_byte) { 138 | 139 | uchar rec_byte = 0; 140 | uchar i; 141 | for (i = 0; i < 8; i++) { 142 | 143 | /* set MSB to MOSI-pin */ 144 | if ((send_byte & 0x80) != 0) { 145 | ISP_OUT |= (1 << ISP_MOSI); /* MOSI high */ 146 | } else { 147 | ISP_OUT &= ~(1 << ISP_MOSI); /* MOSI low */ 148 | } 149 | /* shift to next bit */ 150 | send_byte = send_byte << 1; 151 | 152 | /* receive data */ 153 | rec_byte = rec_byte << 1; 154 | if ((ISP_IN & (1 << ISP_MISO)) != 0) { 155 | rec_byte++; 156 | } 157 | 158 | /* pulse SCK */ 159 | ISP_OUT |= (1 << ISP_SCK); /* SCK high */ 160 | ispDelay(); 161 | ISP_OUT &= ~(1 << ISP_SCK); /* SCK low */ 162 | ispDelay(); 163 | } 164 | 165 | return rec_byte; 166 | } 167 | 168 | uchar ispTransmit_hw(uchar send_byte) { 169 | SPDR = send_byte; 170 | 171 | while (!(SPSR & (1 << SPIF))); 172 | return SPDR; 173 | } 174 | 175 | uchar ispEnterProgrammingMode() { 176 | uchar check; 177 | 178 | if (prog_sck == USBASP_ISP_SCK_AUTO) 179 | prog_sck = USBASP_ISP_SCK_1500; 180 | 181 | while (prog_sck >= USBASP_ISP_SCK_0_5) { 182 | uchar (*spiTx)(uchar) = ispTransmit; 183 | 184 | if (ispTransmit == ispTransmit_hw) spiHWenable(); 185 | 186 | uchar tries = 3; 187 | do { 188 | /* AVR probe */ 189 | 190 | /* pulse RST */ 191 | ISP_OUT |= (1 << ISP_RST); /* RST high */ 192 | clockWait(1); /* 320us */ 193 | ISP_OUT &= ~(1 << ISP_RST); /* RST low */ 194 | 195 | /* datasheet says wait 20ms, even though less seems fine */ 196 | clockWait(20 / 0.320); /* wait before PE */ 197 | 198 | spiTx(0xAC); 199 | spiTx(0x53); 200 | check = spiTx(0); 201 | spiTx(0); 202 | 203 | if (check == 0x53) { 204 | /* Don't bump up speed to 3 Mhz */ 205 | // if(prog_sck < USBASP_ISP_SCK_1500){ 206 | 207 | // /* bump up speed now that programming mode is enabled */ 208 | // /* http://nerdralph.blogspot.com/2020/09/recording-reset-pin.html */ 209 | // spiHWdisable(); 210 | // ispSetSCKOption(prog_sck + 1); 211 | // if (ispTransmit == ispTransmit_hw) spiHWenable(); 212 | 213 | // } 214 | return 0; 215 | } 216 | 217 | 218 | /* AT89* Probe */ 219 | 220 | ISP_OUT |= (1 << ISP_RST); /* RST high */ 221 | clockWait(5); /* 1.6 ms */ 222 | 223 | spiTx(0xAC); 224 | spiTx(0x53); 225 | spiTx(0); 226 | check = spiTx(0); 227 | 228 | if (check == 0x69){ 229 | return 0; 230 | } 231 | 232 | } while (--tries); 233 | 234 | spiHWdisable(); 235 | 236 | ispSetSCKOption(--prog_sck); /* try lower speed */ 237 | } 238 | 239 | return 1; /* error: device dosn't answer */ 240 | } 241 | 242 | static void ispUpdateExtended(unsigned long address) 243 | { 244 | uchar curr_hiaddr; 245 | 246 | curr_hiaddr = (address >> 17); 247 | 248 | /* check if extended address byte is changed */ 249 | if(isp_hiaddr != curr_hiaddr) 250 | { 251 | isp_hiaddr = curr_hiaddr; 252 | /* Load Extended Address byte */ 253 | ispTransmit(0x4D); 254 | ispTransmit(0x00); 255 | ispTransmit(isp_hiaddr); 256 | ispTransmit(0x00); 257 | } 258 | } 259 | 260 | uchar ispReadFlash(unsigned long address) { 261 | 262 | ispUpdateExtended(address); 263 | 264 | ispTransmit(0x20 | ((address & 1) << 3)); 265 | ispTransmit(address >> 9); 266 | ispTransmit(address >> 1); 267 | return ispTransmit(0); 268 | } 269 | 270 | uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode) { 271 | 272 | /* 0xFF is value after chip erase, so skip programming 273 | if (data == 0xFF) { 274 | return 0; 275 | } 276 | */ 277 | 278 | ispUpdateExtended(address); 279 | 280 | ispTransmit(0x40 | ((address & 1) << 3)); 281 | ispTransmit(address >> 9); 282 | ispTransmit(address >> 1); 283 | ispTransmit(data); 284 | 285 | if (pollmode == 0) 286 | return 0; 287 | 288 | if (data == 0x7F) { 289 | clockWait(15); /* wait 4,8 ms */ 290 | return 0; 291 | } else { 292 | 293 | /* polling flash */ 294 | uchar retries = 30; 295 | uint8_t starttime = TIMERVALUE; 296 | while (retries != 0) { 297 | if (ispReadFlash(address) != 0x7F) { 298 | return 0; 299 | }; 300 | 301 | if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { 302 | starttime = TIMERVALUE; 303 | retries--; 304 | } 305 | 306 | } 307 | return 1; /* error */ 308 | } 309 | 310 | } 311 | 312 | uchar ispFlushPage(unsigned long address, uchar pollvalue) { 313 | 314 | ispUpdateExtended(address); 315 | 316 | ispTransmit(0x4C); // write page 317 | ispTransmit(address >> 9); 318 | ispTransmit(address >> 1); 319 | ispTransmit(0); 320 | 321 | if (pollvalue == 0xFF) { 322 | clockWait(15); 323 | return 0; 324 | } else { 325 | 326 | /* polling flash */ 327 | uchar retries = 30; 328 | uint8_t starttime = TIMERVALUE; 329 | 330 | while (retries != 0) { 331 | if (ispReadFlash(address) != 0xFF) { 332 | return 0; 333 | }; 334 | 335 | if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) { 336 | starttime = TIMERVALUE; 337 | retries--; 338 | } 339 | 340 | } 341 | 342 | return 1; /* error */ 343 | } 344 | 345 | } 346 | 347 | uchar ispReadEEPROM(unsigned int address) { 348 | ispTransmit(0xA0); 349 | ispTransmit(address >> 8); 350 | ispTransmit(address); 351 | return ispTransmit(0); 352 | } 353 | 354 | uchar ispWriteEEPROM(unsigned int address, uchar data) { 355 | 356 | ispTransmit(0xC0); 357 | ispTransmit(address >> 8); 358 | ispTransmit(address); 359 | ispTransmit(data); 360 | 361 | clockWait(30); // wait 9,6 ms 362 | 363 | return 0; 364 | } 365 | -------------------------------------------------------------------------------- /firmware/isp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * isp.h - part of USBasp 3 | * 4 | * Autor..........: Thomas Fischl 5 | * Description....: Provides functions for communication/programming 6 | * over ISP interface 7 | * Licence........: GNU GPL v2 (see Readme.txt) 8 | * Creation Date..: 2005-02-23 9 | * Last change....: 2009-02-28 10 | */ 11 | 12 | #ifndef __isp_h_included__ 13 | #define __isp_h_included__ 14 | 15 | #ifndef uchar 16 | #define uchar unsigned char 17 | #endif 18 | 19 | #define ISP_OUT PORTB 20 | #define ISP_IN PINB 21 | #define ISP_DDR DDRB 22 | #define ISP_RST PB2 23 | #define ISP_MOSI PB3 24 | #define ISP_MISO PB4 25 | #define ISP_SCK PB5 26 | 27 | /* defined in main.c */ 28 | extern uchar prog_sck; 29 | 30 | /* Prepare connection to target device */ 31 | void ispConnect(); 32 | 33 | /* Close connection to target device */ 34 | void ispDisconnect(); 35 | 36 | /* read an write a byte from isp using software (slow) */ 37 | uchar ispTransmit_sw(uchar send_byte); 38 | 39 | /* read an write a byte from isp using hardware (fast) */ 40 | uchar ispTransmit_hw(uchar send_byte); 41 | 42 | /* enter programming mode */ 43 | uchar ispEnterProgrammingMode(); 44 | 45 | /* read byte from eeprom at given address */ 46 | uchar ispReadEEPROM(unsigned int address); 47 | 48 | /* write byte to flash at given address */ 49 | uchar ispWriteFlash(unsigned long address, uchar data, uchar pollmode); 50 | 51 | uchar ispFlushPage(unsigned long address, uchar pollvalue); 52 | 53 | /* read byte from flash at given address */ 54 | uchar ispReadFlash(unsigned long address); 55 | 56 | /* write byte to eeprom at given address */ 57 | uchar ispWriteEEPROM(unsigned int address, uchar data); 58 | 59 | /* pointer to sw or hw transmit function */ 60 | uchar (*ispTransmit)(uchar); 61 | 62 | /* set SCK speed. call before ispConnect! */ 63 | void ispSetSCKOption(uchar sckoption); 64 | 65 | /* load extended address byte */ 66 | void ispLoadExtendedAddressByte(unsigned long address); 67 | 68 | #endif /* __isp_h_included__ */ 69 | -------------------------------------------------------------------------------- /firmware/serialnumber.c: -------------------------------------------------------------------------------- 1 | /* 2 | * serialnumber.c - part of USBasp 3 | * 4 | * Autor..........: Dimitrios Chr. Ioannidis ( d.ioannidis@nephelae.eu ) 5 | * Description....: Provides functions for updating the Serial Number 6 | using HID 7 | * Licence........: GNU GPL v2 (see Readme.txt) 8 | * Creation Date..: 2023-04-01 9 | * Last change....: 2023-04-11 10 | */ 11 | 12 | #include "usbdrv.h" 13 | #include "serialnumber.h" 14 | 15 | void serialNumberWrite(uchar *reportData) { 16 | 17 | uchar i; 18 | 19 | unsigned tmp = (reportData[1] << 8) | reportData[0]; 20 | 21 | for (i=4; i >= 1; i--) 22 | { 23 | eeprom_update_byte(((uint8_t *)&usbDescriptorStringSerialNumber + i*2), 48 + tmp%10); 24 | tmp /= 10; 25 | } 26 | } -------------------------------------------------------------------------------- /firmware/serialnumber.h: -------------------------------------------------------------------------------- 1 | /* 2 | * serialnumber.h - part of USBasp 3 | * 4 | * Autor..........: Dimitrios Chr. Ioannidis ( d.ioannidis@nephelae.eu ) 5 | * Description....: Provides functions for updating the Serial Number 6 | using HID 7 | * Licence........: GNU GPL v2 (see Readme.txt) 8 | * Creation Date..: 2023-04-01 9 | * Last change....: 2023-04-11 10 | */ 11 | 12 | #ifndef __serialnumber_h_included__ 13 | #define __serialnumber_h_included__ 14 | 15 | #ifndef uchar 16 | #define uchar unsigned char 17 | #endif 18 | 19 | void serialNumberWrite(uchar *reportData); 20 | 21 | #endif /* __serialnumber_h_included__ */ -------------------------------------------------------------------------------- /firmware/tpi.S: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dioannidis/usbasp/1255367ea0469b52e0694993bbd8a4bf96a97556/firmware/tpi.S -------------------------------------------------------------------------------- /firmware/tpi.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dioannidis/usbasp/1255367ea0469b52e0694993bbd8a4bf96a97556/firmware/tpi.h -------------------------------------------------------------------------------- /firmware/tpi_defs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dioannidis/usbasp/1255367ea0469b52e0694993bbd8a4bf96a97556/firmware/tpi_defs.h -------------------------------------------------------------------------------- /firmware/uart.c: -------------------------------------------------------------------------------- 1 | /* Name: uart.c 2 | * 3 | * UART support 4 | * 5 | * 2016 original implementation Adam Krasuski (https://github.com/akrasuski1) 6 | * 2021 tweaks by Dimitrios Chr. Ioannidis ( d.ioannidis@nephelae.eu ) 7 | * 8 | * Tabsize: 4 9 | * License: GNU GPL v2 (see Readme.txt) 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "usbdrv.h" 17 | #include "usbasp.h" 18 | #include "uart.h" 19 | #include "cbuf.h" 20 | 21 | volatile uint8_t dataByte; 22 | 23 | void __vector_usart_rxc_wrapped() __attribute__ ((signal)); 24 | void __vector_usart_rxc_wrapped(){ 25 | if (!CBUF_IsFull(rx_Q)){ 26 | *CBUF_GetPushEntryPtr(rx_Q) = dataByte; 27 | CBUF_AdvancePushIdx(rx_Q); 28 | } 29 | } 30 | 31 | #if (defined __AVR_ATmega8__) || (defined __AVR_ATmega8A__) 32 | ISR(USART_RXC_vect, ISR_NAKED){ 33 | #elif (defined __AVR_ATmega88__) || (defined __AVR_ATmega88PA__) 34 | ISR(USART_RX_vect, ISR_NAKED){ 35 | #endif 36 | __asm__ volatile( 37 | "lds __tmp_reg__, %0 \n" 38 | " sts %1, __tmp_reg__ \n" 39 | " rjmp __vector_usart_rxc_wrapped \n" 40 | :: "m"(USBASPUART_UDR),"m"(dataByte) 41 | ); 42 | } 43 | 44 | void __vector_usart_udre_wrapped() __attribute__ ((signal)); 45 | void __vector_usart_udre_wrapped(){ 46 | 47 | if(!CBUF_IsEmpty(tx_Q)){ 48 | USBASPUART_UDR=*CBUF_GetPopEntryPtr(tx_Q); 49 | CBUF_AdvancePopIdx(tx_Q); 50 | } else { 51 | USBASPUART_UCSRB &= ~(1<>8); 114 | USBASPUART_UBRRL=(unsigned char)baud; 115 | 116 | // Turn on RX/TX and RX interrupt. 117 | USBASPUART_UCSRB=(1< 18 | 19 | #if (defined __AVR_ATmega8__) || (defined __AVR_ATmega8A__) 20 | 21 | # define USBASPUART_UDR UDR 22 | # define USBASPUART_UDRIE UDRIE 23 | # define USBASPUART_UCSRA UCSRA 24 | # define USBASPUART_UCSRB UCSRB 25 | # define USBASPUART_UCSRC UCSRC 26 | # define USBASPUART_U2X U2X 27 | # define USBASPUART_UCSZ0 UCSZ0 28 | # define USBASPUART_UCSZ1 UCSZ1 29 | # define USBASPUART_UCSZ2 UCSZ2 30 | # define USBASPUART_UPM0 UPM0 31 | # define USBASPUART_UPM1 UPM1 32 | # define USBASPUART_USBS USBS 33 | # define USBASPUART_UBRRL UBRRL 34 | # define USBASPUART_UBRRH UBRRH 35 | # define USBASPUART_RXCIE RXCIE 36 | # define USBASPUART_RXEN RXEN 37 | # define USBASPUART_TXEN TXEN 38 | 39 | #elif (defined __AVR_ATmega88__) || (defined __AVR_ATmega88PA__) 40 | 41 | # define USBASPUART_UDR UDR0 42 | # define USBASPUART_UDRIE UDRIE0 43 | # define USBASPUART_UCSRA UCSR0A 44 | # define USBASPUART_UCSRB UCSR0B 45 | # define USBASPUART_UCSRC UCSR0C 46 | # define USBASPUART_U2X U2X0 47 | # define USBASPUART_UCSZ0 UCSZ00 48 | # define USBASPUART_UCSZ1 UCSZ01 49 | # define USBASPUART_UCSZ2 UCSZ02 50 | # define USBASPUART_UPM0 UPM00 51 | # define USBASPUART_UPM1 UPM01 52 | # define USBASPUART_USBS USBS0 53 | # define USBASPUART_UBRRL UBRR0L 54 | # define USBASPUART_UBRRH UBRR0H 55 | # define USBASPUART_RXCIE RXCIE0 56 | # define USBASPUART_RXEN RXEN0 57 | # define USBASPUART_TXEN TXEN0 58 | 59 | #endif 60 | 61 | #define rx_Q_SIZE 128 62 | #define tx_Q_SIZE 128 63 | 64 | volatile struct 65 | { 66 | uint8_t m_getIdx; 67 | uint8_t m_putIdx; 68 | uint8_t m_entry[rx_Q_SIZE]; 69 | } rx_Q; 70 | 71 | volatile struct 72 | { 73 | uint8_t m_getIdx; 74 | uint8_t m_putIdx; 75 | uint8_t m_entry[tx_Q_SIZE]; 76 | } tx_Q; 77 | 78 | uchar uart_config(uchar *cfgData); 79 | uchar uart_disable(); 80 | 81 | #endif // UART_H 82 | -------------------------------------------------------------------------------- /firmware/usbasp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * usbasp.c - part of USBasp 3 | * 4 | * 2023 Add USBASP_CAP_SNHIDUPDATE by Dimitrios Chr. Ioannidis ( d.ioannidis@nephelae.eu ) 5 | * 6 | * Autor..........: Thomas Fischl 7 | * Description....: Definitions and macros for usbasp 8 | * Licence........: GNU GPL v2 (see Readme.txt) 9 | * Creation Date..: 2009-02-28 10 | * Last change....: 2023-03-22 11 | */ 12 | 13 | #ifndef USBASP_H_ 14 | #define USBASP_H_ 15 | 16 | /* USB function call identifiers */ 17 | // ISP: 18 | #define USBASP_FUNC_CONNECT 1 19 | #define USBASP_FUNC_DISCONNECT 2 20 | #define USBASP_FUNC_TRANSMIT 3 21 | #define USBASP_FUNC_READFLASH 4 22 | #define USBASP_FUNC_ENABLEPROG 5 23 | #define USBASP_FUNC_WRITEFLASH 6 24 | #define USBASP_FUNC_READEEPROM 7 25 | #define USBASP_FUNC_WRITEEEPROM 8 26 | #define USBASP_FUNC_SETLONGADDRESS 9 27 | #define USBASP_FUNC_SETISPSCK 10 28 | // TPI: 29 | #define USBASP_FUNC_TPI_CONNECT 11 30 | #define USBASP_FUNC_TPI_DISCONNECT 12 31 | #define USBASP_FUNC_TPI_RAWREAD 13 32 | #define USBASP_FUNC_TPI_RAWWRITE 14 33 | #define USBASP_FUNC_TPI_READBLOCK 15 34 | #define USBASP_FUNC_TPI_WRITEBLOCK 16 35 | #define USBASP_FUNC_GETCAPABILITIES 127 36 | // UART: 37 | #define USBASP_FUNC_UART_CONFIG 60 38 | #define USBASP_FUNC_UART_DISABLE 63 39 | 40 | /* USBASP capabilities */ 41 | #define USBASP_CAP_0_TPI 0x01 42 | #define USBASP_CAP_6_UART 0x40 43 | #define USBASP_CAP_HIDUART 0x80 44 | #define USBASP_CAP_SNHIDUPDATE 0x20 45 | 46 | #define USBASP_CAP_12MHZ_CLOCK 0x00 47 | #define USBASP_CAP_16MHZ_CLOCK 0x01 48 | #define USBASP_CAP_18MHZ_CLOCK 0x02 49 | #define USBASP_CAP_20MHZ_CLOCK 0x03 50 | 51 | /* programming state */ 52 | #define PROG_STATE_IDLE 0 53 | #define PROG_STATE_WRITEFLASH 1 54 | #define PROG_STATE_READFLASH 2 55 | #define PROG_STATE_READEEPROM 3 56 | #define PROG_STATE_WRITEEEPROM 4 57 | #define PROG_STATE_TPI_READ 5 58 | #define PROG_STATE_TPI_WRITE 6 59 | #define PROG_STATE_SET_REPORT 7 60 | 61 | /* uart state */ 62 | #define UART_STATE_ENABLED 16 63 | #define UART_STATE_DISABLED 0 64 | 65 | /* Block mode flags */ 66 | #define PROG_BLOCKFLAG_FIRST 1 67 | #define PROG_BLOCKFLAG_LAST 2 68 | 69 | /* ISP SCK speed identifiers */ 70 | #define USBASP_ISP_SCK_AUTO 0 71 | #define USBASP_ISP_SCK_0_5 1 /* 500 Hz */ 72 | #define USBASP_ISP_SCK_1 2 /* 1 kHz */ 73 | #define USBASP_ISP_SCK_2 3 /* 2 kHz */ 74 | #define USBASP_ISP_SCK_4 4 /* 4 kHz */ 75 | #define USBASP_ISP_SCK_8 5 /* 8 kHz */ 76 | #define USBASP_ISP_SCK_16 6 /* 16 kHz */ 77 | #define USBASP_ISP_SCK_32 7 /* 32 kHz */ 78 | #define USBASP_ISP_SCK_93_75 8 /* 93.75 kHz */ 79 | #define USBASP_ISP_SCK_187_5 9 /* 187.5 kHz */ 80 | #define USBASP_ISP_SCK_375 10 /* 375 kHz */ 81 | #define USBASP_ISP_SCK_750 11 /* 750 kHz */ 82 | #define USBASP_ISP_SCK_1500 12 /* 1.5 MHz */ 83 | #define USBASP_ISP_SCK_3000 13 /* 3 MHz */ 84 | 85 | // UART flags. 86 | #define USBASP_UART_PARITY_MASK 0b11 87 | #define USBASP_UART_PARITY_NONE 0b00 88 | #define USBASP_UART_PARITY_EVEN 0b01 89 | #define USBASP_UART_PARITY_ODD 0b10 90 | 91 | #define USBASP_UART_STOP_MASK 0b100 92 | #define USBASP_UART_STOP_1BIT 0b000 93 | #define USBASP_UART_STOP_2BIT 0b100 94 | 95 | #define USBASP_UART_BYTES_MASK 0b111000 96 | #define USBASP_UART_BYTES_5B 0b000000 97 | #define USBASP_UART_BYTES_6B 0b001000 98 | #define USBASP_UART_BYTES_7B 0b010000 99 | #define USBASP_UART_BYTES_8B 0b011000 100 | #define USBASP_UART_BYTES_9B 0b100000 101 | 102 | /* macros for gpio functions */ 103 | /* LEDs are active low */ 104 | #define ledRedOff() DDRC &= ~(1 << PC1) 105 | #define ledRedOn() DDRC |= (1 << PC1) 106 | #define ledGreenOff() DDRC &= ~(1 << PC0) 107 | #define ledGreenOn() DDRC |= (1 << PC0) 108 | 109 | #endif /* USBASP_H_ */ -------------------------------------------------------------------------------- /firmware/usbdrv/Changelog.txt: -------------------------------------------------------------------------------- 1 | This file documents changes in the firmware-only USB driver for atmel's AVR 2 | microcontrollers. New entries are always appended to the end of the file. 3 | Scroll down to the bottom to see the most recent changes. 4 | 5 | 2005-04-01: 6 | - Implemented endpoint 1 as interrupt-in endpoint. 7 | - Moved all configuration options to usbconfig.h which is not part of the 8 | driver. 9 | - Changed interface for usbVendorSetup(). 10 | - Fixed compatibility with ATMega8 device. 11 | - Various minor optimizations. 12 | 13 | 2005-04-11: 14 | - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead() 15 | and usbFunctionWrite() now. Added configuration options to choose which 16 | of these functions to compile in. 17 | - Assembler module delivers receive data non-inverted now. 18 | - Made register and bit names compatible with more AVR devices. 19 | 20 | 2005-05-03: 21 | - Allow address of usbRxBuf on any memory page as long as the buffer does 22 | not cross 256 byte page boundaries. 23 | - Better device compatibility: works with Mega88 now. 24 | - Code optimization in debugging module. 25 | - Documentation updates. 26 | 27 | 2006-01-02: 28 | - Added (free) default Vendor- and Product-IDs bought from voti.nl. 29 | - Added USBID-License.txt file which defines the rules for using the free 30 | shared VID/PID pair. 31 | - Added Readme.txt to the usbdrv directory which clarifies administrative 32 | issues. 33 | 34 | 2006-01-25: 35 | - Added "configured state" to become more standards compliant. 36 | - Added "HALT" state for interrupt endpoint. 37 | - Driver passes the "USB Command Verifier" test from usb.org now. 38 | - Made "serial number" a configuration option. 39 | - Minor optimizations, we now recommend compiler option "-Os" for best 40 | results. 41 | - Added a version number to usbdrv.h 42 | 43 | 2006-02-03: 44 | - New configuration variable USB_BUFFER_SECTION for the memory section where 45 | the USB rx buffer will go. This defaults to ".bss" if not defined. Since 46 | this buffer MUST NOT cross 256 byte pages (not even touch a page at the 47 | end), the user may want to pass a linker option similar to 48 | "-Wl,--section-start=.mybuffer=0x800060". 49 | - Provide structure for usbRequest_t. 50 | - New defines for USB constants. 51 | - Prepared for HID implementations. 52 | - Increased data size limit for interrupt transfers to 8 bytes. 53 | - New macro usbInterruptIsReady() to query interrupt buffer state. 54 | 55 | 2006-02-18: 56 | - Ensure that the data token which is sent as an ack to an OUT transfer is 57 | always zero sized. This fixes a bug where the host reports an error after 58 | sending an out transfer to the device, although all data arrived at the 59 | device. 60 | - Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite(). 61 | 62 | * Release 2006-02-20 63 | 64 | - Give a compiler warning when compiling with debugging turned on. 65 | - Added Oleg Semyonov's changes for IAR-cc compatibility. 66 | - Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect() 67 | (also thanks to Oleg!). 68 | - Rearranged tests in usbPoll() to save a couple of instructions in the most 69 | likely case that no actions are pending. 70 | - We need a delay between the SET ADDRESS request until the new address 71 | becomes active. This delay was handled in usbPoll() until now. Since the 72 | spec says that the delay must not exceed 2ms, previous versions required 73 | aggressive polling during the enumeration phase. We have now moved the 74 | handling of the delay into the interrupt routine. 75 | - We must not reply with NAK to a SETUP transaction. We can only achieve this 76 | by making sure that the rx buffer is empty when SETUP tokens are expected. 77 | We therefore don't pass zero sized data packets from the status phase of 78 | a transfer to usbPoll(). This change MAY cause troubles if you rely on 79 | receiving a less than 8 bytes long packet in usbFunctionWrite() to 80 | identify the end of a transfer. usbFunctionWrite() will NEVER be called 81 | with a zero length. 82 | 83 | * Release 2006-03-14 84 | 85 | - Improved IAR C support: tiny memory model, more devices 86 | - Added template usbconfig.h file under the name usbconfig-prototype.h 87 | 88 | * Release 2006-03-26 89 | 90 | - Added provision for one more interrupt-in endpoint (endpoint 3). 91 | - Added provision for one interrupt-out endpoint (endpoint 1). 92 | - Added flowcontrol macros for USB. 93 | - Added provision for custom configuration descriptor. 94 | - Allow ANY two port bits for D+ and D-. 95 | - Merged (optional) receive endpoint number into global usbRxToken variable. 96 | - Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the 97 | variable name from the single port letter instead of computing the address 98 | of related ports from the output-port address. 99 | 100 | * Release 2006-06-26 101 | 102 | - Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the 103 | new features. 104 | - Removed "#warning" directives because IAR does not understand them. Use 105 | unused static variables instead to generate a warning. 106 | - Do not include when compiling with IAR. 107 | - Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each 108 | USB descriptor should be handled. It is now possible to provide descriptor 109 | data in Flash, RAM or dynamically at runtime. 110 | - STALL is now a status in usbTxLen* instead of a message. We can now conform 111 | to the spec and leave the stall status pending until it is cleared. 112 | - Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the 113 | application code to reset data toggling on interrupt pipes. 114 | 115 | * Release 2006-07-18 116 | 117 | - Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes 118 | an assembler error. 119 | - usbDeviceDisconnect() takes pull-up resistor to high impedance now. 120 | 121 | * Release 2007-02-01 122 | 123 | - Merged in some code size improvements from usbtiny (thanks to Dick 124 | Streefland for these optimizations!) 125 | - Special alignment requirement for usbRxBuf not required any more. Thanks 126 | again to Dick Streefland for this hint! 127 | - Reverted to "#warning" instead of unused static variables -- new versions 128 | of IAR CC should handle this directive. 129 | - Changed Open Source license to GNU GPL v2 in order to make linking against 130 | other free libraries easier. We no longer require publication of the 131 | circuit diagrams, but we STRONGLY encourage it. If you improve the driver 132 | itself, PLEASE grant us a royalty free license to your changes for our 133 | commercial license. 134 | 135 | * Release 2007-03-29 136 | 137 | - New configuration option "USB_PUBLIC" in usbconfig.h. 138 | - Set USB version number to 1.10 instead of 1.01. 139 | - Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and 140 | USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences 141 | to USB_CFG_DESCR_PROPS_STRING_PRODUCT. 142 | - New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver 143 | code. 144 | - New assembler module for 16 MHz crystal. 145 | - usbdrvasm.S contains common code only, clock-specific parts have been moved 146 | to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively. 147 | 148 | * Release 2007-06-25 149 | 150 | - 16 MHz module: Do SE0 check in stuffed bits as well. 151 | 152 | * Release 2007-07-07 153 | 154 | - Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary 155 | for negative values. 156 | - Added 15 MHz module contributed by V. Bosch. 157 | - Interrupt vector name can now be configured. This is useful if somebody 158 | wants to use a different hardware interrupt than INT0. 159 | 160 | * Release 2007-08-07 161 | 162 | - Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is 163 | not exceeded. 164 | - More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN, 165 | USB_COUNT_SOF 166 | - USB_INTR_PENDING can now be a memory address, not just I/O 167 | 168 | * Release 2007-09-19 169 | 170 | - Split out common parts of assembler modules into separate include file 171 | - Made endpoint numbers configurable so that given interface definitions 172 | can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h. 173 | - Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut() 174 | can handle any number of endpoints. 175 | - Define usbDeviceConnect() and usbDeviceDisconnect() even if no 176 | USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this 177 | case. 178 | 179 | * Release 2007-12-01 180 | 181 | - Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size 182 | when USB_CFG_PULLUP_IOPORTNAME is not defined. 183 | 184 | * Release 2007-12-13 185 | 186 | - Renamed all include-only assembler modules from *.S to *.inc so that 187 | people don't add them to their project sources. 188 | - Distribute leap bits in tx loop more evenly for 16 MHz module. 189 | - Use "macro" and "endm" instead of ".macro" and ".endm" for IAR 190 | - Avoid compiler warnings for constant expr range by casting some values in 191 | USB descriptors. 192 | 193 | * Release 2008-01-21 194 | 195 | - Fixed bug in 15 and 16 MHz module where the new address set with 196 | SET_ADDRESS was already accepted at the next NAK or ACK we send, not at 197 | the next data packet we send. This caused problems when the host polled 198 | too fast. Thanks to Alexander Neumann for his help and patience debugging 199 | this issue! 200 | 201 | * Release 2008-02-05 202 | 203 | - Fixed bug in 16.5 MHz module where a register was used in the interrupt 204 | handler before it was pushed. This bug was introduced with version 205 | 2007-09-19 when common parts were moved to a separate file. 206 | - Optimized CRC routine (thanks to Reimar Doeffinger). 207 | 208 | * Release 2008-02-16 209 | 210 | - Removed outdated IAR compatibility stuff (code sections). 211 | - Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK(). 212 | - Added optional routine usbMeasureFrameLength() for calibration of the 213 | internal RC oscillator. 214 | 215 | * Release 2008-02-28 216 | 217 | - USB_INITIAL_DATATOKEN defaults to USBPID_DATA1 now, which means that we 218 | start with sending USBPID_DATA0. 219 | - Changed defaults in usbconfig-prototype.h 220 | - Added free USB VID/PID pair for MIDI class devices 221 | - Restructured AVR-USB as separate package, not part of PowerSwitch any more. 222 | 223 | * Release 2008-04-18 224 | 225 | - Restructured usbdrv.c so that it is easier to read and understand. 226 | - Better code optimization with gcc 4. 227 | - If a second interrupt in endpoint is enabled, also add it to config 228 | descriptor. 229 | - Added config option for long transfers (above 254 bytes), see 230 | USB_CFG_LONG_TRANSFERS in usbconfig.h. 231 | - Added 20 MHz module contributed by Jeroen Benschop. 232 | 233 | * Release 2008-05-13 234 | 235 | - Fixed bug in libs-host/hiddata.c function usbhidGetReport(): length 236 | was not incremented, pointer to length was incremented instead. 237 | - Added code to command line tool(s) which claims an interface. This code 238 | is disabled by default, but may be necessary on newer Linux kernels. 239 | - Added usbconfig.h option "USB_CFG_CHECK_DATA_TOGGLING". 240 | - New header "usbportability.h" prepares ports to other development 241 | environments. 242 | - Long transfers (above 254 bytes) did not work when usbFunctionRead() was 243 | used to supply the data. Fixed this bug. [Thanks to Alexander Neumann!] 244 | - In hiddata.c (example code for sending/receiving data over HID), use 245 | USB_RECIP_DEVICE instead of USB_RECIP_INTERFACE for control transfers so 246 | that we need not claim the interface. 247 | - in usbPoll() loop 20 times polling for RESET state instead of 10 times. 248 | This accounts for the higher clock rates we now support. 249 | - Added a module for 12.8 MHz RC oscillator with PLL in receiver loop. 250 | - Added hook to SOF code so that oscillator can be tuned to USB frame clock. 251 | - Added timeout to waitForJ loop. Helps preventing unexpected hangs. 252 | - Added example code for oscillator tuning to libs-device (thanks to 253 | Henrik Haftmann for the idea to this routine). 254 | - Implemented option USB_CFG_SUPPRESS_INTR_CODE. 255 | 256 | * Release 2008-10-22 257 | 258 | - Fixed libs-device/osctune.h: OSCCAL is memory address on ATMega88 and 259 | similar, not offset of 0x20 needs to be added. 260 | - Allow distribution under GPLv3 for those who have to link against other 261 | code distributed under GPLv3. 262 | 263 | * Release 2008-11-26 264 | 265 | - Removed libusb-win32 dependency for hid-data example in Makefile.windows. 266 | It was never required and confused many people. 267 | - Added extern uchar usbRxToken to usbdrv.h. 268 | - Integrated a module with CRC checks at 18 MHz by Lukas Schrittwieser. 269 | 270 | * Release 2009-03-23 271 | 272 | - Hid-mouse example used settings from hid-data example, fixed that. 273 | - Renamed project to V-USB due to a trademark issue with Atmel(r). 274 | - Changed CommercialLicense.txt and USBID-License.txt to make the 275 | background of USB ID registration clearer. 276 | 277 | * Release 2009-04-15 278 | 279 | - Changed CommercialLicense.txt to reflect the new range of PIDs from 280 | Jason Kotzin. 281 | - Removed USBID-License.txt in favor of USB-IDs-for-free.txt and 282 | USB-ID-FAQ.txt 283 | - Fixed a bug in the 12.8 MHz module: End Of Packet decection was made in 284 | the center between bit 0 and 1 of each byte. This is where the data lines 285 | are expected to change and the sampled data may therefore be nonsense. 286 | We therefore check EOP ONLY if bits 0 AND 1 have both been read as 0 on D-. 287 | - Fixed a bitstuffing problem in the 16 MHz module: If bit 6 was stuffed, 288 | the unstuffing code in the receiver routine was 1 cycle too long. If 289 | multiple bytes had the unstuffing in bit 6, the error summed up until the 290 | receiver was out of sync. 291 | - Included option for faster CRC routine. 292 | Thanks to Slawomir Fras (BoskiDialer) for this code! 293 | - Updated bits in Configuration Descriptor's bmAttributes according to 294 | USB 1.1 (in particular bit 7, it is a must-be-set bit now). 295 | 296 | * Release 2009-08-22 297 | 298 | - Moved first DBG1() after odDebugInit() in all examples. 299 | - Use vector INT0_vect instead of SIG_INTERRUPT0 if defined. This makes 300 | V-USB compatible with the new "p" suffix devices (e.g. ATMega328p). 301 | - USB_CFG_CLOCK_KHZ setting is now required in usbconfig.h (no default any 302 | more). 303 | - New option USB_CFG_DRIVER_FLASH_PAGE allows boot loaders on devices with 304 | more than 64 kB flash. 305 | - Built-in configuration descriptor allows custom definition for second 306 | endpoint now. 307 | 308 | * Release 2010-07-15 309 | 310 | - Fixed bug in usbDriverSetup() which prevented descriptor sizes above 255 311 | bytes. 312 | - Avoid a compiler warning for unused parameter in usbHandleResetHook() when 313 | compiler option -Wextra is enabled. 314 | - Fixed wrong hex value for some IDs in USB-IDs-for-free.txt. 315 | - Keep a define for USBATTR_BUSPOWER, although the flag does not exist 316 | in USB 1.1 any more. Set it to 0. This is for backward compatibility. 317 | 318 | * Release 2012-01-09 319 | 320 | - Define a separate (defined) type for usbMsgPtr so that projects using a 321 | tiny memory model can define it to an 8 bit type in usbconfig.h. This 322 | change also saves a couple of bytes when using a scalar 16 bit type. 323 | - Inserted "const" keyword for all PROGMEM declarations because new GCC 324 | requires it. 325 | - Fixed problem with dependence of usbportability.h on usbconfig.h. This 326 | problem occurred with IAR CC only. 327 | - Prepared repository for github.com. 328 | 329 | * Release 2012-12-06 -------------------------------------------------------------------------------- /firmware/usbdrv/CommercialLicense.txt: -------------------------------------------------------------------------------- 1 | V-USB Driver Software License Agreement 2 | Version 2012-07-09 3 | 4 | THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN 5 | ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING 6 | THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. 7 | 8 | 9 | 1 DEFINITIONS 10 | 11 | 1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, 12 | Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. 13 | 14 | 1.2 "You" shall mean the Licensee. 15 | 16 | 1.3 "V-USB" shall mean all files included in the package distributed under 17 | the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/) 18 | unless otherwise noted. This includes the firmware-only USB device 19 | implementation for Atmel AVR microcontrollers, some simple device examples 20 | and host side software examples and libraries. 21 | 22 | 23 | 2 LICENSE GRANTS 24 | 25 | 2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source 26 | code of V-USB. 27 | 28 | 2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the 29 | non-exclusive right to use, copy and distribute V-USB with your hardware 30 | product(s), restricted by the limitations in section 3 below. 31 | 32 | 2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify 33 | the source code and your copy of V-USB according to your needs. 34 | 35 | 2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB 36 | Product ID(s), sent to you in e-mail. These Product IDs are reserved 37 | exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID 38 | ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen 39 | Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from 40 | Jason Kotzin (now flirc.tv, Inc.). Both owners of the Vendor IDs have 41 | obtained these IDs from the USB Implementers Forum, Inc. (www.usb.org). 42 | OBJECTIVE DEVELOPMENT disclaims all liability which might arise from the 43 | assignment of USB IDs. 44 | 45 | 2.5 USB Certification. Although not part of this agreement, we want to make 46 | it clear that you cannot become USB certified when you use V-USB or a USB 47 | Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't 48 | meet the electrical specifications required by the USB specification and 49 | the USB Implementers Forum certifies only members who bought a Vendor ID of 50 | their own. 51 | 52 | 53 | 3 LICENSE RESTRICTIONS 54 | 55 | 3.1 Number of Units. Only one of the following three definitions is 56 | applicable. Which one is determined by the amount you pay to OBJECTIVE 57 | DEVELOPMENT, see section 4 ("Payment") below. 58 | 59 | Hobby License: You may use V-USB according to section 2 above in no more 60 | than 5 hardware units. These units must not be sold for profit. 61 | 62 | Entry Level License: You may use V-USB according to section 2 above in no 63 | more than 150 hardware units. 64 | 65 | Professional License: You may use V-USB according to section 2 above in 66 | any number of hardware units, except for large scale production ("unlimited 67 | fair use"). Quantities below 10,000 units are not considered large scale 68 | production. If your reach quantities which are obviously large scale 69 | production, you must pay a license fee of 0.10 EUR per unit for all units 70 | above 10,000. 71 | 72 | 3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber 73 | any copy of V-USB, or any of the rights granted herein. 74 | 75 | 3.3 Transfer. You may not transfer your rights under this Agreement to 76 | another party without OBJECTIVE DEVELOPMENT's prior written consent. If 77 | such consent is obtained, you may permanently transfer this License to 78 | another party. The recipient of such transfer must agree to all terms and 79 | conditions of this Agreement. 80 | 81 | 3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not 82 | expressly granted. 83 | 84 | 3.5 Non-Exclusive Rights. Your license rights under this Agreement are 85 | non-exclusive. 86 | 87 | 3.6 Third Party Rights. This Agreement cannot grant you rights controlled 88 | by third parties. In particular, you are not allowed to use the USB logo or 89 | other trademarks owned by the USB Implementers Forum, Inc. without their 90 | consent. Since such consent depends on USB certification, it should be 91 | noted that V-USB will not pass certification because it does not 92 | implement checksum verification and the microcontroller ports do not meet 93 | the electrical specifications. 94 | 95 | 96 | 4 PAYMENT 97 | 98 | The payment amount depends on the variation of this agreement (according to 99 | section 3.1) into which you want to enter. Concrete prices are listed on 100 | OBJECTIVE DEVELOPMENT's web site, usually at 101 | http://www.obdev.at/vusb/license.html. You agree to pay the amount listed 102 | there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor 103 | or reseller. 104 | 105 | 106 | 5 COPYRIGHT AND OWNERSHIP 107 | 108 | V-USB is protected by copyright laws and international copyright 109 | treaties, as well as other intellectual property laws and treaties. V-USB 110 | is licensed, not sold. 111 | 112 | 113 | 6 TERM AND TERMINATION 114 | 115 | 6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE 116 | DEVELOPMENT may terminate this Agreement and revoke the granted license and 117 | USB-IDs if you fail to comply with any of its terms and conditions. 118 | 119 | 6.2 Survival of Terms. All provisions regarding secrecy, confidentiality 120 | and limitation of liability shall survive termination of this agreement. 121 | 122 | 123 | 7 DISCLAIMER OF WARRANTY AND LIABILITY 124 | 125 | LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 126 | KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE 127 | DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER 128 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 129 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 130 | NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE 131 | TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL 132 | RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO 133 | STATE/JURISDICTION. 134 | 135 | LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, 136 | IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY 137 | SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER 138 | (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, 139 | BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY 140 | LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE 141 | PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE 142 | DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY 143 | CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS 144 | AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB. 145 | 146 | 147 | 8 MISCELLANEOUS TERMS 148 | 149 | 8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing 150 | purposes that you entered into this agreement. 151 | 152 | 8.2 Entire Agreement. This document represents the entire agreement between 153 | OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by 154 | an authorized representative of both, OBJECTIVE DEVELOPMENT and you. 155 | 156 | 8.3 Severability. In case a provision of these terms and conditions should 157 | be or become partly or entirely invalid, ineffective, or not executable, 158 | the validity of all other provisions shall not be affected. 159 | 160 | 8.4 Applicable Law. This agreement is governed by the laws of the Republic 161 | of Austria. 162 | 163 | 8.5 Responsible Courts. The responsible courts in Vienna/Austria will have 164 | exclusive jurisdiction regarding all disputes in connection with this 165 | agreement. 166 | 167 | -------------------------------------------------------------------------------- /firmware/usbdrv/Readme.txt: -------------------------------------------------------------------------------- 1 | This is the Readme file to Objective Development's firmware-only USB driver 2 | for Atmel AVR microcontrollers. For more information please visit 3 | http://www.obdev.at/vusb/ 4 | 5 | This directory contains the USB firmware only. Copy it as-is to your own 6 | project and add all .c and .S files to your project (these files are marked 7 | with an asterisk in the list below). Then copy usbconfig-prototype.h as 8 | usbconfig.h to your project and edit it according to your configuration. 9 | 10 | 11 | TECHNICAL DOCUMENTATION 12 | ======================= 13 | The technical documentation (API) for the firmware driver is contained in the 14 | file "usbdrv.h". Please read all of it carefully! Configuration options are 15 | documented in "usbconfig-prototype.h". 16 | 17 | The driver consists of the following files: 18 | Readme.txt ............. The file you are currently reading. 19 | Changelog.txt .......... Release notes for all versions of the driver. 20 | usbdrv.h ............... Driver interface definitions and technical docs. 21 | * usbdrv.c ............... High level language part of the driver. Link this 22 | module to your code! 23 | * usbdrvasm.S ............ Assembler part of the driver. This module is mostly 24 | a stub and includes one of the usbdrvasm*.S files 25 | depending on processor clock. Link this module to 26 | your code! 27 | usbdrvasm*.inc ......... Assembler routines for particular clock frequencies. 28 | Included by usbdrvasm.S, don't link it directly! 29 | asmcommon.inc .......... Common assembler routines. Included by 30 | usbdrvasm*.inc, don't link it directly! 31 | usbconfig-prototype.h .. Prototype for your own usbdrv.h file. 32 | * oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is 33 | defined to a value greater than 0. Link this module 34 | to your code! 35 | oddebug.h .............. Interface definitions of the debug module. 36 | usbportability.h ....... Header with compiler-dependent stuff. 37 | usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this 38 | module instead of usbdrvasm.S when you assembler 39 | with IAR's tools. 40 | License.txt ............ Open Source license for this driver. 41 | CommercialLicense.txt .. Optional commercial license for this driver. 42 | USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs. 43 | USB-IDs-for-free.txt ... List and terms of use for free shared PIDs. 44 | 45 | (*) ... These files should be linked to your project. 46 | 47 | 48 | CPU CORE CLOCK FREQUENCY 49 | ======================== 50 | We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz, 51 | 16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The 52 | actual clock rate must be configured in usbconfig.h. 53 | 54 | 12 MHz Clock 55 | This is the traditional clock rate of V-USB because it's the lowest clock 56 | rate where the timing constraints of the USB spec can be met. 57 | 58 | 15 MHz Clock 59 | Similar to 12 MHz, but some NOPs inserted. On the other hand, the higher clock 60 | rate allows for some loops which make the resulting code size somewhat smaller 61 | than the 12 MHz version. 62 | 63 | 16 MHz Clock 64 | This clock rate has been added for users of the Arduino board and other 65 | ready-made boards which come with a fixed 16 MHz crystal. It's also an option 66 | if you need the slightly higher clock rate for performance reasons. Since 67 | 16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code 68 | is somewhat tricky and has to insert a leap cycle every third byte. 69 | 70 | 12.8 MHz and 16.5 MHz Clock 71 | The assembler modules for these clock rates differ from the other modules 72 | because they have been built for an RC oscillator with only 1% precision. The 73 | receiver code inserts leap cycles to compensate for clock deviations. 1% is 74 | also the precision which can be achieved by calibrating the internal RC 75 | oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL 76 | oscillator can reach 16.5 MHz with the RC oscillator. This includes the very 77 | popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost 78 | all AVRs can reach 12.8 MHz, although this is outside the specified range. 79 | 80 | See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for 81 | code which calibrates the RC oscillator based on the USB frame clock. 82 | 83 | 18 MHz Clock 84 | This module is closer to the USB specification because it performs an on the 85 | fly CRC check for incoming packets. Packets with invalid checksum are 86 | discarded as required by the spec. If you also implement checks for data 87 | PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING 88 | in usbconfig.h for more info), this ensures data integrity. Due to the CRC 89 | tables and alignment requirements, this code is bigger than modules for other 90 | clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1 91 | and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h. 92 | 93 | 20 MHz Clock 94 | This module is for people who won't do it with less than the maximum. Since 95 | 20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code 96 | uses similar tricks as the 16 MHz module to insert leap cycles. 97 | 98 | 99 | USB IDENTIFIERS 100 | =============== 101 | Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs 102 | are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you 103 | can assign PIDs at will. 104 | 105 | Since an entry level cost of 1,500 USD is too high for most small companies 106 | and hobbyists, we provide some VID/PID pairs for free. See the file 107 | USB-IDs-for-free.txt for details. 108 | 109 | Objective Development also has some license offerings which include product 110 | IDs. See http://www.obdev.at/vusb/ for details. 111 | 112 | 113 | DEVELOPMENT SYSTEM 114 | ================== 115 | This driver has been developed and optimized for the GNU compiler version 3 116 | and 4. We recommend that you use the GNU compiler suite because it is freely 117 | available. V-USB has also been ported to the IAR compiler and assembler. It 118 | has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the 119 | "small" and "tiny" memory model. Not every release is tested with IAR CC and 120 | the driver may therefore fail to compile with IAR. Please note that gcc is 121 | more efficient for usbdrv.c because this module has been deliberately 122 | optimized for gcc. 123 | 124 | Gcc version 3 produces smaller code than version 4 due to new optimizing 125 | capabilities which don't always improve things on 8 bit CPUs. The code size 126 | generated by gcc 4 can be reduced with the compiler options 127 | -fno-move-loop-invariants, -fno-tree-scev-cprop and 128 | -fno-inline-small-functions in addition to -Os. On devices with more than 129 | 8k of flash memory, we also recommend the linker option --relax (written as 130 | -Wl,--relax for gcc) to convert absolute calls into relative where possible. 131 | 132 | For more information about optimizing options see: 133 | 134 | http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html 135 | 136 | These optimizations are good for gcc 4.x. Version 3.x of gcc does not support 137 | most of these options and produces good code anyway. 138 | 139 | 140 | USING V-USB FOR FREE 141 | ==================== 142 | The AVR firmware driver is published under the GNU General Public License 143 | Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is 144 | your choice whether you apply the terms of version 2 or version 3. 145 | 146 | If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the 147 | following things IN ADDITION to the obligations from the GPL: 148 | 149 | (1) Publish your entire project on a web site and drop us a note with the URL. 150 | Use the form at http://www.obdev.at/vusb/feedback.html for your submission. 151 | If you don't have a web site, you can publish the project in obdev's 152 | documentation wiki at 153 | http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects. 154 | 155 | (2) Adhere to minimum publication standards. Please include AT LEAST: 156 | - a circuit diagram in PDF, PNG or GIF format 157 | - full source code for the host software 158 | - a Readme.txt file in ASCII format which describes the purpose of the 159 | project and what can be found in which directories and which files 160 | - a reference to http://www.obdev.at/vusb/ 161 | 162 | (3) If you improve the driver firmware itself, please give us a free license 163 | to your modifications for our commercial license offerings. 164 | 165 | 166 | COMMERCIAL LICENSES FOR V-USB 167 | ============================= 168 | If you don't want to publish your source code under the terms of the GPL, 169 | you can simply pay money for V-USB. As an additional benefit you get 170 | USB PIDs for free, reserved exclusively to you. See the file 171 | "CommercialLicense.txt" for details. 172 | 173 | -------------------------------------------------------------------------------- /firmware/usbdrv/USB-ID-FAQ.txt: -------------------------------------------------------------------------------- 1 | Version 2012-07-09 2 | 3 | ========================== 4 | WHY DO WE NEED THESE IDs? 5 | ========================== 6 | 7 | USB is more than a low level protocol for data transport. It also defines a 8 | common set of requests which must be understood by all devices. And as part 9 | of these common requests, the specification defines data structures, the 10 | USB Descriptors, which are used to describe the properties of the device. 11 | 12 | From the perspective of an operating system, it is therefore possible to find 13 | out basic properties of a device (such as e.g. the manufacturer and the name 14 | of the device) without a device-specific driver. This is essential because 15 | the operating system can choose a driver to load based on this information 16 | (Plug-And-Play). 17 | 18 | Among the most important properties in the Device Descriptor are the USB 19 | Vendor- and Product-ID. Both are 16 bit integers. The most simple form of 20 | driver matching is based on these IDs. The driver announces the Vendor- and 21 | Product-IDs of the devices it can handle and the operating system loads the 22 | appropriate driver when the device is connected. 23 | 24 | It is obvious that this technique only works if the pair Vendor- plus 25 | Product-ID is unique: Only devices which require the same driver can have the 26 | same pair of IDs. 27 | 28 | 29 | ===================================================== 30 | HOW DOES THE USB STANDARD ENSURE THAT IDs ARE UNIQUE? 31 | ===================================================== 32 | 33 | Since it is so important that USB IDs are unique, the USB Implementers Forum, 34 | Inc. (usb.org) needs a way to enforce this legally. It is not forbidden by 35 | law to build a device and assign it any random numbers as IDs. Usb.org 36 | therefore needs an agreement to regulate the use of USB IDs. The agreement 37 | binds only parties who agreed to it, of course. Everybody else is free to use 38 | any numbers for their IDs. 39 | 40 | So how can usb.org ensure that every manufacturer of USB devices enters into 41 | an agreement with them? They do it via trademark licensing. Usb.org has 42 | registered the trademark "USB", all associated logos and related terms. If 43 | you want to put an USB logo on your product or claim that it is USB 44 | compliant, you must license these trademarks from usb.org. And this is where 45 | you enter into an agreement. See the "USB-IF Trademark License Agreement and 46 | Usage Guidelines for the USB-IF Logo" at 47 | http://www.usb.org/developers/logo_license/. 48 | 49 | Licensing the USB trademarks requires that you buy a USB Vendor-ID from 50 | usb.org (one-time fee of ca. 2,000 USD), that you become a member of usb.org 51 | (yearly fee of ca. 4,000 USD) and that you meet all the technical 52 | specifications from the USB spec. 53 | 54 | This means that most hobbyists and small companies will never be able to 55 | become USB compliant, just because membership is so expensive. And you can't 56 | be compliant with a driver based on V-USB anyway, because the AVR's port pins 57 | don't meet the electrical specifications for USB. So, in principle, all 58 | hobbyists and small companies are free to choose any random numbers for their 59 | IDs. They have nothing to lose... 60 | 61 | There is one exception worth noting, though: If you use a sub-component which 62 | implements USB, the vendor of the sub-components may guarantee USB 63 | compliance. This might apply to some or all of FTDI's solutions. 64 | 65 | 66 | ======================================================================= 67 | WHY SHOULD YOU OBTAIN USB IDs EVEN IF YOU DON'T LICENSE USB TRADEMARKS? 68 | ======================================================================= 69 | 70 | You have learned in the previous section that you are free to choose any 71 | numbers for your IDs anyway. So why not do exactly this? There is still the 72 | technical issue. If you choose IDs which are already in use by somebody else, 73 | operating systems will load the wrong drivers and your device won't work. 74 | Even if you choose IDs which are not currently in use, they may be in use in 75 | the next version of the operating system or even after an automatic update. 76 | 77 | So what you need is a pair of Vendor- and Product-IDs for which you have the 78 | guarantee that no USB compliant product uses them. This implies that no 79 | operating system will ever ship with drivers responsible for these IDs. 80 | 81 | 82 | ============================================== 83 | HOW DOES OBJECTIVE DEVELOPMENT HANDLE USB IDs? 84 | ============================================== 85 | 86 | Objective Development gives away pairs of USB-IDs with their V-USB licenses. 87 | In order to ensure that these IDs are unique, Objective Development has an 88 | agreement with the company/person who has bought the USB Vendor-ID from 89 | usb.org. This agreement ensures that a range of USB Product-IDs is reserved 90 | for assignment by Objective Development and that the owner of the Vendor-ID 91 | won't give it to anybody else. 92 | 93 | This means that you have to trust three parties to ensure uniqueness of 94 | your IDs: 95 | 96 | - Objective Development, that they don't give the same PID to more than 97 | one person. 98 | - The owner of the Vendor-ID that they don't assign PIDs from the range 99 | assigned to Objective Development to anybody else. 100 | - Usb.org that they don't assign the same Vendor-ID a second time. 101 | 102 | 103 | ================================== 104 | WHO IS THE OWNER OF THE VENDOR-ID? 105 | ================================== 106 | 107 | Objective Development has obtained ranges of USB Product-IDs under two 108 | Vendor-IDs: Under Vendor-ID 5824 from Wouter van Ooijen (Van Ooijen 109 | Technische Informatica, www.voti.nl) and under Vendor-ID 8352 from Jason 110 | Kotzin (now flirc.tv, Inc.). Both VID owners have received their Vendor-ID 111 | directly from usb.org. 112 | 113 | 114 | ========================================================================= 115 | CAN I USE USB-IDs FROM OBJECTIVE DEVELOPMENT WITH OTHER DRIVERS/HARDWARE? 116 | ========================================================================= 117 | 118 | The short answer is: Yes. All you get is a guarantee that the IDs are never 119 | assigned to anybody else. What more do you need? 120 | 121 | 122 | ============================ 123 | WHAT ABOUT SHARED ID PAIRS? 124 | ============================ 125 | 126 | Objective Development has reserved some PID/VID pairs for shared use. You 127 | have no guarantee of uniqueness for them, except that no USB compliant device 128 | uses them. In order to avoid technical problems, we must ensure that all 129 | devices with the same pair of IDs use the same driver on kernel level. For 130 | details, see the file USB-IDs-for-free.txt. 131 | 132 | 133 | ====================================================== 134 | I HAVE HEARD THAT SUB-LICENSING OF USB-IDs IS ILLEGAL? 135 | ====================================================== 136 | 137 | A 16 bit integer number cannot be protected by copyright laws. It is not 138 | sufficiently complex. And since none of the parties involved entered into the 139 | USB-IF Trademark License Agreement, we are not bound by this agreement. So 140 | there is no reason why it should be illegal to sub-license USB-IDs. 141 | 142 | 143 | ============================================= 144 | WHO IS LIABLE IF THERE ARE INCOMPATIBILITIES? 145 | ============================================= 146 | 147 | Objective Development disclaims all liabilities which might arise from the 148 | assignment of IDs. If you guarantee product features to your customers 149 | without proper disclaimer, YOU are liable for that. 150 | -------------------------------------------------------------------------------- /firmware/usbdrv/USB-IDs-for-free.txt: -------------------------------------------------------------------------------- 1 | Version 2009-08-22 2 | 3 | =========================== 4 | FREE USB-IDs FOR SHARED USE 5 | =========================== 6 | 7 | Objective Development has reserved a set of USB Product-IDs for use according 8 | to the guidelines outlined below. For more information about the concept of 9 | USB IDs please see the file USB-ID-FAQ.txt. Objective Development guarantees 10 | that the IDs listed below are not used by any USB compliant devices. 11 | 12 | 13 | ==================== 14 | MECHANISM OF SHARING 15 | ==================== 16 | 17 | From a technical point of view, two different devices can share the same USB 18 | Vendor- and Product-ID if they require the same driver on operating system 19 | level. We make use of this fact by assigning separate IDs for various device 20 | classes. On application layer, devices must be distinguished by their textual 21 | name or serial number. We offer separate sets of IDs for discrimination by 22 | textual name and for serial number. 23 | 24 | Examples for shared use of USB IDs are included with V-USB in the "examples" 25 | subdirectory. 26 | 27 | 28 | ====================================== 29 | IDs FOR DISCRIMINATION BY TEXTUAL NAME 30 | ====================================== 31 | 32 | If you use one of the IDs listed below, your device and host-side software 33 | must conform to these rules: 34 | 35 | (1) The USB device MUST provide a textual representation of the manufacturer 36 | and product identification. The manufacturer identification MUST be available 37 | at least in USB language 0x0409 (English/US). 38 | 39 | (2) The textual manufacturer identification MUST contain either an Internet 40 | domain name (e.g. "mycompany.com") registered and owned by you, or an e-mail 41 | address under your control (e.g. "myname@gmx.net"). You can embed the domain 42 | name or e-mail address in any string you like, e.g. "Objective Development 43 | http://www.obdev.at/vusb/". 44 | 45 | (3) You are responsible for retaining ownership of the domain or e-mail 46 | address for as long as any of your products are in use. 47 | 48 | (4) You may choose any string for the textual product identification, as long 49 | as this string is unique within the scope of your textual manufacturer 50 | identification. 51 | 52 | (5) Application side device look-up MUST be based on the textual manufacturer 53 | and product identification in addition to VID/PID matching. The driver 54 | matching MUST be a comparison of the entire strings, NOT a sub-string match. 55 | 56 | (6) For devices which implement a particular USB device class (e.g. HID), the 57 | operating system's default class driver MUST be used. If an operating system 58 | driver for Vendor Class devices is needed, this driver must be libusb or 59 | libusb-win32 (see http://libusb.org/ and 60 | http://libusb-win32.sourceforge.net/). 61 | 62 | Table if IDs for discrimination by textual name: 63 | 64 | PID dec (hex) | VID dec (hex) | Description of use 65 | ==============+===============+============================================ 66 | 1500 (0x05dc) | 5824 (0x16c0) | For Vendor Class devices with libusb 67 | --------------+---------------+-------------------------------------------- 68 | 1503 (0x05df) | 5824 (0x16c0) | For generic HID class devices (which are 69 | | | NOT mice, keyboards or joysticks) 70 | --------------+---------------+-------------------------------------------- 71 | 1505 (0x05e1) | 5824 (0x16c0) | For CDC-ACM class devices (modems) 72 | --------------+---------------+-------------------------------------------- 73 | 1508 (0x05e4) | 5824 (0x16c0) | For MIDI class devices 74 | --------------+---------------+-------------------------------------------- 75 | 76 | Note that Windows caches the textual product- and vendor-description for 77 | mice, keyboards and joysticks. Name-bsed discrimination is therefore not 78 | recommended for these device classes. 79 | 80 | 81 | ======================================= 82 | IDs FOR DISCRIMINATION BY SERIAL NUMBER 83 | ======================================= 84 | 85 | If you use one of the IDs listed below, your device and host-side software 86 | must conform to these rules: 87 | 88 | (1) The USB device MUST provide a textual representation of the serial 89 | number, unless ONLY the operating system's default class driver is used. 90 | The serial number string MUST be available at least in USB language 0x0409 91 | (English/US). 92 | 93 | (2) The serial number MUST start with either an Internet domain name (e.g. 94 | "mycompany.com") registered and owned by you, or an e-mail address under your 95 | control (e.g. "myname@gmx.net"), both terminated with a colon (":") character. 96 | You MAY append any string you like for further discrimination of your devices. 97 | 98 | (3) You are responsible for retaining ownership of the domain or e-mail 99 | address for as long as any of your products are in use. 100 | 101 | (5) Application side device look-up MUST be based on the serial number string 102 | in addition to VID/PID matching. The matching must start at the first 103 | character of the serial number string and include the colon character 104 | terminating your domain or e-mail address. It MAY stop anywhere after that. 105 | 106 | (6) For devices which implement a particular USB device class (e.g. HID), the 107 | operating system's default class driver MUST be used. If an operating system 108 | driver for Vendor Class devices is needed, this driver must be libusb or 109 | libusb-win32 (see http://libusb.org/ and 110 | http://libusb-win32.sourceforge.net/). 111 | 112 | (7) If ONLY the operating system's default class driver is used, e.g. for 113 | mice, keyboards, joysticks, CDC or MIDI devices and no discrimination by an 114 | application is needed, the serial number may be omitted. 115 | 116 | 117 | Table if IDs for discrimination by serial number string: 118 | 119 | PID dec (hex) | VID dec (hex) | Description of use 120 | ===============+===============+=========================================== 121 | 10200 (0x27d8) | 5824 (0x16c0) | For Vendor Class devices with libusb 122 | ---------------+---------------+------------------------------------------- 123 | 10201 (0x27d9) | 5824 (0x16c0) | For generic HID class devices (which are 124 | | | NOT mice, keyboards or joysticks) 125 | ---------------+---------------+------------------------------------------- 126 | 10202 (0x27da) | 5824 (0x16c0) | For USB Mice 127 | ---------------+---------------+------------------------------------------- 128 | 10203 (0x27db) | 5824 (0x16c0) | For USB Keyboards 129 | ---------------+---------------+------------------------------------------- 130 | 10204 (0x27dc) | 5824 (0x16c0) | For USB Joysticks 131 | ---------------+---------------+------------------------------------------- 132 | 10205 (0x27dd) | 5824 (0x16c0) | For CDC-ACM class devices (modems) 133 | ---------------+---------------+------------------------------------------- 134 | 10206 (0x27de) | 5824 (0x16c0) | For MIDI class devices 135 | ---------------+---------------+------------------------------------------- 136 | 10207 (0x27df) | 5824 (0x16c0) | For Mass Storage class devices 137 | ---------------+---------------+------------------------------------------- 138 | 10208 (0x27e0) | 5824 (0x16c0) | For Audio class devices 139 | ---------------+---------------+------------------------------------------- 140 | 10209 (0x27e1) | 5824 (0x16c0) | For CDC-ECM class devices 141 | ---------------+---------------+------------------------------------------- 142 | 10210 (0x27e2) | 5824 (0x16c0) | For MTP class devices 143 | ---------------+---------------+------------------------------------------- 144 | 145 | Note that the last six cannot be implemented using V-USB in a standards 146 | compliant way because they require bulk endpoints which are forbidden for 147 | low speed devices. We provide them nevertheless, either if you want to 148 | implement a non-compliant device or implement it using other technology 149 | than V-USB. 150 | 151 | 152 | ================= 153 | ORIGIN OF USB-IDs 154 | ================= 155 | 156 | OBJECTIVE DEVELOPMENT Software GmbH has obtained all VID/PID pairs listed 157 | here from Wouter van Ooijen (see www.voti.nl) for exclusive disposition. 158 | Wouter van Ooijen has obtained the VID from the USB Implementers Forum, Inc. 159 | (see www.usb.org). The VID is registered for the company name "Van Ooijen 160 | Technische Informatica". 161 | 162 | 163 | ========== 164 | DISCLAIMER 165 | ========== 166 | 167 | OBJECTIVE DEVELOPMENT Software GmbH disclaims all liability for any 168 | problems which are caused by the shared use of these VID/PID pairs. 169 | -------------------------------------------------------------------------------- /firmware/usbdrv/asmcommon.inc: -------------------------------------------------------------------------------- 1 | /* Name: asmcommon.inc 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-11-05 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* Do not link this file! Link usbdrvasm.S instead, which includes the 11 | * appropriate implementation! 12 | */ 13 | 14 | /* 15 | General Description: 16 | This file contains assembler code which is shared among the USB driver 17 | implementations for different CPU cocks. Since the code must be inserted 18 | in the middle of the module, it's split out into this file and #included. 19 | 20 | Jump destinations called from outside: 21 | sofError: Called when no start sequence was found. 22 | se0: Called when a package has been successfully received. 23 | overflow: Called when receive buffer overflows. 24 | doReturn: Called after sending data. 25 | 26 | Outside jump destinations used by this module: 27 | waitForJ: Called to receive an already arriving packet. 28 | sendAckAndReti: 29 | sendNakAndReti: 30 | sendCntAndReti: 31 | usbSendAndReti: 32 | 33 | The following macros must be defined before this file is included: 34 | .macro POP_STANDARD 35 | .endm 36 | .macro POP_RETI 37 | .endm 38 | */ 39 | 40 | #define token x1 41 | 42 | overflow: 43 | ldi x2, 1< 0 13 | 14 | #warning "Never compile production devices with debugging enabled" 15 | 16 | static void uartPutc(char c) 17 | { 18 | while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ 19 | ODDBG_UDR = c; 20 | } 21 | 22 | static uchar hexAscii(uchar h) 23 | { 24 | h &= 0xf; 25 | if(h >= 10) 26 | h += 'a' - (uchar)10 - '0'; 27 | h += '0'; 28 | return h; 29 | } 30 | 31 | static void printHex(uchar c) 32 | { 33 | uartPutc(hexAscii(c >> 4)); 34 | uartPutc(hexAscii(c)); 35 | } 36 | 37 | void odDebug(uchar prefix, uchar *data, uchar len) 38 | { 39 | printHex(prefix); 40 | uartPutc(':'); 41 | while(len--){ 42 | uartPutc(' '); 43 | printHex(*data++); 44 | } 45 | uartPutc('\r'); 46 | uartPutc('\n'); 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /firmware/usbdrv/oddebug.h: -------------------------------------------------------------------------------- 1 | /* Name: oddebug.h 2 | * Project: AVR library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2005-01-16 5 | * Tabsize: 4 6 | * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | #ifndef __oddebug_h_included__ 11 | #define __oddebug_h_included__ 12 | 13 | /* 14 | General Description: 15 | This module implements a function for debug logs on the serial line of the 16 | AVR microcontroller. Debugging can be configured with the define 17 | 'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging 18 | calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is 19 | 2, DBG1 and DBG2 logs will be printed. 20 | 21 | A debug log consists of a label ('prefix') to indicate which debug log created 22 | the output and a memory block to dump in hex ('data' and 'len'). 23 | */ 24 | 25 | 26 | #ifndef F_CPU 27 | # define F_CPU 12000000 /* 12 MHz */ 28 | #endif 29 | 30 | /* make sure we have the UART defines: */ 31 | #include "usbportability.h" 32 | 33 | #ifndef uchar 34 | # define uchar unsigned char 35 | #endif 36 | 37 | #if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ 38 | # warning "Debugging disabled because device has no UART" 39 | # undef DEBUG_LEVEL 40 | #endif 41 | 42 | #ifndef DEBUG_LEVEL 43 | # define DEBUG_LEVEL 0 44 | #endif 45 | 46 | /* ------------------------------------------------------------------------- */ 47 | 48 | #if DEBUG_LEVEL > 0 49 | # define DBG1(prefix, data, len) odDebug(prefix, data, len) 50 | #else 51 | # define DBG1(prefix, data, len) 52 | #endif 53 | 54 | #if DEBUG_LEVEL > 1 55 | # define DBG2(prefix, data, len) odDebug(prefix, data, len) 56 | #else 57 | # define DBG2(prefix, data, len) 58 | #endif 59 | 60 | /* ------------------------------------------------------------------------- */ 61 | 62 | #if DEBUG_LEVEL > 0 63 | extern void odDebug(uchar prefix, uchar *data, uchar len); 64 | 65 | /* Try to find our control registers; ATMEL likes to rename these */ 66 | 67 | #if defined UBRR 68 | # define ODDBG_UBRR UBRR 69 | #elif defined UBRRL 70 | # define ODDBG_UBRR UBRRL 71 | #elif defined UBRR0 72 | # define ODDBG_UBRR UBRR0 73 | #elif defined UBRR0L 74 | # define ODDBG_UBRR UBRR0L 75 | #endif 76 | 77 | #if defined UCR 78 | # define ODDBG_UCR UCR 79 | #elif defined UCSRB 80 | # define ODDBG_UCR UCSRB 81 | #elif defined UCSR0B 82 | # define ODDBG_UCR UCSR0B 83 | #endif 84 | 85 | #if defined TXEN 86 | # define ODDBG_TXEN TXEN 87 | #else 88 | # define ODDBG_TXEN TXEN0 89 | #endif 90 | 91 | #if defined USR 92 | # define ODDBG_USR USR 93 | #elif defined UCSRA 94 | # define ODDBG_USR UCSRA 95 | #elif defined UCSR0A 96 | # define ODDBG_USR UCSR0A 97 | #endif 98 | 99 | #if defined UDRE 100 | # define ODDBG_UDRE UDRE 101 | #else 102 | # define ODDBG_UDRE UDRE0 103 | #endif 104 | 105 | #if defined UDR 106 | # define ODDBG_UDR UDR 107 | #elif defined UDR0 108 | # define ODDBG_UDR UDR0 109 | #endif 110 | 111 | static inline void odDebugInit(void) 112 | { 113 | ODDBG_UCR |= (1< max 25 cycles interrupt disable 38 | ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes 39 | ;Numbers in brackets are maximum cycles since SOF. 40 | USB_INTR_VECTOR: 41 | ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt 42 | push YL ;2 [35] push only what is necessary to sync with edge ASAP 43 | in YL, SREG ;1 [37] 44 | push YL ;2 [39] 45 | ;---------------------------------------------------------------------------- 46 | ; Synchronize with sync pattern: 47 | ;---------------------------------------------------------------------------- 48 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 49 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 50 | ;The first part waits at most 1 bit long since we must be in sync pattern. 51 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 52 | ;waitForJ, ensure that this prerequisite is met. 53 | waitForJ: 54 | inc YL 55 | sbis USBIN, USBMINUS 56 | brne waitForJ ; just make sure we have ANY timeout 57 | waitForK: 58 | ;The following code results in a sampling window of 1/4 bit which meets the spec. 59 | sbis USBIN, USBMINUS 60 | rjmp foundK 61 | sbis USBIN, USBMINUS 62 | rjmp foundK 63 | sbis USBIN, USBMINUS 64 | rjmp foundK 65 | sbis USBIN, USBMINUS 66 | rjmp foundK 67 | sbis USBIN, USBMINUS 68 | rjmp foundK 69 | #if USB_COUNT_SOF 70 | lds YL, usbSofCount 71 | inc YL 72 | sts usbSofCount, YL 73 | #endif /* USB_COUNT_SOF */ 74 | #ifdef USB_SOF_HOOK 75 | USB_SOF_HOOK 76 | #endif 77 | rjmp sofError 78 | foundK: 79 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] 80 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 81 | ;are cycles from center of first sync (double K) bit after the instruction 82 | push YH ;2 [2] 83 | lds YL, usbInputBufOffset;2 [4] 84 | clr YH ;1 [5] 85 | subi YL, lo8(-(usbRxBuf));1 [6] 86 | sbci YH, hi8(-(usbRxBuf));1 [7] 87 | 88 | sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] 89 | rjmp haveTwoBitsK ;2 [10] 90 | pop YH ;2 [11] undo the push from before 91 | rjmp waitForK ;2 [13] this was not the end of sync, retry 92 | haveTwoBitsK: 93 | ;---------------------------------------------------------------------------- 94 | ; push more registers and initialize values while we sample the first bits: 95 | ;---------------------------------------------------------------------------- 96 | push shift ;2 [16] 97 | push x1 ;2 [12] 98 | push x2 ;2 [14] 99 | 100 | in x1, USBIN ;1 [17] <-- sample bit 0 101 | ldi shift, 0xff ;1 [18] 102 | bst x1, USBMINUS ;1 [19] 103 | bld shift, 0 ;1 [20] 104 | push x3 ;2 [22] 105 | push cnt ;2 [24] 106 | 107 | in x2, USBIN ;1 [25] <-- sample bit 1 108 | ser x3 ;1 [26] [inserted init instruction] 109 | eor x1, x2 ;1 [27] 110 | bst x1, USBMINUS ;1 [28] 111 | bld shift, 1 ;1 [29] 112 | ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction] 113 | rjmp rxbit2 ;2 [32] 114 | 115 | ;---------------------------------------------------------------------------- 116 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 117 | ;---------------------------------------------------------------------------- 118 | 119 | unstuff0: ;1 (branch taken) 120 | andi x3, ~0x01 ;1 [15] 121 | mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit 122 | in x2, USBIN ;1 [17] <-- sample bit 1 again 123 | ori shift, 0x01 ;1 [18] 124 | rjmp didUnstuff0 ;2 [20] 125 | 126 | unstuff1: ;1 (branch taken) 127 | mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit 128 | andi x3, ~0x02 ;1 [22] 129 | ori shift, 0x02 ;1 [23] 130 | nop ;1 [24] 131 | in x1, USBIN ;1 [25] <-- sample bit 2 again 132 | rjmp didUnstuff1 ;2 [27] 133 | 134 | unstuff2: ;1 (branch taken) 135 | andi x3, ~0x04 ;1 [29] 136 | ori shift, 0x04 ;1 [30] 137 | mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit 138 | nop ;1 [32] 139 | in x2, USBIN ;1 [33] <-- sample bit 3 140 | rjmp didUnstuff2 ;2 [35] 141 | 142 | unstuff3: ;1 (branch taken) 143 | in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late] 144 | andi x3, ~0x08 ;1 [35] 145 | ori shift, 0x08 ;1 [36] 146 | rjmp didUnstuff3 ;2 [38] 147 | 148 | unstuff4: ;1 (branch taken) 149 | andi x3, ~0x10 ;1 [40] 150 | in x1, USBIN ;1 [41] <-- sample stuffed bit 4 151 | ori shift, 0x10 ;1 [42] 152 | rjmp didUnstuff4 ;2 [44] 153 | 154 | unstuff5: ;1 (branch taken) 155 | andi x3, ~0x20 ;1 [48] 156 | in x2, USBIN ;1 [49] <-- sample stuffed bit 5 157 | ori shift, 0x20 ;1 [50] 158 | rjmp didUnstuff5 ;2 [52] 159 | 160 | unstuff6: ;1 (branch taken) 161 | andi x3, ~0x40 ;1 [56] 162 | in x1, USBIN ;1 [57] <-- sample stuffed bit 6 163 | ori shift, 0x40 ;1 [58] 164 | rjmp didUnstuff6 ;2 [60] 165 | 166 | ; extra jobs done during bit interval: 167 | ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs] 168 | ; bit 1: se0 check 169 | ; bit 2: overflow check 170 | ; bit 3: recovery from delay [bit 0 tasks took too long] 171 | ; bit 4: none 172 | ; bit 5: none 173 | ; bit 6: none 174 | ; bit 7: jump, eor 175 | rxLoop: 176 | eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others 177 | in x1, USBIN ;1 [1] <-- sample bit 0 178 | st y+, x3 ;2 [3] store data 179 | ser x3 ;1 [4] 180 | nop ;1 [5] 181 | eor x2, x1 ;1 [6] 182 | bst x2, USBMINUS;1 [7] 183 | bld shift, 0 ;1 [8] 184 | in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) 185 | andi x2, USBMASK ;1 [10] 186 | breq se0 ;1 [11] SE0 check for bit 1 187 | andi shift, 0xf9 ;1 [12] 188 | didUnstuff0: 189 | breq unstuff0 ;1 [13] 190 | eor x1, x2 ;1 [14] 191 | bst x1, USBMINUS;1 [15] 192 | bld shift, 1 ;1 [16] 193 | rxbit2: 194 | in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) 195 | andi shift, 0xf3 ;1 [18] 196 | breq unstuff1 ;1 [19] do remaining work for bit 1 197 | didUnstuff1: 198 | subi cnt, 1 ;1 [20] 199 | brcs overflow ;1 [21] loop control 200 | eor x2, x1 ;1 [22] 201 | bst x2, USBMINUS;1 [23] 202 | bld shift, 2 ;1 [24] 203 | in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) 204 | andi shift, 0xe7 ;1 [26] 205 | breq unstuff2 ;1 [27] 206 | didUnstuff2: 207 | eor x1, x2 ;1 [28] 208 | bst x1, USBMINUS;1 [29] 209 | bld shift, 3 ;1 [30] 210 | didUnstuff3: 211 | andi shift, 0xcf ;1 [31] 212 | breq unstuff3 ;1 [32] 213 | in x1, USBIN ;1 [33] <-- sample bit 4 214 | eor x2, x1 ;1 [34] 215 | bst x2, USBMINUS;1 [35] 216 | bld shift, 4 ;1 [36] 217 | didUnstuff4: 218 | andi shift, 0x9f ;1 [37] 219 | breq unstuff4 ;1 [38] 220 | nop2 ;2 [40] 221 | in x2, USBIN ;1 [41] <-- sample bit 5 222 | eor x1, x2 ;1 [42] 223 | bst x1, USBMINUS;1 [43] 224 | bld shift, 5 ;1 [44] 225 | didUnstuff5: 226 | andi shift, 0x3f ;1 [45] 227 | breq unstuff5 ;1 [46] 228 | nop2 ;2 [48] 229 | in x1, USBIN ;1 [49] <-- sample bit 6 230 | eor x2, x1 ;1 [50] 231 | bst x2, USBMINUS;1 [51] 232 | bld shift, 6 ;1 [52] 233 | didUnstuff6: 234 | cpi shift, 0x02 ;1 [53] 235 | brlo unstuff6 ;1 [54] 236 | nop2 ;2 [56] 237 | in x2, USBIN ;1 [57] <-- sample bit 7 238 | eor x1, x2 ;1 [58] 239 | bst x1, USBMINUS;1 [59] 240 | bld shift, 7 ;1 [60] 241 | didUnstuff7: 242 | cpi shift, 0x04 ;1 [61] 243 | brsh rxLoop ;2 [63] loop control 244 | unstuff7: 245 | andi x3, ~0x80 ;1 [63] 246 | ori shift, 0x80 ;1 [64] 247 | in x2, USBIN ;1 [65] <-- sample stuffed bit 7 248 | nop ;1 [66] 249 | rjmp didUnstuff7 ;2 [68] 250 | 251 | macro POP_STANDARD ; 12 cycles 252 | pop cnt 253 | pop x3 254 | pop x2 255 | pop x1 256 | pop shift 257 | pop YH 258 | endm 259 | macro POP_RETI ; 5 cycles 260 | pop YL 261 | out SREG, YL 262 | pop YL 263 | endm 264 | 265 | #include "asmcommon.inc" 266 | 267 | ;---------------------------------------------------------------------------- 268 | ; Transmitting data 269 | ;---------------------------------------------------------------------------- 270 | 271 | txByteLoop: 272 | txBitloop: 273 | stuffN1Delay: ; [03] 274 | ror shift ;[-5] [11] [59] 275 | brcc doExorN1 ;[-4] [60] 276 | subi x4, 1 ;[-3] 277 | brne commonN1 ;[-2] 278 | lsl shift ;[-1] compensate ror after rjmp stuffDelay 279 | nop ;[00] stuffing consists of just waiting 8 cycles 280 | rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear 281 | 282 | sendNakAndReti: ;0 [-19] 19 cycles until SOP 283 | ldi x3, USBPID_NAK ;1 [-18] 284 | rjmp usbSendX3 ;2 [-16] 285 | sendAckAndReti: ;0 [-19] 19 cycles until SOP 286 | ldi x3, USBPID_ACK ;1 [-18] 287 | rjmp usbSendX3 ;2 [-16] 288 | sendCntAndReti: ;0 [-17] 17 cycles until SOP 289 | mov x3, cnt ;1 [-16] 290 | usbSendX3: ;0 [-16] 291 | ldi YL, 20 ;1 [-15] 'x3' is R20 292 | ldi YH, 0 ;1 [-14] 293 | ldi cnt, 2 ;1 [-13] 294 | ; rjmp usbSendAndReti fallthrough 295 | 296 | ; USB spec says: 297 | ; idle = J 298 | ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 299 | ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 300 | ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) 301 | 302 | ;usbSend: 303 | ;pointer to data in 'Y' 304 | ;number of bytes in 'cnt' -- including sync byte 305 | ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt] 306 | ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) 307 | usbSendAndReti: 308 | in x2, USBDDR ;[-12] 12 cycles until SOP 309 | ori x2, USBMASK ;[-11] 310 | sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 311 | out USBDDR, x2 ;[-8] <--- acquire bus 312 | in x1, USBOUT ;[-7] port mirror for tx loop 313 | ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror) 314 | ldi x2, USBMASK ;[-5] 315 | push x4 ;[-4] 316 | doExorN1: 317 | eor x1, x2 ;[-2] [06] [62] 318 | ldi x4, 6 ;[-1] [07] [63] 319 | commonN1: 320 | stuffN2Delay: 321 | out USBOUT, x1 ;[00] [08] [64] <--- set bit 322 | ror shift ;[01] 323 | brcc doExorN2 ;[02] 324 | subi x4, 1 ;[03] 325 | brne commonN2 ;[04] 326 | lsl shift ;[05] compensate ror after rjmp stuffDelay 327 | rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear 328 | doExorN2: 329 | eor x1, x2 ;[04] [12] 330 | ldi x4, 6 ;[05] [13] 331 | commonN2: 332 | nop ;[06] [14] 333 | subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1 334 | out USBOUT, x1 ;[08] [16] <--- set bit 335 | brcs txBitloop ;[09] [25] [41] 336 | 337 | stuff6Delay: 338 | ror shift ;[42] [50] 339 | brcc doExor6 ;[43] 340 | subi x4, 1 ;[44] 341 | brne common6 ;[45] 342 | lsl shift ;[46] compensate ror after rjmp stuffDelay 343 | nop ;[47] stuffing consists of just waiting 8 cycles 344 | rjmp stuff6Delay ;[48] after ror, C bit is reliably clear 345 | doExor6: 346 | eor x1, x2 ;[45] [53] 347 | ldi x4, 6 ;[46] 348 | common6: 349 | stuff7Delay: 350 | ror shift ;[47] [55] 351 | out USBOUT, x1 ;[48] <--- set bit 352 | brcc doExor7 ;[49] 353 | subi x4, 1 ;[50] 354 | brne common7 ;[51] 355 | lsl shift ;[52] compensate ror after rjmp stuffDelay 356 | rjmp stuff7Delay ;[53] after ror, C bit is reliably clear 357 | doExor7: 358 | eor x1, x2 ;[51] [59] 359 | ldi x4, 6 ;[52] 360 | common7: 361 | ld shift, y+ ;[53] 362 | tst cnt ;[55] 363 | out USBOUT, x1 ;[56] <--- set bit 364 | brne txByteLoop ;[57] 365 | 366 | ;make SE0: 367 | cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles] 368 | lds x2, usbNewDeviceAddr;[59] 369 | lsl x2 ;[61] we compare with left shifted address 370 | subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3 371 | sbci YH, 0 ;[63] 372 | out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle 373 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 374 | ;set address only after data packet was sent, not after handshake 375 | breq skipAddrAssign ;[01] 376 | sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer 377 | skipAddrAssign: 378 | ;end of usbDeviceAddress transfer 379 | ldi x2, 1< 10.6666666 cycles per bit, 85.333333333 cycles per byte 29 | ; Numbers in brackets are clocks counted from center of last sync bit 30 | ; when instruction starts 31 | 32 | USB_INTR_VECTOR: 33 | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt 34 | push YL ;[-25] push only what is necessary to sync with edge ASAP 35 | in YL, SREG ;[-23] 36 | push YL ;[-22] 37 | push YH ;[-20] 38 | ;---------------------------------------------------------------------------- 39 | ; Synchronize with sync pattern: 40 | ;---------------------------------------------------------------------------- 41 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 42 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 43 | ;The first part waits at most 1 bit long since we must be in sync pattern. 44 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 45 | ;waitForJ, ensure that this prerequisite is met. 46 | waitForJ: 47 | inc YL 48 | sbis USBIN, USBMINUS 49 | brne waitForJ ; just make sure we have ANY timeout 50 | waitForK: 51 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 52 | sbis USBIN, USBMINUS ;[-15] 53 | rjmp foundK ;[-14] 54 | sbis USBIN, USBMINUS 55 | rjmp foundK 56 | sbis USBIN, USBMINUS 57 | rjmp foundK 58 | sbis USBIN, USBMINUS 59 | rjmp foundK 60 | sbis USBIN, USBMINUS 61 | rjmp foundK 62 | sbis USBIN, USBMINUS 63 | rjmp foundK 64 | #if USB_COUNT_SOF 65 | lds YL, usbSofCount 66 | inc YL 67 | sts usbSofCount, YL 68 | #endif /* USB_COUNT_SOF */ 69 | #ifdef USB_SOF_HOOK 70 | USB_SOF_HOOK 71 | #endif 72 | rjmp sofError 73 | foundK: ;[-12] 74 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] 75 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 76 | ;are cycles from center of first sync (double K) bit after the instruction 77 | push bitcnt ;[-12] 78 | ; [---] ;[-11] 79 | lds YL, usbInputBufOffset;[-10] 80 | ; [---] ;[-9] 81 | clr YH ;[-8] 82 | subi YL, lo8(-(usbRxBuf));[-7] [rx loop init] 83 | sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init] 84 | push shift ;[-5] 85 | ; [---] ;[-4] 86 | ldi bitcnt, 0x55 ;[-3] [rx loop init] 87 | sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) 88 | rjmp haveTwoBitsK ;[-1] 89 | pop shift ;[0] undo the push from before 90 | pop bitcnt ;[2] undo the push from before 91 | rjmp waitForK ;[4] this was not the end of sync, retry 92 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 93 | ; bit times (= 21 cycles). 94 | 95 | ;---------------------------------------------------------------------------- 96 | ; push more registers and initialize values while we sample the first bits: 97 | ;---------------------------------------------------------------------------- 98 | haveTwoBitsK: 99 | push x1 ;[1] 100 | push x2 ;[3] 101 | push x3 ;[5] 102 | ldi shift, 0 ;[7] 103 | ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that 104 | push x4 ;[9] == leap 105 | 106 | in x1, USBIN ;[11] <-- sample bit 0 107 | andi x1, USBMASK ;[12] 108 | bst x1, USBMINUS ;[13] 109 | bld shift, 7 ;[14] 110 | push cnt ;[15] 111 | ldi leap, 0 ;[17] [rx loop init] 112 | ldi cnt, USB_BUFSIZE;[18] [rx loop init] 113 | rjmp rxbit1 ;[19] arrives at [21] 114 | 115 | ;---------------------------------------------------------------------------- 116 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 117 | ;---------------------------------------------------------------------------- 118 | 119 | ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap" 120 | ; accordingly to approximate this value in the long run. 121 | 122 | unstuff6: 123 | andi x2, USBMASK ;[03] 124 | ori x3, 1<<6 ;[04] will not be shifted any more 125 | andi shift, ~0x80;[05] 126 | mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6 127 | subi leap, -1 ;[07] total duration = 11 bits -> subtract 1/3 128 | rjmp didUnstuff6 ;[08] 129 | 130 | unstuff7: 131 | ori x3, 1<<7 ;[09] will not be shifted any more 132 | in x2, USBIN ;[00] [10] re-sample bit 7 133 | andi x2, USBMASK ;[01] 134 | andi shift, ~0x80;[02] 135 | subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 136 | rjmp didUnstuff7 ;[04] 137 | 138 | unstuffEven: 139 | ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0 140 | in x1, USBIN ;[00] [10] 141 | andi shift, ~0x80;[01] 142 | andi x1, USBMASK ;[02] 143 | breq se0 ;[03] 144 | subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 145 | nop2 ;[05] 146 | rjmp didUnstuffE ;[06] 147 | 148 | unstuffOdd: 149 | ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1 150 | in x2, USBIN ;[00] [10] 151 | andi shift, ~0x80;[01] 152 | andi x2, USBMASK ;[02] 153 | breq se0 ;[03] 154 | subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 155 | nop2 ;[05] 156 | rjmp didUnstuffO ;[06] 157 | 158 | rxByteLoop: 159 | andi x1, USBMASK ;[03] 160 | eor x2, x1 ;[04] 161 | subi leap, 1 ;[05] 162 | brpl skipLeap ;[06] 163 | subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte 164 | nop ;1 165 | skipLeap: 166 | subi x2, 1 ;[08] 167 | ror shift ;[09] 168 | didUnstuff6: 169 | cpi shift, 0xfc ;[10] 170 | in x2, USBIN ;[00] [11] <-- sample bit 7 171 | brcc unstuff6 ;[01] 172 | andi x2, USBMASK ;[02] 173 | eor x1, x2 ;[03] 174 | subi x1, 1 ;[04] 175 | ror shift ;[05] 176 | didUnstuff7: 177 | cpi shift, 0xfc ;[06] 178 | brcc unstuff7 ;[07] 179 | eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others 180 | st y+, x3 ;[09] store data 181 | rxBitLoop: 182 | in x1, USBIN ;[00] [11] <-- sample bit 0/2/4 183 | andi x1, USBMASK ;[01] 184 | eor x2, x1 ;[02] 185 | andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7 186 | subi x2, 1 ;[04] 187 | ror shift ;[05] 188 | cpi shift, 0xfc ;[06] 189 | brcc unstuffEven ;[07] 190 | didUnstuffE: 191 | lsr x3 ;[08] 192 | lsr x3 ;[09] 193 | rxbit1: 194 | in x2, USBIN ;[00] [10] <-- sample bit 1/3/5 195 | andi x2, USBMASK ;[01] 196 | breq se0 ;[02] 197 | eor x1, x2 ;[03] 198 | subi x1, 1 ;[04] 199 | ror shift ;[05] 200 | cpi shift, 0xfc ;[06] 201 | brcc unstuffOdd ;[07] 202 | didUnstuffO: 203 | subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3 204 | brcs rxBitLoop ;[09] 205 | 206 | subi cnt, 1 ;[10] 207 | in x1, USBIN ;[00] [11] <-- sample bit 6 208 | brcc rxByteLoop ;[01] 209 | rjmp overflow 210 | 211 | macro POP_STANDARD ; 14 cycles 212 | pop cnt 213 | pop x4 214 | pop x3 215 | pop x2 216 | pop x1 217 | pop shift 218 | pop bitcnt 219 | endm 220 | macro POP_RETI ; 7 cycles 221 | pop YH 222 | pop YL 223 | out SREG, YL 224 | pop YL 225 | endm 226 | 227 | #include "asmcommon.inc" 228 | 229 | ; USB spec says: 230 | ; idle = J 231 | ; J = (D+ = 0), (D- = 1) 232 | ; K = (D+ = 1), (D- = 0) 233 | ; Spec allows 7.5 bit times from EOP to SOP for replies 234 | 235 | bitstuffN: 236 | eor x1, x4 ;[5] 237 | ldi x2, 0 ;[6] 238 | nop2 ;[7] 239 | nop ;[9] 240 | out USBOUT, x1 ;[10] <-- out 241 | rjmp didStuffN ;[0] 242 | 243 | bitstuff6: 244 | eor x1, x4 ;[5] 245 | ldi x2, 0 ;[6] Carry is zero due to brcc 246 | rol shift ;[7] compensate for ror shift at branch destination 247 | rjmp didStuff6 ;[8] 248 | 249 | bitstuff7: 250 | ldi x2, 0 ;[2] Carry is zero due to brcc 251 | rjmp didStuff7 ;[3] 252 | 253 | 254 | sendNakAndReti: 255 | ldi x3, USBPID_NAK ;[-18] 256 | rjmp sendX3AndReti ;[-17] 257 | sendAckAndReti: 258 | ldi cnt, USBPID_ACK ;[-17] 259 | sendCntAndReti: 260 | mov x3, cnt ;[-16] 261 | sendX3AndReti: 262 | ldi YL, 20 ;[-15] x3==r20 address is 20 263 | ldi YH, 0 ;[-14] 264 | ldi cnt, 2 ;[-13] 265 | ; rjmp usbSendAndReti fallthrough 266 | 267 | ;usbSend: 268 | ;pointer to data in 'Y' 269 | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] 270 | ;uses: x1...x4, btcnt, shift, cnt, Y 271 | ;Numbers in brackets are time since first bit of sync pattern is sent 272 | ;We don't match the transfer rate exactly (don't insert leap cycles every third 273 | ;byte) because the spec demands only 1.5% precision anyway. 274 | usbSendAndReti: ; 12 cycles until SOP 275 | in x2, USBDDR ;[-12] 276 | ori x2, USBMASK ;[-11] 277 | sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 278 | in x1, USBOUT ;[-8] port mirror for tx loop 279 | out USBDDR, x2 ;[-7] <- acquire bus 280 | ; need not init x2 (bitstuff history) because sync starts with 0 281 | ldi x4, USBMASK ;[-6] exor mask 282 | ldi shift, 0x80 ;[-5] sync byte is first byte sent 283 | txByteLoop: 284 | ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101 285 | txBitLoop: 286 | sbrs shift, 0 ;[-3] [7] 287 | eor x1, x4 ;[-2] [8] 288 | out USBOUT, x1 ;[-1] [9] <-- out N 289 | ror shift ;[0] [10] 290 | ror x2 ;[1] 291 | didStuffN: 292 | cpi x2, 0xfc ;[2] 293 | brcc bitstuffN ;[3] 294 | lsr bitcnt ;[4] 295 | brcc txBitLoop ;[5] 296 | brne txBitLoop ;[6] 297 | 298 | sbrs shift, 0 ;[7] 299 | eor x1, x4 ;[8] 300 | didStuff6: 301 | out USBOUT, x1 ;[-1] [9] <-- out 6 302 | ror shift ;[0] [10] 303 | ror x2 ;[1] 304 | cpi x2, 0xfc ;[2] 305 | brcc bitstuff6 ;[3] 306 | ror shift ;[4] 307 | didStuff7: 308 | ror x2 ;[5] 309 | sbrs x2, 7 ;[6] 310 | eor x1, x4 ;[7] 311 | nop ;[8] 312 | cpi x2, 0xfc ;[9] 313 | out USBOUT, x1 ;[-1][10] <-- out 7 314 | brcc bitstuff7 ;[0] [11] 315 | ld shift, y+ ;[1] 316 | dec cnt ;[3] 317 | brne txByteLoop ;[4] 318 | ;make SE0: 319 | cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles] 320 | lds x2, usbNewDeviceAddr;[6] 321 | lsl x2 ;[8] we compare with left shifted address 322 | subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3 323 | sbci YH, 0 ;[10] 324 | out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle 325 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 326 | ;set address only after data packet was sent, not after handshake 327 | breq skipAddrAssign ;[0] 328 | sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer 329 | skipAddrAssign: 330 | ;end of usbDeviceAddress transfer 331 | ldi x2, 1< 13.333333 cycles per bit, 106.666667 cycles per byte 37 | ; Numbers in brackets are clocks counted from center of last sync bit 38 | ; when instruction starts 39 | ;register use in receive loop: 40 | ; shift assembles the byte currently being received 41 | ; x1 holds the D+ and D- line state 42 | ; x2 holds the previous line state 43 | ; x4 (leap) is used to add a leap cycle once every three bytes received 44 | ; X3 (leap2) is used to add a leap cycle once every three stuff bits received 45 | ; bitcnt is used to determine when a stuff bit is due 46 | ; cnt holds the number of bytes left in the receive buffer 47 | 48 | USB_INTR_VECTOR: 49 | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt 50 | push YL ;[-28] push only what is necessary to sync with edge ASAP 51 | in YL, SREG ;[-26] 52 | push YL ;[-25] 53 | push YH ;[-23] 54 | ;---------------------------------------------------------------------------- 55 | ; Synchronize with sync pattern: 56 | ;---------------------------------------------------------------------------- 57 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 58 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 59 | ;The first part waits at most 1 bit long since we must be in sync pattern. 60 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 61 | ;waitForJ, ensure that this prerequisite is met. 62 | waitForJ: 63 | inc YL 64 | sbis USBIN, USBMINUS 65 | brne waitForJ ; just make sure we have ANY timeout 66 | waitForK: 67 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 68 | sbis USBIN, USBMINUS ;[-19] 69 | rjmp foundK ;[-18] 70 | sbis USBIN, USBMINUS 71 | rjmp foundK 72 | sbis USBIN, USBMINUS 73 | rjmp foundK 74 | sbis USBIN, USBMINUS 75 | rjmp foundK 76 | sbis USBIN, USBMINUS 77 | rjmp foundK 78 | sbis USBIN, USBMINUS 79 | rjmp foundK 80 | sbis USBIN, USBMINUS 81 | rjmp foundK 82 | sbis USBIN, USBMINUS 83 | rjmp foundK 84 | sbis USBIN, USBMINUS 85 | rjmp foundK 86 | #if USB_COUNT_SOF 87 | lds YL, usbSofCount 88 | inc YL 89 | sts usbSofCount, YL 90 | #endif /* USB_COUNT_SOF */ 91 | #ifdef USB_SOF_HOOK 92 | USB_SOF_HOOK 93 | #endif 94 | rjmp sofError 95 | foundK: ;[-16] 96 | ;{3, 5} after falling D- edge, average delay: 4 cycles 97 | ;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample 98 | ;use 1 bit time for setup purposes, then sample again. Numbers in brackets 99 | ;are cycles from center of first sync (double K) bit after the instruction 100 | push bitcnt ;[-16] 101 | ; [---] ;[-15] 102 | lds YL, usbInputBufOffset;[-14] 103 | ; [---] ;[-13] 104 | clr YH ;[-12] 105 | subi YL, lo8(-(usbRxBuf));[-11] [rx loop init] 106 | sbci YH, hi8(-(usbRxBuf));[-10] [rx loop init] 107 | push shift ;[-9] 108 | ; [---] ;[-8] 109 | ldi shift,0x40 ;[-7] set msb to "1" so processing bit7 can be detected 110 | nop2 ;[-6] 111 | ; [---] ;[-5] 112 | ldi bitcnt, 5 ;[-4] [rx loop init] 113 | sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) 114 | rjmp haveTwoBitsK ;[-2] 115 | pop shift ;[-1] undo the push from before 116 | pop bitcnt ;[1] 117 | rjmp waitForK ;[3] this was not the end of sync, retry 118 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 119 | ; bit times (= 27 cycles). 120 | 121 | ;---------------------------------------------------------------------------- 122 | ; push more registers and initialize values while we sample the first bits: 123 | ;---------------------------------------------------------------------------- 124 | haveTwoBitsK: 125 | push x1 ;[0] 126 | push x2 ;[2] 127 | push x3 ;[4] (leap2) 128 | ldi leap2, 0x55 ;[6] add leap cycle on 2nd,5th,8th,... stuff bit 129 | push x4 ;[7] == leap 130 | ldi leap, 0x55 ;[9] skip leap cycle on 2nd,5th,8th,... byte received 131 | push cnt ;[10] 132 | ldi cnt, USB_BUFSIZE ;[12] [rx loop init] 133 | ldi x2, 1< 38 | #ifndef __IAR_SYSTEMS_ASM__ 39 | # include 40 | #endif 41 | 42 | #define __attribute__(arg) /* not supported on IAR */ 43 | 44 | #ifdef __IAR_SYSTEMS_ASM__ 45 | # define __ASSEMBLER__ /* IAR does not define standard macro for asm */ 46 | #endif 47 | 48 | #ifdef __HAS_ELPM__ 49 | # define PROGMEM __farflash 50 | #else 51 | # define PROGMEM __flash 52 | #endif 53 | 54 | #define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) 55 | 56 | /* The following definitions are not needed by the driver, but may be of some 57 | * help if you port a gcc based project to IAR. 58 | */ 59 | #define cli() __disable_interrupt() 60 | #define sei() __enable_interrupt() 61 | #define wdt_reset() __watchdog_reset() 62 | #define _BV(x) (1 << (x)) 63 | 64 | /* assembler compatibility macros */ 65 | #define nop2 rjmp $+2 /* jump to next instruction */ 66 | #define XL r26 67 | #define XH r27 68 | #define YL r28 69 | #define YH r29 70 | #define ZL r30 71 | #define ZH r31 72 | #define lo8(x) LOW(x) 73 | #define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ 74 | 75 | /* Depending on the device you use, you may get problems with the way usbdrv.h 76 | * handles the differences between devices. Since IAR does not use #defines 77 | * for MCU registers, we can't check for the existence of a particular 78 | * register with an #ifdef. If the autodetection mechanism fails, include 79 | * definitions for the required USB_INTR_* macros in your usbconfig.h. See 80 | * usbconfig-prototype.h and usbdrv.h for details. 81 | */ 82 | 83 | /* ------------------------------------------------------------------------- */ 84 | #elif __CODEVISIONAVR__ /* check for CodeVision AVR */ 85 | /* ------------------------------------------------------------------------- */ 86 | /* This port is not working (yet) */ 87 | 88 | /* #define F_CPU _MCU_CLOCK_FREQUENCY_ seems to be defined automatically */ 89 | 90 | #include 91 | #include 92 | 93 | #define __attribute__(arg) /* not supported on IAR */ 94 | 95 | #define PROGMEM __flash 96 | #define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) 97 | 98 | #ifndef __ASSEMBLER__ 99 | static inline void cli(void) 100 | { 101 | #asm("cli"); 102 | } 103 | static inline void sei(void) 104 | { 105 | #asm("sei"); 106 | } 107 | #endif 108 | #define _delay_ms(t) delay_ms(t) 109 | #define _BV(x) (1 << (x)) 110 | #define USB_CFG_USE_SWITCH_STATEMENT 1 /* macro for if() cascase fails for unknown reason */ 111 | 112 | #define macro .macro 113 | #define endm .endmacro 114 | #define nop2 rjmp .+0 /* jump to next instruction */ 115 | 116 | /* ------------------------------------------------------------------------- */ 117 | #else /* default development environment is avr-gcc/avr-libc */ 118 | /* ------------------------------------------------------------------------- */ 119 | 120 | #include 121 | #include 122 | #ifdef __ASSEMBLER__ 123 | # define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ 124 | #else 125 | # include 126 | #endif 127 | 128 | #if USB_CFG_DRIVER_FLASH_PAGE 129 | # define USB_READ_FLASH(addr) pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) 130 | #else 131 | # define USB_READ_FLASH(addr) pgm_read_byte(addr) 132 | #endif 133 | 134 | #define USB_READ_EEPROM(addr) eeprom_read_byte(addr) 135 | 136 | #define macro .macro 137 | #define endm .endm 138 | #define nop2 rjmp .+0 /* jump to next instruction */ 139 | 140 | #endif /* development environment */ 141 | 142 | /* for conveniecne, ensure that PRG_RDB exists */ 143 | #ifndef PRG_RDB 144 | # define PRG_RDB(addr) USB_READ_FLASH(addr) 145 | #endif 146 | #endif /* __usbportability_h_INCLUDED__ */ 147 | -------------------------------------------------------------------------------- /utility/USBaspHIDUART/USBaspHIDUART.lpi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <UseAppBundle Value="False"/> 16 | <ResourceType Value="res"/> 17 | </General> 18 | <VersionInfo> 19 | <UseVersionInfo Value="True"/> 20 | <MinorVersionNr Value="1"/> 21 | </VersionInfo> 22 | <BuildModes Count="2"> 23 | <Item1 Name="Debug" Default="True"/> 24 | <Item2 Name="Release"> 25 | <CompilerOptions> 26 | <Version Value="11"/> 27 | <PathDelim Value="\"/> 28 | <Target> 29 | <Filename Value="bin\$(TargetCPU)-$(TargetOS)\$(BuildMode)\USBaspHIDUART"/> 30 | </Target> 31 | <SearchPaths> 32 | <IncludeFiles Value="$(ProjOutDir)"/> 33 | <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\$(BuildMode)"/> 34 | </SearchPaths> 35 | <CodeGeneration> 36 | <SmartLinkUnit Value="True"/> 37 | <Optimizations> 38 | <OptimizationLevel Value="3"/> 39 | </Optimizations> 40 | </CodeGeneration> 41 | <Linking> 42 | <Debugging> 43 | <GenerateDebugInfo Value="False"/> 44 | </Debugging> 45 | <LinkSmart Value="True"/> 46 | </Linking> 47 | </CompilerOptions> 48 | </Item2> 49 | </BuildModes> 50 | <PublishOptions> 51 | <Version Value="2"/> 52 | <UseFileFilters Value="True"/> 53 | </PublishOptions> 54 | <RunParams> 55 | <FormatVersion Value="2"/> 56 | <Modes Count="0"/> 57 | </RunParams> 58 | <Units Count="1"> 59 | <Unit0> 60 | <Filename Value="USBaspHIDUART.pas"/> 61 | <IsPartOfProject Value="True"/> 62 | </Unit0> 63 | </Units> 64 | </ProjectOptions> 65 | <CompilerOptions> 66 | <Version Value="11"/> 67 | <PathDelim Value="\"/> 68 | <Target> 69 | <Filename Value="bin\$(TargetCPU)-$(TargetOS)\$(BuildMode)\USBaspHIDUART"/> 70 | </Target> 71 | <SearchPaths> 72 | <IncludeFiles Value="$(ProjOutDir)"/> 73 | <OtherUnitFiles Value="hidapi.pas"/> 74 | <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\$(BuildMode)"/> 75 | </SearchPaths> 76 | <Parsing> 77 | <SyntaxOptions> 78 | <IncludeAssertionCode Value="True"/> 79 | </SyntaxOptions> 80 | </Parsing> 81 | <CodeGeneration> 82 | <Checks> 83 | <IOChecks Value="True"/> 84 | <RangeChecks Value="True"/> 85 | <OverflowChecks Value="True"/> 86 | <StackChecks Value="True"/> 87 | </Checks> 88 | <VerifyObjMethodCallValidity Value="True"/> 89 | </CodeGeneration> 90 | <Linking> 91 | <Debugging> 92 | <DebugInfoType Value="dsDwarf3"/> 93 | <TrashVariables Value="True"/> 94 | <UseExternalDbgSyms Value="True"/> 95 | </Debugging> 96 | </Linking> 97 | </CompilerOptions> 98 | <Debugging> 99 | <Exceptions Count="3"> 100 | <Item1> 101 | <Name Value="EAbort"/> 102 | </Item1> 103 | <Item2> 104 | <Name Value="ECodetoolError"/> 105 | </Item2> 106 | <Item3> 107 | <Name Value="EFOpenError"/> 108 | </Item3> 109 | </Exceptions> 110 | </Debugging> 111 | </CONFIG> 112 | -------------------------------------------------------------------------------- /utility/USBaspHIDUART/hidapi.pas/hidapi.pas: -------------------------------------------------------------------------------- 1 | { HIDAPI.pas - Bindings for libhidapi 2 | 3 | Copyright (C) 2016 Bernd Kreuss <prof7bit@gmail.com> 4 | Copyright (C) 2021 Dimitrios Chr. Ioannidis <d.ioannidis@nephelae.eu> 5 | 6 | This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General 7 | Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) 8 | any later version with the following modification: 9 | 10 | As a special exception, the copyright holders of this library give you permission to link this library with 11 | independent modules to produce an executable, regardless of the license terms of these independent modules,and to 12 | copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each 13 | linked independent module, the terms and conditions of the license of that module. An independent module is a module 14 | which is not derived from or based on this library. If you modify this library, you may extend this exception to 15 | your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception 16 | statement from your version. 17 | 18 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 19 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more 20 | details. 21 | 22 | You should have received a copy of the GNU Library General Public License along with this library; if not, write to 23 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 | } 25 | unit hidapi; 26 | 27 | {$define HIDAPI_LOAD_DYNAMICALLY} 28 | {$i hidapi.inc} 29 | 30 | end. 31 | -------------------------------------------------------------------------------- /utility/USBaspHIDUART/hidapi.pas/hidapi_static.pas: -------------------------------------------------------------------------------- 1 | { HIDAPI.pas - Bindings for libhidapi 2 | 3 | Copyright (C) 2016 Bernd Kreuss <prof7bit@gmail.com> 4 | Copyright (C) 2021 Dimitrios Chr. Ioannidis <d.ioannidis@nephelae.eu> 5 | 6 | This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General 7 | Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) 8 | any later version with the following modification: 9 | 10 | As a special exception, the copyright holders of this library give you permission to link this library with 11 | independent modules to produce an executable, regardless of the license terms of these independent modules,and to 12 | copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each 13 | linked independent module, the terms and conditions of the license of that module. An independent module is a module 14 | which is not derived from or based on this library. If you modify this library, you may extend this exception to 15 | your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception 16 | statement from your version. 17 | 18 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 19 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more 20 | details. 21 | 22 | You should have received a copy of the GNU Library General Public License along with this library; if not, write to 23 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 | } 25 | unit hidapi_static; 26 | 27 | {$i hidapi.inc} 28 | 29 | end. 30 | -------------------------------------------------------------------------------- /utility/USBaspHIDUART/spscringbuffer.pas: -------------------------------------------------------------------------------- 1 | unit SPSCRingBuffer; 2 | 3 | { 4 | 5 | Single Producer Single Consumer (SPSC) Ring Buffer . 6 | 7 | Copyright (C) 2022 Dimitrios Chr. Ioannidis. 8 | Nephelae - https://www.nephelae.eu 9 | 10 | https://www.nephelae.eu/ 11 | 12 | Licensed under the MIT License (MIT). 13 | See licence file in root directory. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | } 26 | 27 | {$mode ObjFPC}{$H+} 28 | 29 | interface 30 | 31 | uses 32 | Classes, SysUtils; 33 | 34 | type 35 | 36 | { TSPSCRingBuffer } 37 | 38 | TSPSCRingBuffer = class(TObject) 39 | private 40 | FMemoryData: Pointer; 41 | FMemorySize, FReadIndex, FWriteIndex: PtrUInt; 42 | function MaskIndex(const AValue: PtrUInt): PtrUInt; 43 | function GetEmpty: boolean; 44 | function GetFull: boolean; 45 | function GetCapacity: PtrUInt; 46 | protected 47 | function ReadByte: byte; 48 | procedure WriteByte(const AValue: byte); 49 | function PeekByte(AIndex: PtrUInt = 0): byte; 50 | public 51 | constructor Create(const ASize: PtrUInt); 52 | destructor Destroy; override; 53 | function Read(out ABuffer; const ALength: PtrUInt): PtrUInt; 54 | function Write(const ABuffer; const ALength: PtrUInt): PtrUInt; 55 | function Peek(out ABuffer; ALength: PtrUInt): PtrUInt; 56 | procedure AdvanceReadIdx(ACount: PtrUInt = 1); 57 | property Empty: boolean read GetEmpty; 58 | property Full: boolean read GetFull; 59 | property Size: PtrUInt read FMemorySize; 60 | end; 61 | 62 | implementation 63 | 64 | { TSPSCRingBuffer } 65 | 66 | constructor TSPSCRingBuffer.Create(const ASize: PtrUInt); 67 | begin 68 | inherited Create; 69 | FReadIndex := 0; 70 | FWriteIndex := 0; 71 | FMemorySize := ASize; 72 | Getmem(FMemoryData, FMemorySize); 73 | end; 74 | 75 | destructor TSPSCRingBuffer.Destroy; 76 | begin 77 | Freemem(FMemoryData, FMemorySize); 78 | inherited Destroy; 79 | end; 80 | 81 | function TSPSCRingBuffer.GetEmpty: boolean; //inline; 82 | begin 83 | Result := FReadIndex = FWriteIndex; 84 | end; 85 | 86 | function TSPSCRingBuffer.GetFull: boolean; //inline; 87 | begin 88 | Result := GetCapacity = FMemorySize - 1; 89 | end; 90 | 91 | function TSPSCRingBuffer.MaskIndex(const AValue: PtrUInt): PtrUInt; //inline; 92 | begin 93 | Result := AValue and (FMemorySize - 1); 94 | end; 95 | 96 | // See : https://forum.lazarus.freepascal.org/index.php/topic,59796.msg446453.html#msg446453 97 | function TSPSCRingBuffer.GetCapacity: PtrUInt; //inline; 98 | begin 99 | {$PUSH} 100 | {$Q-} 101 | {$R-} 102 | Result := MaskIndex(FWriteIndex - FReadIndex); 103 | {$POP} 104 | end; 105 | 106 | function TSPSCRingBuffer.ReadByte: byte; inline; 107 | begin 108 | Result := pbyte(FMemoryData)[MaskIndex(FReadIndex)]; 109 | {$PUSH} 110 | {$Q-} 111 | Inc(FReadIndex); 112 | {$POP} 113 | end; 114 | 115 | procedure TSPSCRingBuffer.WriteByte(const AValue: byte); inline; 116 | begin 117 | pbyte(FMemoryData)[MaskIndex(FWriteIndex)] := AValue; 118 | {$PUSH} 119 | {$Q-} 120 | Inc(FWriteIndex); 121 | {$POP} 122 | end; 123 | 124 | function TSPSCRingBuffer.PeekByte(AIndex: PtrUInt): byte; 125 | begin 126 | {$PUSH} 127 | {$Q-} 128 | Result := pbyte(FMemoryData)[MaskIndex(FReadIndex + AIndex)]; 129 | {$POP} 130 | end; 131 | 132 | function TSPSCRingBuffer.Read(out ABuffer; const ALength: PtrUInt): PtrUInt; 133 | begin 134 | Result := 0; 135 | while (not Empty) and (Result < ALength) do 136 | begin 137 | pbyte(@ABuffer + Result)^ := ReadByte; 138 | Inc(Result); 139 | end; 140 | end; 141 | 142 | function TSPSCRingBuffer.Write(const ABuffer; const ALength: PtrUInt): PtrUInt; 143 | begin 144 | Result := 0; 145 | while (not Full) and (Result < ALength) do 146 | begin 147 | WriteByte(pbyte(@ABuffer + Result)^); 148 | Inc(Result); 149 | end; 150 | end; 151 | 152 | function TSPSCRingBuffer.Peek(out ABuffer; ALength: PtrUInt): PtrUInt; 153 | begin 154 | Result := 0; 155 | while (Result < ALength) and (Result < GetCapacity) do 156 | begin 157 | pbyte(@ABuffer + Result)^ := PeekByte(Result); 158 | Inc(Result); 159 | end; 160 | end; 161 | 162 | procedure TSPSCRingBuffer.AdvanceReadIdx(ACount: PtrUInt); 163 | begin 164 | {$PUSH} 165 | {$Q-} 166 | Inc(FReadIndex, ACount); 167 | {$POP} 168 | end; 169 | 170 | end. 171 | -------------------------------------------------------------------------------- /utility/USBaspHIDUART/usbasp_hid.pas: -------------------------------------------------------------------------------- 1 | unit USBasp_HID; 2 | 3 | { 4 | 5 | This file is part of 6 | Nephelae USBasp HID UART. 7 | 8 | HIDAPI Communications. 9 | 10 | Copyright (C) 2021 - 2022 Dimitrios Chr. Ioannidis. 11 | Nephelae - https://www.nephelae.eu 12 | 13 | https://www.nephelae.eu/ 14 | 15 | Licensed under the MIT License (MIT). 16 | See licence file in root directory. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 24 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | } 29 | 30 | {$mode ObjFPC} 31 | 32 | interface 33 | 34 | uses 35 | Classes, SysUtils, hidapi; 36 | 37 | type 38 | 39 | TUSBaspHIDDevice = record 40 | HidDevice: PHidDevice; 41 | index: byte; 42 | Path: string; 43 | Serial: string; 44 | Manufacturer: string; 45 | Product: string; 46 | FirmwareVersion: string; 47 | Capabilities: string; 48 | VendorID: word; 49 | ProductID: word; 50 | InterfaceNumber: integer; 51 | ReportSize: word; 52 | PacketCount: byte; 53 | end; 54 | PUSBaspHIDDevice = ^TUSBaspHIDDevice; 55 | 56 | { TUSBaspHIDDeviceList } 57 | 58 | TUSBaspHIDDeviceList = class(TFPList) 59 | private 60 | function Get(Index: integer): PUSBaspHIDDevice; 61 | public 62 | destructor Destroy; override; 63 | function Add(Value: PUSBaspHIDDevice): integer; 64 | procedure FreeItems; 65 | property Items[Index: integer]: PUSBaspHIDDevice read Get; default; 66 | end; 67 | 68 | procedure usbasp_enumerate(const APrintInfo: boolean = False); 69 | procedure usbasp_open(const AUSBaspHIDDevice: PUSBaspHIDDevice); 70 | procedure usbasp_close(const AUSBaspHIDDevice: PUSBaspHIDDevice); 71 | function usbasp_read(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 72 | function usbasp_write(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 73 | function usbasp_uart_set_conf(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 74 | function usbasp_uart_get_conf(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 75 | function usbasp_uart_write_serial(const AUSBaspHIDDevice: PUSBaspHIDDevice; const ASerialNumber: String): integer; 76 | 77 | var 78 | USBaspHIDList: TUSBaspHIDDeviceList; 79 | 80 | implementation 81 | 82 | uses 83 | StrUtils; 84 | 85 | var 86 | i: integer; 87 | 88 | function enumerate_hid(AUSBaspHIDDeviceList: TUSBaspHIDDeviceList): integer; 89 | var 90 | HidEnumerateList, HidItem: PHidDeviceInfo; 91 | USBaspHIDDevice: PUSBaspHIDDevice; 92 | index: byte; 93 | begin 94 | AUSBaspHIDDeviceList.FreeItems; 95 | AUSBaspHIDDeviceList.Clear; 96 | try 97 | HidEnumerateList := THidDeviceInfo.Enumerate($16C0, $05DC); 98 | HidItem := HidEnumerateList; 99 | index := 0; 100 | while Assigned(HidItem) do 101 | begin 102 | New(USBaspHIDDevice); 103 | USBaspHIDDevice^.index:=index; 104 | USBaspHIDDevice^.Path := HidItem^.Path; 105 | USBaspHIDDevice^.Serial := PCWCharToUnicodeString(HidItem^.SerialNumber); 106 | USBaspHIDDevice^.Manufacturer := 107 | PCWCharToUnicodeString(HidItem^.ManufacturerString); 108 | USBaspHIDDevice^.Product := PCWCharToUnicodeString(HidItem^.ProductString); 109 | USBaspHIDDevice^.InterfaceNumber := HidItem^.InterfaceNumber; 110 | USBaspHIDDevice^.VendorID := HidItem^.VendorID; 111 | USBaspHIDDevice^.ProductID := HidItem^.ProductID; 112 | USBaspHIDDevice^.FirmwareVersion := 113 | ReverseString(ReverseString(BCDToInt(HidItem^.ReleaseNumber).ToString()).Insert(2, '.')); 114 | USBaspHIDDevice^.Capabilities := ''; 115 | USBaspHIDDevice^.ReportSize := 8; 116 | USBaspHIDDevice^.PacketCount := 1; 117 | AUSBaspHIDDeviceList.Add(USBaspHIDDevice); 118 | HidItem := HidItem^.Next; 119 | Inc(Index); 120 | end; 121 | finally 122 | HidEnumerateList^.Free; 123 | end; 124 | Result := AUSBaspHIDDeviceList.Count; 125 | end; 126 | 127 | procedure PrintInfo(const AUSBaspHIDDevice: PUSBaspHIDDevice); 128 | begin 129 | WriteLn('-----------'); 130 | WriteLn('USBasp List index : ', AUSBaspHIDDevice^.index); 131 | WriteLn(); 132 | WriteLn('Type : ', AUSBaspHIDDevice^.VendorID.ToHexString, ' ', AUSBaspHIDDevice^.ProductID.ToHexString); 133 | WriteLn('Path : ', AUSBaspHIDDevice^.Path); 134 | WriteLn('Serial number : ', AUSBaspHIDDevice^.Serial); 135 | WriteLn('Manufacturer : ', AUSBaspHIDDevice^.Manufacturer); 136 | WriteLn('Product : ', AUSBaspHIDDevice^.Product); 137 | WriteLn('Release : ', AUSBaspHIDDevice^.FirmwareVersion); 138 | WriteLn('Interface : ', AUSBaspHIDDevice^.InterfaceNumber); 139 | WriteLn(); 140 | end; 141 | 142 | procedure usbasp_enumerate(const APrintInfo: boolean); 143 | var 144 | USBasp: PUSBaspHIDDevice; 145 | begin 146 | WriteLn(); 147 | WriteLn('Enumerating USBasp HIDUART (Hid Api Library Version : ', HidApiVersion, ' )'); 148 | 149 | if enumerate_hid(USBaspHIDList) > 0 then 150 | begin 151 | for USBasp in USBaspHIDList do 152 | begin 153 | usbasp_open(USBasp); 154 | usbasp_close(USBasp); 155 | if APrintInfo then 156 | PrintInfo(USBasp); 157 | end; 158 | //ReadLn(); 159 | end 160 | else 161 | begin 162 | WriteLn(); 163 | WriteLn('No USBasp HID UART found.'); 164 | end; 165 | end; 166 | 167 | procedure usbasp_open(const AUSBaspHIDDevice: PUSBaspHIDDevice); 168 | begin 169 | AUSBaspHIDDevice^.HidDevice := THidDevice.OpenPath(AUSBaspHIDDevice^.Path); 170 | end; 171 | 172 | procedure usbasp_close(const AUSBaspHIDDevice: PUSBaspHIDDevice); 173 | begin 174 | AUSBaspHIDDevice^.HidDevice^.Close; 175 | end; 176 | 177 | function usbasp_read(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 178 | var 179 | HidBuffer: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); 180 | begin 181 | // Read default 0 Report ID 182 | Result := AUSBaspHIDDevice^.HidDevice^.ReadTimeout(HidBuffer, AUSBaspHIDDevice^.ReportSize, 250); 183 | Move(HidBuffer, Data, AUSBaspHIDDevice^.ReportSize); 184 | end; 185 | 186 | function usbasp_write(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 187 | var 188 | HidBuffer: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); 189 | begin 190 | // Add Report ID 191 | HidBuffer[0] := $00; 192 | Move(Data, HidBuffer[1], AUSBaspHIDDevice^.ReportSize + 1); 193 | 194 | // Report size plus added Report ID 195 | Result := AUSBaspHIDDevice^.HidDevice^.Write(HidBuffer, AUSBaspHIDDevice^.ReportSize + 1) - 1; 196 | end; 197 | 198 | function usbasp_uart_get_conf(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 199 | var 200 | HidBuffer: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); 201 | HidSize: SizeInt; 202 | begin 203 | // Add Report ID 204 | HidBuffer[0] := $00; 205 | 206 | // Report size plus added Report ID 207 | HidSize := AUSBaspHIDDevice^.HidDevice^.GetFeatureReport(HidBuffer, AUSBaspHIDDevice^.ReportSize + 1) - 1; 208 | 209 | Move(HidBuffer[1], Data, HidSize); 210 | 211 | Result := HidSize - 1; 212 | end; 213 | 214 | function usbasp_uart_write_serial(const AUSBaspHIDDevice: PUSBaspHIDDevice; 215 | const ASerialNumber: String): integer; 216 | var 217 | HidBuffer: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); 218 | HidSize: SizeInt; 219 | ErrorCode: integer; 220 | SerNumValue: Word; 221 | begin 222 | Val(ASerialNumber, SerNumValue, ErrorCode); 223 | 224 | // Add Report ID 225 | HidBuffer[0] := $00; 226 | 227 | HidBuffer[1] := lo(SerNumValue); 228 | HidBuffer[2] := Hi(SerNumValue); 229 | 230 | HidBuffer[4] := $01; 231 | 232 | // Report size plus added Report ID 233 | HidSize := AUSBaspHIDDevice^.HidDevice^.SendFeatureReport(HidBuffer, AUSBaspHIDDevice^.ReportSize + 1); 234 | 235 | Result := HidSize; 236 | end; 237 | 238 | function usbasp_uart_set_conf(const AUSBaspHIDDevice: PUSBaspHIDDevice; var Data): integer; 239 | var 240 | HidBuffer: array[0..8] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0); 241 | HidSize: SizeInt; 242 | begin 243 | // Add Report ID 244 | HidBuffer[0] := $00; 245 | Move(Data, HidBuffer[1], AUSBaspHIDDevice^.ReportSize + 1); 246 | 247 | // Report size plus added Report ID 248 | HidSize := AUSBaspHIDDevice^.HidDevice^.SendFeatureReport(HidBuffer, AUSBaspHIDDevice^.ReportSize + 1); 249 | 250 | Move(HidBuffer[1], Data, HidSize - 1); 251 | 252 | Result := HidSize; 253 | end; 254 | 255 | { TUSBaspHIDDeviceList } 256 | 257 | function TUSBaspHIDDeviceList.Get(Index: integer): PUSBaspHIDDevice; 258 | begin 259 | Result := PUSBaspHIDDevice(inherited Get(Index)); 260 | end; 261 | 262 | destructor TUSBaspHIDDeviceList.Destroy; 263 | begin 264 | FreeItems; 265 | inherited Destroy; 266 | end; 267 | 268 | function TUSBaspHIDDeviceList.Add(Value: PUSBaspHIDDevice): integer; 269 | begin 270 | Result := inherited Add(Value); 271 | end; 272 | 273 | procedure TUSBaspHIDDeviceList.FreeItems; 274 | var 275 | i: integer; 276 | begin 277 | for i := 0 to Count - 1 do 278 | Dispose(Items[i]); 279 | end; 280 | 281 | initialization 282 | HidInit(); 283 | USBaspHIDList := TUSBaspHIDDeviceList.Create; 284 | 285 | finalization; 286 | USBaspHIDList.Free; 287 | HidExit(); 288 | 289 | end. 290 | -------------------------------------------------------------------------------- /utility/USBaspHIDUART/usbasp_threads.pas: -------------------------------------------------------------------------------- 1 | unit USBasp_Threads; 2 | 3 | { 4 | 5 | This file is part of 6 | Nephelae USBasp HID UART. 7 | 8 | USB HID Read / Write threads. 9 | 10 | Copyright (C) 2022 Dimitrios Chr. Ioannidis. 11 | Nephelae - https://www.nephelae.eu 12 | 13 | https://www.nephelae.eu/ 14 | 15 | Licensed under the MIT License (MIT). 16 | See licence file in root directory. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 24 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | } 29 | 30 | {$mode ObjFPC}{$H+} 31 | 32 | interface 33 | 34 | uses 35 | Classes, SysUtils, USBasp_HID, SPSCRingBuffer; 36 | 37 | type 38 | 39 | { TThreadUSBRead } 40 | 41 | TThreadUSBRead = class(TThread) 42 | private 43 | FBuffer: TSPSCRingBuffer; 44 | FUSBaspDevice: PUSBaspHIDDevice; 45 | protected 46 | procedure Execute; override; 47 | public 48 | constructor Create(const AUSBaspDevice: PUSBaspHIDDevice; 49 | const ABuffer: TSPSCRingBuffer); reintroduce; 50 | end; 51 | 52 | { TWriteRead } 53 | 54 | TThreadUSBWrite = class(TThread) 55 | private 56 | FBuffer: TSPSCRingBuffer; 57 | FUSBaspDevice: PUSBaspHIDDevice; 58 | protected 59 | procedure Execute; override; 60 | public 61 | constructor Create(const AUSBaspDevice: PUSBaspHIDDevice; 62 | const ABuffer: TSPSCRingBuffer); reintroduce; 63 | end; 64 | 65 | implementation 66 | 67 | { TThreadUSBRead } 68 | 69 | procedure TThreadUSBRead.Execute; 70 | var 71 | USBAspHidPacket: array[0..7] of byte = (0, 0, 0, 0, 0, 0, 0, 0); 72 | SerialDataCount: byte; 73 | begin 74 | repeat 75 | if usbasp_read(FUSBaspDevice, USBAspHidPacket) > 0 then 76 | begin 77 | if (USBAspHidPacket[7] > 0) then 78 | begin 79 | if (USBAspHidPacket[7] > 7) then 80 | SerialDataCount := 8 81 | else 82 | SerialDataCount := USBAspHidPacket[7]; 83 | if FBuffer.Write(USBAspHidPacket, SerialDataCount) <> SerialDataCount then 84 | raise TExceptionClass.Create('Buffer OverRun '); 85 | end; 86 | end 87 | else 88 | Sleep(2); 89 | until Terminated; 90 | end; 91 | 92 | constructor TThreadUSBRead.Create(const AUSBaspDevice: PUSBaspHIDDevice; 93 | const ABuffer: TSPSCRingBuffer); 94 | begin 95 | inherited Create(False); 96 | FBuffer := ABuffer; 97 | FUSBaspDevice := AUSBaspDevice; 98 | end; 99 | 100 | { TThreadUSBWrite } 101 | 102 | procedure TThreadUSBWrite.Execute; 103 | var 104 | USBAspHidPacket: array[0..7] of byte = (0, 0, 0, 0, 0, 0, 0, 0); 105 | SerialCountOrDataByte: byte = 0; 106 | begin 107 | repeat 108 | SerialCountOrDataByte := FBuffer.Peek(USBAspHidPacket, 8); 109 | 110 | if (SerialCountOrDataByte = 8) and (USBAspHidPacket[7] = 7) then 111 | SerialCountOrDataByte := 7 112 | else 113 | if SerialCountOrDataByte < 8 then 114 | USBAspHidPacket[7] := SerialCountOrDataByte; 115 | 116 | if SerialCountOrDataByte > 0 then 117 | begin 118 | if (usbasp_write(FUSBaspDevice, USBAspHidPacket) = 8) then 119 | FBuffer.AdvanceReadIdx(SerialCountOrDataByte); 120 | end 121 | else 122 | Sleep(2); 123 | 124 | until Terminated; 125 | end; 126 | 127 | constructor TThreadUSBWrite.Create(const AUSBaspDevice: PUSBaspHIDDevice; 128 | const ABuffer: TSPSCRingBuffer); 129 | begin 130 | inherited Create(False); 131 | FBuffer := ABuffer; 132 | FUSBaspDevice := AUSBaspDevice; 133 | end; 134 | 135 | 136 | end. 137 | --------------------------------------------------------------------------------