* buspirate.c: Implemented reset= and speed= extended parameters.

* avrdude.1: Document the change.



git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@879 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Michal Ludvig 2009-11-09 02:18:40 +00:00
parent 01f1430e8b
commit d64741e5a2
3 changed files with 180 additions and 41 deletions

View File

@ -1,3 +1,8 @@
2009-11-09 Michal Ludvig <mludvig@logix.net.nz>
* buspirate.c: Implemented reset= and speed= extended parameters.
* avrdude.1: Document the change.
2009-11-04 Michal Ludvig <mludvig@logix.net.nz>
* configure.ac, Makefile.am: Test if GCC accepts -Wno-pointer-sign

View File

@ -111,10 +111,10 @@ The Arduino (which is very similar to the STK500 1.x) is supported via
its own programmer type specification ``arduino''.
.Pp
The BusPirate is a versatile tool that can also be used as an AVR programmer.
Older BusPirate firmwares are supported in ASCII mode, for newer
firmwares (2.7+) avrdude automatically selects binary mode. Should there
be a problem with the binary mode use '-x ascii' to prefer ascii
mode with newer firmwares.
A single BusPirate can be connected to up to 3 independent AVRs. See
the section on
.Em extended parameters
below for details.
.Pp
Atmel's STK600 programmer is supported in ISP and high-voltage
programming modes, and connects through the USB.
@ -851,10 +851,45 @@ programmer creates errors during initial sequence.
.El
.It Ar buspirate
.Bl -tag -offset indent -width indent
.It Ar reset={cs,aux,aux2}
The default setup assumes the BusPirate's CS output pin connected to
the RESET pin on AVR side. It is however possible to have multiple AVRs
connected to the same BP with MISO, MOSI and SCK lines common for all of them.
In such a case one AVR should have its RESET connected to BusPirate's
.Pa CS
pin, second AVR's RESET connected to BusPirate's
.Pa AUX
pin and if your BusPirate has an
.Pa AUX2
pin (only available on BusPirate version v1a with firmware 3.0 or newer)
use that to activate RESET on the third AVR.
.Pp
It may be a good idea to decouple the BusPirate and the AVR's SPI buses from
each other using a 3-state bus buffer. For example 74HC125 or 74HC244 are some
good candidates with the latches driven by the appropriate reset pin (cs,
aux or aux2). Otherwise the SPI traffic in one active circuit may interfere
with programming the AVR in the other design.
.It Ar speed=<0..7>
BusPirate to AVR SPI speed:
.Bd -literal
0 .. 30 kHz (default)
1 .. 125 kHz
2 .. 250 kHz
3 .. 1 MHz
4 .. 2 MHz
5 .. 2.6 MHz
6 .. 4 MHz
7 .. 8 MHz
.Ed
.It Ar ascii
Use ASCII mode even when the firmware supports BinMode (binary mode).
BinMode is supported in firmware 2.7 and newer, older FW's either don't
have BinMode or their BinMode is buggy.
have BinMode or their BinMode is buggy. ASCII mode is slower and makes
the above
.Ar reset=
and
.Ar speed=
parameters unavailable.
.El
.El
.Sh FILES

View File

