Submitted by Darell Tan:

patch #7244: TPI bitbang implementation
* bitbang.c: Add TPI bitbang stuff.
* bitbang.h: (Ditto.)
* avr.c: (Ditto.)
* avr.h: (Ditto.)
* pgm.c: (Ditto.)
* pgm.h: (Ditto.)
* serbb_posix.c: Wire bitbang_cmd_tpi into the struct pgm.
* serbb_win32.c: (Ditto.)
* par.c: (Ditto.)
* doc/avrdude.texi: Document the TPI bitbang support.



git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk@976 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2011-08-23 21:03:36 +00:00
parent e5ad8f6208
commit 73a8d9bffc
13 changed files with 466 additions and 1 deletions

View File

@ -15,6 +15,7 @@ Contributors:
Thomas Fischl <tfischl@gmx.de> Thomas Fischl <tfischl@gmx.de>
David Hoerl <dhoerl@mac.com> David Hoerl <dhoerl@mac.com>
Michal Ludvig <mludvig@logix.net.nz> Michal Ludvig <mludvig@logix.net.nz>
Darell Tan
For minor contributions, please see the ChangeLog files. For minor contributions, please see the ChangeLog files.

View File

@ -1,3 +1,18 @@
2011-08-23 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
Submitted by Darell Tan:
patch #7244: TPI bitbang implementation
* bitbang.c: Add TPI bitbang stuff.
* bitbang.h: (Ditto.)
* avr.c: (Ditto.)
* avr.h: (Ditto.)
* pgm.c: (Ditto.)
* pgm.h: (Ditto.)
* serbb_posix.c: Wire bitbang_cmd_tpi into the struct pgm.
* serbb_win32.c: (Ditto.)
* par.c: (Ditto.)
* doc/avrdude.texi: Document the TPI bitbang support.
2011-08-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de> 2011-08-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
Submitted by Grygoriy Fuchedzhy: Submitted by Grygoriy Fuchedzhy:

View File

@ -13,6 +13,8 @@ Current:
- ATtiny4313 - ATtiny4313
* New programmers supported: * New programmers supported:
- TPI programming through bitbang programmers (both, serial
and parallel ones)
* Bugfixes * Bugfixes

View File

