Shop OBEX P1 Docs P2 Docs Learn Events
P2 Programming an ATTiny85 — Parallax Forums

P2 Programming an ATTiny85

The other day I ran across this MCU and thought it would be a good puzzle to solve.

I like programming and figuring out new devices. It looked like a good win win situation.

There are several you tube videos on the subject but of course none of them deal with the P2 or P1 for that matter. So if I get stuck I can always check them out.

Now the ATTiny85 is at end of life and there are better options out there but for $1.32 it was a small investment to make for my entertainment.

The chip comes in an 8 pin dip so using a bread board was going to work out. I finally found a use for my johnny Mac board.

Armed with the Datasheet I set out to program the ATTiny85 to blink an LED. Once I have that accomplished the puzzle is solved.

To talk to this chip with only 8 pins is very interesting and turns out to be not too bad considering to program the P1 takes a hole lot of crazy code.

The ATTiny85 uses an SPI type of programming where you have MOSI, MISO, and CLK to send and receive data. This makes it simple enough to clock in my data and see the results.

The first step was to put the unit into programming mode so I could program the chip. This turned out to be a little confusing as the docks state the inbound data is clocked on the rising edge and the out bound data is on the falling edge. Well, the outbound data is available before the failing edged so I was losing one bit of data on my return so I was not getting the 0x53 I was expecting.

Next I wrote a function to retrieve the signature bytes so I knew I had an ATTiny85 chip.

After that I thought if I can write to the EEPROM memory I was well on my way. This turned out to be simple enough and was able to program the EEPROM memory.

Now for the hard part. How to write a program that would blink an LED. The program code is difficult to write so I found a program on You Tube that talked about writing a program for the ATTiny85 without Arduino since that is where this came from.

Using avr-gcc I was able to build a program to turn the LED on but not really blink it since figuring out how to delay the processor was not a simple task.

#define DDRB  (*(volatile unsigned char*) 0x37)
#define PORTB (*(volatile unsigned char*) 0x38)

int main()
{
  DDRB |= 1; // set BP0 to output

  PORTB = 1;
}

Now this generates a program in hex that looks like this:

:100000000EC015C014C013C012C011C010C00FC064
:100010000EC00DC00CC00BC00AC009C008C011241E
:100020001FBECFE5D2E0DEBFCDBF02D007C0E8CF14
:10003000B89A81E088BB80E090E00895F894FFCF03
:00000001FF

This is the Intel file format that is very easy to read. Coping this into my program as an array and then converting it to hex was simple enough.

Now to program the flash memory which is in words where the EEPROM was in bytes turned out to be a lot confusing. It states that each page is 32 words and there are 128 pages. So each page goes from 0x00 to 0x1f and then starts over like other flash. Wrong, the first page is 0 and the next page is 0x20, 0x30 and so on. Since I went from zero to 1 as my first page that overwrote the first pages data and so on. A real
head scratcher.

So the addresses go from 0 to 128 and you have to commit each 32 word pages as you go.

Now after a couple of days playing with this, I was able to get the LED to light.

Now to use this chip with Arduino where you can program all kinds of things I would need to turn the P2 into an AVRDUDE programmer. This is what Arduino expects to see when it has to write the program to an ATTiny85 chip.

I haven't decided if I want to do that yet but converting the Arduino code to P2 doesn't look too difficult.

I still might try to blink the LED with some kind of loop. The problem is that the compiler sees it as dead code and gets rid of it. Maybe I can enlist one of the timers.

Here is the C program that writes to the ATTiny85. I guess this would be simple enough for someone to write in SPIN.

#include <stdio.h>
#include <propeller.h>

#define RESET 26
#define MOSI  27
#define MISO  28
#define SCK   29
#define PGMEN 0xAC530000
#define CHPERASE 0xAC800000
#define RDYBSY 0xF0000000
#define LDEADD 0x4D000000
#define LDPGM 0x40000000
#define LDEEPRM 0xC1000000
#define RDPGM 0x20000000
#define RDEEPRM 0xA0000000
#define RDSIGN 0x30000000
#define RDFUSE 0x50000000
#define RDCALB 0x38000000
#define WRPGM 0x4C000000
#define WREEPRM 0xC0000000
#define WRFUSE 0xACA00000


