eddiewwm 发表于 2019-7-24 13:08:27

8F328U 作基礎的 AVR 燒寫器

本帖最后由 eddiewwm 于 2019-7-24 15:20 编辑

用 8F328U 小紅板 按外國大神的指導,完成了以下的 AVR ATmega328P 燒寫器。


參考視頻:
https://www.youtube.com/watch?v=7H8aQ1mWUy4

AVRprogrammer_9_24_18.ino
#include "data.h"
void setup ()
{
Serial.begin(115200);
Serial.println("AVR Programmer Ready...");
pinMode (startSwitch, INPUT);
digitalWrite (startSwitch, HIGH);
pinMode (errorLED, OUTPUT);
pinMode (readyLED, OUTPUT);
pinMode (workingLED, OUTPUT);
pinMode (buzzerPin, OUTPUT);
digitalWrite(buzzerPin, HIGH);
delay(20);
digitalWrite(buzzerPin, LOW);
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards.use SPI_FULL_SPEED for better performance.
while (!sd.begin (chipSelect, SPI_HALF_SPEED))
{
    ShowMessage (MSG_NO_SD_CARD);
    delay (1000);
}

}// end of setup



//------------------------------------------------------------------------------
//      LOOP
//------------------------------------------------------------------------------
void loop ()
{

digitalWrite (readyLED, HIGH);

// wait till they press the start switch
while (!getUserSerial()) {}
//Serial.println("Press Button to Start!!");
//while (digitalRead (startSwitch) == HIGH)
//{
//    //just loop in here till start button is pressed
//
//}// end of waiting for switch press

}// end of loop

data.h
//includes
#include <SdFat.h>// for SDFat library see: https://github.com/greiman/SdFat


//functions
boolean getUserSerial();
boolean getDate();
boolean getIntro();

void burnEEPROM(byte EEPROMdata);
void getString();
void readALlFromChip();
void showHex (const byte b, const boolean newline = false, const boolean show0x = true);
void blink (const int whichLED1,
            const int whichLED2,
            const byte times = 1,
            const unsigned long repeat = 1,
            const unsigned long interval = 200);
void ShowMessage (const byte which);
byte BB_SPITransfer (byte c);
byte program (const byte b1, const byte b2 = 0, const byte b3 = 0, const byte b4 = 0);
byte readFlash (unsigned long addr);
void writeFlash (unsigned long addr, const byte data);
bool hexConv (const char * (& pStr), byte & b);
void pollUntilReady ();
void showProgress ();
void clearPage ();
void commitPage (unsigned long addr);
void writeData (const unsigned long addr, const byte * pData, const int length);
void verifyData (const unsigned long addr, const byte * pData, const int length);
bool processLine (const char * pLine, const byte action);
bool readHexFile (const char * fName, const byte action);
bool startProgramming ();
void stopProgramming ();
void getSignature ();
void getFuseBytes ();
void writeFuse (const byte newValue, const byte instruction);
bool updateFuses (const bool writeIt);
bool chooseInputFile ();
bool writeFlashContents ();



//variables and constants
const unsigned int ENTER_PROGRAMMING_ATTEMPTS = 2;
String inputstring = "";
boolean input_string_complete = false;
byte EEPROMindex = 0;
const bool allowTargetToRun = true;// if true, programming lines are freed when not programming
const char dateMessage[] PROGMEM= {"Please Enter Date like this: MM/DD/YY \n Example for July 4th, 2018, would be 07/04/18\n"};
const char introMessage[]PROGMEM= {"What do you want to do?\nR = Read Board Information\nW = Write parameters\nN = Brand New Board Programming\n"};
const char fuseBurn[]PROGMEM= {"Burning Fuse Config:Should be LFuse=0xFF, HFuse=0xDF, EFuse=0xFD\n"};
const char wrongLength[]PROGMEM= {"Sorry wrong length\n"};
// fixed file name to read from SD card (root directory)
const char wantedFile [] = "firmware.hex";

// which switch to close to start programming the target chip
const byte startSwitch = 2;

// the three "status" LEDs
const int errorLED = A0;
const int readyLED = A1;
const int workingLED = A4;
const int buzzerPin = 3;

const int noLED = -1;// must be int! - can be negative

// status "messages"
typedef enum {
MSG_NO_SD_CARD,          // cannot open SD card
MSG_CANNOT_OPEN_FILE,    // canoot open file 'wantedFile' (above)
MSG_LINE_TOO_LONG,       // line on disk too long to read
MSG_LINE_TOO_SHORT,      // line too short to be valid
MSG_LINE_DOES_NOT_START_WITH_COLON,// line does not start with a colon
MSG_INVALID_HEX_DIGITS,// invalid hex where there should be hex
MSG_BAD_SUMCHECK,      // line fails sumcheck
MSG_LINE_NOT_EXPECTED_LENGTH,// record not length expected
MSG_UNKNOWN_RECORD_TYPE,// record type not known
MSG_NO_END_OF_FILE_RECORD,// no 'end of file' at end of file
MSG_FILE_TOO_LARGE_FOR_FLASH,// file will not fit into flash

MSG_CANNOT_ENTER_PROGRAMMING_MODE,// cannot program target chip
MSG_NO_BOOTLOADER_FUSE,             // chip does not have bootloader
MSG_CANNOT_FIND_SIGNATURE,      // cannot find chip signature
MSG_UNRECOGNIZED_SIGNATURE,   // signature not known
MSG_BAD_START_ADDRESS,          // file start address invalid
MSG_VERIFICATION_ERROR,         // verification error after programming
MSG_FLASHED_OK,               // flashed OK
} msgType;

