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/avrdude@976 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
parent
3a44cb66ef
commit
6431eece98
1
AUTHORS
1
AUTHORS
|
@ -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.
|
||||||
|
|
||||||
|
|
15
ChangeLog
15
ChangeLog
|
@ -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:
|
||||||
|
|
2
NEWS
2
NEWS
|
@ -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
|
||||||
|
|
||||||
|
|
175
avr.c
175
avr.c
|
@ -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
|
||||||
|
|
1
avr.h
1
avr.h
|
@ -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);
|
||||||
|
|
||||||
|
|
224
bitbang.c
224
bitbang.c
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
1
par.c
1
par.c
|
@ -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;
|
||||||
|
|
1
pgm.c
1
pgm.c
|
@ -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;
|
||||||
|
|
2
pgm.h
2
pgm.h
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue