[Description]
Location = "Atmel\AVR\ATTiny13";
Info = " Module for programming AVR microcontrollers via SPI interface.",
    " Chip: ATTiny13. Manufacturer: Atmel",
    " ------------------------------------------------------------------------",
    " Bus: SPI.",
    " FLASH size: 2048 bytes (1024 words).",
    " EEPROM size: 128 bytes",
    "---------------------------------------------",
    " Author: ETL (c) 2005";
Buffer1 = "FLASH",1024;
Buffer2 = "EEPROM",64;
View1   = 16;
Picture = "ATTiny15.BMP";
VCC     = 8;
GND     = 4;
Voltage = 5.0;

[Menu]

ReadSignature   = "Read signature bytes",ChipInfoButton,"Read signature bytes",Ctrl+F1;
Div0            = "-";
Read            = "Read",ReadButton,"Read",F2;
Compare         = "Verify",CheckButton,"Verify",F3;
Div1            = "-";
Write           = "Write",WriteButton,"Write",F5;
Erase           = "Erase chip",EraseButton,"Erase chip",F9;
Div2            = "-";
ReadLock        = "Read lock bits";
WriteLock       = "Write lock bits";
Div4            = "-";
ReadFuses       = "Read fuse bits";
WriteFuses      = "Write fuse bits";
Div5            = "-";
ModuleInfo      = "About module",ModuleInfoButton,"About module",F1;

[Interface Window]

CheckBox(EraseBeforeWrite,"Erase before write",100,5,1);
CheckBox(VerifyDuringWrite,"Verify during write",240,5,1);
ComboBox(LockMode,"Lock mode",46,40,285,"Not memory lock features",
         "Further programming is disabled",
         "Further programming and verification is disabled",0);
ComboBox(SelfProg,"Self programming",18,80,70,"Enabled","Disabled",1);
ComboBox(DebugWire,"debug WIRE",37,110,70,"Enabled","Disabled",1);
ComboBox(SUT,"Startup time",77,140,180,"Fast (BOD enabled)",
                                      "Medium (Fast rising power)",
                                      "Slow (Slowly rising power)",2);

ComboBox(EESAVE,"EEPROM memory through the Chip Erase is",35,170,143,
                "preserved","not preserved",1);
ComboBox(WDTON,"Watchdog Timer",162,200,143,"Always ON","Controlled by WDTCSR",1);
ComboBox(BODLVL,"Brown-out Detector trigger level",92,230,143,
                "Disabled","1.8 V","2.7 V","4.3 V",0);
ComboBox(RSTDISBL,"External reset",250,80,70,"Disabled","Enabled",1);
ComboBox(CKDIV8,"Divide clock by 8",232,110,70,"On","Off",0);
ComboBox(CLCK,"Clock source",25,260,300,
              "00 - External clock",
              "01 - Calibrated Internal RC Oscillator 4.8 MHz",
              "10 - Calibrated Internal RC Oscillator 9.6 MHz",
              "11 - 128kHz  Internal RC Oscillator",2);

Button(WriteFuses,"Write fuses",130,290,100,20);                         
Button(ReadFuses,"Read fuses",235,290,100,20);                         

[Host]

define      FLASH_END   512
define      EEPROM_END  64
define      SIGN        0x9007
define      PAGE_SIZE   16

//***********************************************************************
//*             ReadSignature                                          **
//***********************************************************************
Proc ReadSignature {

    var B1,B2,B3,Signature;
    print("");
    print("   Reading signature bytes...");
    Run(ReadSignature);
    B1 = USB;
    if(B1 != 0x53)
    {
        print("   Error: chip not response.");
        return;
    }
    B1 = USB;
    B2 = USB;
    B3 = USB;
    print("");
    print("   Next signature bytes were readed: %b %b %b",B1,B2,B3);
    Signature = B2 << 8;
    Signature = Signature | B3;
    if(B1 = 0)
    {
      if(Signature = 0x0102) {
        print("   Unknown device or locked device.");
        print("");
        print("   Note: The Lock Bits can only be erased with the Chip Erase operation.");
        return(0);
      }
    }
    if(B1 = 0x1E)
    {
        print("    Manufacturer: Atmel");
    }
    else
    {
        print("    Unknown manufacturer");
    }
    if(Signature = SIGN)
    {
        print("    Device: ATTiny13");
    }
    else
    {
        print("    Device is not ATTiny13. Use AVR detector for identification.");
    }
}