@ -1,6 +1,7 @@
/* /*
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright 2011 Darell Tan
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -36,17 +37,61 @@
#include "ppi.h" #include "ppi.h"
#include "safemode.h" #include "safemode.h"
#include "update.h" #include "update.h"
#include "tpi.h"
FP_UpdateProgress update_progress; FP_UpdateProgress update_progress;
#define DEBUG 0 #define DEBUG 0
/* TPI: returns 1 if NVM controller busy, 0 if free */
int avr_tpi_poll_nvmbsy(PROGRAMMER *pgm)
{
unsigned char cmd;
unsigned char res;
int rc = 0;
cmd = TPI_CMD_SIN | TPI_SIO_ADDR(TPI_IOREG_NVMCSR);
rc = pgm->cmd_tpi(pgm, &cmd, 1, &res, 1);
return (rc & TPI_IOREG_NVMCSR_NVMBSY);
}
/* TPI: setup NVMCMD register and pointer register (PR) for read/write/erase */
static int avr_tpi_setup_rw(PROGRAMMER * pgm, AVRMEM * mem,
unsigned long addr, unsigned char nvmcmd)
{
unsigned char cmd[4];
int rc;
/* set NVMCMD register */
cmd[0] = TPI_CMD_SOUT | TPI_SIO_ADDR(TPI_IOREG_NVMCMD);
cmd[1] = nvmcmd;
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
if (rc == -1)
return -1;
/* set Pointer Register (PR) */
cmd[0] = TPI_CMD_SSTPR | 0;
cmd[1] = (mem->offset + addr) & 0xFF;
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
if (rc == -1)
return -1;
cmd[0] = TPI_CMD_SSTPR | 1;
cmd[1] = ((mem->offset + addr) >> 8) & 0xFF;
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
if (rc == -1)
return -1;
return 0;
}
int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char * value) unsigned long addr, unsigned char * value)
{ {
unsigned char cmd[4]; unsigned char cmd[4];
unsigned char res[4]; unsigned char res[4];
unsigned char data; unsigned char data;
int r;
OPCODE * readop, * lext; OPCODE * readop, * lext;
if (pgm->cmd == NULL) { if (pgm->cmd == NULL) {
@ -60,6 +105,27 @@ int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
pgm->pgm_led(pgm, ON); pgm->pgm_led(pgm, ON);
pgm->err_led(pgm, OFF); pgm->err_led(pgm, OFF);
if (p->flags & AVRPART_HAS_TPI) {
if (pgm->cmd_tpi == NULL) {
fprintf(stderr, "%s: Error: %s programmer does not support TPI\n",
progname, pgm->type);
return -1;
}
while (avr_tpi_poll_nvmbsy(pgm));
/* setup for read */
avr_tpi_setup_rw(pgm, mem, addr, TPI_NVMCMD_NO_OPERATION);
/* load byte */
cmd[0] = TPI_CMD_SLD;
r = pgm->cmd_tpi(pgm, cmd, 1, value, 1);
if (r == -1)
return -1;
return 0;
}
/* /*
* figure out what opcode to use * figure out what opcode to use
*/ */
@ -151,6 +217,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
unsigned char rbyte; unsigned char rbyte;
unsigned long i; unsigned long i;
unsigned char * buf; unsigned char * buf;
unsigned char cmd[4];
AVRMEM * mem; AVRMEM * mem;
int rc; int rc;
@ -171,6 +238,33 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
*/ */
memset(buf, 0xff, size); memset(buf, 0xff, size);
/* supports "paged load" thru post-increment */
if ((p->flags & AVRPART_HAS_TPI) && mem->page_size != 0) {
if (pgm->cmd_tpi == NULL) {
fprintf(stderr, "%s: Error: %s programmer does not support TPI\n",
progname, pgm->type);
return -1;
}
while (avr_tpi_poll_nvmbsy(pgm));
/* setup for read (NOOP) */
avr_tpi_setup_rw(pgm, mem, 0, TPI_NVMCMD_NO_OPERATION);
/* load bytes */
for (i = 0; i < size; i++) {
cmd[0] = TPI_CMD_SLD_PI;
rc = pgm->cmd_tpi(pgm, cmd, 1, &buf[i], 1);
if (rc == -1) {
fprintf(stderr, "avr_read(): error reading address 0x%04lx\n", i);
return -1;
}
report_progress(i, size, NULL);
}
return avr_mem_hiaddr(mem);
}
if (pgm->paged_load != NULL && mem->page_size != 0) { if (pgm->paged_load != NULL && mem->page_size != 0) {
/* /*
* the programmer supports a paged mode read, perhaps more * the programmer supports a paged mode read, perhaps more
@ -303,6 +397,52 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
return -1; return -1;
} }
if (p->flags & AVRPART_HAS_TPI) {
if (pgm->cmd_tpi == NULL) {
fprintf(stderr, "%s: Error: %s programmer does not support TPI\n",
progname, pgm->type);
return -1;
}
if (strcmp(mem->desc, "flash") == 0) {
fprintf(stderr, "Writing a byte to flash is not supported for %s\n", p->desc);
return -1;
} else if ((mem->offset + addr) & 1) {
fprintf(stderr, "Writing a byte to an odd location is not supported for %s\n", p->desc);
return -1;
}
while (avr_tpi_poll_nvmbsy(pgm));
/* must erase fuse first */
if (strcmp(mem->desc, "fuse") == 0) {
/* setup for SECTION_ERASE (high byte) */
avr_tpi_setup_rw(pgm, mem, addr | 1, TPI_NVMCMD_SECTION_ERASE);
/* write dummy byte */
cmd[0] = TPI_CMD_SST;
cmd[1] = 0xFF;
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
while (avr_tpi_poll_nvmbsy(pgm));
}
/* setup for WORD_WRITE */
avr_tpi_setup_rw(pgm, mem, addr, TPI_NVMCMD_WORD_WRITE);
cmd[0] = TPI_CMD_SST_PI;
cmd[1] = data;
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
/* dummy high byte to start WORD_WRITE */
cmd[0] = TPI_CMD_SST_PI;
cmd[1] = data;
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
while (avr_tpi_poll_nvmbsy(pgm));
return 0;
}
if (!mem->paged) { if (!mem->paged) {
/* /*
* check to see if the write is necessary by reading the existing * check to see if the write is necessary by reading the existing
@ -540,6 +680,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
long i; long i;
unsigned char data; unsigned char data;
int werror; int werror;
unsigned char cmd[4];
AVRMEM * m; AVRMEM * m;
m = avr_locate_mem(p, memtype); m = avr_locate_mem(p, memtype);
@ -566,6 +707,40 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
progbuf, wsize); progbuf, wsize);
} }
if ((p->flags & AVRPART_HAS_TPI) && m->page_size != 0) {
if (pgm->cmd_tpi == NULL) {
fprintf(stderr,
"%s: Error: %s programmer does not support TPI\n",
progname, pgm->type);
return -1;
}
while (avr_tpi_poll_nvmbsy(pgm));
/* setup for WORD_WRITE */
avr_tpi_setup_rw(pgm, m, 0, TPI_NVMCMD_WORD_WRITE);
/* make sure it's aligned to a word boundary */
if (wsize & 0x1) {
wsize++;
}
/* write words, low byte first */
for (i = 0; i < wsize; i++) {
cmd[0] = TPI_CMD_SST_PI;
cmd[1] = m->buf[i];
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
cmd[1] = m->buf[++i];
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
while (avr_tpi_poll_nvmbsy(pgm));
report_progress(i, wsize, NULL);
}
return i;
}
if (pgm->paged_write != NULL && m->page_size != 0) { if (pgm->paged_write != NULL && m->page_size != 0) {
/* /*
* the programmer supports a paged mode write, perhaps more * the programmer supports a paged mode write, perhaps more

View File

@ -37,6 +37,7 @@ extern FP_UpdateProgress update_progress;
extern "C" { extern "C" {
#endif #endif
int avr_tpi_poll_nvmbsy(PROGRAMMER *pgm);
int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char * value); unsigned long addr, unsigned char * value);

View File

@ -2,6 +2,7 @@
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org> * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
* Copyright 2011 Darell Tan
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -39,6 +40,7 @@
#include "pgm.h" #include "pgm.h"
#include "par.h" #include "par.h"
#include "serbb.h" #include "serbb.h"
#include "tpi.h"
static int delay_decrement; static int delay_decrement;
@ -212,6 +214,93 @@ static unsigned char bitbang_txrx(PROGRAMMER * pgm, unsigned char byte)
return rbyte; return rbyte;
} }
static int bitbang_tpi_clk(PROGRAMMER * pgm)
{
unsigned char r = 0;
pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 1);
r = pgm->getpin(pgm, pgm->pinno[PIN_AVR_MISO]);
pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
return r;
}
void bitbang_tpi_tx(PROGRAMMER * pgm, unsigned char byte)
{
int i;
unsigned char b, parity;
/* start bit */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], 0);
bitbang_tpi_clk(pgm);
parity = 0;
for (i = 0; i <= 7; i++) {
b = (byte >> i) & 0x01;
parity ^= b;
/* set the data input line as desired */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], b);
bitbang_tpi_clk(pgm);
}
/* parity bit */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], parity);
bitbang_tpi_clk(pgm);
/* 2 stop bits */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], 1);
bitbang_tpi_clk(pgm);
bitbang_tpi_clk(pgm);
}
int bitbang_tpi_rx(PROGRAMMER * pgm)
{
int i;
unsigned char b, rbyte, parity;
/* make sure pin is on for "pullup" */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], 1);
/* wait for start bit (up to 10 bits) */
b = 1;
for (i = 0; i < 10; i++) {
b = bitbang_tpi_clk(pgm);
if (b == 0)
break;
}
if (b != 0) {
fprintf(stderr, "bitbang_tpi_rx: start bit not received correctly\n");
return -1;
}
rbyte = 0;
parity = 0;
for (i=0; i<=7; i++) {
b = bitbang_tpi_clk(pgm);
parity ^= b;
rbyte |= b << i;
}
/* parity bit */
if (bitbang_tpi_clk(pgm) != parity) {
fprintf(stderr, "bitbang_tpi_rx: parity bit is wrong\n");
return -1;
}
/* 2 stop bits */
b = 1;
b &= bitbang_tpi_clk(pgm);
b &= bitbang_tpi_clk(pgm);
if (b != 1) {
fprintf(stderr, "bitbang_tpi_rx: stop bits not received correctly\n");
return -1;
}
return rbyte;
}
int bitbang_rdy_led(PROGRAMMER * pgm, int value) int bitbang_rdy_led(PROGRAMMER * pgm, int value)
{ {
@ -267,6 +356,44 @@ int bitbang_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
return 0; return 0;
} }
int bitbang_cmd_tpi(PROGRAMMER * pgm, unsigned char cmd[],
int cmd_len, unsigned char res[], int res_len)
{
int i, r;
pgm->pgm_led(pgm, ON);
for (i=0; i<cmd_len; i++) {
bitbang_tpi_tx(pgm, cmd[i]);
}
r = 0;
for (i=0; i<res_len; i++) {
r = bitbang_tpi_rx(pgm);
if (r == -1)
break;
res[i] = r;
}
if(verbose >= 2)
{
fprintf(stderr, "bitbang_cmd_tpi(): [ ");
for(i = 0; i < cmd_len; i++)
fprintf(stderr, "%02X ", cmd[i]);
fprintf(stderr, "] [ ");
for(i = 0; i < res_len; i++)
{
fprintf(stderr, "%02X ", res[i]);
}
fprintf(stderr, "]\n");
}
pgm->pgm_led(pgm, OFF);
if (r == -1)
return -1;
return 0;
}
/* /*
* transmit bytes via SPI and return the results; 'cmd' and * transmit bytes via SPI and return the results; 'cmd' and
* 'res' must point to data buffers * 'res' must point to data buffers
@ -308,6 +435,39 @@ int bitbang_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{ {
unsigned char cmd[4]; unsigned char cmd[4];
unsigned char res[4]; unsigned char res[4];
AVRMEM *mem;
if (p->flags & AVRPART_HAS_TPI) {
pgm->pgm_led(pgm, ON);
while (avr_tpi_poll_nvmbsy(pgm));
/* NVMCMD <- CHIP_ERASE */
bitbang_tpi_tx(pgm, TPI_CMD_SOUT | TPI_SIO_ADDR(TPI_IOREG_NVMCMD));
bitbang_tpi_tx(pgm, TPI_NVMCMD_CHIP_ERASE); /* CHIP_ERASE */
/* Set Pointer Register */
mem = avr_locate_mem(p, "flash");
if (mem == NULL) {
fprintf(stderr, "No flash memory to erase for part %s\n",
p->desc);
return -1;
}
bitbang_tpi_tx(pgm, TPI_CMD_SSTPR | 0);
bitbang_tpi_tx(pgm, (mem->offset & 0xFF) | 1); /* high byte */
bitbang_tpi_tx(pgm, TPI_CMD_SSTPR | 1);
bitbang_tpi_tx(pgm, (mem->offset >> 8) & 0xFF);
/* write dummy value to start erase */
bitbang_tpi_tx(pgm, TPI_CMD_SST);
bitbang_tpi_tx(pgm, 0xFF);
while (avr_tpi_poll_nvmbsy(pgm));
pgm->pgm_led(pgm, OFF);
return 0;
}
if (p->op[AVR_OP_CHIP_ERASE] == NULL) { if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n", fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
@ -336,6 +496,19 @@ int bitbang_program_enable(PROGRAMMER * pgm, AVRPART * p)
{ {
unsigned char cmd[4]; unsigned char cmd[4];
unsigned char res[4]; unsigned char res[4];
int i;
if (p->flags & AVRPART_HAS_TPI) {
/* enable NVM programming */
bitbang_tpi_tx(pgm, TPI_CMD_SKEY);
for (i = sizeof(tpi_skey) - 1; i >= 0; i--)
bitbang_tpi_tx(pgm, tpi_skey[i]);
/* check NVMEN bit */
bitbang_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPISR);
i = bitbang_tpi_rx(pgm);
return (i != -1 && (i & TPI_REG_TPISR_NVMEN)) ? 0 : -2;
}
if (p->op[AVR_OP_PGM_ENABLE] == NULL) { if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
fprintf(stderr, "program enable instruction not defined for part \"%s\"\n", fprintf(stderr, "program enable instruction not defined for part \"%s\"\n",
@ -360,17 +533,68 @@ int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
{ {
int rc; int rc;
int tries; int tries;
int i;
bitbang_calibrate_delay(); bitbang_calibrate_delay();
pgm->powerup(pgm); pgm->powerup(pgm);
usleep(20000); usleep(20000);
/* TPIDATA is a single line, so MISO & MOSI should be connected */
if (p->flags & AVRPART_HAS_TPI) {
/* make sure cmd_tpi() is defined */
if (pgm->cmd_tpi == NULL) {
fprintf(stderr, "%s: Error: %s programmer does not support TPI\n",
progname, pgm->type);
return -1;
}
/* bring RESET high first */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 1);
usleep(1000);
if (verbose >= 2)
fprintf(stderr, "doing MOSI-MISO link check\n");
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], 0);
if (pgm->getpin(pgm, pgm->pinno[PIN_AVR_MISO]) != 0) {
fprintf(stderr, "MOSI->MISO 0 failed\n");
return -1;
}
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], 1);
if (pgm->getpin(pgm, pgm->pinno[PIN_AVR_MISO]) != 1) {
fprintf(stderr, "MOSI->MISO 1 failed\n");
return -1;
}
if (verbose >= 2)
fprintf(stderr, "MOSI-MISO link present\n");
}
pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0); pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0); pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
usleep(20000); usleep(20000);
if (p->flags & AVRPART_HAS_TPI) {
/* keep TPIDATA high for 16 clock cycles */
pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], 1);
for (i = 0; i < 16; i++)
pgm->highpulsepin(pgm, pgm->pinno[PIN_AVR_SCK]);
/* remove extra guard timing bits */
bitbang_tpi_tx(pgm, TPI_CMD_SSTCS | TPI_REG_TPIPCR);
bitbang_tpi_tx(pgm, 0x7);
/* read TPI ident reg */
bitbang_tpi_tx(pgm, TPI_CMD_SLDCS | TPI_REG_TPIIR);
rc = bitbang_tpi_rx(pgm);
if (rc != 0x80) {
fprintf(stderr, "TPIIR not correct\n");
return -1;
}
} else {
pgm->highpulsepin(pgm, pgm->pinno[PIN_AVR_RESET]); pgm->highpulsepin(pgm, pgm->pinno[PIN_AVR_RESET]);
}
usleep(20000); /* 20 ms XXX should be a per-chip parameter */ usleep(20000); /* 20 ms XXX should be a per-chip parameter */