//SPI to target pins
const byte MSPIM_SCK = 4;// port D bit 4
const byte MSPIM_SS= 5;// port D bit 5
const byte BB_MISO   = 6;// port D bit 6
const byte BB_MOSI   = 7;// port D bit 7
// 8 MHz clock on this pin
const byte CLOCKOUT = 9;

#define BB_MISO_PORT PIND
#define BB_MOSI_PORT PORTD
#define BB_SCK_PORT PORTD
const byte BB_SCK_BIT = 4;
const byte BB_MISO_BIT = 6;
const byte BB_MOSI_BIT = 7;

// control speed of programming
const byte BB_DELAY_MICROSECONDS = 6;
// target board reset goes to here
const byte RESET = MSPIM_SS;
// SD chip select pin
const uint8_t chipSelect = SS;
const unsigned long NO_PAGE = 0xFFFFFFFF;
const int MAX_FILENAME = 13;

// actions to take
enum {
checkFile,
verifyFlash,
writeToFlash,
};

// file system object
SdFat sd;

// copy of fuses/lock bytes found for this processor
byte fuses ;

// meaning of bytes in above array
enum {
lowFuse,
highFuse,
extFuse,
lockByte,
calibrationByte
};

// structure to hold signature and other relevant data about each chip
typedef struct {
byte sig ;
const char * desc;
unsigned long flashSize;
unsigned int baseBootSize;
unsigned long pageSize;   // bytes
byte fuseWithBootloaderSize;// ie. one of: lowFuse, highFuse, extFuse
byte timedWrites;    // if pollUntilReady won't work by polling the chip
} signatureType;

const unsigned long kb = 1024;
const byte NO_FUSE = 0xFF;

// see Atmega datasheets
const signatureType signatures [] PROGMEM =
{
//   signature      description   flash size   bootloaderflashfuse
//                                                   size    page    to
//                                                             size   change

// Attiny84 family
{ { 0x1E, 0x91, 0x0B }, "ATtiny24",   2 * kb,         0,   32,   NO_FUSE },
{ { 0x1E, 0x92, 0x07 }, "ATtiny44",   4 * kb,         0,   64,   NO_FUSE },
{ { 0x1E, 0x93, 0x0C }, "ATtiny84",   8 * kb,         0,   64,   NO_FUSE },

// Attiny85 family
{ { 0x1E, 0x91, 0x08 }, "ATtiny25",   2 * kb,         0,   32,   NO_FUSE },
{ { 0x1E, 0x92, 0x06 }, "ATtiny45",   4 * kb,         0,   64,   NO_FUSE },
{ { 0x1E, 0x93, 0x0B }, "ATtiny85",   8 * kb,         0,   64,   NO_FUSE },

// Atmega328 family
{ { 0x1E, 0x92, 0x0A }, "ATmega48PA",   4 * kb,         0,    64,NO_FUSE },
{ { 0x1E, 0x93, 0x0F }, "ATmega88PA",   8 * kb,       256,   128,extFuse },
{ { 0x1E, 0x94, 0x0B }, "ATmega168PA", 16 * kb,       256,   128,extFuse },
{ { 0x1E, 0x95, 0x0F }, "ATmega328P",32 * kb,       512,   128,highFuse },

// Atmega644 family
{ { 0x1E, 0x94, 0x0A }, "ATmega164P",   16 * kb,      256,   128,highFuse },
{ { 0x1E, 0x95, 0x08 }, "ATmega324P",   32 * kb,      512,   128,highFuse },
{ { 0x1E, 0x96, 0x0A }, "ATmega644P",   64 * kb,   1 * kb,   256,highFuse },

// Atmega2560 family
{ { 0x1E, 0x96, 0x08 }, "ATmega640",    64 * kb,   1 * kb,   256,highFuse },
{ { 0x1E, 0x97, 0x03 }, "ATmega1280",128 * kb,   1 * kb,   256,highFuse },
{ { 0x1E, 0x97, 0x04 }, "ATmega1281",128 * kb,   1 * kb,   256,highFuse },
{ { 0x1E, 0x98, 0x01 }, "ATmega2560",256 * kb,   1 * kb,   256,highFuse },

{ { 0x1E, 0x98, 0x02 }, "ATmega2561",256 * kb,   1 * kb,   256,highFuse },

// AT90USB family
{ { 0x1E, 0x93, 0x82 }, "At90USB82",    8 * kb,       512,   128,highFuse },
{ { 0x1E, 0x94, 0x82 }, "At90USB162",16 * kb,       512,   128,highFuse },

// Atmega32U2 family
{ { 0x1E, 0x93, 0x89 }, "ATmega8U2",    8 * kb,       512,   128,highFuse},
{ { 0x1E, 0x94, 0x89 }, "ATmega16U2",16 * kb,       512,   128,highFuse},
{ { 0x1E, 0x95, 0x8A }, "ATmega32U2",32 * kb,       512,   128,highFuse},

// Atmega32U4 family -(datasheet is wrong about flash page size being 128 words)
{ { 0x1E, 0x94, 0x88 }, "ATmega16U4",16 * kb,       512,   128,highFuse },
{ { 0x1E, 0x95, 0x87 }, "ATmega32U4",32 * kb,       512,   128,highFuse },

// ATmega1284P family
{ { 0x1E, 0x97, 0x05 }, "ATmega1284P", 128 * kb,   1 * kb,   256,highFuse},

// ATtiny4313 family
{ { 0x1E, 0x91, 0x0A }, "ATtiny2313A",   2 * kb,      0,    32,NO_FUSE},
{ { 0x1E, 0x92, 0x0D }, "ATtiny4313",    4 * kb,      0,    64,NO_FUSE},

// ATtiny13 family
{ { 0x1E, 0x90, 0x07 }, "ATtiny13A",   1 * kb,      0,    32,NO_FUSE },

// Atmega8A family
{ { 0x1E, 0x93, 0x07 }, "ATmega8A",      8 * kb,      256,    64,highFuse, true },

// ATmega64rfr2 family
{ { 0x1E, 0xA6, 0x02 }, "ATmega64rfr2",256 * kb, 1 * kb,   256, highFuse },
{ { 0x1E, 0xA7, 0x02 }, "ATmega128rfr2", 256 * kb, 1 * kb,   256, highFuse },
{ { 0x1E, 0xA8, 0x02 }, "ATmega256rfr2", 256 * kb, 1 * kb,   256, highFuse },

};// end of signatures