Proc Read
{
    var Address,Temp,FlashEnd;
    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    Temp = USB;Temp = USB;Temp = USB;
    if(ActiveBuffer = 0)
    {
        print("");
        print("   Reading FLASH...");
        Address = 0;
        Run(ReadFlash);
        FlashEnd = FLASH_END << 1;PBMax = FlashEnd;
        while(Address != FlashEnd)
        {
            Temp = USB;
            if(Temp = 0x8000) { break; }
            FBUF[Address] = Temp;
            Address++;PBPos++;
        }
        Address = Address >> 1;
        print("");
        if(Temp = 0x8000)
        {
            print("   Reading error. Time out. Address %i.",Address);
        }
        else
        {
            if(ForceCloseAfterRead != 0) { return(0x7FFFFFFF);}
            print("   Reading is done. %i word were readed.",Address);
        }
    }
    else
    {
        print("");
        print("   Reading EEPROM...");
        Address = 0;
        Run(ReadEEPROM);
        PBMax = EEPROM_END;
        while(Address != EEPROM_END)
        {
            Temp = USB;
            if(Temp = 0x8000) { break; }
            EBUF[Address] = Temp;
            Address++;PBPos++;
        }
        print("");
        if(Temp = 0x8000)
        {
            print("   Reading error. Time out. Address %i.",Address);
        }
        else
        {
            if(ForceCloseAfterRead != 0) { return(0x7FFFFFFF);}
            print("   Reading is done. %i bytes were readed.",Address);
        }
    }
}

Proc Write
{
    var Address,Temp,Temp2,Counter,Error,Back,WritedWord;

    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    Temp = USB;Temp = USB;Temp = USB;

    if(ActiveBuffer = 1)
    {
        // write eeprom
        Temp = WriteEEPROM();
    }
    else
    {
        // write FLASH

        if(EraseBeforeWrite = 1)
        {
            print("");
            print("   Erasing chip...");
            Run(ChipErase);
            Temp = USB;
            if(Temp = 0x8000)
            {
                print("");
                print("   Erasing error. Time out.");
                return;
            }
        }
        print("");
        if(VerifyDuringWrite = 0)
        {
            print("   Writing FLASH...");
        }
        else
        {
            print("   Writing and verifying FLASH...");
        }
        Address = 0;Counter = 0;PBPos = 0;PBMax = FLASH_END;WritedWord = 0;
        while(Counter != FLASH_END)
        {
            Temp = EmptyPage(Address);
            if(Temp != 0)
            {
                Run(WriteFlashPage);
                Temp2 = PAGE_SIZE;
                BeginBlock;
                while(Temp2 != 0)
                {
                    Temp = FBUF[Address];USB = Temp;Address++;
                    Temp = FBUF[Address];USB = Temp;Address++;
                    Temp2--;
                }
                EndBlock;
                Temp = Counter >> 8; USB = Temp; USB = Counter;
                Temp = USB;
                if(VerifyDuringWrite != 0)
                {
                    Error = 0;
                    USB = 1;
                    Temp2 = PAGE_SIZE;
                    Address = Counter * 2;
                    while(Temp2 != 0)
                    {
                        Back = USB;
                        Temp = FBUF[Address];Address++;
                        if(Temp != Back) 
                        {
                            if(Error = 0) { Error = Address; }
                        }
                        Back = USB;
                        Temp = FBUF[Address];Address++;
                        if(Temp != Back) 
                        {
                            if(Error = 0) { Error = Address; }
                        }
                        Temp2--;
                    }
                    WritedWord = WritedWord + PAGE_SIZE;
                }
                else { USB = 0;}
            }
            if(Error != 0) { break;}
            Counter = Counter + PAGE_SIZE;
            Address = Counter * 2;
            PBPos = Counter;
        }

        if(Error != 0)
        {
            Error--;
            print("");
            print("   Writing error. Address: %i",Error);
        }
        else
        {
            if(ForceCloseAfterWrite != 0) { return(0x7FFFFFFF); }
            print("");
            print("   Writing success. %i words were writed.",WritedWord);
        }
    }
}

