AVRisp tested on ATMega88A inspired by various implementations around: - AVR_SPI_Programmer_v2 ( BO Qiang ) - mAVRISP (Aaron Berk) - TestAVRISP(Chester Hamilton)

Dependencies:   mbed

AVRisp implementation for mBED

AVRISP/AVRISP.cpp

Committer:
Ellips
Date:
2015-04-28
Revision:
0:29abe3c0b902

File content as of revision 0:29abe3c0b902:

#include "AVRISP.h"

// constructor
AVRISP::AVRISP(PinName mosi, PinName miso, PinName sclk, PinName reset, uint32_t targetClk, uint16_t pageSize, PRGCB pCB )
: spiPort(mosi, miso, sclk )
, resetPin(reset)
, mPageSize(pageSize)
, progressCB(pCB)
{
    spiPort.frequency(targetClk>>2);//1/4 th of the clock frequency of the unit
    spiPort.format(8,0);
}

AVRISP::~AVRISP()
{
}

//A function to poll BSY to prevent loading a new instruction prematurely
void AVRISP::StillProgramming() 
{
    uint8_t check = 1;
    while(check & 0x1){//check LSB only
        spiPort.write(0xF0);
        spiPort.write(0x00);
        spiPort.write(0x00);
        check = spiPort.write(0x00); //read data byte out
    }
}

// enable programming mode
bool AVRISP::EnableProgrammingMode()
{
    int failed = 0;
    
    resetPin = 1;
    wait(0.02);
    resetPin = 0;
    wait(0.02);
    
    while(failed < 5)               //loop to try to enable programming mode 5 times
    {
        spiPort.write(0xAC);
        spiPort.write(0x53);
        int echoBack= spiPort.write(0x00);
        if(echoBack == 0x53)
        {                           //if data read on 3rd byte load is 0x53
            spiPort.write(0x00);   //programming mode was enabled...good job!
            return true;
        }
        else
        {
            failed++;
            resetPin = 1;          //pulse reset and try again
            resetPin = 0;
            wait(0.5);
        }
     }
    return false;                   //Bummer...
}

void AVRISP::LeaveProgrammingMode()
{
    resetPin = 1;
    wait(0.02);
}

// read chip signature byte
uint8_t AVRISP::ReadChipSignatureByte(SignatureByte Nr)
{
    spiPort.write(0x30);
    spiPort.write(0x00);
    spiPort.write(Nr);
    return spiPort.write(0x00);
}

// erase chip
void AVRISP::ChipErase()
{
    spiPort.write(0xAC);
    spiPort.write(0x80);
    spiPort.write(0x00);
    spiPort.write(0x00);
    StillProgramming();
    resetPin = 1;
    wait(0.02);
    resetPin = 0;
    wait(0.02);
    EnableProgrammingMode();
}

// write fuse byte
void AVRISP::WriteFuse(FuseType Typ, uint8_t fuse)
{
    spiPort.write(0xAC);
    switch ( Typ ){
        case eFTLo:
        spiPort.write(0xA0); break;
        case eFTHi:
        spiPort.write(0xA8); break;
        case eFTEx:
        spiPort.write(0xA4); break;
        case eFTLock:
        spiPort.write(0xE0); break;
        default:
        spiPort.write(0x00); break;
    };        
    spiPort.write(0x00);
    spiPort.write(fuse&0xff);
    StillProgramming();
}

// read fuse byte
uint8_t AVRISP::ReadFuse(FuseType Typ)
{
    switch (Typ){    
    case eFTLo:
    spiPort.write(0x50);
    spiPort.write(0x00);
    break;
    case eFTHi:
    spiPort.write(0x58);
    spiPort.write(0x08);
    break;
    case eFTEx:
    spiPort.write(0x50);
    spiPort.write(0x08);
    break;
    case eFTLock:
    spiPort.write(0x58);
    spiPort.write(0x00);
    break;
    default:
    spiPort.write(0x00);
    spiPort.write(0x00);
    break;
    }
    spiPort.write(0x00);
    return spiPort.write(0x00);
}
#define LSB(I) ((I) & 0xFF)
#define MSB(I) (((I) & 0xF00) >> 8)
// write program page
void AVRISP::WriteProgramPage(uint16_t addr)
{
    //write program memory page
    spiPort.write(0x4C);
    spiPort.write(MSB(addr));
    spiPort.write(LSB(addr));
    spiPort.write(0x00);
    
    StillProgramming(); //make sure the operation worked
}