char name = { 0 };// current file name

// number of items in an array
#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg )))

// programming commands to send via SPI to the chip
enum {
progamEnable = 0xAC,

// writes are preceded by progamEnable
chipErase = 0x80,
writeLockByte = 0xE0,
writeLowFuseByte = 0xA0,
writeHighFuseByte = 0xA8,
writeExtendedFuseByte = 0xA4,

pollReady = 0xF0,

programAcknowledge = 0x53,

readSignatureByte = 0x30,
readCalibrationByte = 0x38,

readLowFuseByte = 0x50,       readLowFuseByteArg2 = 0x00,
readExtendedFuseByte = 0x50,readExtendedFuseByteArg2 = 0x08,
readHighFuseByte = 0x58,      readHighFuseByteArg2 = 0x08,
readLockByte = 0x58,          readLockByteArg2 = 0x00,

readProgramMemory = 0x20,
writeProgramMemory = 0x4C,
loadExtendedAddressByte = 0x4D,
loadProgramMemory = 0x40,
readEEPROMbyte = 0xA0,
writeEEPROMbyte = 0xC0

                  /*
                     0xC0 WRITE BYTE TO EEPROM
                      0xA0 READ BYTE FROM EEPROM

                  */

};// end of enum

// which program instruction writes which fuse
const byte fuseCommands = { writeLowFuseByte, writeHighFuseByte, writeExtendedFuseByte, writeLockByte };

// types of record in .hex file
enum {
hexDataRecord,// 00
hexEndOfFile,   // 01
hexExtendedSegmentAddressRecord, // 02
hexStartSegmentAddressRecord,// 03
hexExtendedLinearAddressRecord, // 04
hexStartLinearAddressRecord // 05
};
// if signature found in above table, this is its index
int foundSig = -1;
byte lastAddressMSB = 0;
// copy of current signature entry for matching processor
signatureType currentSignature;

unsigned long pagesize;
unsigned long pagemask;
unsigned long oldPage;
unsigned int progressBarCount;
// count errors
unsigned int errors;
bool gotEndOfFile;
unsigned long extendedAddress;

unsigned long lowestAddress;
unsigned long highestAddress;
unsigned long bytesWritten;
unsigned int lineCount;


/*
LED codes (flash counts) - each sequence repeats 5 times

If you are using the Crossroads programming board, the statuses are also shown
as a 2-digit code in the 7-segment display. If you have the board with only one
7-segment display you will see the first letter only.

Problems with SD card or programming target chip
------------------------------------------------

Red x 1 = Cannot open SD card (Sd)
Red x 2 = Cannot read file 'firmware.hex' (FL)
Red x 3 = Cannot enter programming mode in target chip (Ch)
Red x 4 = This chip does not have a bootloader fuse (Fu)
Red x 5 = Cannot read chip signature (Sg)
Red x 6 = Unrecognized signature (Un)
Red x 7 = Bad start address in hex file for code (Ad)
Red x 8 = Verification error (bd)

Problems with firmware.hex file
-------------------------------

Red + yellow x 1 = Line in file is too long (E1)
Red + yellow x 2 = Line in file is too short (E2)
Red + yellow x 3 = Line does not start with a colon (:) (E3)
Red + yellow x 4 = Invalid hex digits (should be 0-9, A-F) (E4)
Red + yellow x 5 = Bad sumcheck at end of line (E5)
Red + yellow x 6 = Line not expected length (E6)
Red + yellow x 7 = Unknown record type (E7)
Red + yellow x 8 = No 'end of file' record in file (E8)
Red + yellow x 9 = File will not fit into flash of target (LG)

Worked OK
---------

Green x 3 = Flashed and verified OK - sequence repeats 10 times (AA)

Other statuses
--------------

Green (steady) = Ready to program (close switch to commence)
Yellow (flashing) = Programming (Pr)
Green (steady) + yellow (flashing) = verifying (uF)
No LEDs on = No power?

*/



getUserInput.ino

