| |
avrprog.c
// avrprog.c
#include "iodefs.h"
#include "timer.h"
#include "uart.h"
#define VERSION "1.0"
//#define ASCII /* use for debug with terminal emulator */
//#define SIMULATE 'e'
#ifdef SIMULATE
#define getchar() SIMULATE
#endif
char version[] PROGMEM = VERSION"\r\n";
#define FLASH_PROG_MSECS 5 /* 4.1 msec min. */
#define EEPROM_PROG_MSECS 9 /* 8.2 msec min. */
#define ENABLE_1 0xac
#define ENABLE_2 0x53
#define CHIP_ERASE 0x80
#define MEM_HI_BIT 0x08 /* set if program memory addresses high byte */
#define MEM_WRITE_BIT 0x40 /* set if program/EEPROM write */
#define EEPROM_BIT 0x80 /* set if EEPROM memory read/write */
#define READ_MEM 0x20
#define READ_MEM_LO READ_MEM
#define READ_MEM_HI (READ_MEM | MEM_HI_BIT)
#define WRITE_MEM 0x40
#define WRITE_MEM_LO WRITE_MEM
#define WRITE_MEM_HI (WRITE_MEM | MEM_HI_BIT)
#define WRITE_MEM_PAGE 0x4c
#define READ_EEPROM 0xa0
#define WRITE_EEPROM 0xc0
#define WRITE_LOCK 0xe0
#define READ_DEV_CODE 0x30
#define MEGA_READ_FUSE 0x50
#define WRITE_LOCK_BITS 0xacf9
#define READ_LOCK_BITS 0x54
#define WRITE_FUSE_BITS 0xaca0
#define READ_FUSE_BITS 0x50
#define READ_CAL_BYTE 0x38
#define make_oc_low(port, bit) \
cbi(port, bit); /* disable pull-up */ \
sbi(DDR(port), bit) /* drive I/O pin low */
#define make_oc_high(port, bit) \
cbi(DDR(port), bit); /* disable I/O driver */ \
sbi(port, bit); /* enable pull-up */
#define make_output(port, bit) \
sbi(DDR(port), bit); /* make I/O pin output */
#define make_input(port, bit) \
cbi(DDR(port), bit); /* make I/O pin input */
#define set_low(port, bit) \
cbi(port, bit); /* drive output pin low */
#define set_high(port, bit) \
sbi(port, bit); /* drive output pin high */
#ifdef ASCII
static void puthexn(unsigned char nib)
{
nib &= 0x0f;
nib += '0';
if (nib > '9') nib += ('a' - '9' - 1);
putchar(nib);
}
#undef puthexb
#define puthexb(ch) puthexn(swap(ch)); puthexn(ch)
void crlf(void)
{
uart_tx();
putchar('\r');
putchar('\n');
}
#endif
unsigned char shift_bits(
unsigned char out,
unsigned char n
){
unsigned char resp = 0;
while (n--) {
if (out & 0x80) {
set_high(SPI_PORT, MOSI_BIT);
} else {
set_low(SPI_PORT, MOSI_BIT);
}
out = out << 1;
set_high(SPI_PORT, SCK_BIT);
resp = resp << 1;
if (bit_is_set(PINS(SPI_PORT), MISO_BIT)) {
resp |= 1;
}
//////_putchar((resp & 1) ? '1' : '0');
set_low(SPI_PORT, SCK_BIT);
}
set_low(SPI_PORT, MOSI_BIT);
return resp;
}
unsigned char rw_memory(
unsigned char code,
unsigned short addr,
unsigned char data
){
unsigned char n = 32;
unsigned char resp; // ignore warning
if (!(code & EEPROM_BIT)) { // special processing for program memory
if (addr & 1) code |= MEM_HI_BIT;
addr = addr >> 1;
}
while (n--) {
if (n == 23) {
code = hi(addr);
} else if (n == 15) {
code = (unsigned char)addr;
} else if (n == 7) {
code = data;
}
if (code & 0x80) {
set_high(SPI_PORT, MOSI_BIT);
} else {
set_low(SPI_PORT, MOSI_BIT);
}
code = code << 1;
set_high(SPI_PORT, SCK_BIT);
resp = resp << 1;
if (bit_is_set(PINS(SPI_PORT), MISO_BIT)) {
resp |= 1;
}
///_putchar((resp & 1) ? '1' : '0');
set_low(SPI_PORT, SCK_BIT);
}
set_low(SPI_PORT, MOSI_BIT);
return resp;
}
void disable_programmer(void)
{
outb(0, DDR(SPI_PORT)); // disable all output drivers
outb(0xff, SPI_PORT); // enable pull-ups
}
void enable_programmer(void)
{
// setup I/O
set_low(SPI_PORT, MOSI_BIT); // MOSI is output from remote
make_output(SPI_PORT, MOSI_BIT);
set_low(SPI_PORT, SCK_BIT); // SCK is output from remote
make_output(SPI_PORT, SCK_BIT);
make_input(SPI_PORT, MISO_BIT); // MISO is input from remote
}
unsigned char reset_chip(void)
{
make_oc_low(SPI_PORT, RESET_BIT); // reset external AVR chip
delay_ms(1); // delay
if (bit_is_clear(SPI_PORT, SCK_BIT)) { // check SCK line is free
return 0; // RESET is not working!
} else {
return 1; // all OK
}
}
void release_chip(void)
{
disable_programmer();
make_oc_high(SPI_PORT, RESET_BIT); // release reset of external AVR chip
}
int main(void)
{
unsigned char chip_enabled;
unsigned char resp; // ignore warning
unsigned char ch;
unsigned short addr = 0;
osccal(); // calibrate internal processor clock
release_chip();
chip_enabled = 0;
delay_ms(250); // delay 1/4 second
_uart_reset(); // enable UART output
while (1) {
//
// prompt user
//
#ifdef ASCII
crlf();
#endif
uart_tx();
putchar('*');
uart_rx();
ch = getchar();
//
// show version
//
if (ch == 'v') {
uart_tx();
_putstr(version);
//
// no-operation
//
} else if (ch == 'n' || ch == 0xff) {
; // do nothing...
//
// set address
//
} else if (ch == 'a') {
addr = getchar();
ch = getchar();
addr |= (ch << 8);
#ifdef ASCII
crlf();
puthexb(hi(addr));
puthexb(addr);
#endif
//
// send bytes
//
} else if (ch == '>') {
unsigned char ch0, ch1, ch2;
ch0 = getchar();
ch1 = getchar();
ch2 = getchar();
ch = getchar();
if (chip_enabled) {
shift_bits(ch0, 8);
shift_bits(ch1, 8);
shift_bits(ch2, 8);
resp = shift_bits(ch, 8);
} else {
putchar(resp);
goto oops;
}
goto log;
//
// reset chip
//
} else if (ch == 'r') {
chip_enabled = 0;
make_oc_low(SPI_PORT, RESET_BIT); // reset external AVR chip
disable_programmer();
delay_ms(1); // minimum delay
//
// release chip
//
} else if (ch == 'R') {
chip_enabled = 0;
disable_programmer();
//
// enable chip
//
} else if (ch == 'e') {
addr = 0;
disable_programmer();
if (!reset_chip()) goto oops;
enable_programmer();
chip_enabled = BYTE(1);
// cycle RESET* with SCK low
make_oc_high(SPI_PORT, RESET_BIT);
delay_ms(1);
make_oc_low(SPI_PORT, RESET_BIT);
delay_ms(20);
uart_tx();
for (ch = 0; ch < 32; ++ch) {
// send chip enable
shift_bits(ENABLE_1, 8);
resp = shift_bits(ENABLE_2, 16);
shift_bits(0, 8);
if (resp == ENABLE_2) break;
delay_ms(4);
set_high(SPI_PORT, SCK_BIT);
delay_ms(4);
set_low(SPI_PORT, SCK_BIT);
delay_ms(4);
#ifdef ASCII
puthexb(resp);
putchar('!');
#endif
}
if (resp != ENABLE_2) goto oops;
goto log;
//
// read flash program or EEPROM memory
//
} else if (ch == 'f' || ch == 'm') {
unsigned char n;
n = getchar(); // read number of bytes to dump
uart_tx();
if (!chip_enabled) goto oops;
while (n--) {
resp = rw_memory(
(ch == 'f') ? READ_MEM : READ_EEPROM, addr, 0);
#ifdef ASCII
crlf();
puthexb(resp);
#else
putchar(resp);
#endif
addr += BYTE(1);
}
//
// write flash program memory
//
} else if (ch == 'F' || ch == 'M') {
unsigned char i;
unsigned char j;
unsigned char n;
unsigned char data;
unsigned char ch1, ch2, ch3, ch4, ch5, ch6, ch7;
n = getchar(); // read number of bytes to actually write
if (n > 8) n = BYTE(8);
data = getchar(); // always read 8 bytes from serial port
ch1 = getchar();
ch2 = getchar();
ch3 = getchar();
ch4 = getchar();
ch5 = getchar();
ch6 = getchar();
ch7 = getchar();
if (!chip_enabled) goto oops;
i = 0;
while (i < n) { // only write actual number of bytes requested
if (i == 1) data = ch1;
if (i == 2) data = ch2;
if (i == 3) data = ch3;
if (i == 4) data = ch4;
if (i == 5) data = ch5;
if (i == 6) data = ch6;
if (i == 7) data = ch7;
++i;
resp = rw_memory(
(ch == 'F') ? WRITE_MEM : WRITE_EEPROM, addr, data);
if (data == 0xff || data == 0x7f) {
delay_ms(
(ch == 'F') ? FLASH_PROG_MSECS : EEPROM_PROG_MSECS);
} else {
j = BYTE(10);
while (j) {
--j;
delay_ms(1);
resp = rw_memory(
(ch == 'F') ? READ_MEM : READ_EEPROM, addr, 0);
if (resp == data) break;
}
#ifdef ASCII
crlf();
puthexb(resp);
#endif
if (!j) goto oops;
}
addr += BYTE(1);
}
resp = BYTE('+');
goto log;
} else {
//
// none of the above...error
//
oops: uart_tx();
putchar('?');
putchar('?');
}
continue;
//
// log response byte
//
log:
#ifdef ASCII
crlf();
puthexb(resp);
#else
uart_tx();
putchar(resp);
#endif
}
}
Back
|
|
|