@ -46,20 +46,47 @@
#include "serial.h"
/* ====== Private data structure ====== */
/* CS and AUX pin bitmasks in
* 0100wxyz Configure peripherals command */
#define BP_RESET_CS 0x01
#define BP_RESET_AUX 0x02
#define BP_RESET_AUX2 0x04
#define BP_FLAG_IN_BINMODE (1<<0)
#define BP_FLAG_XPARM_FORCE_ASCII (1<<1)
#define BP_FLAG_XPARM_RESET (1<<2)
#define BP_FLAG_XPARM_SPIFREQ (1<<3)
struct pdata
{
char hw_version[10];
int fw_version; /* = 100*fw_major + fw_minor */
int binmode_version;
int bin_spi_version;
int in_binmode;
int force_ascii;
int current_peripherals_config;
int spifreq; /* 0..7 - see buspirate manual for what freq each value means */
int reset; /* See BP_RESET_* above */
};
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
/* Binary mode is available from firmware v2.7 on */
#define FW_BINMODE_VER 207
/* ====== Feature checks ====== */
static inline int
buspirate_has_aux2(struct programmer_t *pgm)
{
return ((PDATA(pgm)->fw_version >= 300) &&
strcmp(PDATA(pgm)->hw_version, "v1a") == 0);
}
static inline int
buspirate_uses_ascii(struct programmer_t *pgm)
{
return (pgm->flag & BP_FLAG_XPARM_FORCE_ASCII) ||
(PDATA(pgm)->fw_version < FW_BINMODE_VER);
}
/* ====== Serial talker functions - binmode ====== */
static void dump_mem(unsigned char *buf, size_t len)
@ -113,7 +140,7 @@ static int buspirate_expect_bin(struct programmer_t *pgm,
char *expect_data, size_t expect_len)
{
char *recv_buf = alloca(expect_len);
if (!PDATA(pgm)->in_binmode) {
if (!pgm->flag & BP_FLAG_IN_BINMODE) {
fprintf(stderr, "BusPirate: Internal error: buspirate_send_bin() called from ascii mode");
exit(1);
}
@ -138,7 +165,7 @@ static int buspirate_getc(struct programmer_t *pgm)
int rc;
unsigned char ch = 0;
if (PDATA(pgm)->in_binmode) {
if (pgm->flag & BP_FLAG_IN_BINMODE) {
fprintf(stderr, "BusPirate: Internal error: buspirate_getc() called from binmode");
exit(1);
}
@ -197,7 +224,7 @@ static int buspirate_send(struct programmer_t *pgm, char *str)
if (verbose)
fprintf(stderr, "%s: buspirate_send(): %s", progname, str);
if (PDATA(pgm)->in_binmode) {
if (pgm->flag & BP_FLAG_IN_BINMODE) {
fprintf(stderr, "BusPirate: Internal error: buspirate_send() called from binmode");
exit(1);
}
@ -244,6 +271,85 @@ static void buspirate_dummy_6(struct programmer_t *pgm,
{
}
/* ====== Config / parameters handling functions ====== */
static int
buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
{
LNODEID ln;
const char *extended_param;
char reset[10];
char *preset = reset; /* for strtok() */
int spifreq;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if (strcmp(extended_param, "ascii") == 0) {
pgm->flag |= BP_FLAG_XPARM_FORCE_ASCII;
continue;
}
if (sscanf(extended_param, "spifreq=%d", &spifreq) == 1) {
if (spifreq & (~0x07)) {
fprintf(stderr, "BusPirate: spifreq must be between 0 and 7.\n");
fprintf(stderr, "BusPirate: see BusPirate manual for details.\n");
return -1;
}
PDATA(pgm)->spifreq = spifreq;
pgm->flag |= BP_FLAG_XPARM_SPIFREQ;
continue;
}
if (sscanf(extended_param, "reset=%s", reset) == 1) {
char *resetpin;
while ((resetpin = strtok(preset, ","))) {
preset = NULL; /* for subsequent strtok() calls */
if (strcasecmp(resetpin, "cs") == 0)
PDATA(pgm)->reset |= BP_RESET_CS;
else if (strcasecmp(resetpin, "aux") == 0 || strcasecmp(reset, "aux1") == 0)
PDATA(pgm)->reset |= BP_RESET_AUX;
else if (strcasecmp(resetpin, "aux2") == 0)
PDATA(pgm)->reset |= BP_RESET_AUX2;
else {
fprintf(stderr, "BusPirate: reset must be either CS or AUX.\n");
return -1;
}
}
pgm->flag |= BP_FLAG_XPARM_RESET;
continue;
}
}
return 0;
}
static int
buspirate_verifyconfig(struct programmer_t *pgm)
{
/* Default reset pin is CS */
if (PDATA(pgm)->reset == 0x00)
PDATA(pgm)->reset |= BP_RESET_CS;
/* reset=AUX2 is only available on HW=v1a and FW>=3.0 */
if ((PDATA(pgm)->reset & BP_RESET_AUX2) && !buspirate_has_aux2(pgm)) {
fprintf(stderr, "BusPirate: Pin AUX2 is only available in binary mode\n");
fprintf(stderr, "BusPirate: with hardware==v1a && firmware>=3.0\n");
fprintf(stderr, "BusPirate: Your hardware==%s and firmware==%d.%d\n",
PDATA(pgm)->hw_version, PDATA(pgm)->fw_version/100, PDATA(pgm)->fw_version%100);
return -1;
}
if ((PDATA(pgm)->reset != BP_RESET_CS) && buspirate_uses_ascii(pgm)) {
fprintf(stderr, "BusPirate: RESET pin other than CS is not supported in ASCII mode\n");
return -1;
}
if ((pgm->flag & BP_FLAG_XPARM_SPIFREQ) && buspirate_uses_ascii(pgm)) {
fprintf(stderr, "BusPirate: SPI speed selection is not supported in ASCII mode\n");
return -1;
}
return 0;
}
/* ====== Programmer methods ======= */
static int buspirate_open(struct programmer_t *pgm, char * port)
{
@ -276,7 +382,7 @@ static void buspirate_reset_from_binmode(struct programmer_t *pgm)
buf[0] = 0x0F; /* BinMode: reset */
buspirate_send_bin(pgm, buf, 1);
PDATA(pgm)->in_binmode = 0;
pgm->flag &= ~BP_FLAG_IN_BINMODE;
while(1) {
buspirate_readline(pgm, buf, sizeof(buf) - 1);
if (buspirate_is_prompt(buf))
@ -304,7 +410,7 @@ static int buspirate_start_spi_mode_bin(struct programmer_t *pgm)
if (verbose)
printf("BusPirate binmode version: %d\n", PDATA(pgm)->binmode_version);
PDATA(pgm)->in_binmode = 1;
pgm->flag |= BP_FLAG_IN_BINMODE;
/* == Enter SPI mode == */
buf[0] = 0x01; /* Enter raw SPI mode */
@ -319,16 +425,21 @@ static int buspirate_start_spi_mode_bin(struct programmer_t *pgm)
if (verbose)
printf("BusPirate SPI version: %d\n", PDATA(pgm)->bin_spi_version);
/* 0b0100wxyz Configure peripherals w=power, x=pull-ups, y=AUX, z=CS
* we want power and CS -- 0b01001001 = 0x49 */
buspirate_expect_bin_byte(pgm, 0x49, 0x01);
/* 0b0100wxyz Configure peripherals w=power, x=pull-ups/aux2, y=AUX, z=CS
* we want power (0x48) and all reset pins high. */
PDATA(pgm)->current_peripherals_config = 0x48;
PDATA(pgm)->current_peripherals_config |= BP_RESET_CS;
PDATA(pgm)->current_peripherals_config |= BP_RESET_AUX;
if (buspirate_has_aux2(pgm))
PDATA(pgm)->current_peripherals_config |= BP_RESET_AUX2;
buspirate_expect_bin_byte(pgm, PDATA(pgm)->current_peripherals_config, 0x01);
usleep(50000); // sleep for 50ms after power up
/* 01100xxx - SPI speed
* xxx = 000=30kHz, 001=125kHz, 010=250kHz, 011=1MHz,
* 100=2MHz, 101=2.6MHz, 110=4MHz, 111=8MHz
* use 30kHz = 0x60 */
buspirate_expect_bin_byte(pgm, 0x60, 0x01);
buspirate_expect_bin_byte(pgm, 0x60 | PDATA(pgm)->spifreq, 0x01);
/* 1000wxyz SPI config, w=HiZ(0)/3.3v(1), x=CLK idle, y=CLK edge, z=SMP sample
* we want: 3.3V(1), idle low(0), data change on trailing edge (1),
@ -417,14 +528,15 @@ static void buspirate_enable(struct programmer_t *pgm)
exit(1);
}
printf("BusPirate: firmware %d.%d\n", fw_v1, fw_v2);
if (buspirate_verifyconfig(pgm) < 0)
exit(1);
if (PDATA(pgm)->fw_version >= FW_BINMODE_VER && !PDATA(pgm)->force_ascii) {
if (PDATA(pgm)->fw_version >= FW_BINMODE_VER && !(pgm->flag & BP_FLAG_XPARM_FORCE_ASCII)) {
printf("BusPirate: using BINARY mode\n");
if (buspirate_start_spi_mode_bin(pgm) < 0)
fprintf(stderr, "%s: Failed to start binary SPI mode\n", progname);
}
if (! PDATA(pgm)->in_binmode) {
if (!pgm->flag & BP_FLAG_IN_BINMODE) {
printf("BusPirate: using ASCII mode\n");
if (buspirate_start_spi_mode_ascii(pgm) < 0) {
fprintf(stderr, "%s: Failed to start ascii SPI mode\n", progname);
@ -435,7 +547,7 @@ static void buspirate_enable(struct programmer_t *pgm)
static void buspirate_disable(struct programmer_t *pgm)
{
if (PDATA(pgm)->in_binmode)
if (pgm->flag & BP_FLAG_IN_BINMODE)
buspirate_reset_from_binmode(pgm);
else
buspirate_expect(pgm, "#\n", "RESET", 1);
@ -450,7 +562,7 @@ static int buspirate_initialize(struct programmer_t *pgm, AVRPART * p)
static void buspirate_powerup(struct programmer_t *pgm)
{
if (PDATA(pgm)->in_binmode) {
if (pgm->flag & BP_FLAG_IN_BINMODE) {
/* Powerup in BinMode is handled in SPI init */
return;
} else
@ -463,7 +575,7 @@ static void buspirate_powerup(struct programmer_t *pgm)
static void buspirate_powerdown(struct programmer_t *pgm)
{
if (PDATA(pgm)->in_binmode) {
if (pgm->flag & BP_FLAG_IN_BINMODE) {
/* 0b0100wxyz Configure peripherals w=power, x=pull-ups, y=AUX, z=CS
* we want everything off -- 0b01000000 = 0x40 */
if (buspirate_expect_bin_byte(pgm, 0x40, 0x01))
@ -527,7 +639,7 @@ static int buspirate_cmd(struct programmer_t *pgm,
unsigned char cmd[4],
unsigned char res[4])
{
if (PDATA(pgm)->in_binmode)
if (pgm->flag & BP_FLAG_IN_BINMODE)
return buspirate_cmd_bin(pgm, cmd, res);
else
return buspirate_cmd_ascii(pgm, cmd, res);
@ -538,10 +650,11 @@ static int buspirate_program_enable(struct programmer_t *pgm, AVRPART * p)
unsigned char cmd[4];
unsigned char res[4];
if (PDATA(pgm)->in_binmode)
/* 0000001x CS high (1) or low (0)
* we want CS low -> 0x02 */
buspirate_expect_bin_byte(pgm, 0x02, 0x01);
if (pgm->flag & BP_FLAG_IN_BINMODE) {
/* Clear configured reset pin(s): CS and/or AUX and/or AUX2 */
PDATA(pgm)->current_peripherals_config &= ~PDATA(pgm)->reset;
buspirate_expect_bin_byte(pgm, PDATA(pgm)->current_peripherals_config, 0x01);
}
else
buspirate_expect(pgm, "{\n", "CS ENABLED", 1);
@ -588,20 +701,6 @@ static int buspirate_chip_erase(struct programmer_t *pgm, AVRPART * p)
return 0;
}
static int buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
{
LNODEID ln;
const char *extended_param;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if (strcmp(extended_param, "ascii") == 0)
PDATA(pgm)->force_ascii = 1;
}
return 0;
}
void buspirate_initpgm(struct programmer_t *pgm)
{
strcpy(pgm->type, "BusPirate");