boolean getUserSerial() {
EEPROMindex = 0;
inputstring.reserve(15);
digitalWrite (readyLED, HIGH);
if (!getIntro())
    return 0;
digitalWrite(buzzerPin, HIGH);
delay(20);
digitalWrite(buzzerPin, LOW);
if (inputstring == "R") {

    readALlFromChip();

    return 0;
}
if (inputstring == "N") {
    strcpy (name, wantedFile);
    Serial.println("Programming Started");

    digitalWrite (readyLED, LOW);
    if (!startProgramming ())
    {
      ShowMessage (MSG_CANNOT_ENTER_PROGRAMMING_MODE);
      return;
    }// end of could not enter programming mode

    //FUSES ARE BURNED HERE!!!
    // WOULD BE NICE IF WE COULD DETERMINE FUSE SETTINGS BASED ON SIGNATURE
    writeFuse (0xFF, writeLowFuseByte);
    stopProgramming();
    startProgramming ();
    //writeFuse (0xD6, writeHighFuseByte);//retains EEPROM
    writeFuse (0xDE, writeHighFuseByte);
    stopProgramming();
    startProgramming ();
    writeFuse (0x05, writeExtendedFuseByte);//BO at 2.7V
    stopProgramming();
    startProgramming ();
    getSignature ();
    for (int k = 0; k < strlen_P(fuseBurn); k++)
    {
      char myChar =pgm_read_byte_near(fuseBurn + k);
      Serial.print(myChar);
    }
    getFuseBytes ();
    // don't have signature? don't proceed
    if (foundSig == -1)
    {
      ShowMessage (MSG_CANNOT_FIND_SIGNATURE);
      return;
    }// end of no signature

    digitalWrite (workingLED, HIGH);
    bool ok = writeFlashContents ();
    digitalWrite (workingLED, LOW);
    digitalWrite (readyLED, LOW);
    stopProgramming ();
    //delay (500);
    if (ok) {
      //ShowMessage (MSG_FLASHED_OK);
      for (int i = 0; i < 10; i++) {
      digitalWrite(buzzerPin, HIGH);
      delay(50);
      digitalWrite(buzzerPin, LOW);
      delay(50);
      }
    }
    Serial.println("Programming Complete!");

}

digitalWrite (readyLED, HIGH);
digitalWrite(buzzerPin, HIGH);
delay(20);
digitalWrite(buzzerPin, LOW);

if (!getDate())
    return 0;
digitalWrite(buzzerPin, HIGH);
delay(20);
digitalWrite(buzzerPin, LOW);

for (int i = 0; i < 10; i++) {
    digitalWrite(buzzerPin, HIGH);
    delay(20);
    digitalWrite(buzzerPin, LOW);
    delay(20);
}
Serial.println("DONE!\n\n");
readALlFromChip();
return 0;

}




void burnEEPROM(byte EEPROMdata) {
startProgramming();
digitalWrite(workingLED, HIGH);
program (writeEEPROMbyte, 0, EEPROMindex, EEPROMdata);
delay(100);
digitalWrite(workingLED, LOW);
stopProgramming();
}


boolean getDate() {
inputstring = "";
//Serial.println("Please Enter Date like this: MM/DD/YY");
for (int k = 0; k < strlen_P(dateMessage); k++)
{
    char myChar =pgm_read_byte_near(dateMessage + k);
    Serial.print(myChar);
}
getString();
if (inputstring.length() > 8 || inputstring.length() < 8) {
    for (int k = 0; k < strlen_P(wrongLength); k++)
    {
      char myChar =pgm_read_byte_near(wrongLength + k);
      Serial.print(myChar);
    }
    // Serial.println("Sorry wrong length");
    return 0;
}
Serial.print("Thanks, will use ");
Serial.println(inputstring);
for (int i = 0; i < 8; i++) {
    burnEEPROM(inputstring);
    EEPROMindex++;
}
return 1;
}


boolean getIntro() {
inputstring = "";
for (int k = 0; k < strlen_P(introMessage); k++)
{
    char myChar =pgm_read_byte_near(introMessage + k);
    Serial.print(myChar);
}

getString();
if (inputstring.length() > 1 || inputstring.length() < 1) {
    for (int k = 0; k < strlen_P(wrongLength); k++)
    {
      char myChar =pgm_read_byte_near(wrongLength + k);
      Serial.print(myChar);
    }
    return 0;
}

return 1;
}

void getString() {
inputstring = "";
//digitalWrite (readyLED, LOW);
unsigned long blinkerStart = millis();
while (1) {
    if (millis() - blinkerStart > 50) {
      digitalWrite(readyLED, !digitalRead(readyLED));
      blinkerStart = millis();
    }

    if (digitalRead (startSwitch) == LOW) {
      inputstring = "N";
      break;
    }

    if (Serial.available() > 0) {
      delay(10);
      inputstring = Serial.readStringUntil(13);         //read the string until we see a <CR>
      //Serial.println(inputstring);
      digitalWrite (readyLED, HIGH);
      //digitalWrite(workingLED, LOW);
      break;
    }
}
}

void readALlFromChip() {

if (!startProgramming ()) {
    Serial.println("NO BOARD DETECTED!!");
    return;
}
Serial.println("***** Reading From Board *****");
Serial.println("Config Fuses Set:");
getFuseBytes ();
//startProgramming();
Serial.println("");
//    Serial.println("Reading Board Data...");
Serial.print("Date Prog = ");
byte indexTracker = 0;
for (byte i = 0; i < 8; i++) {
    Serial.print(char(program (readEEPROMbyte, 0, i)));
    indexTracker++;
}
Serial.println("");

Serial.print("Firmware Date Code = ");
for (byte i = indexTracker; i < indexTracker + 8; i++) {
    Serial.print(char(program (readEEPROMbyte, 0, i)));
}

stopProgramming();
Serial.println("");
Serial.println("*********************");
Serial.println("\n");
}