Proc EmptyPage(Address)
{
    var Result,Counter,Temp;
    Result = 0;
    Counter = PAGE_SIZE;
    while(Counter != 0)
    {
        Temp = FBUF[Address];
        if(Temp != 255) { Result = 1;}
        Counter--;
        Address++;    
    }
    return(Result);
}

Proc WriteEEPROM
{
    var Address,Temp;
    print("");print("   Writing EEPROM...");
    Address = 0;PBMax = EEPROM_END;
    Run(WriteEEPROM);
    while(Address != EEPROM_END)
    {
        Temp = EBUF[Address];
        USB = Temp;Temp = USB;if(Temp = 0x8000) { break; }
        Address++;PBPos++;
    }
    return(Temp);
}

Proc Compare
{
    var Address,Temp,FlashEnd,Byte,Mismatch;
    print("");
    print("   Verifying FLASH...");
    Address = 0;
    Run(ReadFlash);
    FlashEnd = FLASH_END << 1;
    PBMax = FlashEnd;
    Mismatch = 0;
    while(Address != FlashEnd)
    {
        Temp = USB;
        if(Temp = 0x8000) { break; }
        Byte = FBUF[Address];
        if(Byte != Temp)
        {
            FSEL[Address] = 0;
            Mismatch++;    
        }
        else
        {
            FSEL[Address] = 1;
        }
        Address++;
        PBPos++;
    }
    Address = Address >> 1;
    print("");
    if(Temp = 0x8000)
    {
        print("   Verifying error. Time out. Address %i.",Address);
    }
    else
    {
        if(ForceCloseAfterVerify != 0) { return(0x7FFFFFFF);}
        print("   Verifying is done. %i word were compared. Number of mismatch %i",Address,Mismatch);
    }
}


Proc Erase
{
    var Temp,Temp2;
    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    print("");
    Temp = USB;Temp = USB;Temp = USB;
    print("   Erasing...");
    Run(ChipErase);
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("");
        print("   Erasing error. Time out.");    
    }
    else
    {
        print("");
        print("   Erasing success.");
    }
}

Proc WriteLock
{
    var Temp,Temp2;
    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    print("");
    Temp = USB;Temp = USB;Temp = USB;

    print("");
    if(LockMode = 0)
    {
        print("   Lock mode not set. Writing lock bits canceled.");
        return;
    }
    if(LockMode = 0) { Temp = 3;}
    if(LockMode = 1) { Temp = 2;}
    if(LockMode = 2) { Temp = 0;}
    
    Temp = Temp | 0xFC;
    print("Temp = ");PrintBin(Temp);
    print("   Writing lock bits...");
    Run(WriteLock);
    USB = Temp;
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("   Writing error. Time out."); 
    }
    else
    {
        if(ForceCloseAfterWrite != 0) { return(0x7FFFFFFF);}
        print("\; success.");
    }
}