View File

@ -2,6 +2,7 @@
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org> * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
* Copyright 2011 Darell Tan
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -39,6 +40,8 @@ int bitbang_pgm_led (PROGRAMMER * pgm, int value);
int bitbang_vfy_led (PROGRAMMER * pgm, int value); int bitbang_vfy_led (PROGRAMMER * pgm, int value);
int bitbang_cmd (PROGRAMMER * pgm, unsigned char cmd[4], int bitbang_cmd (PROGRAMMER * pgm, unsigned char cmd[4],
unsigned char res[4]); unsigned char res[4]);
int bitbang_cmd_tpi (PROGRAMMER * pgm, unsigned char cmd[],
int cmd_len, unsigned char res[], int res_len);
int bitbang_spi (PROGRAMMER * pgm, unsigned char cmd[], int bitbang_spi (PROGRAMMER * pgm, unsigned char cmd[],
unsigned char res[], int count); unsigned char res[], int count);
int bitbang_chip_erase (PROGRAMMER * pgm, AVRPART * p); int bitbang_chip_erase (PROGRAMMER * pgm, AVRPART * p);

View File

@ -2436,6 +2436,44 @@ Solution: Use the following pin mapping:
@item 6 (GND) @tab GND @tab 2 @item 6 (GND) @tab GND @tab 2
@end multitable @end multitable
@item
Problem: I want to program an ATtiny4/5/9/10 device using a serial/parallel
bitbang programmer. How to connect the pins?
Solution: Since TPI has only 1 pin for bi-directional data transfer, both
@var{MISO} and @var{MOSI} pins should be connected to the @var{TPIDATA} pin
on the ATtiny device.
However, a 1K resistor should be placed between the @var{MOSI} and @var{TPIDATA}.
The @var{MISO} pin connects to @var{TPIDATA} directly.
The @var{SCK} pin is connected to @var{TPICLK}.
In addition, the @var{Vcc}, @var{/RESET} and @var{GND} pins should
be connected to their respective ports on the ATtiny device.
@item
Problem: How can I use a FTDI FT232R USB-to-Serial device for bitbang programming?
Solution: When connecting the FT232 directly to the pins of the target Atmel device,
the polarity of the pins defined in the @code{programmer} definition should be
inverted by prefixing a tilde. For example, the @var{dasa} programmer would
look like this when connected via a FT232R device (notice the tildes in
front of pins 7, 4, 3 and 8):
@example
programmer
id = "dasa_ftdi";
desc = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts";
type = serbb;
reset = ~7;
sck = ~4;
mosi = ~3;
miso = ~8;
;
@end example
Note that this uses the FT232 device as a normal serial port, not using the
FTDI drivers in the special bitbang mode.
@item @item
Problem: My ATtiny4/5/9/10 reads out fine, but any attempt to program Problem: My ATtiny4/5/9/10 reads out fine, but any attempt to program
it (through TPI) fails. Instead, the memory retains the old contents. it (through TPI) fails. Instead, the memory retains the old contents.