programmingFunctions.ino
/// changed this line: lowestAddress = 0x7E00;//I HAD TO FORCE THIS FOR THE ATMEGA328P

void showHex (const byte b, const boolean newline, const boolean show0x)
{
if (show0x)
    Serial.print (F("0x"));
// try to avoid using sprintf
char buf ;
buf = ((b >> 4) & 0x0F) | '0';
buf = (b & 0x0F) | '0';
buf = ' ';
buf = 0;
if (buf > '9')
    buf += 7;
if (buf > '9')
    buf += 7;
Serial.print (buf);
if (newline)
    Serial.println ();
}// end of showHex
// blink one or two LEDs for "times" times, with a delay of "interval". Wait a second and do it again "repeat" times.
void blink (const int whichLED1,
            const int whichLED2,
            const byte times = 1,
            const unsigned long repeat = 1,
            const unsigned long interval = 200)
{
for (unsigned long i = 0; i < repeat; i++)
{
    for (byte j = 0; j < times; j++)
    {
      digitalWrite (whichLED1, HIGH);
      if (whichLED2 != noLED)
      digitalWrite (whichLED2, HIGH);
      delay (interval);
      digitalWrite (whichLED1, LOW);
      if (whichLED2 != noLED)
      digitalWrite (whichLED2, LOW);
      delay (interval);
    }// end of for loop
    if (i < (repeat - 1))
      delay (1000);
}// end of repeating the sequence
}// end of blink

void ShowMessage (const byte which)
{
// first turn off all LEDs
digitalWrite (errorLED, LOW);
digitalWrite (workingLED, LOW);
digitalWrite (readyLED, LOW);
Serial.println("SOMETHING IS NOT RIGHT!! Press RED Button to try again...");
while (1) {
    // now flash an appropriate sequence
    switch (which)
    {
      // problems with SD card or finding the file
      case MSG_NO_SD_CARD:                      blink (errorLED, noLED, 1, 5); break;
      case MSG_CANNOT_OPEN_FILE:                blink (errorLED, noLED, 2, 5); break;

      // problems reading the .hex file
      case MSG_LINE_TOO_LONG:                   blink (errorLED, workingLED, 1, 5); break;
      case MSG_LINE_TOO_SHORT:                  blink (errorLED, workingLED, 2, 5); break;
      case MSG_LINE_DOES_NOT_START_WITH_COLON:blink (errorLED, workingLED, 3, 5); break;
      case MSG_INVALID_HEX_DIGITS:            blink (errorLED, workingLED, 4, 5); break;
      case MSG_BAD_SUMCHECK:                  blink (errorLED, workingLED, 5, 5); break;
      case MSG_LINE_NOT_EXPECTED_LENGTH:      blink (errorLED, workingLED, 6, 5); break;
      case MSG_UNKNOWN_RECORD_TYPE:             blink (errorLED, workingLED, 7, 5); break;
      case MSG_NO_END_OF_FILE_RECORD:         blink (errorLED, workingLED, 8, 5); break;

      // problems with the file contents
      case MSG_FILE_TOO_LARGE_FOR_FLASH:      blink (errorLED, workingLED, 9, 5); break;

      // problems programming the chip
      case MSG_CANNOT_ENTER_PROGRAMMING_MODE:blink (errorLED, noLED, 3, 5); break;
      case MSG_NO_BOOTLOADER_FUSE:             blink (errorLED, noLED, 4, 5); break;
      case MSG_CANNOT_FIND_SIGNATURE:          blink (errorLED, noLED, 5, 5); break;
      case MSG_UNRECOGNIZED_SIGNATURE:         blink (errorLED, noLED, 6, 5); break;
      case MSG_BAD_START_ADDRESS:            blink (errorLED, noLED, 7, 5); break;
      case MSG_VERIFICATION_ERROR:             blink (errorLED, noLED, 8, 5); break;
      case MSG_FLASHED_OK:                     blink (readyLED, noLED, 3, 2); break;

      default:                                  blink (errorLED, 10, 10);break;   // unknown error
    }// end of switch on which message
}
}// end of ShowMessage

// Bit Banged SPI transfer
byte BB_SPITransfer (byte c)
{
byte bit;

for (bit = 0; bit < 8; bit++)
{
    // write MOSI on falling edge of previous clock
    if (c & 0x80)
      BB_MOSI_PORT |= bit (BB_MOSI_BIT);
    else
      BB_MOSI_PORT &= ~bit (BB_MOSI_BIT);
    c <<= 1;

    // read MISO
    c |= (BB_MISO_PORT & bit (BB_MISO_BIT)) != 0;

    // clock high
    BB_SCK_PORT |= bit (BB_SCK_BIT);

    // delay between rise and fall of clock
    delayMicroseconds (BB_DELAY_MICROSECONDS);

    // clock low
    BB_SCK_PORT &= ~bit (BB_SCK_BIT);

    // delay between rise and fall of clock
    delayMicroseconds (BB_DELAY_MICROSECONDS);
}

return c;
}// end of BB_SPITransfer