Proc ReadFuses
{
    var Temp,Temp2;
    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    Temp = USB;Temp = USB;Temp = USB;
    Run(ReadFuses);
    Temp = USB;
    print("   Fuse bits: ");PrintBin(Temp);
    print("         Self Programming: ");
    if(Temp.4 = 0) { print("\; 0 (Enable)");}
    else {print("\; 1 (Disable)");}
    print("         debugWire: ");
    if(Temp.3 = 0) { print("\; 0 (Enable)");}
    else {print("\; 1 (Disable)");}
    print("         Brown-out Detector trigger level: ");
    Temp2 = Temp >> 1;Temp2 = Temp2 & 3;
    if(Temp2 = 0) { print("\;4.3 V");}
    if(Temp2 = 1) { print("\;2.7 V");}
    if(Temp2 = 2) { print("\;1.8 V");}
    if(Temp2 = 3) { print("\;Brown-out disabled");}
    print("         External reset: ");
    if(Temp.0 = 1) { print("\;Enabled");}
    else { print("\;Disabled");}

    print("");
    Temp = USB;
    print("   Fuse High bits: ");PrintBin(Temp);
    print("         Serial downloading: ");
    if(Temp.7 = 0) { print("\; 0 (Enabled)");}
    else {print("\; 1 (Disabled)");}
    print("         EEPROM memory is preserved through the Chip Erase: ");
    if(Temp.6 = 0) { print("\; 0 (ON)");}
    else {print("\; 1 (OFF)");}
    print("         Watchdog Timer always on: ");
    if(Temp.5 = 0) { print("\; 0 (ON)");}
    else {print("\; 1 (OFF)");}
    print("         Divide clock by 8: ");
    if(Temp.4 = 0) { print("\; 0 (ON)");}
    else {print("\; 1 (OFF)");}

    print("         Start-up time: ");
    Temp2 = Temp >> 2;
    Temp2 = Temp2 & 3;

    if(Temp2 = 0) { print("\;Fast (BOD enabled)");}
    if(Temp2 = 1) { print("\;");}
    if(Temp2 = 2) { print("\;Slow (Slowly rising power)");}
    if(Temp2 = 3) { print("\;Reserved value");}

    Temp2 = Temp & 3;
    print("         Clock source: ");
    if(Temp2 = 0) { print("\;External clock");}
    if(Temp2 = 1) { print("\;Internal RC oscillator 4.8 MHz");}
    if(Temp2 = 2) { print("\;Internal RC oscillator 9.6 MHz");}
    if(Temp2 = 3) { print("\;128 KHz internal RC oscillator");}
  }

Proc PrintBin(Value)
{
    var Counter;
    Counter = 8;
    while(Counter != 0)
    {
        if(Value.7 = 0) { print("\;0");}
        else { print("\;1"); }
        Value = Value << 1;
        Counter--;
    }
}

Proc WriteFuses
{
    var Temp,Temp2;
    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    Temp = USB;Temp = USB;Temp = USB;
    print("   Writing fuses...");
    Run(WriteFuses);
    Temp = 0;
    Temp.6 = EESAVE.0;
    Temp.5 = WDTON.0;
    Temp.4 = CKDIV8.0;
    Temp2 = SUT << 2;
    Temp = Temp | Temp2;
    Temp = Temp | CLCK;
    
    print(" Fuses: ");PrintBin(Temp); 

    USB = Temp;
    Temp = 0xE0;
    Temp.4 = SelfProg.0;
    Temp.3 = DebugWire.0;
    Temp2 = BODLVL << 1;
    Temp2 = Temp2 ^ 0x06;
    Temp = Temp | Temp2;
    Temp.0 = RSTDISBL.0;

    print(" High Fuses: ");PrintBin(Temp); 
    USB = Temp;
    Temp = USB;
    if(Temp != 0)
    {
        print("Writing error. Time-out.");
    }
    else
    {
        if(ForceCloseAfterWrite != 0) { return(0x7FFFFFFF);}
        print("\; Success.");
    }
}

