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

[Menu]

ReadSignature = "Read signature bytes",ChipInfoButton,"Read signature bytes",F1;
Div1 = "-";
ReadFlash = "Read FLASH",ReadButton,"Read FLASH",F2;
WriteFlash = "Write FLASH",WriteButton,"Write FLASH",F3;
Compare = "Verify FLASH",CheckButton,"Verify FLASH",F4;
Div2 = "-";
Erase = "Erase FLASH and EEPROM",EraseButton,"Erase FLASH and EEPROM",Ctrl+E;
Div3 = "-";
ReadEEPROM = "Read EEPROM",ReadEEPROMButton,"Read EEPROM",Ctrl+F2;
WriteEEPROM = "Write EEPROM",WriteEEPROMButton,"Write EEPROM",Ctrl+F3;
Div4 = "-";
ReadLock = "Read lock bits";
WriteLock = "Write lock bits";
Div5 = "-";
ReadFuse = "Read Fuse bits";
WriteFuse = "Write Fuse bits";
Div6 = "-";
ReadCalibrationByte = "Read calibration byte";
Div7 = "-";
ModuleInfo = "About module",ModuleInfoButton,"About module",F10;

[Interface window]

CheckBox(EraseBeforeWrite,"Erase before write",100,10,1);
CheckBox(VerifyDuringWrite,"Verify during write",230,10,1);
ComboBox(LockMode,"Lock mode",140,50,90,"Not lock","LB1=0,LB2=1","LB2=0,LB1=0",0);
ComboBox(EESave,"EEPROM preserve",25,90,90,"Not erase","Erase",1);
ComboBox(BODEN,"Brown-out Detector",23,115,90,"Enabled","Disabled",1);
ComboBox(BODLEVEL,"Brown-out voltage",29,140,90,"4 V","2.7 V",0);
ComboBox(PLLCK,"PLL for internal clock",230,90,110,"Use","Not use",1);
ComboBox(CKOPT,"CKOPT",294,115,110,"0","1",1);
ComboBox(SUT,"SUT",308,140,110,"SUT1=0,SUT0=0","SUT1=1,SUT0=0","SUT1=0,SUT0=1","SUT1=1,SUT0=1",1);
ComboBox(CKSEL,"CKSEL",70,170,300,"0000 - External clock",
                                  "0001 - Internal RC oscillator 1 MHz",
                                  "0010 - Internal RC oscillator 2 MHz",
                                  "0011 - Internal RC oscillator 4 MHz",
                                  "0100 - Internal RC oscillator 8 MHz",
                                  "0101 - External RC oscillator 0.1-0.9 MHz",
                                  "0110 - External RC oscillator 0.9-3.0 MHz",
                                  "0111 - External RC oscillator 3.0-8.0 MHz",
                                  "1000 - External RC oscillator 8.0-12.0 MHz",
                                  "1001 - External low-frequency crystal",
                                  "1010 - External crystal/ceramic resonator",
                                  "1011 - External crystal/ceramic resonator",
                                  "1100 - External crystal/ceramic resonator",
                                  "1101 - External crystal/ceramic resonator",
                                  "1110 - External crystal/ceramic resonator",
                                  "1111 - External crystal/ceramic resonator",1);

[Host]

define      FLASH_END       2048
define      EEPROM_END      128
define      SIGN            0x9109
define      FLASH_PAGE_SIZE 32