//function to load and write program memory
//args: addr is the 12 bit address of the memory location
//      low_data and high_data are the values to write to that location
void AVRISP::LoadProgramPage(uint16_t addr,uint8_t lowData,uint8_t highData)//int addr_MSB, 
{
    //load program memory low byte (little endian)
    spiPort.write(0x40);
    spiPort.write(0x00);
    spiPort.write(LSB(addr));
    spiPort.write(lowData);
    
    //load program memory high byte
    spiPort.write(0x48);
    spiPort.write(0x00);
    spiPort.write(LSB(addr));
    spiPort.write(highData);    
}

inline uint8_t AVRISP::ReadByte(FILE *file)
{
    char ascii_char[2];
    fread(&ascii_char, 1, 2, file);
    return   (((ascii_char[0] < 65) ? (ascii_char[0]-48) : (ascii_char[0]-55)) << 4)
            | ((ascii_char[1] < 65) ? (ascii_char[1]-48) : (ascii_char[1]-55));
}

uint8_t AVRISP::ReadProgramFlash(uint16_t addr, bool highByte)
{
    spiPort.write(highByte ? 0x28: 0x20 );
    spiPort.write(MSB(addr));
    spiPort.write(LSB(addr));
    return spiPort.write(0x00);
}
#define AT_BOUNDARY(addr,size) ((addr % size) == (size -1))
// program flash

//TODO: Implement address gaps in the hex file format
bool AVRISP::ProgramFlash(FILE *hexFile)
{
    int flag = 0;    
    if(hexFile != NULL)
    {    
        uint16_t address = 0;
        char temp;        
        temp = fgetc(hexFile);
        while(flag == 0)
        {
            if(temp == ':')
            {
                uint8_t length = ReadByte(hexFile);
                if(length == 0)
                {
                    flag = 1;
                }
                else
                {
                    fseek(hexFile,6,SEEK_CUR); //2 if reading address
                    
                    for(uint8_t i=0;i<length;i+=2)
                    {
                        uint8_t lowData = ReadByte(hexFile);                        
                        uint8_t highData = ReadByte(hexFile);
                       
                        //load data bytes here
                        LoadProgramPage(address,lowData,highData);
                        
                        if (AT_BOUNDARY(address, mPageSize))        // write page if 32 words have now been written                        
                        {                    
                            WriteProgramPage(address);                            
                            if( progressCB ) (*progressCB)(); //activity callback                            
                        }
                        
                        address++;
                    }
                    while((temp = fgetc(hexFile)) != ':');            
                }
            }
            else flag = 1;
        }
        WriteProgramPage(address);//write the last part
    }
    else
    {
        return false;
    }
    return true;
}

//TODO: Implement address gaps in the hex file format
bool AVRISP::VerifyFlash(FILE* hexFile)
{
    int flag = 0;  
    bool Error = false;  
    if(hexFile != NULL)
    {    
        uint16_t address = 0;
        char temp;        
        temp = fgetc(hexFile);
        while(flag == 0)
        {
            if(temp == ':')
            {
                uint8_t length = ReadByte(hexFile);
                if(length == 0)
                {
                    flag = 1;
                }
                else
                {
                    fseek(hexFile,6,SEEK_CUR); //2 if reading address
                    
                    for(uint8_t i=0;i<length;i+=2)
                    {
                        uint8_t lowData = ReadByte(hexFile);                        
                        uint8_t highData = ReadByte(hexFile);
                        uint8_t lowDataF = ReadProgramFlash(address, false);
                        uint8_t highDataF = ReadProgramFlash(address, true);                        
                        
                        if( lowData != lowDataF || highData != highDataF )
                        {
                            printf( "\n@%04x src %02x,%02x != %02x,%02x\n", address, lowData, highData, lowDataF,highDataF);                            
                            Error = true;
                        }                          
                        
                        if (AT_BOUNDARY(address, mPageSize))
                        {
                            if( progressCB ) (*progressCB)(); //activity callback      
                        }
                        address++;
                    }
                    while((temp = fgetc(hexFile)) != ':');                    
                }                            
            }
            else flag = 1;
        }
        if(Error)
            return false;
    }
    else
    {
        return false;
    }                  
    
    return true;
}