Submitted by <ladyada@gmail.com>:
Patch #6233: Add support for USBtinyISP programmer * usbtiny.c: New file. * usbtiny.h: (Ditto.) * Makefile.am: Include usbtiny into the build. * avrdude.conf.in: (Ditto.) * config_gram.y: (Ditto.) * lexer.l: (Ditto.) * avrdude.1: Document the usbtiny support. * doc/avrdude.texi: (Ditto.) git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@749 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
parent
3aa7889d2a
commit
190a4b87e8
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
|
||||
Submitted by <ladyada@gmail.com>:
|
||||
Patch #6233: Add support for USBtinyISP programmer
|
||||
* usbtiny.c: New file.
|
||||
* usbtiny.h: (Ditto.)
|
||||
* Makefile.am: Include usbtiny into the build.
|
||||
* avrdude.conf.in: (Ditto.)
|
||||
* config_gram.y: (Ditto.)
|
||||
* lexer.l: (Ditto.)
|
||||
* avrdude.1: Document the usbtiny support.
|
||||
* doc/avrdude.texi: (Ditto.)
|
||||
|
||||
2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
|
||||
|
||||
* doc/avrdude.texi: Sort list of supported programmers into
|
||||
|
|
|
@ -138,6 +138,8 @@ libavrdude_a_SOURCES = \
|
|||
usbasp.h \
|
||||
usbdevs.h \
|
||||
usb_libusb.c \
|
||||
usbtiny.h \
|
||||
usbtiny.c \
|
||||
update.h \
|
||||
update.c
|
||||
|
||||
|
|
1
NEWS
1
NEWS
|
@ -7,6 +7,7 @@ Approximate change log for AVRDUDE by version.
|
|||
----------------------------------------------------------------------
|
||||
Current:
|
||||
|
||||
* Add support for the USBtinyISP programmer (patch #6233)
|
||||
|
||||
Version 5.4:
|
||||
|
||||
|
|
12
avrdude.1
12
avrdude.1
|
@ -1,6 +1,6 @@
|
|||
.\"
|
||||
.\" avrdude - A Downloader/Uploader for AVR device programmers
|
||||
.\" Copyright (C) 2001, 2002, 2003, 2005, 2006 Joerg Wunsch
|
||||
.\" Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007 Joerg Wunsch
|
||||
.\"
|
||||
.\" This program is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,7 +19,7 @@
|
|||
.\"
|
||||
.\" $Id$
|
||||
.\"
|
||||
.Dd DATE October 26, 2006
|
||||
.Dd DATE October 29, 2007
|
||||
.Os
|
||||
.Dt AVRDUDE 1
|
||||
.Sh NAME
|
||||
|
@ -127,11 +127,11 @@ frequency, so the
|
|||
.Fl B Ar bitclock
|
||||
option might be required to achieve a stable ISP communication.
|
||||
.Pp
|
||||
The USBasp ISP adapter is also supported, provided
|
||||
The USBasp ISP and USBtinyISP adapters are also supported, provided
|
||||
.Nm avrdude
|
||||
has been compiled with libusb support.
|
||||
It features a simple firwmare-only USB implementation, running on
|
||||
an ATmega8 (or ATmega88).
|
||||
They both feature simple firwmare-only USB implementations, running on
|
||||
an ATmega8 (or ATmega88), or ATtiny2313, respectively.
|
||||
.Pp
|
||||
Input files can be provided, and output files can be written in
|
||||
different file formats, such as raw binary files containing the data
|
||||
|
@ -817,6 +817,6 @@ option) requires a prior chip erase.
|
|||
This is an inherent feature of the way JTAG EEPROM programming works.
|
||||
This also applies to the STK500 in parallel programming mode.
|
||||
.Pp
|
||||
The USBasp driver does not offer any option to distinguish multiple
|
||||
The USBasp and USBtinyISP drivers do not offer any option to distinguish multiple
|
||||
devices connected simultaneously, so effectively only a single device
|
||||
is supported.
|
||||
|
|
|
@ -377,6 +377,12 @@ programmer
|
|||
type = usbasp;
|
||||
;
|
||||
|
||||
programmer
|
||||
id = "usbtiny";
|
||||
desc = "USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/";
|
||||
type = usbtiny;
|
||||
;
|
||||
|
||||
programmer
|
||||
id = "butterfly";
|
||||
desc = "Atmel Butterfly Development Board";
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "avr910.h"
|
||||
#include "butterfly.h"
|
||||
#include "usbasp.h"
|
||||
#include "usbtiny.h"
|
||||
#include "avr.h"
|
||||
#include "jtagmkI.h"
|
||||
#include "jtagmkII.h"
|
||||
|
@ -136,6 +137,7 @@ static int parse_cmdbits(OPCODE * op);
|
|||
%token K_STK500GENERIC
|
||||
%token K_AVR910
|
||||
%token K_USBASP
|
||||
%token K_USBTINY
|
||||
%token K_BUTTERFLY
|
||||
%token K_TYPE
|
||||
%token K_VCC
|
||||
|
@ -421,6 +423,12 @@ prog_parm :
|
|||
}
|
||||
} |
|
||||
|
||||
K_TYPE TKN_EQUAL K_USBTINY {
|
||||
{
|
||||
usbtiny_initpgm(current_prog);
|
||||
}
|
||||
} |
|
||||
|
||||
K_TYPE TKN_EQUAL K_BUTTERFLY {
|
||||
{
|
||||
butterfly_initpgm(current_prog);
|
||||
|
|
|
@ -462,6 +462,9 @@ Atmel STK500, running a version 2.x firmware
|
|||
@item @code{usbasp} @tab
|
||||
USBasp,@*
|
||||
@url{http://www.fischl.de/usbasp/}
|
||||
@item @code{usbtiny} @tab
|
||||
USBtiny simple USB programmer,@*
|
||||
@url{http://www.ladyada.net/make/usbtinyisp/}
|
||||
@item @code{xil} @tab
|
||||
Xilinx JTAG cable
|
||||
@end multitable
|
||||
|
|
1
lexer.l
1
lexer.l
|
@ -120,6 +120,7 @@ allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
|
|||
avr910 { yylval=NULL; return K_AVR910; }
|
||||
avr910_devcode { yylval=NULL; return K_AVR910_DEVCODE; }
|
||||
usbasp { yylval=NULL; return K_USBASP; }
|
||||
usbtiny { yylval=NULL; return K_USBTINY; }
|
||||
bank_size { yylval=NULL; return K_PAGE_SIZE; }
|
||||
banked { yylval=NULL; return K_PAGED; }
|
||||
baudrate { yylval=NULL; return K_BAUDRATE; }
|
||||
|
|
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2007 Dick Streefland, adapted for 5.4 by Limor Fried
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver for "usbtiny"-type programmers
|
||||
* Please see http://www.xs4all.nl/~dicks/avr/usbtiny/
|
||||
* and http://www.ladyada.net/make/usbtinyisp/
|
||||
* For example schematics and detailed documentation
|
||||
*/
|
||||
|
||||
#include "ac_cfg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "avrdude.h"
|
||||
#include "avr.h"
|
||||
#include "pgm.h"
|
||||
#include "usbtiny.h"
|
||||
|
||||
#if defined(HAVE_LIBUSB) // we use LIBUSB to talk to the board
|
||||
#include <usb.h>
|
||||
|
||||
typedef unsigned int uint_t;
|
||||
typedef unsigned long ulong_t;
|
||||
|
||||
extern int avr_write_byte_default ( PROGRAMMER* pgm, AVRPART* p,
|
||||
AVRMEM* mem, ulong_t addr,
|
||||
unsigned char data );
|
||||
static usb_dev_handle* usb_handle;
|
||||
static int sck_period;
|
||||
static int chunk_size;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// Wrapper for simple usb_control_msg messages
|
||||
static int usb_control (unsigned int requestid, unsigned int val, unsigned int index )
|
||||
{
|
||||
int nbytes;
|
||||
nbytes = usb_control_msg( usb_handle,
|
||||
USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
requestid,
|
||||
val, index, // 2 bytes each of data
|
||||
NULL, 0, // no data buffer in control messge
|
||||
USB_TIMEOUT ); // default timeout
|
||||
if(nbytes < 0){
|
||||
fprintf(stderr, "%s: error: usbtiny_transmit: %s\n", progname, usb_strerror());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
// Wrapper for simple usb_control_msg messages to receive data from programmer
|
||||
static int usb_in (unsigned int requestid, unsigned int val, unsigned int index,
|
||||
unsigned char* buffer, int buflen, int bitclk )
|
||||
{
|
||||
int nbytes;
|
||||
int timeout;
|
||||
|
||||
// calculate the amout of time we expect the process to take by
|
||||
// figuring the bit-clock time and buffer size and adding to the standard USB timeout.
|
||||
timeout = USB_TIMEOUT + (buflen * bitclk) / 1000;
|
||||
|
||||
nbytes = usb_control_msg( usb_handle,
|
||||
USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
requestid,
|
||||
val, index,
|
||||
(char *)buffer, buflen,
|
||||
timeout);
|
||||
if (nbytes != buflen) {
|
||||
fprintf(stderr, "%s: error: usbtiny_receive: %s (expected %d, got %d)\n",
|
||||
progname, usb_strerror(), buflen, nbytes);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
// Wrapper for simple usb_control_msg messages to send data to programmer
|
||||
static int usb_out (unsigned int requestid, unsigned int val, unsigned int index,
|
||||
unsigned char* buffer, int buflen, int bitclk )
|
||||
{
|
||||
int nbytes;
|
||||
int timeout;
|
||||
|
||||
// calculate the amout of time we expect the process to take by
|
||||
// figuring the bit-clock time and buffer size and adding to the standard USB timeout.
|
||||
timeout = USB_TIMEOUT + (buflen * bitclk) / 1000;
|
||||
|
||||
nbytes = usb_control_msg( usb_handle,
|
||||
USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
requestid,
|
||||
val, index,
|
||||
(char *)buffer, buflen,
|
||||
timeout);
|
||||
if (nbytes != buflen) {
|
||||
fprintf(stderr, "%s: error: usbtiny_send: %s (expected %d, got %d)\n",
|
||||
progname, usb_strerror(), buflen, nbytes);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
// Sometimes we just need to know the SPI command for the part to perform
|
||||
// a function. Here we wrap this request for an operation so that we
|
||||
// can just specify the part and operation and it'll do the right stuff
|
||||
// to get the information from AvrDude and send to the USBtiny
|
||||
static int usbtiny_avr_op (PROGRAMMER * pgm, AVRPART * p,
|
||||
int op,
|
||||
unsigned char res[4])
|
||||
{
|
||||
unsigned char cmd[4];
|
||||
|
||||
if (p->op[op] == NULL) {
|
||||
fprintf( stderr, "Operation %d not defined for this chip!\n", op );
|
||||
return -1;
|
||||
}
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
avr_set_bits(p->op[op], cmd);
|
||||
|
||||
return pgm->cmd(pgm, cmd, res);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/* Find a device with the correct VID/PID match for USBtiny */
|
||||
|
||||
static int usbtiny_open(PROGRAMMER* pgm, char* name)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev = 0;
|
||||
|
||||
usb_init(); // initialize the libusb system
|
||||
usb_find_busses(); // have libusb scan all the usb busses available
|
||||
usb_find_devices(); // have libusb scan all the usb devices available
|
||||
|
||||
usb_handle = NULL;
|
||||
|
||||
// now we iterate through all the busses and devices
|
||||
for ( bus = usb_busses; bus; bus = bus->next ) {
|
||||
for ( dev = bus->devices; dev; dev = dev->next ) {
|
||||
if (dev->descriptor.idVendor == USBTINY_VENDOR
|
||||
&& dev->descriptor.idProduct == USBTINY_PRODUCT ) { // found match?
|
||||
|
||||
usb_handle = usb_open(dev); // attempt to connect to device
|
||||
|
||||
// wrong permissions or something?
|
||||
if (!usb_handle) {
|
||||
fprintf(stderr, "%s: Warning: cannot open USB device: %s\n",
|
||||
progname, usb_strerror());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!usb_handle) {
|
||||
fprintf( stderr, "%s: Error: Could not find USBtiny device (0x%x/0x%x)\n",
|
||||
progname, USBTINY_VENDOR, USBTINY_PRODUCT );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0; // If we got here, we must have found a good USB device
|
||||
}
|
||||
|
||||
/* Clean up the handle for the usbtiny */
|
||||
static void usbtiny_close ( PROGRAMMER* pgm )
|
||||
{
|
||||
if (! usb_handle) {
|
||||
return; // not a valid handle, bail!
|
||||
}
|
||||
usb_close(usb_handle); // ask libusb to clean up
|
||||
usb_handle = NULL;
|
||||
}
|
||||
|
||||
/* A simple calculator function determines the maximum size of data we can
|
||||
shove through a USB connection without getting errors */
|
||||
static void usbtiny_set_chunk_size (int period)
|
||||
{
|
||||
chunk_size = CHUNK_SIZE; // start with the maximum (default)
|
||||
while (chunk_size > 8 && period > 16) {
|
||||
// Reduce the chunk size for a slow SCK to reduce
|
||||
// the maximum time of a single USB transfer.
|
||||
chunk_size >>= 1;
|
||||
period >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a SCK bit-clock speed (in useconds) we verify its an OK speed and tell the
|
||||
USBtiny to update itself to the new frequency */
|
||||
static int usbtiny_set_sck_period (PROGRAMMER *pgm, double v)
|
||||
{
|
||||
sck_period = (int)(v * 1e6 + 0.5); // convert from us to 'int', the 0.5 is for rounding up
|
||||
|
||||
// Make sure its not 0, as that will confuse the usbtiny
|
||||
if (sck_period < SCK_MIN)
|
||||
sck_period = SCK_MIN;
|
||||
|
||||
// We can't go slower, due to the byte-size of the clock variable
|
||||
if (sck_period > SCK_MAX)
|
||||
sck_period = SCK_MAX;
|
||||
|
||||
printf( "%s: Setting SCK period to %d usec\n", progname, sck_period );
|
||||
|
||||
// send the command to the usbtiny device.
|
||||
usb_control(USBTINY_POWERUP, sck_period, RESET_LOW); // MEME: for at90's fix resetstate?
|
||||
|
||||
// with the new speed, we'll have to update how much data we send per usb transfer
|
||||
usbtiny_set_chunk_size(sck_period);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p )
|
||||
{
|
||||
unsigned char res[4]; // store the response from usbtinyisp
|
||||
|
||||
// Check for bit-clock and tell the usbtiny to adjust itself
|
||||
if (pgm->bitclock > 0.0) {
|
||||
// -B option specified: convert to valid range for sck_period
|
||||
usbtiny_set_sck_period(pgm, pgm->bitclock);
|
||||
} else {
|
||||
// -B option not specified: use default
|
||||
sck_period = SCK_DEFAULT;
|
||||
if (verbose) {
|
||||
printf( "%s: Using SCK period of %d usec\n",
|
||||
progname, sck_period );
|
||||
}
|
||||
usb_control( USBTINY_POWERUP, sck_period, RESET_LOW );
|
||||
usbtiny_set_chunk_size(sck_period);
|
||||
}
|
||||
|
||||
// Let the device wake up.
|
||||
usleep(50000);
|
||||
|
||||
// Attempt to use the underlying avrdude methods to connect (MEME: is this kosher?)
|
||||
if (! usbtiny_avr_op(pgm, p, AVR_OP_PGM_ENABLE, res)) {
|
||||
// no response, RESET and try again
|
||||
usb_control(USBTINY_POWERUP, sck_period, RESET_HIGH);
|
||||
usb_control(USBTINY_POWERUP, sck_period, RESET_LOW);
|
||||
usleep(50000);
|
||||
if ( ! usbtiny_avr_op( pgm, p, AVR_OP_PGM_ENABLE, res)) {
|
||||
// give up
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Tell the USBtiny to release the output pins, etc */
|
||||
static void usbtiny_powerdown(PROGRAMMER * pgm)
|
||||
{
|
||||
if (!usb_handle) {
|
||||
return; // wasn't connected in the first place
|
||||
}
|
||||
usb_control(USBTINY_POWERDOWN, 0, 0); // Send USB control command to device
|
||||
}
|
||||
|
||||
/* Send a 4-byte SPI command to the USBtinyISP for execution
|
||||
This procedure is used by higher-level Avrdude procedures */
|
||||
static int usbtiny_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4])
|
||||
{
|
||||
int nbytes;
|
||||
|
||||
// Make sure its empty so we don't read previous calls if it fails
|
||||
memset(res, '\0', sizeof(res) );
|
||||
|
||||
nbytes = usb_in( USBTINY_SPI,
|
||||
(cmd[1] << 8) | cmd[0], // convert to 16-bit words
|
||||
(cmd[3] << 8) | cmd[2], // "
|
||||
res, sizeof(res), 8 * sck_period );
|
||||
if (verbose > 1) {
|
||||
// print out the data we sent and received
|
||||
printf( "CMD: [%02x %02x %02x %02x] [%02x %02x %02x %02x]\n",
|
||||
cmd[0], cmd[1], cmd[2], cmd[3],
|
||||
res[0], res[1], res[2], res[3] );
|
||||
}
|
||||
return ((nbytes == sizeof(res)) && // should have read 4 bytes
|
||||
res[2] == cmd[1]); // AVR's do a delayed-echo thing
|
||||
}
|
||||
|
||||
/* Send the chip-erase command */
|
||||
static int usbtiny_chip_erase(PROGRAMMER * pgm, AVRPART * p)
|
||||
{
|
||||
unsigned char res[4];
|
||||
|
||||
if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
|
||||
fprintf(stderr, "Chip erase instruction not defined for part \"%s\"\n",
|
||||
p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the command for erasing this chip and transmit to avrdude
|
||||
if (! usbtiny_avr_op( pgm, p, AVR_OP_CHIP_ERASE, res )) {
|
||||
return -1;
|
||||
}
|
||||
usleep( p->chip_erase_delay );
|
||||
|
||||
// prepare for further instruction
|
||||
pgm->initialize(pgm, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These are required functions but don't actually do anything
|
||||
static void usbtiny_enable ( PROGRAMMER* pgm ) {}
|
||||
|
||||
static void usbtiny_disable ( PROGRAMMER* pgm ) {}
|
||||
|
||||
|
||||
/* To speed up programming and reading, we do a 'chunked' read.
|
||||
* We request just the data itself and the USBtiny uses the SPI function
|
||||
* given to read in the data. Much faster than sending a 4-byte SPI request
|
||||
* per byte
|
||||
*/
|
||||
static int usbtiny_paged_load (PROGRAMMER * pgm, AVRPART * p, AVRMEM* m,
|
||||
int page_size, int n_bytes )
|
||||
{
|
||||
int i;
|
||||
int chunk;
|
||||
int function;
|
||||
|
||||
|
||||
// First determine what we're doing
|
||||
if (strcmp( m->desc, "flash" ) == 0) {
|
||||
function = USBTINY_FLASH_READ;
|
||||
} else {
|
||||
function = USBTINY_EEPROM_READ;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_bytes; i += chunk) {
|
||||
chunk = chunk_size; // start with the maximum chunk size possible
|
||||
|
||||
// If we want to xmit less than a chunk, thats OK
|
||||
if (chunk > n_bytes-i)
|
||||
chunk = n_bytes - i;
|
||||
|
||||
// Send the chunk of data to the USBtiny with the function we want
|
||||
// to perform
|
||||
usb_in(function, // EEPROM or flash
|
||||
0, // delay between SPI commands
|
||||
i, // index
|
||||
m->buf + i, // pointer to where we store data
|
||||
chunk, // number of bytes
|
||||
32 * sck_period); // each byte gets turned into a 4-byte SPI cmd
|
||||
// usb_in() multiplies this per byte.
|
||||
|
||||
// Tell avrdude how we're doing to provide user feedback
|
||||
report_progress(i + chunk, n_bytes, NULL );
|
||||
}
|
||||
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
/* To speed up programming and reading, we do a 'chunked' write.
|
||||
* We send just the data itself and the USBtiny uses the SPI function
|
||||
* given to write the data. Much faster than sending a 4-byte SPI request
|
||||
* per byte.
|
||||
*/
|
||||
static int usbtiny_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
||||
int page_size, int n_bytes)
|
||||
{
|
||||
int i;
|
||||
int chunk; // Size of data to write at once
|
||||
int next;
|
||||
int function; // which SPI command to use
|
||||
int delay; // delay required between SPI commands
|
||||
|
||||
// First determine what we're doing
|
||||
if (strcmp( m->desc, "flash" ) == 0) {
|
||||
function = USBTINY_FLASH_WRITE;
|
||||
} else {
|
||||
function = USBTINY_EEPROM_WRITE;
|
||||
}
|
||||
|
||||
delay = 0;
|
||||
if (! m->paged) {
|
||||
// Does this chip not support paged writes?
|
||||
i = (m->readback[1] << 8) | m->readback[0];
|
||||
usb_control( USBTINY_POLL_BYTES, i, 0 );
|
||||
delay = m->max_write_delay;
|
||||
}
|
||||
|
||||
for (i=0; i < n_bytes; i=next) {
|
||||
// start with the max chunk size
|
||||
chunk = chunk_size;
|
||||
|
||||
// we can only write a page at a time anyways
|
||||
if (m->paged && chunk > page_size)
|
||||
chunk = page_size;
|
||||
|
||||
// if there's less data remaining than one chunk
|
||||
if (chunk > n_bytes-i)
|
||||
chunk = n_bytes - i;
|
||||
|
||||
usb_out(function, // Flash or EEPROM
|
||||
delay, // How much to wait between each byte
|
||||
i, // Index of data
|
||||
m->buf + i, // Pointer to data
|
||||
chunk, // Number of bytes to write
|
||||
32 * sck_period + delay // each byte gets turned into a
|
||||
// 4-byte SPI cmd usb_in() multiplies
|
||||
// this per byte. Then add the cmd-delay
|
||||
);
|
||||
|
||||
next = i + chunk; // Calculate what address we're at now
|
||||
if (m->paged
|
||||
&& ((next % page_size) == 0 || next == n_bytes) ) {
|
||||
// If we're at a page boundary, send the SPI command to flush it.
|
||||
avr_write_page(pgm, p, m, (unsigned long) i);
|
||||
}
|
||||
|
||||
report_progress( next, n_bytes, NULL );
|
||||
}
|
||||
return n_bytes;
|
||||
}
|
||||
|
||||
extern void usbtiny_initpgm ( PROGRAMMER* pgm )
|
||||
{
|
||||
strcpy(pgm->type, "USBtiny");
|
||||
|
||||
/* Mandatory Functions */
|
||||
pgm->initialize = usbtiny_initialize;
|
||||
pgm->enable = usbtiny_enable;
|
||||
pgm->disable = usbtiny_disable;
|
||||
pgm->program_enable = NULL;
|
||||
pgm->chip_erase = usbtiny_chip_erase;
|
||||
pgm->cmd = usbtiny_cmd;
|
||||
pgm->open = usbtiny_open;
|
||||
pgm->close = usbtiny_close;
|
||||
pgm->read_byte = avr_read_byte_default;
|
||||
pgm->write_byte = avr_write_byte_default;
|
||||
|
||||
/* Optional Functions */
|
||||
pgm->powerup = NULL;
|
||||
pgm->powerdown = usbtiny_powerdown;
|
||||
pgm->paged_load = usbtiny_paged_load;
|
||||
pgm->paged_write = usbtiny_paged_write;
|
||||
pgm->set_sck_period = usbtiny_set_sck_period;
|
||||
}
|
||||
|
||||
#else /* !HAVE_LIBUSB */
|
||||
|
||||
// Give a proper error if we were not compiled with libusb
|
||||
|
||||
static int usbtiny_nousb_open(struct programmer_t *pgm, char * name)
|
||||
{
|
||||
fprintf(stderr, "%s: error: no usb support. Please compile again with libusb installed.\n",
|
||||
progname);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void usbtiny_initpgm(PROGRAMMER * pgm)
|
||||
{
|
||||
strcpy(pgm->type, "usbtiny");
|
||||
|
||||
pgm->open = usbtiny_nousb_open;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* avrdude - A Downloader/Uploader for AVR device programmers
|
||||
* Copyright (C) 2007 Limor Fried
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef usbtiny_h
|
||||
#define usbtiny_h
|
||||
|
||||
#include "avrpart.h"
|
||||
|
||||
// these are specifically assigned to USBtiny,
|
||||
// if you need your own VID and PIDs you can get them for cheap from
|
||||
// www.mecanique.co.uk so please don't reuse these. Thanks!
|
||||
#define USBTINY_VENDOR 0x1781
|
||||
#define USBTINY_PRODUCT 0x0C9F
|
||||
|
||||
// Generic requests to the USBtiny
|
||||
#define USBTINY_ECHO 0 // echo test
|
||||
#define USBTINY_READ 1 // read byte (wIndex:address)
|
||||
#define USBTINY_WRITE 2 // write byte (wIndex:address, wValue:value)
|
||||
#define USBTINY_CLR 3 // clear bit (wIndex:address, wValue:bitno)
|
||||
#define USBTINY_SET 4 // set bit (wIndex:address, wValue:bitno)
|
||||
|
||||
// Programming requests
|
||||
#define USBTINY_POWERUP 5 // apply power (wValue:SCK-period, wIndex:RESET)
|
||||
#define USBTINY_POWERDOWN 6 // remove power from chip
|
||||
#define USBTINY_SPI 7 // issue SPI command (wValue:c1c0, wIndex:c3c2)
|
||||
#define USBTINY_POLL_BYTES 8 // set poll bytes for write (wValue:p1p2)
|
||||
#define USBTINY_FLASH_READ 9 // read flash (wIndex:address)
|
||||
#define USBTINY_FLASH_WRITE 10 // write flash (wIndex:address, wValue:timeout)
|
||||
#define USBTINY_EEPROM_READ 11 // read eeprom (wIndex:address)
|
||||
#define USBTINY_EEPROM_WRITE 12 // write eeprom (wIndex:address, wValue:timeout)
|
||||
|
||||
|
||||
|
||||
// Flags to indicate how to set RESET on power up
|
||||
#define RESET_LOW 0
|
||||
#define RESET_HIGH 1
|
||||
|
||||
// The SCK speed can be set by avrdude, to allow programming of slow-clocked parts
|
||||
#define SCK_MIN 1 // usec delay (target clock >= 4 MHz)
|
||||
#define SCK_MAX 250 // usec (target clock >= 16 KHz)
|
||||
#define SCK_DEFAULT 10 // usec (target clock >= 0.4 MHz)
|
||||
|
||||
// How much data, max, do we want to send in one USB packet?
|
||||
#define CHUNK_SIZE 128 // must be power of 2 less than 256
|
||||
|
||||
// The default USB Timeout
|
||||
#define USB_TIMEOUT 500 // msec
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void usbtiny_initpgm (PROGRAMMER * pgm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* usbtiny_h */
|
Loading…
Reference in New Issue