//***********************************************************************
//*             ReadSignature                                          **
//***********************************************************************
Proc ReadSignature
{
    var B1,B2,B3;
    print("");
    print("   Read signature");
    Run(InitSPI);
    B1 = USB;
    if(B1 != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Run(ReadSignature);
    B1 = USB;
    B2 = USB;
    B3 = USB;
    print("   Next signature bytes were readed: %b %b %b",B1,B2,B3);
    print("");
    if(B1 = 0x1e)
    {
        print("    Manufacturer: Atmel");
    }     
    else
    {
        print("    Unknown manufacturer");
    }
    B2 = B2 << 8;
    B2 = B2 | B3;
    if(B2 = SIGN)
    {
        print("    Device: ATTiny26");
    }
    else
    {
        print("    Device is not ATTiny26. Use AVR detector for identification.");        
    }
}

Proc ReadFlash
{
    var Address,Temp;
    print("");
    print("   Reading FLASH...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Address = 0;
    Run(ReadFlash);
    PBMax = FLASH_END;
    while(Address != FLASH_END)
    {
        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);
    }
}

Proc WriteFlash
{
    var Address,Temp,PageAddress,Counter,EmptyPage,WritedWords,Error,Temp2;

    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    if(EraseBeforeWrite = 1)
    {
        print("");
        print("   Erasing chip...");
        Run(ChipErase);
        Temp = USB;
        if(Temp = 0x8000)
        {
            print("");
            print("   Erasing error. Time out.");
            return;
        }
    }
    print("\; Success");
    print("");
    print("   Writing FLASH...");
    Address = 0;
    Run(WriteFlash);
    USB = VerifyDuringWrite;
    PBMax = FLASH_END;
    PageAddress = 0;
    while(PageAddress != FLASH_END)
    {
        // if all cells in a page are 0xFF, not program this page

        Counter = FLASH_PAGE_SIZE;
        EmptyPage = 0;
        Address = PageAddress;
        while(Counter != 0)
        {
            Temp = FBUF[Address];
            if(Temp != 0xFF) { EmptyPage = 1;}
            Address++;
            Counter--;
        } 
        if(EmptyPage != 0)
        {
            WritedWords = WritedWords + FLASH_PAGE_SIZE;
            USB = 1;        // next page

            // load page

            Counter = FLASH_PAGE_SIZE;
            Address = PageAddress;
            BeginBlock;
            while(Counter != 0)
            {
                Temp = FBUF[Address];
                USB = Temp;
                Address++;
                Counter--;
            } 
            EndBlock;

            // send to ETSmart page address
            Temp = PageAddress >> 9;USB = Temp;   // high byte
            Temp = PageAddress >> 1;USB = Temp;   // low byte

            Error = USB;
            if(Error = 0x8000) { break; }
            if(VerifyDuringWrite != 0)
            {
                // read back and verify page
                Address = PageAddress;
                Error = 0x00;
                Counter = FLASH_PAGE_SIZE;
                while(Counter != 0)
                {
                    Temp = USB;
                    Temp2 = FBUF[Address];
                    if(Temp != Temp2)
                    {
                        if(Error = 0x00) { Error = Address + 1; }
                    }
                    Counter--;
                    Address++;
                }
                if(Error != 0) { break; }
            }
        }
        PageAddress = PageAddress + FLASH_PAGE_SIZE;
        PBPos = PageAddress;     
    }
    USB = 0;  // Finish writing      
    if(Error = 0x8000)
    {
        print("");
        print("   Writing error. Time out. Address: %i",Address);
    }
    else
    {
        if(Error != 0)
        {
            Error--;
            print("");
            print("   Writing error. Address: %i",PageAddress);            
        }
        else
        {
            print("");
            print("   Writing success. %i bytes were writed.",WritedWords);
        }
    }
}

Proc Compare
{
    var Address,Temp,Byte,Mismatch;
    print("");
    print("   Verifying FLASH...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Address = 0;
    Run(ReadFlash);
    PBMax = FLASH_END;
    Mismatch = 0;
    while(Address != FLASH_END)
    {
        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
    {
        print("   Verifying is done. %i word were compared. Number of mismatch %i",Address,Mismatch);
    }
}

Proc ReadEEPROM
{
    var Address,Temp;
    print("");
    print("   Reading EEPROM...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    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
    {
        print("   Reading is done. %i bytes were readed.",Address);
    }
}

Proc WriteEEPROM
{
    var Address,Temp;
    print("");
    print("   Writing EEPROM...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Address = 0;
    Run(WriteEEPROM);
    PBMax = EEPROM_END;
    while(Address != EEPROM_END)
    {
        Temp = EBUF[Address];
        USB = Temp;
        Temp = USB;
        if(Temp = 0x8000) { break; }
        Address++;
        PBPos++;
    }
    print("");
    if(Temp = 0x8000)
    {
        print("   Writing error. Time out. Address %i.",Address);
    }
    else
    {
        print("   Writing is done. %i bytes were writed.",Address);
    }
}

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

Proc ReadCalibrationByte
{
    var Temp;
    print("   Reading calibration byte...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Run(ReadCalibrationByte);
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("");
        print("   Reading error. Time out."); 
    }
    else
    {
        print("");
        print("   Success. Value of calibration byte: %b (HEX), %i (DEC).",Temp,Temp);
    }
}

Proc ReadLock
{
    var Temp;
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    print("   Reading lock bits...");
    Run(ReadLock);
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("");
        print("   Reading error. Time out."); 
    }
    else
    {
        print("");
        print("   Lock bit 1 = ");
        if(Temp.0 = 0) { print("\;0 (programmed)"); }
        else { print("\;1 (unprogrammed)"); }
        print("   Lock bit 2 = ");
        if(Temp.1 = 0) { print("\;0 (programmed)"); }
        else { print("\;1 (unprogrammed)"); }
    }
}

Proc ReadFuse
{
    var Temp,FuseH;
    print("   Reading FUSE bits...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Run(ReadFuse);
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("");
        print("   Reading error. Time out."); 
        return;
    }
    FuseH = USB;
    if(FuseH = 0x8000)
    {
        print("");
        print("   Reading error. Time out."); 
        return;
    }
    print("");
    print("   Success. Next fuse bits were readed: %b %b",Temp,FuseH);
    print("");
    print("   PLLCK         = ");
    if(Temp.7 = 0) { print("\;0 (PLL clock enabled)"); }
    else { print("\;1 (PLL clock disabled)"); }
    print("   CKOPT        = ");
    if(Temp.6 = 0) { print("\;0 (Oscillator capacitors enabled)"); }
    else { print("\;1 (Oscillator capacitors disabled)"); }
    print("   SUT1           = ");
    if(Temp.5 = 0) { print("\;0"); }
    else { print("\;1"); }
    print("   SUT0           = ");
    if(Temp.4 = 0) { print("\;0"); }
    else { print("\;1"); }
    print("   CKSEL3...0  = ");
    if(Temp.3 = 0) { print("\;0"); }
    else { print("\;1"); }
    if(Temp.2 = 0) { print("\;0"); }
    else { print("\;1"); }
    if(Temp.1 = 0) { print("\;0"); }
    else { print("\;1"); }
    if(Temp.0 = 0) { print("\;0"); }
    else { print("\;1"); }
    print("   EESAVE      = ");
    if(FuseH.2 = 0) { print("\;0 (EEPROM preserved)"); }
    else {print("\;1 (EEPROM not preserved)");}
    print("   BODLEVEL = ");
    if(FuseH.1 = 1) { print("\;1 (Brown out level 2.7 V)"); }
    else {print("\;0 (Brown out level 4.0 V)");}
    print("   BODEN       = ");
    if(FuseH.0 = 1) { print("\;1 (Brown out detector disabled)"); }
    else {print("\;0 (Brown out detector enabled)");}
}

Proc WriteFuse
{
    var Temp;
    print("   Writing FUSE bits...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    Temp = 0xFF;
    if(EESave = 0)      {Temp.2 = 0;}
    if(BODLEVEL = 0)    {Temp.1 = 0;}
    if(BODEN = 0)       {Temp.0 = 0;}
    print("Temp = %b",Temp);
    Run(WriteFuse);
    USB = Temp;
    Temp = 0xF0;
    if(PLLCK = 0)       {Temp.7 = 0;}
    if(CKOPT = 0)       {Temp.6 = 0;}
    if(SUT.0 = 0)       {Temp.5 = 0;}
    if(SUT.1 = 0)       {Temp.4 = 0;}
    Temp = Temp | CKSEL;
    print("Temp = %b",Temp);
    USB = Temp;
    Temp = USB;
    if(Temp != 0)
    {
        print("\;  Error.");
        return;
    }
    print("\; Success.");
    ReadFuse();
}

Proc WriteLock
{
    var Temp;
    print("   Writing Lock bits...");
    Run(InitSPI);
    Temp = USB;
    if(Temp != 0x53)
    {
        print("   Error. Device not response");
        return;
    }
    if(LockMode = 0) {Temp = 0xFF;}
    if(LockMode = 1) {Temp = 0xFE;}
    if(LockMode = 2) {Temp = 0xFC;}
    print("   Temp = %b",Temp);
    Run(WriteLock);
    USB = Temp;
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("   Error. TimeOut.");
    }
    else
    {
        print("\; Success.");
        ReadLock();
    }
}

Proc ModuleInfo {

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

[Device]

define      FLASH_END               1024
define      EEPROM_END              128
define      FLASH_PAGE_SIZE         16

define      PROG_ENABLE             0b1010110001010011
define      READ_DEVICE_CODE        0b0011000000000000
define      READ_PROGRAM_MEMORY     0b0010000000000000
define      WRITE_PROGRAM_MEMORY    0b0100110000000000
define      READ_EEPROM_MEMORY      0b1010000000000000
define      WRITE_EEPROM_MEMORY     0b1100000000000000
define      CHIP_ERASE              0b1010110010000000
define      WRITE_LOCK_BITS         0b1010110011111111
define      READ_LOCK_BITS          0b0101100000000000
define      READ_FUSE_BITS          0b0101000000000000
define      READ_HFUSE_BITS         0b0101100000001000
define      READ_CALIBRATION        0b0011100000000000
define      WRITE_FUSE_BITS         0b1010110010100000
define      WRITE_HFUSE_BITS        0b1010110010101000
define      LOAD_PROGRAM_MEMORY     0b0100000000000000

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

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

Proc ReadSignature
{
    InstructionW = READ_DEVICE_CODE;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;
    InstructionB++;
    InstructionIn;
    USB = SPIWord;
    InstructionB++;
    InstructionIn;
    USB = SPIWord;
}


Proc ReadFlash
{
    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 WriteFlash
{
    VerifyDuringWrite = USB;
    while
    {
        Byte = USB;
        if(Byte = 0) { break;}

        // ----- Load page into buffer

        InstructionW = LOAD_PROGRAM_MEMORY;
        WriteCounter = 0;
        while(WriteCounter != FLASH_PAGE_SIZE)
        {
            InstructionW.11 = 0;    
            InstructionB = USB;             // low byte of word
            Byte = WriteCounter << 8;
            InstructionB = InstructionB | Byte;
            InstructionOut;
            InstructionW.11 = 1;    
            InstructionB = USB;             // high byte of word
            InstructionB = InstructionB | Byte;
            InstructionOut;
            WriteCounter++;
        }
        // -----  get page address and program
        
        InstructionW = USB;          // high byte
        Address = InstructionW << 8;
        InstructionW = InstructionW | WRITE_PROGRAM_MEMORY;
        Byte = USB;                 // low byte
        Address = Address | Byte;
        InstructionB = Byte << 8;
        InstructionOut;

        // ------- wait until ready
        
        Delay(6000);
        USB = 0;

        if(VerifyDuringWrite != 0)
        {
            // verify writed page
            // read back and send to host
            WriteCounter = FLASH_PAGE_SIZE;
            while(WriteCounter != 0)
            {
                
                InstructionW = Address >> 8;
                InstructionW = InstructionW | READ_PROGRAM_MEMORY;
                InstructionB = Address;
                InstructionIn;
                USB = SPIWord;
                InstructionW.11 = 1;
                InstructionIn;
                USB = SPIWord;
                WriteCounter--;
                Address++;
            }
        }
    }
}

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

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

Proc ReadCalibrationByte
{
    InstructionW = READ_CALIBRATION;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;    
}

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

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

Proc ReadFuse
{
    InstructionW = READ_FUSE_BITS;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;    
    InstructionW = READ_HFUSE_BITS;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;    
}

Proc WriteFuse
{
    InstructionW = WRITE_HFUSE_BITS;
    InstructionB = USB;
    InstructionOut;
    Delay(6000);
    InstructionW = WRITE_FUSE_BITS;
    InstructionB = USB;
    InstructionOut;
    Delay(6000);        
    USB = 0;
}

Proc ReadCalibration
{
    InstructionW = READ_CALIBRATION;
    InstructionB = 0;
    InstructionIn;
    USB = SPIWord;    
}

Proc ChipErase
{
    InstructionW = CHIP_ERASE;
    InstructionB = 0xFFFF;
    InstructionOut;
    Delay(50000);
    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;
    MISOOUT = 1;
    while(Counter != 0)
    {
        SPIWord = SPIWord << 1;
        SCK = 0;
        SPIWord.0 = MISO;
        SCK = 1;
        Counter--;    
    }
}

Proc InitSPI
{
    POUT = 0b00100000;
    Delay(10000);
    InitCounter = 33;
    while
    {
        RESET = 1;Delay(21000);RESET = 0;
        Delay(25000);
        
        SPIWord = PROG_ENABLE;SendWordToSPI;
        // check echo
        SPIWord = 0;
        GetByteFromSPI;
        Echo = SPIWord;
        SPIWord = 0xFF;
        SendByteToSPI;
        if(Echo = 0x53) { break; }
        InitCounter--;
        if(InitCounter = 0) { break; }
    }
    USB = Echo;
}

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

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