// execute one programming instruction ... b1 is command, b2, b3, b4 are arguments
//processor may return a result on the 4th transfer, this is returned.
byte program (const byte b1, const byte b2 = 0, const byte b3 = 0, const byte b4 = 0)
{
noInterrupts ();
BB_SPITransfer (b1);
BB_SPITransfer (b2);
BB_SPITransfer (b3);
byte b = BB_SPITransfer (b4);
interrupts ();
return b;
} // end of program

// read a byte from flash memory
byte readFlash (unsigned long addr)
{
byte high = (addr & 1) ? 0x08 : 0;// set if high byte wanted
addr >>= 1;// turn into word address

// set the extended (most significant) address byte if necessary
byte MSB = (addr >> 16) & 0xFF;
if (MSB != lastAddressMSB)
{
    program (loadExtendedAddressByte, 0, MSB);
    lastAddressMSB = MSB;
}// end if different MSB

return program (readProgramMemory | high, highByte (addr), lowByte (addr));
} // end of readFlash
// write a byte to the flash memory buffer (ready for committing)

void writeFlash (unsigned long addr, const byte data)
{
byte high = (addr & 1) ? 0x08 : 0;// set if high byte wanted
addr >>= 1;// turn into word address
program (loadProgramMemory | high, 0, lowByte (addr), data);
} // end of writeFlash

// convert two hex characters into a byte
//    returns true if error, false if OK
bool hexConv (const char * (& pStr), byte & b)
{

if (!isxdigit (pStr ) || !isxdigit (pStr ))
{
    ShowMessage (MSG_INVALID_HEX_DIGITS);
    return true;
} // end not hex

b = *pStr++ - '0';
if (b > 9)
    b -= 7;

// high-order nybble
b <<= 4;

byte b1 = *pStr++ - '0';
if (b1 > 9)
    b1 -= 7;

b |= b1;

return false;// OK
}// end of hexConv
// poll the target device until it is ready to be programmed
void pollUntilReady ()
{
if (currentSignature.timedWrites)
    delay (10);// at least 2 x WD_FLASH which is 4.5 mS
else
{
    while ((program (pollReady) & 1) == 1)
    {}// wait till ready
}// end of if
}// end of pollUntilReady

// shows progress, toggles working LED
void showProgress ()
{
digitalWrite (workingLED, ! digitalRead (workingLED));
}// end of showProgress
// clear entire temporary page to 0xFF in case we don't write to all of it
void clearPage ()
{
unsigned int len = currentSignature.pageSize;
for (unsigned int i = 0; i < len; i++)
    writeFlash (i, 0xFF);
}// end of clearPage
// commit page to flash memory
void commitPage (unsigned long addr)
{
addr >>= 1;// turn into word address

// set the extended (most significant) address byte if necessary
byte MSB = (addr >> 16) & 0xFF;
if (MSB != lastAddressMSB)
{
    program (loadExtendedAddressByte, 0, MSB);
    lastAddressMSB = MSB;
}// end if different MSB

showProgress ();

program (writeProgramMemory, highByte (addr), lowByte (addr));
pollUntilReady ();

clearPage();// clear ready for next page full
}// end of commitPage
// write data to temporary buffer, ready for committing
void writeData (const unsigned long addr, const byte * pData, const int length)
{
// write each byte
for (int i = 0; i < length; i++)
{
    unsigned long thisPage = (addr + i) & pagemask;
    // page changed? commit old one
    if (thisPage != oldPage && oldPage != NO_PAGE)
      commitPage (oldPage);
    // now this is the current page
    oldPage = thisPage;
    // put byte into work buffer
    writeFlash (addr + i, pData );
}// end of for

}// end of writeData
void verifyData (const unsigned long addr, const byte * pData, const int length)
{
// check each byte
for (int i = 0; i < length; i++)
{
    unsigned long thisPage = (addr + i) & pagemask;
    // page changed? show progress
    if (thisPage != oldPage && oldPage != NO_PAGE)
      showProgress ();
    // now this is the current page
    oldPage = thisPage;

    byte found = readFlash (addr + i);
    byte expected = pData ;
    if (found != expected)
      errors++;
}// end of for

}// end of verifyData

/*
Line format:

:nnaaaatt(data)ss

Where:
:      = a colon

(All of below in hex format)

nn   = length of data part
aaaa   = address (eg. where to write data)
tt   = transaction type
         00 = data
         01 = end of file
         02 = extended segment address (changes high-order byte of the address)
         03 = start segment address *
         04 = linear address *
         05 = start linear address *
(data) = variable length data
ss   = sumcheck

            We don't use these

*/