void PgmMode(void);
unsigned int SendIt(unsigned int);
void Reset(void);
unsigned int Signature(void);
unsigned char *ReadPgm(int);
void WritePgm(int, unsigned char *);
unsigned char *ReadEEProm(void);
void WriteEEProm(unsigned char *);
void Erase(void);
int DoHex(unsigned char*);

char Hex[][65] = {"0EC015C014C013C012C011C010C00FC00EC00DC00CC00BC00AC009C008C01124", 
             "1FBECFE5D2E0DEBFCDBF02D007C0E8CFB89A81E088BB80E090E00895F894FFCF"};
unsigned char Buffer[256] = {0x21, 0x22, 0x23, 0x24};
unsigned short Instr[256] = { 0x21, 0x22, 0x23, 0x24};
int verbose;


int main(int argc, char** argv)
{
    unsigned int data;
    verbose = 0;

    data = 0;

    Reset();

    PgmMode();

    Erase();

    data = SendIt(RDFUSE);
    printf("Fuse: %X\n", data);

    //data = SendIt(WRFUSE | 0xE2);
    //printf("FuseW: %X\n", data);

    data = SendIt(RDYBSY);

    printf("Busy: %x\n", data);

    data = Signature();

    printf("Signature: %x\n", data);

    data = SendIt(RDCALB);

    printf("Calibration: %x\n", data);

    ReadPgm(0);

    ReadEEProm();

    DoHex(Hex[0]);
    DoHex(Hex[1]);
//    verbose = 1;
    WritePgm(0, Hex[0]);
    WritePgm(0x20, Hex[1]);
//    verbose = 0;
    ReadPgm(0);
    ReadPgm(0x20);

    //WriteEEProm(Buffer);

    while (1)
    {
        _pinl(56);
        _waitms(1000);
        _pinh(56);
        _waitms(1000);
    }
}

/**
 * @brief Send data high byte first
 * @param cmd 
 * @return unsigned int 
 */
unsigned int SendIt(unsigned int cmd)
{
    int r;

    if (verbose)
        printf("S: %x\n", cmd);
    r = 0;
    for (int i=0;i<32;i++)
    {
        if ((cmd & 0x80000000) == 0)
            _pinl(MOSI);
        else
            _pinh(MOSI);
        _waitus(100);
        _pinh(SCK);
        _waitus(100);
        r = r << 1;
        r = r | _pinr(MISO);
        _pinl(SCK);
        _waitus(100);
        cmd = cmd << 1;
    }

    return r;
}

/**
 * @brief Put chip in program mode
 */
void Reset()
{
    _pinl(RESET);
    _waitms(50);
    _pinl(SCK);
    _pinh(RESET);
    _waitms(50);
    _pinl(RESET);
}

/**
 * @brief Enable Program Mode
 */
void PgmMode()
{
    unsigned int data;

    data = SendIt(PGMEN);
    if (data == 0x5300)
        return;
    printf("Error\n");
}

/**
 * @brief Read Signature bytes
 * @return signature bytes 
 */
unsigned int Signature()
{
    unsigned int data;
    unsigned int value;
    unsigned int j = RDSIGN;

    value = 0;
    for (int i=0;i<3;i++)
    {
        data = SendIt(j | (i << 8));
        value = (value << 8) | (data & 0xff);
    }

    return value;
}

unsigned char *ReadPgm(int addr)
{
    unsigned short instruction;
    int p;
    int v;

    for (int i=0;i<32;i++)
    {
        instruction = SendIt(RDPGM | (i+addr) << 8);
        instruction |= (SendIt(RDPGM | 0x08000000 | (i+addr) << 8)) << 8;
        Instr[i] = instruction;
        printf("Instruction:%4x: %x\n", i+addr, instruction);
    }
    return NULL;
}