View File

@ -416,6 +416,7 @@ void par_initpgm(PROGRAMMER * pgm)
pgm->program_enable = bitbang_program_enable; pgm->program_enable = bitbang_program_enable;
pgm->chip_erase = bitbang_chip_erase; pgm->chip_erase = bitbang_chip_erase;
pgm->cmd = bitbang_cmd; pgm->cmd = bitbang_cmd;
pgm->cmd_tpi = bitbang_cmd_tpi;
pgm->spi = bitbang_spi; pgm->spi = bitbang_spi;
pgm->open = par_open; pgm->open = par_open;
pgm->close = par_close; pgm->close = par_close;

View File

@ -118,6 +118,7 @@ PROGRAMMER * pgm_new(void)
* assigned before they are called * assigned before they are called
*/ */
pgm->cmd = NULL; pgm->cmd = NULL;
pgm->cmd_tpi = NULL;
pgm->spi = NULL; pgm->spi = NULL;
pgm->paged_write = NULL; pgm->paged_write = NULL;
pgm->paged_load = NULL; pgm->paged_load = NULL;

View File

@ -78,6 +78,8 @@ typedef struct programmer_t {
int (*chip_erase) (struct programmer_t * pgm, AVRPART * p); int (*chip_erase) (struct programmer_t * pgm, AVRPART * p);
int (*cmd) (struct programmer_t * pgm, unsigned char cmd[4], int (*cmd) (struct programmer_t * pgm, unsigned char cmd[4],
unsigned char res[4]); unsigned char res[4]);
int (*cmd_tpi) (struct programmer_t * pgm, unsigned char cmd[],
int cmd_len, unsigned char res[], int res_len);
int (*spi) (struct programmer_t * pgm, unsigned char cmd[], int (*spi) (struct programmer_t * pgm, unsigned char cmd[],
unsigned char res[], int count); unsigned char res[], int count);
int (*open) (struct programmer_t * pgm, char * port); int (*open) (struct programmer_t * pgm, char * port);

View File

@ -300,6 +300,7 @@ void serbb_initpgm(PROGRAMMER *pgm)
pgm->program_enable = bitbang_program_enable; pgm->program_enable = bitbang_program_enable;
pgm->chip_erase = bitbang_chip_erase; pgm->chip_erase = bitbang_chip_erase;
pgm->cmd = bitbang_cmd; pgm->cmd = bitbang_cmd;
pgm->cmd_tpi = bitbang_cmd_tpi;
pgm->open = serbb_open; pgm->open = serbb_open;
pgm->close = serbb_close; pgm->close = serbb_close;
pgm->setpin = serbb_setpin; pgm->setpin = serbb_setpin;

View File

@ -361,6 +361,7 @@ void serbb_initpgm(PROGRAMMER *pgm)
pgm->program_enable = bitbang_program_enable; pgm->program_enable = bitbang_program_enable;
pgm->chip_erase = bitbang_chip_erase; pgm->chip_erase = bitbang_chip_erase;
pgm->cmd = bitbang_cmd; pgm->cmd = bitbang_cmd;
pgm->cmd_tpi = bitbang_cmd_tpi;
pgm->open = serbb_open; pgm->open = serbb_open;
pgm->close = serbb_close; pgm->close = serbb_close;
pgm->setpin = serbb_setpin; pgm->setpin = serbb_setpin;