// returns true if error, false if OK
bool processLine (const char * pLine, const byte action)
{
if (*pLine++ != ':')
{
    ShowMessage (MSG_LINE_DOES_NOT_START_WITH_COLON);
    return true;// error
}

const int maxHexData = 40;
byte hexBuffer ;
int bytesInLine = 0;

if (action == checkFile)
    if (lineCount++ % 40 == 0)
      showProgress ();

// convert entire line from ASCII into binary
while (isxdigit (*pLine))
{
    // can't fit?
    if (bytesInLine >= maxHexData)
    {
      ShowMessage (MSG_LINE_TOO_LONG);
      return true;
    } // end if too long

    if (hexConv (pLine, hexBuffer ))
      return true;
}// end of while

if (bytesInLine < 5)
{
    ShowMessage (MSG_LINE_TOO_SHORT);
    return true;
}

// sumcheck it

byte sumCheck = 0;
for (int i = 0; i < (bytesInLine - 1); i++)
    sumCheck += hexBuffer ;

// 2's complement
sumCheck = ~sumCheck + 1;

// check sumcheck
if (sumCheck != hexBuffer )
{
    ShowMessage (MSG_BAD_SUMCHECK);
    return true;
}

// length of data (eg. how much to write to memory)
byte len = hexBuffer ;

// the data length should be the number of bytes, less
//   length / address (2) / transaction type / sumcheck
if (len != (bytesInLine - 5))
{
    ShowMessage (MSG_LINE_NOT_EXPECTED_LENGTH);
    return true;
}

// two bytes of address
unsigned long addrH = hexBuffer ;
unsigned long addrL = hexBuffer ;

unsigned long addr = addrL | (addrH << 8);

byte recType = hexBuffer ;

switch (recType)
{
    // stuff to be written to memory
    case hexDataRecord:
      //lowestAddress= min (lowestAddress, addr + extendedAddress);
      lowestAddress = 0x7E00;//I HAD TO FORCE THIS FOR THE ATMEGA328P
      highestAddress = max (lowestAddress, addr + extendedAddress + len - 1);
      bytesWritten += len;

      switch (action)
      {
      case checkFile:// nothing much to do, we do the checks anyway
          break;

      case verifyFlash:
          verifyData (addr + extendedAddress, &hexBuffer , len);
          break;

      case writeToFlash:
          writeData (addr + extendedAddress, &hexBuffer , len);
          break;
      } // end of switch on action
      break;

    // end of data
    case hexEndOfFile:
      gotEndOfFile = true;
      break;

    // we are setting the high-order byte of the address
    case hexExtendedSegmentAddressRecord:
      extendedAddress = ((unsigned long) hexBuffer ) << 12;
      break;

    // ignore these, who cares?
    case hexStartSegmentAddressRecord:
    case hexExtendedLinearAddressRecord:
    case hexStartLinearAddressRecord:
      break;

    default:
      ShowMessage (MSG_UNKNOWN_RECORD_TYPE);
      return true;
}// end of switch on recType

return false;
} // end of processLine

//------------------------------------------------------------------------------
// returns true if error, false if OK
bool readHexFile (const char * fName, const byte action)
{
const int maxLine = 80;
char buffer;
ifstream sdin (fName);
int lineNumber = 0;
gotEndOfFile = false;
extendedAddress = 0;
errors = 0;
lowestAddress = 0xFFFFFFFF;
//lowestAddress
highestAddress = 0;
bytesWritten = 0;
progressBarCount = 0;

pagesize = currentSignature.pageSize;
pagemask = ~(pagesize - 1);
oldPage = NO_PAGE;

// check for open error
if (!sdin.is_open())
{
    ShowMessage (MSG_CANNOT_OPEN_FILE);
    return true;
}

switch (action)
{
    case checkFile:
      break;

    case verifyFlash:
      break;

    case writeToFlash:
      program (progamEnable, chipErase);   // erase it
      delay (20);// for Atmega8
      pollUntilReady ();
      clearPage();// clear temporary page
      break;
} // end of switch

while (sdin.getline (buffer, maxLine))
{
    lineNumber++;
    int count = sdin.gcount();
    if (sdin.fail())
    {
      ShowMessage (MSG_LINE_TOO_LONG);
      return true;
    }// end of fail (line too long?)

    // ignore empty lines
    if (count > 1)
    {
      if (processLine (buffer, action))
      {
      return true;// error
      }
    }
}    // end of while each line

if (!gotEndOfFile)
{
    ShowMessage (MSG_NO_END_OF_FILE_RECORD);
    return true;
}

switch (action)
{
    case writeToFlash:
      // commit final page
      if (oldPage != NO_PAGE)
      commitPage (oldPage);
      break;

    case verifyFlash:
      if (errors > 0)
      {
      ShowMessage (MSG_VERIFICATION_ERROR);
      return true;
      }// end if
      break;

    case checkFile:
      break;
}// end of switch

return false;
}// end of readHexFile

// returns true if managed to enter programming mode
bool startProgramming ()
{

byte confirm;
pinMode (RESET, OUTPUT);
digitalWrite (MSPIM_SCK, LOW);
pinMode (MSPIM_SCK, OUTPUT);
pinMode (BB_MOSI, OUTPUT);
//pinMode (BB_MISO, INPUT);
unsigned int timeout = 0;

// we are in sync if we get back programAcknowledge on the third byte
do
{
    // regrouping pause
    delay (100);

    // ensure SCK low
    noInterrupts ();
    digitalWrite (MSPIM_SCK, LOW);
    // then pulse reset, see page 309 of datasheet
    digitalWrite (RESET, HIGH);
    delayMicroseconds (10);// pulse for at least 2 clock cycles
    digitalWrite (RESET, LOW);
    interrupts ();

    delay (25);// wait at least 20 mS
    //delay (25);
    noInterrupts ();
    BB_SPITransfer (progamEnable);
    BB_SPITransfer (programAcknowledge);
    confirm = BB_SPITransfer (0);
    BB_SPITransfer (0);
    interrupts ();

    if (confirm != programAcknowledge)
    {
      if (timeout++ >= ENTER_PROGRAMMING_ATTEMPTS)
      return false;
    }// end of not entered programming mode

} while (confirm != programAcknowledge);
return true;// entered programming mode OK
}// end of startProgramming

