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

[Menu]

ReadSignature = "Read signature bytes",ChipInfoButton,"Read signature bytes";
ReadFlash = "Read FLASH",ReadButton,"Read FLASH";
WriteFlash = "Write FLASH",WriteButton,"Write FLASH";
Compare = "Verify FLASH",CheckButton,"Verify FLASH";
Erase = "Erase FLASH and EEPROM",EraseButton,"Erase FLASH and EEPROM";
ReadEEPROM = "Read EEPROM",ReadEEPROMButton,"Read EEPROM";
WriteEEPROM = "Write EEPROM",WriteEEPROMButton,"Write EEPROM";
ModuleInfo = "About module",ModuleInfoButton,"About module";
WriteLock = "Write lock bits";

[Interface]

CheckBox(EraseBeforeWrite,"Erase before write",5,5,1);
CheckBox(VerifyDuringWrite,"Verify during write",125,5,1);
ComboBox(LockMode,"Lock mode",250,6,90,"Not lock","Lock bit 1 (LB1)",
                                           "Lock bit 2 (LB2)",0);

[Host]

define      FLASH_END   2048
define      EEPROM_END  256
define      SIGN        0x9201

//***********************************************************************
//*             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: AT90S4414");
    }
    else
    {
        print("    Device is not AT90S4414. Use AVR Detector for identification.");
    }
}

Proc ReadFlash
{
    var Address,Temp,FlashEnd;
    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
    {
        print("   Reading is done. %i word were readed.",Address);
    }
}

Proc WriteFlash
{
    var Address,Temp,WordAddress,Temp2,Word,Error,WritedWords;

    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...");
    }
    Run(WriteFlash);
    USB = VerifyDuringWrite;
    WordAddress = 0;
    PBPos = 0;
    PBMax = FLASH_END;
    Address = 0;
    WritedWords = 0;
    while(WordAddress != FLASH_END)
    {
        Temp = FBUF[Address]; Address++;
        Temp2 = FBUF[Address]; Address++;
        Word = Temp << 8;
        Word = Word | Temp2;
        if(Word != 0xFFFF)
        {
            BeginBlock;
                USB = 0;
                Word = WordAddress >> 8;
                USB = Word;
                USB = WordAddress;
                USB = Temp;
                USB = Temp2;
            EndBlock;
            Error = USB;
            if(Error = 0x8000) { break; }
            if(Error = 255)  { break; }
            WritedWords++;
        }
        PBPos++;
        WordAddress++;
    }
    if(Error = 0x8000)
    {
        print("");
        print("   Writing error. Time out. Address: %i",WordAddress);
    }
    else
    {
        USB = 255;
        if(Error = 255)
        {
            print("");
            print("   Writing error. Address: %i",Address);
        }
        else
        {
            print("");
            print("   Writing success. %i words were writed.",WritedWords);
        }
    }
}


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
    {
        print("   Verifying is done. %i word were compared. Number of mismatch %i",Address,Mismatch);
    }
}

Proc ReadEEPROM
{
    var Address,Temp;
    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
    {
        print("   Reading is done. %i bytes were readed.",Address);
    }
}

Proc WriteEEPROM
{
    var Address,Temp;
    print("");
    print("   Writing EEPROM...");
    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(ChipErase);
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("");
        print("   Erasing error. Time out.");    
    }
    else
    {
        print("");
        print("   Erasing success.");
    }
}

Proc WriteLock
{
    var Temp;

    print("");
    if(LockMode = 0)
    {
        print("   Lock mode not set. Writing lock bits canceled.");
        return;
    }
    print("   Writing lock bits...");
    print("");
    Run(WriteLock);
    USB = LockMode;
    Temp = USB;
    if(Temp = 0x8000)
    {
        print("   Writing error. Time out."); 
    }
    else
    {
        print("   Writing success.");
    }
}

Proc ModuleInfo {

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



[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   2048
define      EEPROM_END  256
define      SIGN        0x9201

define      PROG_ENABLE             0b1010110001010011
define      READ_DEVICE_CODE        0b0011000000000000
define      READ_PROGRAM_MEMORY     0b0010000000000000
define      WRITE_PROGRAM_MEMORY    0b0100000000000000
define      READ_EEPROM_MEMORY      0b1010000000000000
define      WRITE_EEPROM_MEMORY     0b1100000000000000
define      CHIP_ERASE              0b1010110010000000
define      WRITE_LOCK_BITS         0b1010110011100110

var Counter,Address,InstructionW,InstructionB,SPIWord,Byte,FlashEnd,Echo,
    InitCounter,VerifyDuringWrite, VerifyWord, 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;
        InstructionW.2 = Address.10;
        InstructionB = Address;
        InstructionIn;
        USB = SPIWord;
        InstructionW.11 = 1;
        InstructionIn;
        USB = SPIWord;
        Address++;
    }
}

Proc WriteFlash
{
    VerifyDuringWrite = USB;
    InitSPI;
    while
    {
        Byte = USB;
        if(Byte != 0) { break;}
        Address = USB; Address = Address << 8;

        Byte = USB;
        Address = Address | Byte;

        InstructionW = WRITE_PROGRAM_MEMORY;
        InstructionW.0 = Address.8;
        InstructionW.1 = Address.9;
        InstructionW.2 = Address.10;
        InstructionW.3 = Address.11;
        InstructionB = Address << 8;
        Byte = USB;
        VerifyWord = Byte << 8;
        InstructionB = InstructionB | Byte;
        InstructionOut;
        Delay(4500);
        InstructionW.11 = 1;
        Byte = USB;
        VerifyWord = VerifyWord | Byte;
        InstructionB = InstructionB & 0xFF00;
        InstructionB = InstructionB | Byte;
        InstructionOut;
        Delay(4500);

        if(VerifyDuringWrite != 0)
        {
            // verify writed word
            InstructionW = READ_PROGRAM_MEMORY;
            InstructionW.0 = Address.8;
            InstructionW.1 = Address.9;
            InstructionW.2 = Address.10;
            InstructionW.3 = Address.11;
            InstructionB = Address;
            InstructionIn;
            ReadedWord = SPIWord << 8;
            InstructionW.11 = 1;
            InstructionIn;
            ReadedWord = ReadedWord | SPIWord;
            if(ReadedWord != VerifyWord)
            {
                USB = 255;
                return;
            }
        }
        USB = 0;
    }
}


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(20000);
    USB = 0;
}

Proc WriteLock
{
    InitSPI;
    Byte = USB;
    InstructionW = WRITE_LOCK_BITS;
    if(Byte = 1)
    {
        InstructionW.1 = 0;    
    }
    if(Byte = 2)
    {
        InstructionW.1 = 0;
        InstructionW.2 = 0;
    }
    InstructionB = 0;
    InstructionOut;
    Delay(20000);
    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;
}