Proc ReadLock
{
    var Temp,Temp2;
    Run(ReadSignature);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("");
        print("   Error: chip not response.");
        return;
    }
    Temp = USB;Temp = USB;Temp = USB;
    print("");
    print("   Read lock...");
    Run(ReadLock);
    Temp = USB;
    if(Temp != 0x8000)
    {
        Temp = Temp & 0x03;
        print("   Lock bits: ");PrintBin(Temp);
        if(Temp = 3) { print("\;   ( No memory lock features enabled. )");}
        if(Temp = 2) 
        { 
            print("   Further programming of the Flash and EEPROM is disabled");
        }
        if(Temp = 0) 
        { 
            print("   Further programming and verification of the Flash and EEPROM is disabled");
        }
    }
}

Proc ModuleInfo {

    print("");
    print("    ***********************************************");
    print("    Module for programming a chip ATTiny2313.");
    print("    Low-voltage programming via SPI interface");
    print("    ***********************************************");
    print("    Author: ETL (c) 2007");
}



[Device]

define      RESET       POUT.0
define      SCK         POUT.6
define      MISO_OUT    POUT.5
define      MISO        PIN.5
define      MOSI        POUT.4

define      FLASH_END   512
define      EEPROM_END  64

define      PROG_ENABLE                 0b1010110001010011
define      READ_DEVICE_CODE            0b0011000000000000
define      READ_PROGRAM_MEMORY         0b0010000000000000
define      WRITE_PROGRAM_MEMORY_PAGE   0b0100110000000000
define      LOAD_PROGRAM_MEMORY_PAGE    0b0100000000000000
define      READ_EEPROM_MEMORY          0b1010000000000000
define      WRITE_EEPROM_MEMORY         0b1100000000000000
define      CHIP_ERASE                  0b1010110010000000
define      WRITE_LOCK_BITS             0b1010110011100000
define      READ_LOCK_BITS              0b0101100000000000

define      READ_FUSE_BITS              0b0101000000000000
define      READ_FUSE_HIGH_BITS         0b0101100000001000

define      WRITE_FUSE_BITS             0b1010110010100000
define      WRITE_FUSE_HIGH_BITS        0b1010110010101000

define      PAGE_SIZE                   16


var Counter,Address,InstructionW,InstructionB,SPIWord,Byte,Echo,
    InitCounter,VerifyDuringWrite, Temp, ReadedWord;

Proc ReadSignature
{
    InitSPI;
    if(Echo != 0x53)
    {
        USB = 0xFF;
        return;
    }
    USB = Echo;
    InstructionW = READ_DEVICE_CODE;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;
    InstructionB++;
    InstructionIn;
    USB = SPIWord;
    InstructionB++;
    InstructionIn;
    USB = SPIWord;
}

Proc ReadFlash
{
    InitSPI;
    Address = 0;
    while(Address != FLASH_END)
    {
        InstructionW = READ_PROGRAM_MEMORY;
        InstructionW.0 = Address.8;
        InstructionW.1 = Address.9;
        InstructionB = Address;
        InstructionIn;
        USB = SPIWord;
        InstructionW.11 = 1;
        InstructionIn;
        USB = SPIWord;
        Address++;
    }
}

Proc WriteFlashPage
{
    Address = 0;
    InstructionW = LOAD_PROGRAM_MEMORY_PAGE;
    Temp = 0;

    // ------------  load FLASH page into buffer

    while(Address != PAGE_SIZE)
    {
        InstructionW.11 = 0;    // low byte
        Byte = USB;
        Byte = Byte | Temp;
        InstructionB = Byte;
        InstructionOut;
        InstructionW.11 = 1;    // high byte
        Byte = USB;
        Byte = Byte | Temp;
        InstructionB = Byte;
        InstructionOut;
        Temp = Temp + 256;
        Address++;
    }
    // get from host page address and program page
    Temp = USB;
    Address = Temp << 8;
    InstructionW = WRITE_PROGRAM_MEMORY_PAGE | Temp;
    InstructionB = USB;
    Address = Address | InstructionB;
    InstructionB = InstructionB << 8;
    InstructionOut;
    Delay(6000);
    USB = 0;
    Temp = USB;
    if(Temp != 0)
    {
        // ---- Read back page for verify
        Temp = PAGE_SIZE;
        while(Temp != 0)
        {
            InstructionW = READ_PROGRAM_MEMORY;
            InstructionW.0 = Address.8;
            InstructionW.1 = Address.9;
            InstructionB = Address;
            InstructionIn;
            USB = SPIWord;
            InstructionW.11 = 1;
            InstructionIn;
            USB = SPIWord;
            Address++;
            Temp--;
        }
    }
}

