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