void WritePgm(int addr, unsigned char *pgm)
{
    int p;
    int x;

    p = addr;
    for (int i=0;i<64;i++)
    {
        if ((i & 0x01) == 0)
            x = SendIt(LDPGM | (p << 8) | pgm[i]);
        else
            x = SendIt((LDPGM | 0x08000000 | (p++ << 8)) | pgm[i]);
    }
    p = addr & 0xffffffe0;
    SendIt(WRPGM | (p << 8));
    _waitms(10);
    while ((SendIt(RDYBSY) & 0x01) == 0x01)
        _waitms(4);
}

unsigned char *ReadEEProm()
{
    unsigned char data[16];

    printf("Data: ");
    for (int i=0;i<16;i++)
    {
        data[i] = SendIt(RDEEPRM | i << 8);
        printf("%x ", data[i]);
    }
    printf("\n");
    return NULL;
}

void WriteEEProm(unsigned char *data)
{

    for (int i=0;i<4;i++)
    {
        SendIt(WREEPRM | (i << 8) | data[i]);
        while ((SendIt(RDYBSY) & 0x01) == 0x01)
            _waitus(10);
    }
}

void Erase()
{
    SendIt(CHPERASE);
    while ((SendIt(RDYBSY) & 0x01) == 0x01)
        _waitms(5);
}

int DoHex(unsigned char *data)
{
    int i, j, h, l;

    j = 0;
    i = 0;
    while (data[i] != NULL)
    {
        h = data[i] - '0';
        l = data[i+1] - '0';
        if (h > 9)
            h = h - 7;
        if (l > 9)
            l = l - 7;
        data[j++] = h << 4 | l;
        i += 2;
    }
    return j;
}

Mike