Proc ReadEEPROM
{
//    InitSPI;
    Address = 0;
    while(Address != EEPROM_END)
    {
        InstructionW = READ_EEPROM_MEMORY;
        InstructionB = Address;
        InstructionIn;
        USB = SPIWord;
        Address++;
    }
}

Proc WriteEEPROM
{
//    InitSPI;
    Address = 0;
    while(Address != EEPROM_END)
    {
        InstructionW = WRITE_EEPROM_MEMORY;
        InstructionB = Address << 8;
        Byte = USB;
        InstructionB = InstructionB | Byte;
        InstructionOut;
        Delay(6000);
        USB = 0;
        Address++;
    }
}

Proc ChipErase
{
    //InitSPI;
    InstructionW = CHIP_ERASE;
    InstructionB = 0xFFFF;
    InstructionOut;
    Delay(30000);
    USB = 0;
}

Proc WriteLock
{
    InstructionW = WRITE_LOCK_BITS;
    InstructionB = USB;
    InstructionOut;
    Delay(25000);
    USB = 0;
}

Proc SendWordToSPI
{
    Counter = 16;
    while(Counter != 0)
    {
        MOSI = SPIWord.15;
        SCK = 0; SCK = 1;
        SPIWord = SPIWord << 1;
        Counter--;    
    }
    SCK = 0;
}

Proc SendByteToSPI
{
    Counter = 8;
    while(Counter != 0)
    {
        MOSI = SPIWord.7;
        SCK = 0; SCK = 1;
        SPIWord = SPIWord << 1;
        Counter--;    
    }
    SCK = 0;
}

Proc GetByteFromSPI
{
    Counter = 8;
    while(Counter != 0)
    {
        SPIWord = SPIWord << 1;
        SCK = 0;
        SPIWord.0 = MISO;
        SCK = 1;
        Counter--;    
    }
}

Proc InitSPI
{
    POUT = 0b00100000;
    Delay(10000);
    RESET = 1;RESET = 0;
    Delay(21000);
    InitCounter = 33;
    while
    {
        SPIWord = PROG_ENABLE;SendWordToSPI;

        // check echo
        SPIWord = 0;
        GetByteFromSPI;
        Echo = SPIWord;
        SPIWord = 0xFF;
        SendByteToSPI;
        if(Echo = 0x53) { break; }
        SCK = 0;SCK = 1; SCK = 0;
        InitCounter--;
        if(InitCounter = 0) { break; }
    }
    SCK = 0;
}

Proc InstructionIn
{
    SPIWord = InstructionW; SendWordToSPI;
    SPIWord = InstructionB; SendByteToSPI;
    GetByteFromSPI;
}

Proc InstructionOUT
{
    SPIWord = InstructionW; SendWordToSPI;
    SPIWord = InstructionB; SendWordToSPI;
}

Proc ReadFuses
{
    InstructionW = READ_FUSE_HIGH_BITS;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;
    InstructionW = READ_FUSE_BITS;
    InstructionIn;
    USB = SPIWord;
}

Proc WriteFuses
{
    InstructionW = WRITE_FUSE_BITS;
    InstructionB = USB;
    InstructionOut;
    Delay(10000);
    InstructionW = WRITE_FUSE_HIGH_BITS;
    InstructionB = USB;
    InstructionOut;
    Delay(10000);
    USB = 0;
}

Proc ReadLock
{
    InstructionW = READ_LOCK_BITS;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;    
}