void stopProgramming ()
{
// turn off pull-ups
digitalWrite (RESET, LOW);
digitalWrite (MSPIM_SCK, LOW);
digitalWrite (BB_MOSI, LOW);
digitalWrite (BB_MISO, LOW);

// set everything back to inputs
pinMode (RESET, INPUT);
pinMode (MSPIM_SCK, INPUT);
pinMode (BB_MOSI, INPUT);
pinMode (BB_MISO, INPUT);

} // end of stopProgramming

void getSignature ()
{
foundSig = -1;
lastAddressMSB = 0;

byte sig ;
// Serial.print (F("Signature = "));




for (byte i = 0; i < 3; i++)
{
    sig = program (readSignatureByte, 0, i);
    //   showHex (sig );
}// end for each signature byte
Serial.println ("");
for (unsigned int j = 0; j < NUMITEMS (signatures); j++)
{
    memcpy_P (&currentSignature, &signatures , sizeof currentSignature);

    if (memcmp (sig, currentSignature.sig, sizeof sig) == 0)
    {
      foundSig = j;
      // make sure extended address is zero to match lastAddressMSB variable
      program (loadExtendedAddressByte, 0, 0);
      return;
    }// end of signature found
}// end of for each signature

ShowMessage (MSG_UNRECOGNIZED_SIGNATURE);
}// end of getSignature

void getFuseBytes ()
{
fuses    = program (readLowFuseByte, readLowFuseByteArg2);
fuses = program (readHighFuseByte, readHighFuseByteArg2);
fuses    = program (readExtendedFuseByte, readExtendedFuseByteArg2);
fuses = program (readLockByte, readLockByteArg2);
fuses = program (readCalibrationByte);

Serial.print (F("LFuse = "));
showHex (fuses , true);
Serial.print (F("HFuse = "));
showHex (fuses , true);
Serial.print (F("EFuse = "));
showHex (fuses , true);
Serial.print (F("Lock byte = "));
showHex (fuses , true);
Serial.print (F("Clock calibration = "));
showHex (fuses , true);

}// end of getFuseBytes


// write specified value to specified fuse/lock byte
void writeFuse (const byte newValue, const byte instruction)
{
//if (newValue == 0)
//    return;// ignore

program (progamEnable, instruction, 0, newValue);
pollUntilReady ();
}// end of writeFuse

// returns true if error, false if OK
bool updateFuses (const bool writeIt)
{
unsigned long addr;
unsigned intlen;

byte fusenumber = currentSignature.fuseWithBootloaderSize;

// if no fuse, can't change it
if (fusenumber == NO_FUSE)
{
    //    ShowMessage (MSG_NO_BOOTLOADER_FUSE);   // maybe this doesn't matter?
    return false;// ok return
}

addr = currentSignature.flashSize;
len = currentSignature.baseBootSize;

if (lowestAddress == 0)
{
    // don't use bootloader
    fuses |= 1;
}
else
{
    byte newval = 0xFF;

    if (lowestAddress == (addr - len))
      newval = 3;
    else if (lowestAddress == (addr - len * 2))
      newval = 2;
    else if (lowestAddress == (addr - len * 4))
      newval = 1;
    else if (lowestAddress == (addr - len * 8))
      newval = 0;
    else
    {
      ShowMessage (MSG_BAD_START_ADDRESS);
      return true;
    }

    if (newval != 0xFF)
    {
      newval <<= 1;
      fuses &= ~0x07;   // also program (clear) "boot into bootloader" bit
      fuses |= newval;
    }// if valid

}// if not address 0

if (writeIt)
{
    writeFuse (fuses , fuseCommands );

}

return false;
}// end of updateFuses

// returns true if error, false if OK
bool chooseInputFile ()
{

if (readHexFile(name, checkFile))
{
    return true;// error, don't attempt to write
}

// check file would fit into device memory
if (highestAddress > currentSignature.flashSize)
{
    ShowMessage (MSG_FILE_TOO_LARGE_FOR_FLASH);
    return true;
}

// check start address makes sense
if (updateFuses (false))
{
    return true;
}

return false;
}// end of chooseInputFile

// returns true if OK, false on error
bool writeFlashContents ()
{

errors = 0;

if (chooseInputFile ())
    return false;


// ensure back in programming mode
if (!startProgramming ())
    return false;

// now commit to flash
if (readHexFile(name, writeToFlash))
    return false;

// turn ready LED on during verification
digitalWrite (readyLED, HIGH);

// verify
if (readHexFile(name, verifyFlash))
    return false;

// now fix up fuses so we can boot
if (errors == 0)
    updateFuses (true);

return errors == 0;
}// end of writeFlashContents

yzw92 发表于 2019-7-31 06:13:47

耗电问题:):):)

wing 发表于 2019-7-31 11:30:01

看上去代码有点长...
另外,这块和耗电有什么关系么?

eddiewwm 发表于 2019-7-31 21:54:16

這是 AVR ATmega328P 的燒寫器,跟耗電沒關係!

活得精彩 发表于 2019-10-17 10:24:03

这个可以作为 LGT328P的编程器使用吗?

eddiewwm 发表于 2019-10-17 11:27:10

活得精彩 发表于 2019-10-17 10:24
这个可以作为 LGT328P的编程器使用吗?

不可以,LGT8F328P 的燒寫方法跟 ATmega328P 不同。
页: [1]
查看完整版本: 8F328U 作基礎的 AVR 燒寫器