Comments

  • iseriesiseries Posts: 1,496
    edited 2023-04-28 13:06

    Well, I had sum success but ran into issues with programming the ATTiny85. I could not get a program over 64 bytes to work. Just did strange things that I could not figure out.

    I finally went and built an Arduino ISP programmer and loaded the code. Then I used AVRDUDE to program the chip and it worked.

    Now I ran my program and found I was missing some data?

    Then it hit me. The ATTiny85 has 32 words of program and not 32 bytes. I was programming 32 bytes and reading back 32 bytes. All was good except half the program was missing.

    Updated my program and tested and it now works as described.

    I guess this was more of an excursion then I had planned. Cheap puzzle at that.

    Anyway I now can blink the LED.

    #include <stdio.h>
    #include <propeller.h>
    
    #define RESET 26
    #define MOSI  37
    #define MISO  38
    #define SCK   39
    #define PGMEN 0xAC530000
    #define CHPERASE 0xAC800000
    #define RDYBSY 0xF0000000
    #define LDEADD 0x4D000000
    #define LDPGM 0x40000000
    #define LDEEPRM 0xC1000000
    #define RDPGM 0x20000000
    #define RDEEPRM 0xA0000000
    #define RDSIGN 0x30000000
    #define RDFUSE 0x50000000
    #define RDCALB 0x38000000
    #define WRPGM 0x4C000000
    #define WREEPRM 0xC0000000
    #define WRFUSE 0xACA00000
    
    
    void PgmMode(void);
    unsigned int SendIt(unsigned int);
    void Reset(void);
    unsigned int Signature(void);
    unsigned char *ReadPgm(int);
    void WritePgm(int, unsigned char *);
    unsigned char *ReadEEProm(void);
    void WriteEEProm(unsigned char *);
    void Erase(void);
    int DoHex(unsigned char*);
    void Program(void);
    
    /* only write full lines and stop on short lines */
    char Hex[][65] = {"0EC01DC01CC01BC01AC019C018C017C016C015C014C013C012C011C010C01124", // 0
                      "1FBECFE5D2E0DEBFCDBF20E0A0E6B0E001C01D92A136B207E1F715D01FC0E0CF", // 10
                      "9C012115310509F4089500000000000000000000000000000000000000000000", // 20
                      "21503109EECFB89AB99AC19AB09A8FEF9FEFE6DF8FEF9FEFE3DFF8CFF894FFCF", // 30
                      "FF", // 40
                      "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // 50
                      "FF",
                      "FF"};
    unsigned char Buffer[256] = {0x21, 0x22, 0x23, 0x24};
    unsigned short Instr[256] = { 0x21, 0x22, 0x23, 0x24};
    int verbose;
    
    
    int main(int argc, char** argv)
    {
        unsigned int data;
        unsigned int addr;
        verbose = 0;
    
        data = 0;
    
        Reset();
    
        PgmMode();
    
        data = SendIt(RDFUSE);
        printf("Fuse: %X\n", data);
    
        /* run at 8Mhz instead of 1Mhz */
        //data = SendIt(WRFUSE | 0xE2);
        //printf("FuseW: %X\n", data);
    
        data = Signature();
    
        printf("Signature: %x\n", data);
    
        data = SendIt(RDCALB);
    
        printf("Calibration: %x\n", data);
    
        Erase();
    
    //    verbose = 1;
        Program();
    //    verbose = 0;
    
        for (int i=0;i<256;i+=32)
            ReadPgm(i);
    
        //WriteEEProm(Buffer);
    
        while (1)
        {
            _pinl(56);
            _waitms(1000);
            _pinh(56);
            _waitms(1000);
        }
    }
    
    /**
     * @brief Send data high byte first
     * @param cmd 
     * @return unsigned int 
     */
    unsigned int SendIt(unsigned int cmd)
    {
        int r;
    
        if (verbose)
            printf("S: %x\n", cmd);
        r = 0;
        for (int i=0;i<32;i++)
        {
            if ((cmd & 0x80000000) == 0)
                _pinl(MOSI);
            else
                _pinh(MOSI);
            _waitus(10);
            _pinh(SCK);
            _waitus(10);
            r = r << 1;
            r = r | _pinr(MISO);
            _pinl(SCK);
            _waitus(10);
            cmd = cmd << 1;
        }
    
        return r;
    }
    
    /**
     * @brief Put chip in program mode
     */
    void Reset()
    {
        _pinl(RESET);
        _waitms(50);
        _pinl(SCK);
        _pinh(RESET);
        _waitms(50);
        _pinl(RESET);
    }
    
    /**
     * @brief Enable Program Mode
     */
    void PgmMode()
    {
        unsigned int data;
    
        data = SendIt(PGMEN);
        if (data == 0x5300)
            return;
        printf("Error\n");
    }
    
    /**
     * @brief Read Signature bytes
     * @return signature bytes 
     */
    unsigned int Signature()
    {
        unsigned int data;
        unsigned int value;
        unsigned int j = RDSIGN;
    
        value = 0;
        for (int i=0;i<3;i++)
        {
            data = SendIt(j | (i << 8));
            value = (value << 8) | (data & 0xff);
        }
    
        return value;
    }
    
    unsigned char *ReadPgm(int addr)
    {
        unsigned char h, l;
        unsigned int v;
    
        for (int i=0;i<32;i++)
        {
            if ((addr & 0x0f) == 0)
                printf("\nInstruction: %4X-> ", addr);
            l = SendIt(RDPGM | addr << 8);
            h = SendIt(RDPGM | 0x08000000 | (addr << 8));
            addr++;
            v = (l << 8) | h;
            printf("%4X", v);
        }
        return NULL;
    }
    
    void WritePgm(int addr, unsigned char *pgm)
    {
        int p;
    
        p = 0;
        for (int i=0;i<32;i++)
        {
            SendIt(LDPGM | (i << 8) | pgm[p++]);
            SendIt((LDPGM | 0x08000000 | (i << 8)) | pgm[p++]);
        }
        p = addr & 0xffffffe0;
        SendIt(WRPGM | (p << 8));
        _waitms(10);
        while ((SendIt(RDYBSY) & 0x01) == 0x01)
            _waitms(4);
    }
    
    unsigned char *ReadEEProm()
    {
        unsigned char data[16];
    
        printf("Data: ");
        for (int i=0;i<16;i++)
        {
            data[i] = SendIt(RDEEPRM | i << 8);
            printf("%X ", data[i]);
        }
        printf("\n");
        return NULL;
    }
    
    void WriteEEProm(unsigned char *data)
    {
    
        for (int i=0;i<4;i++)
        {
            SendIt(WREEPRM | (i << 8) | data[i]);
            while ((SendIt(RDYBSY) & 0x01) == 0x01)
                _waitus(10);
        }
    }
    
    void Erase()
    {
        SendIt(CHPERASE);
        while ((SendIt(RDYBSY) & 0x01) == 0x01)
            _waitms(5);
    }
    
    int DoHex(unsigned char *data)
    {
        int i, j, h, l;
    
        j = 0;
        i = 0;
        while (data[i] != NULL)
        {
            h = data[i] - '0';
            l = data[i+1] - '0';
            if (h > 9)
                h = h - 7;
            if (l > 9)
                l = l - 7;
            data[j++] = h << 4 | l;
            i += 2;
        }
        return j;
    }
    
    void Program()
    {
        int i, j;
        i = 0;
        j = 0;
        while (strlen(Hex[i]) > 5)
        {
            DoHex(Hex[i]);
            memcpy(Buffer, Hex[i++], 32);
    
            DoHex(Hex[i]);
            memcpy(&Buffer[32], Hex[i++], 32);
    
            WritePgm(j, Buffer);
            j += 32;
        }
    }
    

    I really like those LED's I got from Adafruit. They are the ones that fad into different colors while they are turned on. They are also 3 volt so no resistance is needed to hook them up. And if the pin is pulsing they stay red so you know there is activity.

    Mike

  • In my advancement of programming the ATTiny85 I started to write more complex programs as I wanted to do serial in and serial out.

    This development get old using just a simple array to write the program code out. So I bit the bullet and converted the AVRISP program written for the Arduino to run on the P2. With this code I could use the AVRDUDE program that comes with the GNU compiler to load programs onto the ATTiny85.

    Even though the code is written in C all that is needed is to set the pins that you need to use for your programming environment and compile it with Flexprop. From there it is transparent to just send your Intel Hex file to the P2 using AVRDUDE.

    #include <stdio.h>
    #include <propeller.h>
    
    
    void fill(int);
    void pulse(int, int);
    void heartbeat(void);
    void empty_reply(void);
    void breply(unsigned char);
    void get_version(unsigned char);
    void set_parameters(void);
    void start_pmode(void);
    void end_pmode(void);
    void universal(void);
    void flash(int, unsigned int, unsigned char);
    void commit(unsigned int);
    unsigned int current_page(void);
    void write_flash(int);
    unsigned char write_flash_pages(int);
    unsigned char flash_read(unsigned, unsigned);
    unsigned char flash_read_page(int);
    unsigned char eeprom_read_page(int);
    unsigned char write_eeprom(unsigned int);
    unsigned char write_eeprom_chunk(unsigned int, unsigned int);
    void read_page(void);
    void read_signature(void);
    void program_page(void);
    unsigned int SPI(unsigned int);
    
    
    #define RESET 16
    #define MOSI  37
    #define MISO  38
    #define SCK   39
    #define LED   56
    #define LEDE  57
    #define LEDH  24
    
    #define HWVER 2
    #define SWMAJ 1
    #define SWMIN 18
    
    // STK Definitions
    #define STK_OK      0x10
    #define STK_FAILED  0x11
    #define STK_UNKNOWN 0x12
    #define STK_INSYNC  0x14
    #define STK_NOSYNC  0x15
    #define CRC_EOP     0x20 //ok it is a space...
    
    int error = 0;
    int pmode = 0;
    unsigned int here;
    unsigned char buff[256];
    int its = 0;
    
    
    typedef struct param
    {
        unsigned char devicecode;
        unsigned char revision;
        unsigned char progtype;
        unsigned char parmode;
        unsigned char polling;
        unsigned char selftimed;
        unsigned char lockbytes;
        unsigned char fusebytes;
        unsigned char flashpoll;
        unsigned short eeprompoll;
        unsigned short pagesize;
        unsigned short eepromsize;
        unsigned int flashsize;
    } parameter;
    
    parameter param;
    
    
    int main(int argc, char** argv)
    {
        _setbaud(19200);
    
        pulse(LED, 2);
        pulse(LEDE, 2);
        pulse(LEDH, 2);
    
        while (1)
        {
            if (pmode)
                _pinh(LED);
            else
                _pinl(LED);
            if (error)
                _pinh(LEDE);
            else
                _pinl(LEDE);
            heartbeat();
            avrisp();
        }
    }
    
    void heartbeat()
    {
        int i;
    
        i = _getms() - its;
        if (i > 512)
        {
            its = _getms();
            _pinnot(LEDH);
        }
    }
    
    void fill(int n)
    {
        for (int i=0;i<n;i++)
            buff[i] = _rxraw(0);
    }
    
    void pulse(int pin, int times)
    {
        for (int i=0;i<times;i++)
        {
            _pinh(pin);
            _waitms(30);
            _pinl(pin);
            _waitms(30);
        }
    }
    
    void empty_reply()
    {
        if (CRC_EOP == _rxraw(0))
        {
            _txraw(STK_INSYNC);
            _txraw(STK_OK);
        }
        else
        {
            error++;
            _txraw(STK_NOSYNC);
        }
    }
    
    void breply(unsigned char b)
    {
        if (CRC_EOP == _rxraw(0))
        {
            _txraw(STK_INSYNC);
            _txraw(b);
            _txraw(STK_OK);
        }
        else
        {
            error++;
            _txraw(STK_NOSYNC);
        }
    }
    
    void get_version(unsigned char c)
    {
        switch (c)
        {
        case 0x80:
            breply(HWVER);
            break;
        case 0x81:
            breply(SWMAJ);
            break;
        case 0x82:
            breply(SWMIN);
            break;
        case 0x93:
            breply('S');
            break;
        default:
            breply(0);
            break;
        }
    }
    
    void set_parameters()
    {
        param.devicecode = buff[0];
        param.revision   = buff[1];
        param.progtype   = buff[2];
        param.parmode    = buff[3];
        param.polling    = buff[4];
        param.selftimed  = buff[5];
        param.lockbytes  = buff[6];
        param.fusebytes  = buff[7];
        param.flashpoll  = buff[8];
        param.eeprompoll = (buff[10] << 8) | buff[11];
        param.pagesize   = (buff[12] << 8) | buff[13];
        param.eepromsize = (buff[14] << 8) | buff[15];
        param.flashsize  = (buff[16] << 24) | (buff[17] << 16) | (buff[18] << 8) | buff[19];
    }
    
    void start_pmode()
    {
        unsigned int i;
    
        _pinl(RESET);
        _waitms(20);
        _pinl(SCK);
        _waitms(20);
        _pinh(RESET);
        _waitus(100);
        _pinl(RESET);
        _waitms(50);
        i = SPI(0xAC530000);
        pmode = 1;
    }
    
    void end_pmode()
    {
        _dirl(MOSI);
        _dirl(MISO);
        _dirl(SCK);
        _pinh(RESET);
        _dirl(RESET);
        pmode = 0;
    }
    
    void universal()
    {
        unsigned int i;
        unsigned char ch;
    
        fill(4);
        i = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3];
        ch = SPI(i);
        breply(ch);
    }
    
    void commit(unsigned int addr)
    {
        unsigned int i;
    
        i = 0x4C000000 | (addr << 8);
        SPI(i);
    }
    
    unsigned int current_page()
    {
        if (param.pagesize == 32)
            return here & 0xfffffff0;
        if (param.pagesize == 64)
            return here & 0xffffffe0;
        if (param.pagesize == 128)
            return here & 0xffffffc0;
        if (param.pagesize == 256)
            return here & 0xffffff80;
        return here;
    }
    
    void write_flash(int len)
    {
        fill(len);
        if (CRC_EOP == _rxraw(0))
        {
            _txraw(STK_INSYNC);
            _txraw(write_flash_pages(len));
        }
        else
        {
            error++;
            _txraw(STK_NOSYNC);
        }
    }
    
    void flash(int hl, unsigned int addr, unsigned char data)
    {
        unsigned int i;
    
        i = 0x40000000;
        i = i | (hl << 27) | (addr << 8) | data;
        SPI(i);
    }
    
    unsigned char write_flash_pages(int len)
    {
        int x;
        unsigned int page;
    
        x = 0;
        page = current_page();
        while (x < len)
        {
            if (page != current_page())
            {
                commit(page);
                page = current_page();
            }
            flash(0, here, buff[x++]);
            flash(1, here, buff[x++]);
            here++;
        }
    
        commit(page);
    
        return STK_OK;    
    }
    
    unsigned char flash_read_page(int len)
    {
        unsigned char low, high;
    
        for (int i=0;i<len;i += 2)
        {
            low = flash_read(0, here);
            _txraw(low);
            high = flash_read(1, here);
            _txraw(high);
            here++;
        }
        return STK_OK;
    }
    
    unsigned char flash_read(unsigned int hilo, unsigned int addr)
    {
        unsigned int i;
    
        i = 0x20000000 | (hilo << 27) | (addr << 8);
        return SPI(i);
    }
    
    unsigned char eeprom_read_page(int len)
    {
        int start;
        int addr;
        unsigned char ee;
    
        start = here * 2;
        for (int i=0;i<len;i++)
        {
            addr = start + i;
            ee = SPI(0xA0000000 | (addr << 8) | 0xFF);
            _txraw(ee);
        }
        return STK_OK;
    }
    
    unsigned char write_eeprom(unsigned int len)
    {
        unsigned int start;
        unsigned int remaining;
    
        start = here * 2;
        remaining = len;
        if (len > param.eepromsize)
        {
            error++;
            return STK_FAILED;
        }
        while (remaining >> 32)
        {
            write_eeprom_chunk(start, 32);
            start += 32;
            remaining -= 32;
        }
        write_eeprom_chunk(start, remaining);
        return STK_OK;
    }
    
    unsigned char write_eeprom_chunk(unsigned int start, unsigned int len)
    {
        unsigned int addr;
    
        fill(len);
        for (unsigned int i=0;i<len;i++)
        {
            addr = start + i;
            SPI(0xC0000000 | (addr << 8) | buff[i]);
            _waitms(45);
        }
        return STK_OK;
    }
    
    void read_page()
    {
        unsigned char results;
        unsigned char t;
        unsigned int length;
    
        results = STK_NOSYNC;
        length = (_rxraw(0) << 8);
        length = length | _rxraw(0);
        t = _rxraw(0);
        if (CRC_EOP != _rxraw(0))
        {
            error++;
            _txraw(STK_NOSYNC);
            return;
        }
        _txraw(STK_INSYNC);
        if (t == 'E')
            results = eeprom_read_page(length);
        if (t == 'F')
            results = flash_read_page(length);
        _txraw(results);
    }
    
    void read_signature()
    {
        if (CRC_EOP != getchar())
        {
            error++;
            _txraw(STK_NOSYNC);
            return;
        }
        _txraw(STK_INSYNC);
    }
    
    void program_page()
    {
        char results;
        unsigned int length;
        char memtype;
    
        results = STK_FAILED;
        length = _rxraw(0) << 8;
        length |= _rxraw(0);
        memtype = _rxraw(0);
        if (memtype == 'F')
        {
            write_flash(length);
            return;
        }
        if (memtype == 'E')
        {
            results = write_eeprom(length);
            if (CRC_EOP == _rxraw(0))
            {
                _txraw(STK_INSYNC);
                _txraw(results);
            }
            else
            {
                error++;
                _txraw(STK_NOSYNC);
            }
            return;
        }
        _txraw(STK_FAILED);
    }
    
    unsigned int SPI(unsigned int cmd)
    {
        unsigned int r;
    
        r = 0;
        for (int i=0;i<32;i++)
        {
            if ((cmd & 0x80000000) == 0)
                _pinl(MOSI);
            else
                _pinh(MOSI);
            _waitus(10);
            _pinh(SCK);
            _waitus(10);
            r = r << 1;
            r = r | _pinr(MISO);
            _pinl(SCK);
            _waitus(10);
            cmd = cmd << 1;
        }
        return r;
    }
    
    void avrisp()
    {
        int ch;
    
        ch = _rxraw(1);
    
        switch (ch)
        {
        case -1 :
            break;
        case '0': // signon
            error = 0;
            empty_reply();
            break;
        case '1': 
            if (_rxraw(0) == CRC_EOP)
            {
                _txraw(STK_INSYNC);
                _txraw('A');
                _txraw('V');
                _txraw('R');
                _txraw(' ');
                _txraw('I');
                _txraw('S');
                _txraw('P');
                _txraw(STK_OK);
            }
            else
            {
                error++;
                _txraw(STK_NOSYNC);
            }
            break;
        case 'A':
            get_version(_rxraw(0));
            break;
        case 'B':
            fill(20);
            set_parameters();
            empty_reply();
            break;
        case 'E':
            fill(5);
            empty_reply();
            break;
        case 'P':
            if (!pmode)
                start_pmode();
            empty_reply();
            break;
        case 'U':
            here = _rxraw(0);
            here |= _rxraw(0) << 8;
            empty_reply();
            break;
        case 0x60:
            _rxraw(0);
            _rxraw(0);
            empty_reply();
            break;
        case 0x61:
            _rxraw(0);
            empty_reply();
            break;
        case 0x64:
            program_page();
            break;
        case 0x74:
            read_page();
            break;
        case 'V':
            universal();
            break;
        case 'Q':
            error = 0;
            end_pmode();
            empty_reply();
            break;
        case 0x75:
            read_signature();
            break;
        case CRC_EOP:
            error++;
            _txraw(STK_NOSYNC);
            break;
        default:
            error++;
            if (CRC_EOP == _rxraw(0))
                _txraw(STK_UNKNOWN);
            else
                _txraw(STK_NOSYNC);
            break;
        }
    }
    

    Since there are no special libraries require to run this program it just needs to be compiled.
    There are 3 LED's that are needed but not required but show the status of what is happening.

    define LED --> Turns on when in programming mode

    define LEDE ---> Turns on when there is an Error in serial data

    define LEDH ---> Heartbeat that flashes about every 1/2 second.

    The steps to build and load a program is as follows:

    avr-gcc -Os -mmcu=attiny85 -o <helloworld.binary> <helloworld>
    avr-objcopy -O ihex <helloworld.binary> <helloworld.hex>
    avrdude -c avrisp -P <com5> -b 19200 -p t85 -U flash:w:<helloworld.hex>:i
    

    The output should look like this:

    avrdude.exe: AVR device initialized and ready to accept instructions
    
    Reading | ################################################## | 100% 0.05s
    
    avrdude.exe: Device signature = 0x1e930b (probably t85)
    avrdude.exe: NOTE: "flash" memory has been specified, an erase cycle will be performed
                 To disable this feature, specify the -D option.
    avrdude.exe: erasing chip
    avrdude.exe: reading input file "D:\Documents\ATTiny85/build/Uart.hex"
    avrdude.exe: writing flash (510 bytes):
    
    Writing | ################################################## | 100% 1.02s
    
    avrdude.exe: 510 bytes of flash written
    avrdude.exe: verifying flash memory against D:\Documents\ATTiny85/build/Uart.hex:
    
    Reading | ################################################## | 100% 0.76s
    
    avrdude.exe: 510 bytes of flash verified
    
    avrdude.exe done.  Thank you.
    

    Mike

  • Interesting idea. This could be useful for repeat programming where you have to program a lot of devices, perhaps with a serial number increment on each one

Sign In or Register to comment.