Прошить PIC ардуиной

MaksVV
Offline
Зарегистрирован: 06.08.2015

нужно прошить 8-ми лапый Dip  PIC 12F675  .Нашел вот здесь инфу, что можно пик прошить ардуиной .  Там автор выложил скетч для ардуино, схему подключения и программу для прошивки пика ардуиной.  Далее там люди благодарят автора, что у них получилось, значит скетч должен быть рабочий, но у меня почему то не компилируется (файл скетча выложен с расширением *.pde ). Компилятор много чего ругает, мне не понятно. Может кто подскажет, если не сложно. 

/*
 * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define __PROG_TYPES_COMPAT__
#include <avr/pgmspace.h>       // For PROGMEM

// Pin mappings for the PIC programming shield.
#define PIN_MCLR        A1      // 0: MCLR is VPP voltage, 1: Reset PIC
#define PIN_ACTIVITY    A5      // LED that indicates read/write activity
#define PIN_VDD         2       // Controls the power to the PIC
#define PIN_CLOCK       4       // Clock pin
#define PIN_DATA        7       // Data pin

#define MCLR_RESET      HIGH    // PIN_MCLR state to reset the PIC
#define MCLR_VPP        LOW     // PIN_MCLR state to apply 13v to MCLR/VPP pin

// All delays are in microseconds.
#define DELAY_SETTLE    50      // Delay for lines to settle for reset
#define DELAY_TPPDP     5       // Hold time after raising MCLR
#define DELAY_THLD0     5       // Hold time after raising VDD
#define DELAY_TSET1     1       // Data in setup time before lowering clock
#define DELAY_THLD1     1       // Data in hold time after lowering clock
#define DELAY_TDLY2     1       // Delay between commands or data
#define DELAY_TDLY3     1       // Delay until data bit read will be valid
#define DELAY_TPROG     4000    // Time for a program memory write to complete
#define DELAY_TDPROG    6000    // Time for a data memory write to complete
#define DELAY_TERA      6000    // Time for a word erase to complete
#define DELAY_TPROG5    1000    // Time for program write on FLASH5 systems
#define DELAY_TFULLERA  50000   // Time for a full chip erase
#define DELAY_TFULL84   20000   // Intermediate wait for PIC16F84/PIC16F84A

// Commands that may be sent to the device.
#define CMD_LOAD_CONFIG         0x00    // Load (write) to config memory
#define CMD_LOAD_PROGRAM_MEMORY 0x02    // Load to program memory
#define CMD_LOAD_DATA_MEMORY    0x03    // Load to data memory
#define CMD_INCREMENT_ADDRESS   0x06    // Increment the PC
#define CMD_READ_PROGRAM_MEMORY 0x04    // Read from program memory
#define CMD_READ_DATA_MEMORY    0x05    // Read from data memory
#define CMD_BEGIN_PROGRAM       0x08    // Begin programming with erase cycle
#define CMD_BEGIN_PROGRAM_ONLY  0x18    // Begin programming only cycle
#define CMD_END_PROGRAM_ONLY    0x17    // End programming only cycle
#define CMD_BULK_ERASE_PROGRAM  0x09    // Bulk erase program memory
#define CMD_BULK_ERASE_DATA     0x0B    // Bulk erase data memory
#define CMD_CHIP_ERASE          0x1F    // Erase the entire chip

// States this application may be in.
#define STATE_IDLE      0       // Idle, device is held in the reset state
#define STATE_PROGRAM   1       // Active, reading and writing program memory
#define STATE_CONFIG    2       // Active, reading and writing config memory
int state = STATE_IDLE;

// Flash types.  Uses a similar naming system to picprog.
#define EEPROM          0
#define FLASH           1
#define FLASH4          4
#define FLASH5          5

unsigned long pc = 0;           // Current program counter.

// Flat address ranges for the various memory spaces.  Defaults to the values
// for the PIC16F628A.  "DEVICE" command updates to the correct values later.
unsigned long programEnd    = 0x07FF;
unsigned long configStart   = 0x2000;
unsigned long configEnd     = 0x2007;
unsigned long dataStart     = 0x2100;
unsigned long dataEnd       = 0x217F;
unsigned long reservedStart = 0x0800;
unsigned long reservedEnd   = 0x07FF;
unsigned int  configSave    = 0x0000;
byte progFlashType          = FLASH4;
byte dataFlashType          = EEPROM;

// Device names, forced out into PROGMEM.
const char s_pic12f629[]  PROGMEM = "pic12f629";
const char s_pic12f675[]  PROGMEM = "pic12f675";
const char s_pic16f630[]  PROGMEM = "pic16f630";
const char s_pic16f676[]  PROGMEM = "pic16f676";
const char s_pic16f84[]   PROGMEM = "pic16f84";
const char s_pic16f84a[]  PROGMEM = "pic16f84a";
const char s_pic16f87[]   PROGMEM = "pic16f87";
const char s_pic16f88[]   PROGMEM = "pic16f88";
const char s_pic16f627[]  PROGMEM = "pic16f627";
const char s_pic16f627a[] PROGMEM = "pic16f627a";
const char s_pic16f628[]  PROGMEM = "pic16f628";
const char s_pic16f628a[] PROGMEM = "pic16f628a";
const char s_pic16f648a[] PROGMEM = "pic16f648a";
const char s_pic16f882[]  PROGMEM = "pic16f882";
const char s_pic16f883[]  PROGMEM = "pic16f883";
const char s_pic16f884[]  PROGMEM = "pic16f884";
const char s_pic16f886[]  PROGMEM = "pic16f886";
const char s_pic16f887[]  PROGMEM = "pic16f887";

// List of devices that are currently supported and their properties.
// Note: most of these are based on published information and have not
// been tested by the author.  Patches welcome to improve the list.
struct deviceInfo
{
    const prog_char *name;      // User-readable name of the device.
    prog_int16_t deviceId;      // Device ID for the PIC (-1 if no id).
    prog_uint32_t programSize;  // Size of program memory (words).
    prog_uint32_t configStart;  // Flat address start of configuration memory.
    prog_uint32_t dataStart;    // Flat address start of EEPROM data memory.
    prog_uint16_t configSize;   // Number of configuration words.
    prog_uint16_t dataSize;     // Size of EEPROM data memory (bytes).
    prog_uint16_t reservedWords;// Reserved program words (e.g. for OSCCAL).
    prog_uint16_t configSave;   // Bits in config word to be saved.
    prog_uint8_t progFlashType; // Type of flash for program memory.
    prog_uint8_t dataFlashType; // Type of flash for data memory.

};
struct deviceInfo const devices[] PROGMEM = {
    // http://ww1.microchip.com/downloads/en/DeviceDoc/41191D.pdf
    {s_pic12f629,  0x0F80, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
    {s_pic12f675,  0x0FC0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
    {s_pic16f630,  0x10C0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
    {s_pic16f676,  0x10E0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},

    // http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf
    {s_pic16f84,   -1,     1024, 0x2000, 0x2100, 8,  64, 0, 0, FLASH,  EEPROM},
    {s_pic16f84a,  0x0560, 1024, 0x2000, 0x2100, 8,  64, 0, 0, FLASH,  EEPROM},

    // http://ww1.microchip.com/downloads/en/DeviceDoc/39607c.pdf
    {s_pic16f87,   0x0720, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM},
    {s_pic16f88,   0x0760, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM},

    // 627/628:  http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf
    // A series: http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf
    {s_pic16f627,  0x07A0, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH,  EEPROM},
    {s_pic16f627a, 0x1040, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM},
    {s_pic16f628,  0x07C0, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH,  EEPROM},
    {s_pic16f628a, 0x1060, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM},
    {s_pic16f648a, 0x1100, 4096, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM},

    // http://ww1.microchip.com/downloads/en/DeviceDoc/41287D.pdf
    {s_pic16f882,  0x2000, 2048, 0x2000, 0x2100, 9, 128, 0, 0, FLASH4, EEPROM},
    {s_pic16f883,  0x2020, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
    {s_pic16f884,  0x2040, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
    {s_pic16f886,  0x2060, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
    {s_pic16f887,  0x2080, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},

    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

// Buffer for command-line character input and READBIN data packets.
#define BINARY_TRANSFER_MAX 64
#define BUFFER_MAX (BINARY_TRANSFER_MAX + 1)
char buffer[BUFFER_MAX];
int buflen = 0;

unsigned long lastActive = 0;

void setup()
{
    // Need a serial link to the host.
    Serial.begin(9600);

    // Hold the PIC in the powered down/reset state until we are ready for it.
    pinMode(PIN_MCLR, OUTPUT);
    pinMode(PIN_VDD, OUTPUT);
    digitalWrite(PIN_MCLR, MCLR_RESET);
    digitalWrite(PIN_VDD, LOW);

    // Clock and data are floating until the first PIC command.
    pinMode(PIN_CLOCK, INPUT);
    pinMode(PIN_DATA, INPUT);

    // Turn off the activity LED initially.
    pinMode(PIN_ACTIVITY, OUTPUT);
    digitalWrite(PIN_ACTIVITY, LOW);
}

void loop()
{
    if (Serial.available()) {
        // Process serial input for commands from the host.
        int ch = Serial.read();
        if (ch == 0x0A || ch == 0x0D) {
            // End of the current command.  Blank lines are ignored.
            if (buflen > 0) {
                buffer[buflen] = '\0';
                buflen = 0;
                digitalWrite(PIN_ACTIVITY, HIGH);   // Turn on activity LED.
                processCommand(buffer);
                digitalWrite(PIN_ACTIVITY, LOW);    // Turn off activity LED.
            }
        } else if (ch == 0x08) {
            // Backspace over the last character.
            if (buflen > 0)
                --buflen;
        } else if (buflen < (BUFFER_MAX - 1)) {
            // Add the character to the buffer after forcing to upper case.
            if (ch >= 'a' && ch <= 'z')
                buffer[buflen++] = ch - 'a' + 'A';
            else
                buffer[buflen++] = ch;
        }
        lastActive = millis();
    } else if (state != STATE_IDLE) {
        // Power off the programming socket if no activity for 2 seconds.
        // Normally the host will issue the "PWROFF" command, but if we are
        // operating in interactive mode or the host has crashed, then this
        // timeout will ensure that the system eventually enters safe mode.
        if ((millis() - lastActive) >= 2000)
            exitProgramMode();
    }
}

void printHex1(unsigned int value)
{
    if (value >= 10)
        Serial.print((char)('A' + value - 10));
    else
        Serial.print((char)('0' + value));
}

void printHex4(unsigned int word)
{
    printHex1((word >> 12) & 0x0F);
    printHex1((word >> 8) & 0x0F);
    printHex1((word >> 4) & 0x0F);
    printHex1(word & 0x0F);
}

void printHex8(unsigned long word)
{
    unsigned int upper = (unsigned int)(word >> 16);
    if (upper)
        printHex4(upper);
    printHex4((unsigned int)word);
}

void printProgString(const prog_char *str)
{
    for (;;) {
        char ch = (char)(pgm_read_byte(str));
        if (ch == '\0')
            break;
        Serial.print(ch);
        ++str;
    }
}

// PROGRAM_PIC_VERSION command.
void cmdVersion(const char *args)
{
    Serial.println("ProgramPIC 1.0");
}

// Initialize device properties from the "devices" list and
// print them to the serial port.  Note: "dev" is in PROGMEM.
void initDevice(const struct deviceInfo *dev)
{
    // Update the global device details.
    programEnd = pgm_read_dword(&(dev->programSize)) - 1;
    configStart = pgm_read_dword(&(dev->configStart));
    configEnd = configStart + pgm_read_word(&(dev->configSize)) - 1;
    dataStart = pgm_read_dword(&(dev->dataStart));
    dataEnd = dataStart + pgm_read_word(&(dev->dataSize)) - 1;
    reservedStart = programEnd - pgm_read_word(&(dev->reservedWords)) + 1;
    reservedEnd = programEnd;
    configSave = pgm_read_word(&(dev->configSave));
    progFlashType = pgm_read_byte(&(dev->progFlashType));
    dataFlashType = pgm_read_byte(&(dev->dataFlashType));

    // Print the extra device information.
    Serial.print("DeviceName: ");
    printProgString((const prog_char *)(pgm_read_word(&(dev->name))));
    Serial.println();
    Serial.print("ProgramRange: 0000-");
    printHex8(programEnd);
    Serial.println();
    Serial.print("ConfigRange: ");
    printHex8(configStart);
    Serial.print('-');
    printHex8(configEnd);
    Serial.println();
    if (configSave != 0) {
        Serial.print("ConfigSave: ");
        printHex4(configSave);
        Serial.println();
    }
    Serial.print("DataRange: ");
    printHex8(dataStart);
    Serial.print('-');
    printHex8(dataEnd);
    Serial.println();
    if (reservedStart <= reservedEnd) {
        Serial.print("ReservedRange: ");
        printHex8(reservedStart);
        Serial.print('-');
        printHex8(reservedEnd);
        Serial.println();
    }
}

// Offsets of interesting config locations that contain device information.
#define DEV_USERID0         0
#define DEV_USERID1         1
#define DEV_USERID2         2
#define DEV_USERID3         3
#define DEV_ID              6
#define DEV_CONFIG_WORD     7

// DEVICE command.
void cmdDevice(const char *args)
{
    // Make sure the device is reset before we start.
    exitProgramMode();

    // Read identifiers and configuration words from config memory.
    unsigned int userid0 = readConfigWord(DEV_USERID0);
    unsigned int userid1 = readConfigWord(DEV_USERID1);
    unsigned int userid2 = readConfigWord(DEV_USERID2);
    unsigned int userid3 = readConfigWord(DEV_USERID3);
    unsigned int deviceId = readConfigWord(DEV_ID);
    unsigned int configWord = readConfigWord(DEV_CONFIG_WORD);

    // If the device ID is all-zeroes or all-ones, then it could mean
    // one of the following:
    //
    // 1. There is no PIC in the programming socket.
    // 2. The VPP programming voltage is not available.
    // 3. Code protection is enabled and the PIC is unreadable.
    // 4. The PIC is an older model with no device identifier.
    //
    // Case 4 is the interesting one.  We look for any word in configuration
    // memory or the first 16 words of program memory that is non-zero.
    // If we find a non-zero word, we assume that we have a PIC but we
    // cannot detect what type it is.
    if (deviceId == 0 || deviceId == 0x3FFF) {
        unsigned int word = userid0 | userid1 | userid2 | userid3 | configWord;
        unsigned int addr = 0;
        while (!word && addr < 16) {
            word |= readWord(addr);
            ++addr;
        }
        if (!word) {
            Serial.println("ERROR");
            exitProgramMode();
            return;
        }
        deviceId = 0;
    }

    Serial.println("OK");

    Serial.print("DeviceID: ");
    printHex4(deviceId);
    Serial.println();

    // Find the device in the built-in list if we have details for it.
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(devices[index].name)));
        if (!name) {
            index = -1;
            break;
        }
        int id = pgm_read_word(&(devices[index].deviceId));
        if (id == (deviceId & 0xFFE0))
            break;
        ++index;
    }
    if (index >= 0) {
        initDevice(&(devices[index]));
    } else {
        // Reset the global parameters to their defaults.  A separate
        // "SETDEVICE" command will be needed to set the correct values.
        programEnd    = 0x07FF;
        configStart   = 0x2000;
        configEnd     = 0x2007;
        dataStart     = 0x2100;
        dataEnd       = 0x217F;
        reservedStart = 0x0800;
        reservedEnd   = 0x07FF;
        configSave    = 0x0000;
        progFlashType = FLASH4;
        dataFlashType = EEPROM;
    }

    Serial.print("ConfigWord: ");
    printHex4(configWord);
    Serial.println();

    Serial.println(".");

    // Don't need programming mode once the details have been read.
    exitProgramMode();
}

// DEVICES command.
void cmdDevices(const char *args)
{
    Serial.println("OK");
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(devices[index].name)));
        if (!name)
            break;
        if (index > 0) {
            Serial.print(',');
            if ((index % 6) == 0)
                Serial.println();
            else
                Serial.print(' ');
        }
        printProgString(name);
        int id = (int)(pgm_read_word(&(devices[index].deviceId)));
        if (id != -1)
            Serial.print('*');
        ++index;
    }
    Serial.println();
    Serial.println(".");
}

// SETDEVICE command.
void cmdSetDevice(const char *args)
{
    // Extract the name of the device from the command arguments.
    int len = 0;
    for (;;) {
        char ch = args[len];
        if (ch == '\0' || ch == ' ' || ch == '\t')
            break;
        ++len;
    }

    // Look for the name in the devices list.
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(devices[index].name)));
        if (!name)
            break;
        if (matchString(name, args, len)) {
            Serial.println("OK");
            initDevice(&(devices[index]));
            Serial.println(".");
            exitProgramMode(); // Force a reset upon the next command.
            return;
        }
        ++index;
    }
    Serial.println("ERROR");
}

int parseHex(const char *args, unsigned long *value)
{
    int size = 0;
    *value = 0;
    for (;;) {
        char ch = *args;
        if (ch >= '0' && ch <= '9')
            *value = (*value << 4) | (ch - '0');
        else if (ch >= 'A' && ch <= 'F')
            *value = (*value << 4) | (ch - 'A' + 10);
        else if (ch >= 'a' && ch <= 'f')
            *value = (*value << 4) | (ch - 'a' + 10);
        else
            break;
        ++size;
        ++args;
    }
    if (*args != '\0' && *args != '-' && *args != ' ' && *args != '\t')
        return 0;
    return size;
}

// Parse a range of addresses of the form START or START-END.
bool parseRange(const char *args, unsigned long *start, unsigned long *end)
{
    int size = parseHex(args, start);
    if (!size)
        return false;
    args += size;
    while (*args == ' ' || *args == '\t')
        ++args;
    if (*args != '-') {
        *end = *start;
        return true;
    }
    ++args;
    while (*args == ' ' || *args == '\t')
        ++args;
    if (!parseHex(args, end))
        return false;
    return *end >= *start;
}

bool parseCheckedRange(const char *args, unsigned long *start, unsigned long *end)
{
    // Parse the basic values and make sure that start <= end.
    if (!parseRange(args, start, end))
        return false;

    // Check that both start and end are within the same memory area
    // and within the bounds of that memory area.
    if (*start <= programEnd) {
        if (*end > programEnd)
            return false;
    } else if (*start >= configStart && *start <= configEnd) {
        if (*end < configStart || *end > configEnd)
            return false;
    } else if (*start >= dataStart && *start <= dataEnd) {
        if (*end < dataStart || *end > dataEnd)
            return false;
    } else {
        return false;
    }
    return true;
}

// READ command.
void cmdRead(const char *args)
{
    unsigned long start;
    unsigned long end;
    if (!parseCheckedRange(args, &start, &end)) {
        Serial.println("ERROR");
        return;
    }
    Serial.println("OK");
    int count = 0;
    bool activity = true;
    while (start <= end) {
        unsigned int word = readWord(start);
        if (count > 0) {
            if ((count % 8) == 0)
                Serial.println();
            else
                Serial.print(' ');
        }
        printHex4(word);
        ++start;
        ++count;
        if ((count % 32) == 0) {
            // Toggle the activity LED to make it blink during long reads.
            activity = !activity;
            if (activity)
                digitalWrite(PIN_ACTIVITY, HIGH);
            else
                digitalWrite(PIN_ACTIVITY, LOW);
        }
    }
    Serial.println();
    Serial.println(".");
}

// READBIN command.
void cmdReadBinary(const char *args)
{
    unsigned long start;
    unsigned long end;
    if (!parseCheckedRange(args, &start, &end)) {
        Serial.println("ERROR");
        return;
    }
    Serial.println("OK");
    int count = 0;
    bool activity = true;
    size_t offset = 0;
    while (start <= end) {
        unsigned int word = readWord(start);
        buffer[++offset] = (char)word;
        buffer[++offset] = (char)(word >> 8);
        if (offset >= BINARY_TRANSFER_MAX) {
            // Buffer is full - flush it to the host.
            buffer[0] = (char)offset;
            Serial.write((const uint8_t *)buffer, offset + 1);
            offset = 0;
        }
        ++start;
        ++count;
        if ((count % 64) == 0) {
            // Toggle the activity LED to make it blink during long reads.
            activity = !activity;
            if (activity)
                digitalWrite(PIN_ACTIVITY, HIGH);
            else
                digitalWrite(PIN_ACTIVITY, LOW);
        }
    }
    if (offset > 0) {
        // Flush the final packet before the terminator.
        buffer[0] = (char)offset;
        Serial.write((const uint8_t *)buffer, offset + 1);
    }
    // Write the terminator (a zero-length packet).
    Serial.write((uint8_t)0x00);
}

const char s_force[] PROGMEM = "FORCE";

// WRITE command.
void cmdWrite(const char *args)
{
    unsigned long addr;
    unsigned long limit;
    unsigned long value;
    int size;

    // Was the "FORCE" option given?
    int len = 0;
    while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
        ++len;
    bool force = matchString(s_force, args, len);
    if (force) {
        args += len;
        while (*args == ' ' || *args == '\t')
            ++args;
    }

    size = parseHex(args, &addr);
    if (!size) {
        Serial.println("ERROR");
        return;
    }
    args += size;
    if (addr <= programEnd) {
        limit = programEnd;
    } else if (addr >= configStart && addr <= configEnd) {
        limit = configEnd;
    } else if (addr >= dataStart && addr <= dataEnd) {
        limit = dataEnd;
    } else {
        // Address is not within one of the valid ranges.
        Serial.println("ERROR");
        return;
    }
    int count = 0;
    for (;;) {
        while (*args == ' ' || *args == '\t')
            ++args;
        if (*args == '\0')
            break;
        if (*args == '-') {
            Serial.println("ERROR");
            return;
        }
        size = parseHex(args, &value);
        if (!size) {
            Serial.println("ERROR");
            return;
        }
        args += size;
        if (addr > limit) {
            // We've reached the limit of this memory area, so fail.
            Serial.println("ERROR");
            return;
        }
        if (!force) {
            if (!writeWord(addr, (unsigned int)value)) {
                // The actual write to the device failed.
                Serial.println("ERROR");
                return;
            }
        } else {
            if (!writeWordForced(addr, (unsigned int)value)) {
                // The actual write to the device failed.
                Serial.println("ERROR");
                return;
            }
        }
        ++addr;
        ++count;
    }
    if (!count) {
        // Missing word argument.
        Serial.println("ERROR");
    } else {
        Serial.println("OK");
    }
}

// Blocking serial read for use by WRITEBIN.
int readBlocking()
{
    while (!Serial.available())
        ;   // Do nothing.
    return Serial.read();
}

// WRITEBIN command.
void cmdWriteBinary(const char *args)
{
    unsigned long addr;
    unsigned long limit;
    int size;

    // Was the "FORCE" option given?
    int len = 0;
    while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
        ++len;
    bool force = matchString(s_force, args, len);
    if (force) {
        args += len;
        while (*args == ' ' || *args == '\t')
            ++args;
    }

    size = parseHex(args, &addr);
    if (!size) {
        Serial.println("ERROR");
        return;
    }
    args += size;
    if (addr <= programEnd) {
        limit = programEnd;
    } else if (addr >= configStart && addr <= configEnd) {
        limit = configEnd;
    } else if (addr >= dataStart && addr <= dataEnd) {
        limit = dataEnd;
    } else {
        // Address is not within one of the valid ranges.
        Serial.println("ERROR");
        return;
    }
    Serial.println("OK");
    int count = 0;
    bool activity = true;
    for (;;) {
        // Read in the next binary packet.
        int len = readBlocking();
        while (len == 0x0A && count == 0) {
            // Skip 0x0A bytes before the first packet as they are
            // probably part of a CRLF pair rather than a packet length.
            len = readBlocking();
        }

        // Stop if we have a zero packet length - end of upload.
        if (!len)
            break;

        // Read the contents of the packet from the serial input stream.
        int offset = 0;
        while (offset < len) {
            if (offset < BINARY_TRANSFER_MAX) {
                buffer[offset++] = (char)readBlocking();
            } else {
                readBlocking();     // Packet is too big - discard extra bytes.
                ++offset;
            }
        }

        // Write the words to memory.
        for (int posn = 0; posn < (len - 1); posn += 2) {
            if (addr > limit) {
                // We've reached the limit of this memory area, so fail.
                Serial.println("ERROR");
                return;
            }
            unsigned int value =
                (((unsigned int)buffer[posn]) & 0xFF) |
                ((((unsigned int)buffer[posn + 1]) & 0xFF) << 8);
            if (!force) {
                if (!writeWord(addr, (unsigned int)value)) {
                    // The actual write to the device failed.
                    Serial.println("ERROR");
                    return;
                }
            } else {
                if (!writeWordForced(addr, (unsigned int)value)) {
                    // The actual write to the device failed.
                    Serial.println("ERROR");
                    return;
                }
            }
            ++addr;
            ++count;
            if ((count % 24) == 0) {
                // Toggle the activity LED to make it blink during long writes.
                activity = !activity;
                if (activity)
                    digitalWrite(PIN_ACTIVITY, HIGH);
                else
                    digitalWrite(PIN_ACTIVITY, LOW);
            }
        }

        // All words in this packet have been written successfully.
        Serial.println("OK");
    }
    Serial.println("OK");
}

const char s_noPreserve[] PROGMEM = "NOPRESERVE";

// ERASE command.
void cmdErase(const char *args)
{
    // Was the "NOPRESERVE" option given?
    int len = 0;
    while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
        ++len;
    bool preserve = !matchString(s_noPreserve, args, len);

    // Preserve reserved words if necessary.
    unsigned int *reserved = 0;
    unsigned int configWord = 0x3FFF;
    if (preserve && reservedStart <= reservedEnd) {
        size_t size = ((size_t)(reservedEnd - reservedStart + 1))
            * sizeof(unsigned int);
        reserved = (unsigned int *)malloc(size);
        if (reserved) {
            unsigned long addr = reservedStart;
            int offset = 0;
            while (addr <= reservedEnd) {
                reserved[offset] = readWord(addr);
                ++addr;
                ++offset;
            }
        } else {
            // If we cannot preserve the reserved words, then abort now.
            Serial.println("ERROR");
            return;
        }
    }
    if (configSave != 0 && preserve) {
        // Some of the bits in the configuration word must also be saved.
        configWord &= ~configSave;
        configWord |= readWord(configStart + DEV_CONFIG_WORD) & configSave;
    }

    // Perform the memory type specific erase sequence.
    switch (progFlashType) {
    case FLASH4:
        setErasePC();
        sendSimpleCommand(CMD_BULK_ERASE_PROGRAM);
        delayMicroseconds(DELAY_TERA);
        sendSimpleCommand(CMD_BULK_ERASE_DATA);
        break;
    case FLASH5:
        setErasePC();
        sendSimpleCommand(CMD_CHIP_ERASE);
        break;
    default:
        // Details for disabling code protection and erasing all memory
        // for PIC16F84/PIC16F84A comes from this doc, section 4.1:
        // http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf
        setErasePC();
        for (int count = 0; count < 7; ++count)
            sendSimpleCommand(CMD_INCREMENT_ADDRESS); // Advance to 0x2007
        sendSimpleCommand(0x01);    // Command 1
        sendSimpleCommand(0x07);    // Command 7
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        delayMicroseconds(DELAY_TFULL84);
        sendSimpleCommand(0x01);    // Command 1
        sendSimpleCommand(0x07);    // Command 7

        // Some FLASH devices need the data memory to be erased separately.
        sendWriteCommand(CMD_LOAD_DATA_MEMORY, 0x3FFF);
        sendSimpleCommand(CMD_BULK_ERASE_DATA);
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        break;
    }

    // Wait until the chip is fully erased.
    delayMicroseconds(DELAY_TFULLERA);

    // Force the device to reset after it has been erased.
    exitProgramMode();
    enterProgramMode();

    // Write the reserved words back to program memory.
    if (reserved) {
        unsigned long addr = reservedStart;
        int offset = 0;
        bool ok = true;
        while (addr <= reservedEnd) {
            if (!writeWord(addr, reserved[offset]))
                ok = false;
            ++addr;
            ++offset;
        }
        free(reserved);
        if (!ok) {
            // Reserved words did not read back correctly.
            Serial.println("ERROR");
            return;
        }
    }

    // Forcibly write 0x3FFF over the configuration words as erase
    // sometimes won't reset the words (e.g. PIC16F628A).  If the
    // write fails, then leave the words as-is - don't report the failure.
    for (unsigned long configAddr = configStart + DEV_CONFIG_WORD;
            configAddr <= configEnd; ++configAddr)
        writeWordForced(configAddr, configWord);

    // Done.
    Serial.println("OK");
}

// PWROFF command.
void cmdPowerOff(const char *args)
{
    exitProgramMode();
    Serial.println("OK");
}

// List of all commands that are understood by the programmer.
typedef void (*commandFunc)(const char *args);
typedef struct
{
    const prog_char *name;
    commandFunc func;
    const prog_char *desc;
    const prog_char *args;
} command_t;
const char s_cmdRead[] PROGMEM = "READ";
const char s_cmdReadDesc[] PROGMEM =
    "Reads program and data words from device memory (text)";
const char s_cmdReadArgs[] PROGMEM = "STARTADDR[-ENDADDR]";
const char s_cmdReadBinary[] PROGMEM = "READBIN";
const char s_cmdReadBinaryDesc[] PROGMEM =
    "Reads program and data words from device memory (binary)";
const char s_cmdWrite[] PROGMEM = "WRITE";
const char s_cmdWriteDesc[] PROGMEM =
    "Writes program and data words to device memory (text)";
const char s_cmdWriteArgs[] PROGMEM = "STARTADDR WORD [WORD ...]";
const char s_cmdWriteBinary[] PROGMEM = "WRITEBIN";
const char s_cmdWriteBinaryDesc[] PROGMEM =
    "Writes program and data words to device memory (binary)";
const char s_cmdWriteBinaryArgs[] PROGMEM = "STARTADDR";
const char s_cmdErase[] PROGMEM = "ERASE";
const char s_cmdEraseDesc[] PROGMEM =
    "Erases the contents of program, configuration, and data memory";
const char s_cmdDevice[] PROGMEM = "DEVICE";
const char s_cmdDeviceDesc[] PROGMEM =
    "Probes the device and returns information about it";
const char s_cmdDevices[] PROGMEM = "DEVICES";
const char s_cmdDevicesDesc[] PROGMEM =
    "Returns a list of all supported device types";
const char s_cmdSetDevice[] PROGMEM = "SETDEVICE";
const char s_cmdSetDeviceDesc[] PROGMEM =
    "Sets a specific device type manually";
const char s_cmdSetDeviceArgs[] PROGMEM = "DEVTYPE";
const char s_cmdPowerOff[] PROGMEM = "PWROFF";
const char s_cmdPowerOffDesc[] PROGMEM =
    "Powers off the device in the programming socket";
const char s_cmdVersion[] PROGMEM = "PROGRAM_PIC_VERSION";
const char s_cmdVersionDesc[] PROGMEM =
    "Prints the version of ProgramPIC";
const char s_cmdHelp[] PROGMEM = "HELP";
const char s_cmdHelpDesc[] PROGMEM =
    "Prints this help message";
const command_t commands[] PROGMEM = {
    {s_cmdRead, cmdRead, s_cmdReadDesc, s_cmdReadArgs},
    {s_cmdReadBinary, cmdReadBinary, s_cmdReadBinaryDesc, s_cmdReadArgs},
    {s_cmdWrite, cmdWrite, s_cmdWriteDesc, s_cmdWriteArgs},
    {s_cmdWriteBinary, cmdWriteBinary, s_cmdWriteBinaryDesc, s_cmdWriteBinaryArgs},
    {s_cmdErase, cmdErase, s_cmdEraseDesc, 0},
    {s_cmdDevice, cmdDevice, s_cmdDeviceDesc, 0},
    {s_cmdDevices, cmdDevices, s_cmdDevicesDesc, 0},
    {s_cmdSetDevice, cmdSetDevice, s_cmdSetDeviceDesc, s_cmdSetDeviceArgs},
    {s_cmdPowerOff, cmdPowerOff, s_cmdPowerOffDesc, 0},
    {s_cmdVersion, cmdVersion, s_cmdVersionDesc, 0},
    {s_cmdHelp, cmdHelp, s_cmdHelpDesc, 0},
    {0, 0}
};

// "HELP" command.
void cmdHelp(const char *args)
{
    Serial.println("OK");
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(commands[index].name)));
        if (!name)
            break;
        const prog_char *desc = (const prog_char *)
            (pgm_read_word(&(commands[index].desc)));
        const prog_char *args = (const prog_char *)
            (pgm_read_word(&(commands[index].args)));
        printProgString(name);
        if (args) {
            Serial.print(' ');
            printProgString(args);
        }
        Serial.println();
        Serial.print("    ");
        printProgString(desc);
        Serial.println();
        ++index;
    }
    Serial.println(".");
}

// Match a data-space string where the name comes from PROGMEM.
bool matchString(const prog_char *name, const char *str, int len)
{
    for (;;) {
        char ch1 = (char)(pgm_read_byte(name));
        if (ch1 == '\0')
            return len == 0;
        else if (len == 0)
            break;
        if (ch1 >= 'a' && ch1 <= 'z')
            ch1 = ch1 - 'a' + 'A';
        char ch2 = *str;
        if (ch2 >= 'a' && ch2 <= 'z')
            ch2 = ch2 - 'a' + 'A';
        if (ch1 != ch2)
            break;
        ++name;
        ++str;
        --len;
    }
    return false;
}

// Process commands from the host.
void processCommand(const char *buf)
{
    // Skip white space at the start of the command.
    while (*buf == ' ' || *buf == '\t')
        ++buf;
    if (*buf == '\0')
        return;     // Ignore blank lines.

    // Extract the command portion of the line.
    const char *cmd = buf;
    int len = 0;
    for (;;) {
        char ch = *buf;
        if (ch == '\0' || ch == ' ' || ch == '\t')
            break;
        ++buf;
        ++len;
    }

    // Skip white space after the command name and before the arguments.
    while (*buf == ' ' || *buf == '\t')
        ++buf;

    // Find the command and execute it.
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(commands[index].name)));
        if (!name)
            break;
        if (matchString(name, cmd, len)) {
            commandFunc func =
                (commandFunc)(pgm_read_word(&(commands[index].func)));
            (*func)(buf);
            return;
        }
        ++index;
    }

    // Unknown command.
    Serial.println("NOTSUPPORTED");
}

// Enter high voltage programming mode.
void enterProgramMode()
{
    // Bail out if already in programming mode.
    if (state != STATE_IDLE)
        return;

    // Lower MCLR, VDD, DATA, and CLOCK initially.  This will put the
    // PIC into the powered-off, reset state just in case.
    digitalWrite(PIN_MCLR, MCLR_RESET);
    digitalWrite(PIN_VDD, LOW);
    digitalWrite(PIN_DATA, LOW);
    digitalWrite(PIN_CLOCK, LOW);

    // Wait for the lines to settle.
    delayMicroseconds(DELAY_SETTLE);

    // Switch DATA and CLOCK into outputs.
    pinMode(PIN_DATA, OUTPUT);
    pinMode(PIN_CLOCK, OUTPUT);

    // Raise MCLR, then VDD.
    digitalWrite(PIN_MCLR, MCLR_VPP);
    delayMicroseconds(DELAY_TPPDP);
    digitalWrite(PIN_VDD, HIGH);
    delayMicroseconds(DELAY_THLD0);

    // Now in program mode, starting at the first word of program memory.
    state = STATE_PROGRAM;
    pc = 0;
}

// Exit programming mode and reset the device.
void exitProgramMode()
{
    // Nothing to do if already out of programming mode.
    if (state == STATE_IDLE)
        return;

    // Lower MCLR, VDD, DATA, and CLOCK.
    digitalWrite(PIN_MCLR, MCLR_RESET);
    digitalWrite(PIN_VDD, LOW);
    digitalWrite(PIN_DATA, LOW);
    digitalWrite(PIN_CLOCK, LOW);

    // Float the DATA and CLOCK pins.
    pinMode(PIN_DATA, INPUT);
    pinMode(PIN_CLOCK, INPUT);

    // Now in the idle state with the PIC powered off.
    state = STATE_IDLE;
    pc = 0;
}

// Send a command to the PIC.
void sendCommand(byte cmd)
{
    for (byte bit = 0; bit < 6; ++bit) {
        digitalWrite(PIN_CLOCK, HIGH);
        if (cmd & 1)
            digitalWrite(PIN_DATA, HIGH);
        else
            digitalWrite(PIN_DATA, LOW);
        delayMicroseconds(DELAY_TSET1);
        digitalWrite(PIN_CLOCK, LOW);
        delayMicroseconds(DELAY_THLD1);
        cmd >>= 1;
    }
}

// Send a command to the PIC that has no arguments.
void sendSimpleCommand(byte cmd)
{
    sendCommand(cmd);
    delayMicroseconds(DELAY_TDLY2);
}

// Send a command to the PIC that writes a data argument.
void sendWriteCommand(byte cmd, unsigned int data)
{
    sendCommand(cmd);
    delayMicroseconds(DELAY_TDLY2);
    for (byte bit = 0; bit < 16; ++bit) {
        digitalWrite(PIN_CLOCK, HIGH);
        if (data & 1)
            digitalWrite(PIN_DATA, HIGH);
        else
            digitalWrite(PIN_DATA, LOW);
        delayMicroseconds(DELAY_TSET1);
        digitalWrite(PIN_CLOCK, LOW);
        delayMicroseconds(DELAY_THLD1);
        data >>= 1;
    }
    delayMicroseconds(DELAY_TDLY2);
}

// Send a command to the PIC that reads back a data value.
unsigned int sendReadCommand(byte cmd)
{
    unsigned int data = 0;
    sendCommand(cmd);
    digitalWrite(PIN_DATA, LOW);
    pinMode(PIN_DATA, INPUT);
    delayMicroseconds(DELAY_TDLY2);
    for (byte bit = 0; bit < 16; ++bit) {
        data >>= 1;
        digitalWrite(PIN_CLOCK, HIGH);
        delayMicroseconds(DELAY_TDLY3);
        if (digitalRead(PIN_DATA))
            data |= 0x8000;
        digitalWrite(PIN_CLOCK, LOW);
        delayMicroseconds(DELAY_THLD1);
    }
    pinMode(PIN_DATA, OUTPUT);
    delayMicroseconds(DELAY_TDLY2);
    return data;
}

// Set the program counter to a specific "flat" address.
void setPC(unsigned long addr)
{
    if (addr >= dataStart && addr <= dataEnd) {
        // Data memory.
        addr -= dataStart;
        if (state != STATE_PROGRAM || addr < pc) {
            // Device is off, currently looking at configuration memory,
            // or the address is further back.  Reset the device.
            exitProgramMode();
            enterProgramMode();
        }
    } else if (addr >= configStart && addr <= configEnd) {
        // Configuration memory.
        addr -= configStart;
        if (state == STATE_IDLE) {
            // Enter programming mode and switch to config memory.
            enterProgramMode();
            sendWriteCommand(CMD_LOAD_CONFIG, 0);
            state = STATE_CONFIG;
        } else if (state == STATE_PROGRAM) {
            // Switch from program memory to config memory.
            sendWriteCommand(CMD_LOAD_CONFIG, 0);
            state = STATE_CONFIG;
            pc = 0;
        } else if (addr < pc) {
            // Need to go backwards in config memory, so reset the device.
            exitProgramMode();
            enterProgramMode();
            sendWriteCommand(CMD_LOAD_CONFIG, 0);
            state = STATE_CONFIG;
        }
    } else {
        // Program memory.
        if (state != STATE_PROGRAM || addr < pc) {
            // Device is off, currently looking at configuration memory,
            // or the address is further back.  Reset the device.
            exitProgramMode();
            enterProgramMode();
        }
    }
    while (pc < addr) {
        sendSimpleCommand(CMD_INCREMENT_ADDRESS);
        ++pc;
    }
}

// Sets the PC for "erase mode", which is activated by loading the
// data value 0x3FFF into location 0 of configuration memory.
void setErasePC()
{
    // Forcibly reset the device so we know what state it is in.
    exitProgramMode();
    enterProgramMode();

    // Load 0x3FFF for the configuration.
    sendWriteCommand(CMD_LOAD_CONFIG, 0x3FFF);
    state = STATE_CONFIG;
}

// Read a word from memory (program, config, or data depending upon addr).
// The start and stop bits will be stripped from the raw value from the PIC.
unsigned int readWord(unsigned long addr)
{
    setPC(addr);
    if (addr >= dataStart && addr <= dataEnd)
        return (sendReadCommand(CMD_READ_DATA_MEMORY) >> 1) & 0x00FF;
    else
        return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
}

// Read a word from config memory using relative, non-flat, addressing.
// Used by the "DEVICE" command to fetch information about devices whose
// flat address ranges are presently unknown.
unsigned int readConfigWord(unsigned long addr)
{
    if (state == STATE_IDLE) {
        // Enter programming mode and switch to config memory.
        enterProgramMode();
        sendWriteCommand(CMD_LOAD_CONFIG, 0);
        state = STATE_CONFIG;
    } else if (state == STATE_PROGRAM) {
        // Switch from program memory to config memory.
        sendWriteCommand(CMD_LOAD_CONFIG, 0);
        state = STATE_CONFIG;
        pc = 0;
    } else if (addr < pc) {
        // Need to go backwards in config memory, so reset the device.
        exitProgramMode();
        enterProgramMode();
        sendWriteCommand(CMD_LOAD_CONFIG, 0);
        state = STATE_CONFIG;
    }
    while (pc < addr) {
        sendSimpleCommand(CMD_INCREMENT_ADDRESS);
        ++pc;
    }
    return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
}

// Begin a programming cycle, depending upon the type of flash being written.
void beginProgramCycle(unsigned long addr, bool isData)
{
    switch (isData ? dataFlashType : progFlashType) {
    case FLASH:
    case EEPROM:
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        delayMicroseconds(DELAY_TDPROG + DELAY_TERA);
        break;
    case FLASH4:
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        delayMicroseconds(DELAY_TPROG);
        break;
    case FLASH5:
        sendSimpleCommand(CMD_BEGIN_PROGRAM_ONLY);
        delayMicroseconds(DELAY_TPROG5);
        sendSimpleCommand(CMD_END_PROGRAM_ONLY);
        break;
    }
}

// Write a word to memory (program, config, or data depending upon addr).
// Returns true if the write succeeded, false if read-back failed to match.
bool writeWord(unsigned long addr, unsigned int word)
{
    unsigned int readBack;
    setPC(addr);
    if (addr >= dataStart && addr <= dataEnd) {
        word &= 0x00FF;
        sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
        beginProgramCycle(addr, true);
        readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
        readBack = (readBack >> 1) & 0x00FF;
    } else if (!configSave || addr != (configStart + DEV_CONFIG_WORD)) {
        word &= 0x3FFF;
        sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
        beginProgramCycle(addr, false);
        readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
        readBack = (readBack >> 1) & 0x3FFF;
    } else {
        // The configuration word has calibration bits within it that
        // must be preserved when we write to it.  Read the current value
        // and preserve the necessary bits.
        readBack = (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
        word = (readBack & configSave) | (word & 0x3FFF & ~configSave);
        sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
        beginProgramCycle(addr, false);
        readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
        readBack = (readBack >> 1) & 0x3FFF;
    }
    return readBack == word;
}

// Force a word to be written even if it normally would protect config bits.
bool writeWordForced(unsigned long addr, unsigned int word)
{
    unsigned int readBack;
    setPC(addr);
    if (addr >= dataStart && addr <= dataEnd) {
        word &= 0x00FF;
        sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
        beginProgramCycle(addr, true);
        readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
        readBack = (readBack >> 1) & 0x00FF;
    } else {
        word &= 0x3FFF;
        sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
        beginProgramCycle(addr, false);
        readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
        readBack = (readBack >> 1) & 0x3FFF;
    }
    return readBack == word;
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

создал тему, пока качалась версия IDE 1.0.5. На ней скомпилировалось. Если удастся залить hex в пик при помощи дуни, отпишусь

MaksVV
Offline
Зарегистрирован: 06.08.2015

собрал всё по схеме - ВСЁ работает!!! Загрузил блинк

 

схема

b707
Offline
Зарегистрирован: 26.05.2017

MaksVV - просто интересно - а зачем в наше время нужны ПИКи? - они ж во всем сливают соответствующим  АВР-кам

d13lider
d13lider аватар
Offline
Зарегистрирован: 19.10.2015

у меня от дядьки осталось вагон пиков)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

b707, знаю как минимум одну фишку, которой нет в AVR.   -у PICов есть асинхронный счётчик, и он может считать импульсы с частотами сильно выше собственной тактовой. Поэтому всё мало-мальски серьёзные частотометры делают на пиках. Ещё на некоторые популярные пики есть полностью переведённый на русский даташит, мелочь как грится, но приятно)

MaksVV
Offline
Зарегистрирован: 06.08.2015

просто есть готовое устройство к повторению. Я бы с радостью переделал на AVR, но исходник никто не выложил. Я и так полгода собирался его сделать, только пик и останавливал)) Вот щас плату делаю. FTDI учиться паять надо, мелко всё это, однако, для ЛУТ.

MaksVV
Offline
Зарегистрирован: 06.08.2015

это адаптер для диагностики подогревателей Eberspacher. 

b707
Offline
Зарегистрирован: 26.05.2017

MaksVV пишет:

просто есть готовое устройство к повторению.

ну да, я так и предполагал. Для Пиков можно найти кучу полезных прошивок в инете...

И если что - я не наезжаю на ПИК. спросил именно из любопытства :)

vsrgv
Offline
Зарегистрирован: 20.06.2017

MaksVV пишет:

собрал всё по схеме - ВСЁ работает!!! Загрузил блинк

 

схема

подключаю как написано в скетче, ничего не происходит, помоги пожалуйста, не могу ответ найти второй вечер

MaksVV
Offline
Зарегистрирован: 06.08.2015

что не происходит. программа горит зелёным? сом или connect? внимательнее проверьте схему подключения 

vsrgv
Offline
Зарегистрирован: 20.06.2017

13 вольт через транзистор нужно?

MaksVV
Offline
Зарегистрирован: 06.08.2015

я 12 подавал, да, через транзистор. Светодиод не подключал. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

схема вроде как такая должна быть. 

vsrgv
Offline
Зарегистрирован: 20.06.2017

Спасибо, уже понижайку настроил от ноутбучного блока питания, вечером попробую.

vsrgv
Offline
Зарегистрирован: 20.06.2017

Erase не помогает, куда копать?

 

 

 

vsrgv
Offline
Зарегистрирован: 20.06.2017

вроде прошивка залилась, но в окне одни нули

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

может где не контачит, нули не должны. Может это erase прошёл

vsrgv
Offline
Зарегистрирован: 20.06.2017

полсе erase там 3FFF

MaksVV
Offline
Зарегистрирован: 06.08.2015

или имя файла не выбрали и он пустоту с нулями залил. 

vsrgv
Offline
Зарегистрирован: 20.06.2017

залил блинк, диод не покдлючал, но видно что код залился.

а это уже файл прошивки, который нужно прошить

подал на pic ровно 13 вольт, читал что это может быть защита от чтения, мало верится

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Непонятно , дак всё таки получилось или нет? 

vsrgv
Offline
Зарегистрирован: 20.06.2017

нет, не работает в устройстве, думаю собирать програматор для COM порта

MaksVV
Offline
Зарегистрирован: 06.08.2015

дак блинк ведь загрузился. Проверьте с реальным диодом. Если будет мигать и всё норм, то прошивка с проектом у вас корявая , наверное. посмотрите её в НЕХ редакторе, какие там байты

tirexx
Offline
Зарегистрирован: 28.06.2014

Прошу помощи народ, кто шарит в прошивке PIC-ов. Нужно прошить 18F25k50, в списке поддерживаемых микросхем на гитхабе этого контроллера нет. Как я понял принцип программирования пиков по сути идентичен (в основном), может можно добавить поддержку нужного мне чипа?

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

Точно такая же проблема. Write error to device-Please erase device first, надыбал исходники этой программы на VB. вроде как связано с самим хекс файлом. Решил проблему с этим? Я пробовал нажимать reset на прошивающей ардуино. Но он вроде начинает заливать, но потом останавливается и уходит в бутлуп, но проивка не заливается.

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

Точно такая же проблема. Write error to device-Please erase device first, надыбал исходники этой программы на VB. вроде как связано с самим хекс файлом. Решил проблему с этим? Я пробовал нажимать reset на прошивающей ардуино. Но он вроде начинает заливать, но потом останавливается и уходит в бутлуп, но проивка не заливается.

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

MaksVV пишет:

это адаптер для диагностики подогревателей Eberspacher. 

какая последовательность действий при прошивки? Для чего кнопка reset  используется ардуиновская?? нигде не нашел описание у них на сайте для чего она нужна.

MaksVV
Offline
Зарегистрирован: 06.08.2015

на сколько помню не нажимал я ресет на ардуине. Все так шьётся, по клику в проге. 

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

Просто у них на сайте есть два варианта схемы,один вариант без кнопки ресет и двух индикаторных светодиодов дополнительных, а второй вариант с ними. Второй вариант, который у вас для новой версии. Предполагаю, что для новой версии , где уже указаны новые контроллеры,это и нужно. У меня PIC16F877.. Версия скетча 1.8. Для версии 1.0 он вообще не работал В списке скетча он есть, и он определяется, считывается и  даже вроде как стирается, но при записи выдает вот эту ошибку сразу "Write error to device - Please erase device first!" . Если же зажать кнопку ресет на некоторое время, то он начинает показывать, что будто бы записывает, НО ОООчень медленно. Отпускаешь кнопку и он вроде опять как продолжает записывать, но через какое-то время просто уходит в бутлуп, а прога не записывается, контроллер чист. Контроллер причем новый.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

tirexx пишет:

Прошу помощи народ, кто шарит в прошивке PIC-ов. Нужно прошить 18F25k50, в списке поддерживаемых микросхем на гитхабе этого контроллера нет. Как я понял принцип программирования пиков по сути идентичен (в основном), может можно добавить поддержку нужного мне чипа?


Зайдите в любой сервисный центр, наверняка зашьют, там чипрогами пользуются

А добавлять новые чипы видимо придётся в нескольких местах  и не только в прошивке

/*
 * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define __PROG_TYPES_COMPAT__
#include <avr/pgmspace.h>       // For PROGMEM

// Pin mappings for the PIC programming shield.
#define PIN_MCLR        A1      // 0: MCLR is VPP voltage, 1: Reset PIC
#define PIN_ACTIVITY    A5      // LED that indicates read/write activity
#define PIN_VDD         2       // Controls the power to the PIC
#define PIN_CLOCK       4       // Clock pin
#define PIN_DATA        7       // Data pin

#define MCLR_RESET      HIGH    // PIN_MCLR state to reset the PIC
#define MCLR_VPP        LOW     // PIN_MCLR state to apply 13v to MCLR/VPP pin

// All delays are in microseconds.
#define DELAY_SETTLE    50      // Delay for lines to settle for reset
#define DELAY_TPPDP     5       // Hold time after raising MCLR
#define DELAY_THLD0     5       // Hold time after raising VDD
#define DELAY_TSET1     1       // Data in setup time before lowering clock
#define DELAY_THLD1     1       // Data in hold time after lowering clock
#define DELAY_TDLY2     1       // Delay between commands or data
#define DELAY_TDLY3     1       // Delay until data bit read will be valid
#define DELAY_TPROG     4000    // Time for a program memory write to complete
#define DELAY_TDPROG    6000    // Time for a data memory write to complete
#define DELAY_TERA      6000    // Time for a word erase to complete
#define DELAY_TPROG5    1000    // Time for program write on FLASH5 systems
#define DELAY_TFULLERA  50000   // Time for a full chip erase
#define DELAY_TFULL84   20000   // Intermediate wait for PIC16F84/PIC16F84A

// Commands that may be sent to the device.
#define CMD_LOAD_CONFIG         0x00    // Load (write) to config memory
#define CMD_LOAD_PROGRAM_MEMORY 0x02    // Load to program memory
#define CMD_LOAD_DATA_MEMORY    0x03    // Load to data memory
#define CMD_INCREMENT_ADDRESS   0x06    // Increment the PC
#define CMD_READ_PROGRAM_MEMORY 0x04    // Read from program memory
#define CMD_READ_DATA_MEMORY    0x05    // Read from data memory
#define CMD_BEGIN_PROGRAM       0x08    // Begin programming with erase cycle
#define CMD_BEGIN_PROGRAM_ONLY  0x18    // Begin programming only cycle
#define CMD_END_PROGRAM_ONLY    0x17    // End programming only cycle
#define CMD_BULK_ERASE_PROGRAM  0x09    // Bulk erase program memory
#define CMD_BULK_ERASE_DATA     0x0B    // Bulk erase data memory
#define CMD_CHIP_ERASE          0x1F    // Erase the entire chip

// States this application may be in.
#define STATE_IDLE      0       // Idle, device is held in the reset state
#define STATE_PROGRAM   1       // Active, reading and writing program memory
#define STATE_CONFIG    2       // Active, reading and writing config memory
int state = STATE_IDLE;

// Flash types.  Uses a similar naming system to picprog.
#define EEPROM          0
#define FLASH           1
#define FLASH4          4
#define FLASH5          5

unsigned long pc = 0;           // Current program counter.

// Flat address ranges for the various memory spaces.  Defaults to the values
// for the PIC16F628A.  "DEVICE" command updates to the correct values later.
unsigned long programEnd    = 0x07FF;
unsigned long configStart   = 0x2000;
unsigned long configEnd     = 0x2007;
unsigned long dataStart     = 0x2100;
unsigned long dataEnd       = 0x217F;
unsigned long reservedStart = 0x0800;
unsigned long reservedEnd   = 0x07FF;
unsigned int  configSave    = 0x0000;
byte progFlashType          = FLASH4;
byte dataFlashType          = EEPROM;

// Device names, forced out into PROGMEM.
const char s_pic12f629[]  PROGMEM = "pic12f629";
const char s_pic12f675[]  PROGMEM = "pic12f675";
const char s_pic16f630[]  PROGMEM = "pic16f630";
const char s_pic16f676[]  PROGMEM = "pic16f676";
const char s_pic16f84[]   PROGMEM = "pic16f84";
const char s_pic16f84a[]  PROGMEM = "pic16f84a";
const char s_pic16f87[]   PROGMEM = "pic16f87";
const char s_pic16f88[]   PROGMEM = "pic16f88";
const char s_pic16f627[]  PROGMEM = "pic16f627";
const char s_pic16f627a[] PROGMEM = "pic16f627a";
const char s_pic16f628[]  PROGMEM = "pic16f628";
const char s_pic16f628a[] PROGMEM = "pic16f628a";
const char s_pic16f648a[] PROGMEM = "pic16f648a";
const char s_pic16f882[]  PROGMEM = "pic16f882";
const char s_pic16f883[]  PROGMEM = "pic16f883";
const char s_pic16f884[]  PROGMEM = "pic16f884";
const char s_pic16f886[]  PROGMEM = "pic16f886";
const char s_pic16f887[]  PROGMEM = "pic16f887";
const char s_pic18f25k50[] PROGMEM = "pic18f25k50";

// List of devices that are currently supported and their properties.
// Note: most of these are based on published information and have not
// been tested by the author.  Patches welcome to improve the list.
struct deviceInfo
{
    const prog_char *name;      // User-readable name of the device.
    prog_int16_t deviceId;      // Device ID for the PIC (-1 if no id).
    prog_uint32_t programSize;  // Size of program memory (words).
    prog_uint32_t configStart;  // Flat address start of configuration memory.
    prog_uint32_t dataStart;    // Flat address start of EEPROM data memory.
    prog_uint16_t configSize;   // Number of configuration words.
    prog_uint16_t dataSize;     // Size of EEPROM data memory (bytes).
    prog_uint16_t reservedWords;// Reserved program words (e.g. for OSCCAL).
    prog_uint16_t configSave;   // Bits in config word to be saved.
    prog_uint8_t progFlashType; // Type of flash for program memory.
    prog_uint8_t dataFlashType; // Type of flash for data memory.

};
struct deviceInfo const devices[] PROGMEM = {
    // http://ww1.microchip.com/downloads/en/DeviceDoc/41191D.pdf
    {s_pic12f629,  0x0F80, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
    {s_pic12f675,  0x0FC0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
    {s_pic16f630,  0x10C0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
    {s_pic16f676,  0x10E0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},

    // http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf
    {s_pic16f84,   -1,     1024, 0x2000, 0x2100, 8,  64, 0, 0, FLASH,  EEPROM},
    {s_pic16f84a,  0x0560, 1024, 0x2000, 0x2100, 8,  64, 0, 0, FLASH,  EEPROM},

    // http://ww1.microchip.com/downloads/en/DeviceDoc/39607c.pdf
    {s_pic16f87,   0x0720, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM},
    {s_pic16f88,   0x0760, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM},

    // 627/628:  http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf
    // A series: http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf
    {s_pic16f627,  0x07A0, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH,  EEPROM},
    {s_pic16f627a, 0x1040, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM},
    {s_pic16f628,  0x07C0, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH,  EEPROM},
    {s_pic16f628a, 0x1060, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM},
    {s_pic16f648a, 0x1100, 4096, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM},

    // http://ww1.microchip.com/downloads/en/DeviceDoc/41287D.pdf
    {s_pic16f882,  0x2000, 2048, 0x2000, 0x2100, 9, 128, 0, 0, FLASH4, EEPROM},
    {s_pic16f883,  0x2020, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
    {s_pic16f884,  0x2040, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
    {s_pic16f886,  0x2060, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
    {s_pic16f887,  0x2080, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
	
	// new PIC18F25K50 исправить в соответствии с DATASHEET
    {s_pic18f25k50, 0x2000, 32768, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},

    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

// Buffer for command-line character input and READBIN data packets.
#define BINARY_TRANSFER_MAX 64
#define BUFFER_MAX (BINARY_TRANSFER_MAX + 1)
char buffer[BUFFER_MAX];
int buflen = 0;

unsigned long lastActive = 0;

void setup()
{
    // Need a serial link to the host.
    Serial.begin(9600);

    // Hold the PIC in the powered down/reset state until we are ready for it.
    pinMode(PIN_MCLR, OUTPUT);
    pinMode(PIN_VDD, OUTPUT);
    digitalWrite(PIN_MCLR, MCLR_RESET);
    digitalWrite(PIN_VDD, LOW);

    // Clock and data are floating until the first PIC command.
    pinMode(PIN_CLOCK, INPUT);
    pinMode(PIN_DATA, INPUT);

    // Turn off the activity LED initially.
    pinMode(PIN_ACTIVITY, OUTPUT);
    digitalWrite(PIN_ACTIVITY, LOW);
}

void loop()
{
    if (Serial.available()) {
        // Process serial input for commands from the host.
        int ch = Serial.read();
        if (ch == 0x0A || ch == 0x0D) {
            // End of the current command.  Blank lines are ignored.
            if (buflen > 0) {
                buffer[buflen] = '\0';
                buflen = 0;
                digitalWrite(PIN_ACTIVITY, HIGH);   // Turn on activity LED.
                processCommand(buffer);
                digitalWrite(PIN_ACTIVITY, LOW);    // Turn off activity LED.
            }
        } else if (ch == 0x08) {
            // Backspace over the last character.
            if (buflen > 0)
                --buflen;
        } else if (buflen < (BUFFER_MAX - 1)) {
            // Add the character to the buffer after forcing to upper case.
            if (ch >= 'a' && ch <= 'z')
                buffer[buflen++] = ch - 'a' + 'A';
            else
                buffer[buflen++] = ch;
        }
        lastActive = millis();
    } else if (state != STATE_IDLE) {
        // Power off the programming socket if no activity for 2 seconds.
        // Normally the host will issue the "PWROFF" command, but if we are
        // operating in interactive mode or the host has crashed, then this
        // timeout will ensure that the system eventually enters safe mode.
        if ((millis() - lastActive) >= 2000)
            exitProgramMode();
    }
}

void printHex1(unsigned int value)
{
    if (value >= 10)
        Serial.print((char)('A' + value - 10));
    else
        Serial.print((char)('0' + value));
}

void printHex4(unsigned int word)
{
    printHex1((word >> 12) & 0x0F);
    printHex1((word >> 8) & 0x0F);
    printHex1((word >> 4) & 0x0F);
    printHex1(word & 0x0F);
}

void printHex8(unsigned long word)
{
    unsigned int upper = (unsigned int)(word >> 16);
    if (upper)
        printHex4(upper);
    printHex4((unsigned int)word);
}

void printProgString(const prog_char *str)
{
    for (;;) {
        char ch = (char)(pgm_read_byte(str));
        if (ch == '\0')
            break;
        Serial.print(ch);
        ++str;
    }
}

// PROGRAM_PIC_VERSION command.
void cmdVersion(const char *args)
{
    Serial.println("ProgramPIC 1.0");
}

// Initialize device properties from the "devices" list and
// print them to the serial port.  Note: "dev" is in PROGMEM.
void initDevice(const struct deviceInfo *dev)
{
    // Update the global device details.
    programEnd = pgm_read_dword(&(dev->programSize)) - 1;
    configStart = pgm_read_dword(&(dev->configStart));
    configEnd = configStart + pgm_read_word(&(dev->configSize)) - 1;
    dataStart = pgm_read_dword(&(dev->dataStart));
    dataEnd = dataStart + pgm_read_word(&(dev->dataSize)) - 1;
    reservedStart = programEnd - pgm_read_word(&(dev->reservedWords)) + 1;
    reservedEnd = programEnd;
    configSave = pgm_read_word(&(dev->configSave));
    progFlashType = pgm_read_byte(&(dev->progFlashType));
    dataFlashType = pgm_read_byte(&(dev->dataFlashType));

    // Print the extra device information.
    Serial.print("DeviceName: ");
    printProgString((const prog_char *)(pgm_read_word(&(dev->name))));
    Serial.println();
    Serial.print("ProgramRange: 0000-");
    printHex8(programEnd);
    Serial.println();
    Serial.print("ConfigRange: ");
    printHex8(configStart);
    Serial.print('-');
    printHex8(configEnd);
    Serial.println();
    if (configSave != 0) {
        Serial.print("ConfigSave: ");
        printHex4(configSave);
        Serial.println();
    }
    Serial.print("DataRange: ");
    printHex8(dataStart);
    Serial.print('-');
    printHex8(dataEnd);
    Serial.println();
    if (reservedStart <= reservedEnd) {
        Serial.print("ReservedRange: ");
        printHex8(reservedStart);
        Serial.print('-');
        printHex8(reservedEnd);
        Serial.println();
    }
}

// Offsets of interesting config locations that contain device information.
#define DEV_USERID0         0
#define DEV_USERID1         1
#define DEV_USERID2         2
#define DEV_USERID3         3
#define DEV_ID              6
#define DEV_CONFIG_WORD     7

// DEVICE command.
void cmdDevice(const char *args)
{
    // Make sure the device is reset before we start.
    exitProgramMode();

    // Read identifiers and configuration words from config memory.
    unsigned int userid0 = readConfigWord(DEV_USERID0);
    unsigned int userid1 = readConfigWord(DEV_USERID1);
    unsigned int userid2 = readConfigWord(DEV_USERID2);
    unsigned int userid3 = readConfigWord(DEV_USERID3);
    unsigned int deviceId = readConfigWord(DEV_ID);
    unsigned int configWord = readConfigWord(DEV_CONFIG_WORD);

    // If the device ID is all-zeroes or all-ones, then it could mean
    // one of the following:
    //
    // 1. There is no PIC in the programming socket.
    // 2. The VPP programming voltage is not available.
    // 3. Code protection is enabled and the PIC is unreadable.
    // 4. The PIC is an older model with no device identifier.
    //
    // Case 4 is the interesting one.  We look for any word in configuration
    // memory or the first 16 words of program memory that is non-zero.
    // If we find a non-zero word, we assume that we have a PIC but we
    // cannot detect what type it is.
    if (deviceId == 0 || deviceId == 0x3FFF) {
        unsigned int word = userid0 | userid1 | userid2 | userid3 | configWord;
        unsigned int addr = 0;
        while (!word && addr < 16) {
            word |= readWord(addr);
            ++addr;
        }
        if (!word) {
            Serial.println("ERROR");
            exitProgramMode();
            return;
        }
        deviceId = 0;
    }

    Serial.println("OK");

    Serial.print("DeviceID: ");
    printHex4(deviceId);
    Serial.println();

    // Find the device in the built-in list if we have details for it.
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(devices[index].name)));
        if (!name) {
            index = -1;
            break;
        }
        int id = pgm_read_word(&(devices[index].deviceId));
        if (id == (deviceId & 0xFFE0))
            break;
        ++index;
    }
    if (index >= 0) {
        initDevice(&(devices[index]));
    } else {
        // Reset the global parameters to their defaults.  A separate
        // "SETDEVICE" command will be needed to set the correct values.
        programEnd    = 0x07FF;
        configStart   = 0x2000;
        configEnd     = 0x2007;
        dataStart     = 0x2100;
        dataEnd       = 0x217F;
        reservedStart = 0x0800;
        reservedEnd   = 0x07FF;
        configSave    = 0x0000;
        progFlashType = FLASH4;
        dataFlashType = EEPROM;
    }

    Serial.print("ConfigWord: ");
    printHex4(configWord);
    Serial.println();

    Serial.println(".");

    // Don't need programming mode once the details have been read.
    exitProgramMode();
}

// DEVICES command.
void cmdDevices(const char *args)
{
    Serial.println("OK");
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(devices[index].name)));
        if (!name)
            break;
        if (index > 0) {
            Serial.print(',');
            if ((index % 6) == 0)
                Serial.println();
            else
                Serial.print(' ');
        }
        printProgString(name);
        int id = (int)(pgm_read_word(&(devices[index].deviceId)));
        if (id != -1)
            Serial.print('*');
        ++index;
    }
    Serial.println();
    Serial.println(".");
}

// SETDEVICE command.
void cmdSetDevice(const char *args)
{
    // Extract the name of the device from the command arguments.
    int len = 0;
    for (;;) {
        char ch = args[len];
        if (ch == '\0' || ch == ' ' || ch == '\t')
            break;
        ++len;
    }

    // Look for the name in the devices list.
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(devices[index].name)));
        if (!name)
            break;
        if (matchString(name, args, len)) {
            Serial.println("OK");
            initDevice(&(devices[index]));
            Serial.println(".");
            exitProgramMode(); // Force a reset upon the next command.
            return;
        }
        ++index;
    }
    Serial.println("ERROR");
}

int parseHex(const char *args, unsigned long *value)
{
    int size = 0;
    *value = 0;
    for (;;) {
        char ch = *args;
        if (ch >= '0' && ch <= '9')
            *value = (*value << 4) | (ch - '0');
        else if (ch >= 'A' && ch <= 'F')
            *value = (*value << 4) | (ch - 'A' + 10);
        else if (ch >= 'a' && ch <= 'f')
            *value = (*value << 4) | (ch - 'a' + 10);
        else
            break;
        ++size;
        ++args;
    }
    if (*args != '\0' && *args != '-' && *args != ' ' && *args != '\t')
        return 0;
    return size;
}

// Parse a range of addresses of the form START or START-END.
bool parseRange(const char *args, unsigned long *start, unsigned long *end)
{
    int size = parseHex(args, start);
    if (!size)
        return false;
    args += size;
    while (*args == ' ' || *args == '\t')
        ++args;
    if (*args != '-') {
        *end = *start;
        return true;
    }
    ++args;
    while (*args == ' ' || *args == '\t')
        ++args;
    if (!parseHex(args, end))
        return false;
    return *end >= *start;
}

bool parseCheckedRange(const char *args, unsigned long *start, unsigned long *end)
{
    // Parse the basic values and make sure that start <= end.
    if (!parseRange(args, start, end))
        return false;

    // Check that both start and end are within the same memory area
    // and within the bounds of that memory area.
    if (*start <= programEnd) {
        if (*end > programEnd)
            return false;
    } else if (*start >= configStart && *start <= configEnd) {
        if (*end < configStart || *end > configEnd)
            return false;
    } else if (*start >= dataStart && *start <= dataEnd) {
        if (*end < dataStart || *end > dataEnd)
            return false;
    } else {
        return false;
    }
    return true;
}

// READ command.
void cmdRead(const char *args)
{
    unsigned long start;
    unsigned long end;
    if (!parseCheckedRange(args, &start, &end)) {
        Serial.println("ERROR");
        return;
    }
    Serial.println("OK");
    int count = 0;
    bool activity = true;
    while (start <= end) {
        unsigned int word = readWord(start);
        if (count > 0) {
            if ((count % 8) == 0)
                Serial.println();
            else
                Serial.print(' ');
        }
        printHex4(word);
        ++start;
        ++count;
        if ((count % 32) == 0) {
            // Toggle the activity LED to make it blink during long reads.
            activity = !activity;
            if (activity)
                digitalWrite(PIN_ACTIVITY, HIGH);
            else
                digitalWrite(PIN_ACTIVITY, LOW);
        }
    }
    Serial.println();
    Serial.println(".");
}

// READBIN command.
void cmdReadBinary(const char *args)
{
    unsigned long start;
    unsigned long end;
    if (!parseCheckedRange(args, &start, &end)) {
        Serial.println("ERROR");
        return;
    }
    Serial.println("OK");
    int count = 0;
    bool activity = true;
    size_t offset = 0;
    while (start <= end) {
        unsigned int word = readWord(start);
        buffer[++offset] = (char)word;
        buffer[++offset] = (char)(word >> 8);
        if (offset >= BINARY_TRANSFER_MAX) {
            // Buffer is full - flush it to the host.
            buffer[0] = (char)offset;
            Serial.write((const uint8_t *)buffer, offset + 1);
            offset = 0;
        }
        ++start;
        ++count;
        if ((count % 64) == 0) {
            // Toggle the activity LED to make it blink during long reads.
            activity = !activity;
            if (activity)
                digitalWrite(PIN_ACTIVITY, HIGH);
            else
                digitalWrite(PIN_ACTIVITY, LOW);
        }
    }
    if (offset > 0) {
        // Flush the final packet before the terminator.
        buffer[0] = (char)offset;
        Serial.write((const uint8_t *)buffer, offset + 1);
    }
    // Write the terminator (a zero-length packet).
    Serial.write((uint8_t)0x00);
}

const char s_force[] PROGMEM = "FORCE";

// WRITE command.
void cmdWrite(const char *args)
{
    unsigned long addr;
    unsigned long limit;
    unsigned long value;
    int size;

    // Was the "FORCE" option given?
    int len = 0;
    while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
        ++len;
    bool force = matchString(s_force, args, len);
    if (force) {
        args += len;
        while (*args == ' ' || *args == '\t')
            ++args;
    }

    size = parseHex(args, &addr);
    if (!size) {
        Serial.println("ERROR");
        return;
    }
    args += size;
    if (addr <= programEnd) {
        limit = programEnd;
    } else if (addr >= configStart && addr <= configEnd) {
        limit = configEnd;
    } else if (addr >= dataStart && addr <= dataEnd) {
        limit = dataEnd;
    } else {
        // Address is not within one of the valid ranges.
        Serial.println("ERROR");
        return;
    }
    int count = 0;
    for (;;) {
        while (*args == ' ' || *args == '\t')
            ++args;
        if (*args == '\0')
            break;
        if (*args == '-') {
            Serial.println("ERROR");
            return;
        }
        size = parseHex(args, &value);
        if (!size) {
            Serial.println("ERROR");
            return;
        }
        args += size;
        if (addr > limit) {
            // We've reached the limit of this memory area, so fail.
            Serial.println("ERROR");
            return;
        }
        if (!force) {
            if (!writeWord(addr, (unsigned int)value)) {
                // The actual write to the device failed.
                Serial.println("ERROR");
                return;
            }
        } else {
            if (!writeWordForced(addr, (unsigned int)value)) {
                // The actual write to the device failed.
                Serial.println("ERROR");
                return;
            }
        }
        ++addr;
        ++count;
    }
    if (!count) {
        // Missing word argument.
        Serial.println("ERROR");
    } else {
        Serial.println("OK");
    }
}

// Blocking serial read for use by WRITEBIN.
int readBlocking()
{
    while (!Serial.available())
        ;   // Do nothing.
    return Serial.read();
}

// WRITEBIN command.
void cmdWriteBinary(const char *args)
{
    unsigned long addr;
    unsigned long limit;
    int size;

    // Was the "FORCE" option given?
    int len = 0;
    while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
        ++len;
    bool force = matchString(s_force, args, len);
    if (force) {
        args += len;
        while (*args == ' ' || *args == '\t')
            ++args;
    }

    size = parseHex(args, &addr);
    if (!size) {
        Serial.println("ERROR");
        return;
    }
    args += size;
    if (addr <= programEnd) {
        limit = programEnd;
    } else if (addr >= configStart && addr <= configEnd) {
        limit = configEnd;
    } else if (addr >= dataStart && addr <= dataEnd) {
        limit = dataEnd;
    } else {
        // Address is not within one of the valid ranges.
        Serial.println("ERROR");
        return;
    }
    Serial.println("OK");
    int count = 0;
    bool activity = true;
    for (;;) {
        // Read in the next binary packet.
        int len = readBlocking();
        while (len == 0x0A && count == 0) {
            // Skip 0x0A bytes before the first packet as they are
            // probably part of a CRLF pair rather than a packet length.
            len = readBlocking();
        }

        // Stop if we have a zero packet length - end of upload.
        if (!len)
            break;

        // Read the contents of the packet from the serial input stream.
        int offset = 0;
        while (offset < len) {
            if (offset < BINARY_TRANSFER_MAX) {
                buffer[offset++] = (char)readBlocking();
            } else {
                readBlocking();     // Packet is too big - discard extra bytes.
                ++offset;
            }
        }

        // Write the words to memory.
        for (int posn = 0; posn < (len - 1); posn += 2) {
            if (addr > limit) {
                // We've reached the limit of this memory area, so fail.
                Serial.println("ERROR");
                return;
            }
            unsigned int value =
                (((unsigned int)buffer[posn]) & 0xFF) |
                ((((unsigned int)buffer[posn + 1]) & 0xFF) << 8);
            if (!force) {
                if (!writeWord(addr, (unsigned int)value)) {
                    // The actual write to the device failed.
                    Serial.println("ERROR");
                    return;
                }
            } else {
                if (!writeWordForced(addr, (unsigned int)value)) {
                    // The actual write to the device failed.
                    Serial.println("ERROR");
                    return;
                }
            }
            ++addr;
            ++count;
            if ((count % 24) == 0) {
                // Toggle the activity LED to make it blink during long writes.
                activity = !activity;
                if (activity)
                    digitalWrite(PIN_ACTIVITY, HIGH);
                else
                    digitalWrite(PIN_ACTIVITY, LOW);
            }
        }

        // All words in this packet have been written successfully.
        Serial.println("OK");
    }
    Serial.println("OK");
}

const char s_noPreserve[] PROGMEM = "NOPRESERVE";

// ERASE command.
void cmdErase(const char *args)
{
    // Was the "NOPRESERVE" option given?
    int len = 0;
    while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
        ++len;
    bool preserve = !matchString(s_noPreserve, args, len);

    // Preserve reserved words if necessary.
    unsigned int *reserved = 0;
    unsigned int configWord = 0x3FFF;
    if (preserve && reservedStart <= reservedEnd) {
        size_t size = ((size_t)(reservedEnd - reservedStart + 1))
            * sizeof(unsigned int);
        reserved = (unsigned int *)malloc(size);
        if (reserved) {
            unsigned long addr = reservedStart;
            int offset = 0;
            while (addr <= reservedEnd) {
                reserved[offset] = readWord(addr);
                ++addr;
                ++offset;
            }
        } else {
            // If we cannot preserve the reserved words, then abort now.
            Serial.println("ERROR");
            return;
        }
    }
    if (configSave != 0 && preserve) {
        // Some of the bits in the configuration word must also be saved.
        configWord &= ~configSave;
        configWord |= readWord(configStart + DEV_CONFIG_WORD) & configSave;
    }

    // Perform the memory type specific erase sequence.
    switch (progFlashType) {
    case FLASH4:
        setErasePC();
        sendSimpleCommand(CMD_BULK_ERASE_PROGRAM);
        delayMicroseconds(DELAY_TERA);
        sendSimpleCommand(CMD_BULK_ERASE_DATA);
        break;
    case FLASH5:
        setErasePC();
        sendSimpleCommand(CMD_CHIP_ERASE);
        break;
    default:
        // Details for disabling code protection and erasing all memory
        // for PIC16F84/PIC16F84A comes from this doc, section 4.1:
        // http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf
        setErasePC();
        for (int count = 0; count < 7; ++count)
            sendSimpleCommand(CMD_INCREMENT_ADDRESS); // Advance to 0x2007
        sendSimpleCommand(0x01);    // Command 1
        sendSimpleCommand(0x07);    // Command 7
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        delayMicroseconds(DELAY_TFULL84);
        sendSimpleCommand(0x01);    // Command 1
        sendSimpleCommand(0x07);    // Command 7

        // Some FLASH devices need the data memory to be erased separately.
        sendWriteCommand(CMD_LOAD_DATA_MEMORY, 0x3FFF);
        sendSimpleCommand(CMD_BULK_ERASE_DATA);
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        break;
    }

    // Wait until the chip is fully erased.
    delayMicroseconds(DELAY_TFULLERA);

    // Force the device to reset after it has been erased.
    exitProgramMode();
    enterProgramMode();

    // Write the reserved words back to program memory.
    if (reserved) {
        unsigned long addr = reservedStart;
        int offset = 0;
        bool ok = true;
        while (addr <= reservedEnd) {
            if (!writeWord(addr, reserved[offset]))
                ok = false;
            ++addr;
            ++offset;
        }
        free(reserved);
        if (!ok) {
            // Reserved words did not read back correctly.
            Serial.println("ERROR");
            return;
        }
    }

    // Forcibly write 0x3FFF over the configuration words as erase
    // sometimes won't reset the words (e.g. PIC16F628A).  If the
    // write fails, then leave the words as-is - don't report the failure.
    for (unsigned long configAddr = configStart + DEV_CONFIG_WORD;
            configAddr <= configEnd; ++configAddr)
        writeWordForced(configAddr, configWord);

    // Done.
    Serial.println("OK");
}

// PWROFF command.
void cmdPowerOff(const char *args)
{
    exitProgramMode();
    Serial.println("OK");
}

// List of all commands that are understood by the programmer.
typedef void (*commandFunc)(const char *args);
typedef struct
{
    const prog_char *name;
    commandFunc func;
    const prog_char *desc;
    const prog_char *args;
} command_t;
const char s_cmdRead[] PROGMEM = "READ";
const char s_cmdReadDesc[] PROGMEM =
    "Reads program and data words from device memory (text)";
const char s_cmdReadArgs[] PROGMEM = "STARTADDR[-ENDADDR]";
const char s_cmdReadBinary[] PROGMEM = "READBIN";
const char s_cmdReadBinaryDesc[] PROGMEM =
    "Reads program and data words from device memory (binary)";
const char s_cmdWrite[] PROGMEM = "WRITE";
const char s_cmdWriteDesc[] PROGMEM =
    "Writes program and data words to device memory (text)";
const char s_cmdWriteArgs[] PROGMEM = "STARTADDR WORD [WORD ...]";
const char s_cmdWriteBinary[] PROGMEM = "WRITEBIN";
const char s_cmdWriteBinaryDesc[] PROGMEM =
    "Writes program and data words to device memory (binary)";
const char s_cmdWriteBinaryArgs[] PROGMEM = "STARTADDR";
const char s_cmdErase[] PROGMEM = "ERASE";
const char s_cmdEraseDesc[] PROGMEM =
    "Erases the contents of program, configuration, and data memory";
const char s_cmdDevice[] PROGMEM = "DEVICE";
const char s_cmdDeviceDesc[] PROGMEM =
    "Probes the device and returns information about it";
const char s_cmdDevices[] PROGMEM = "DEVICES";
const char s_cmdDevicesDesc[] PROGMEM =
    "Returns a list of all supported device types";
const char s_cmdSetDevice[] PROGMEM = "SETDEVICE";
const char s_cmdSetDeviceDesc[] PROGMEM =
    "Sets a specific device type manually";
const char s_cmdSetDeviceArgs[] PROGMEM = "DEVTYPE";
const char s_cmdPowerOff[] PROGMEM = "PWROFF";
const char s_cmdPowerOffDesc[] PROGMEM =
    "Powers off the device in the programming socket";
const char s_cmdVersion[] PROGMEM = "PROGRAM_PIC_VERSION";
const char s_cmdVersionDesc[] PROGMEM =
    "Prints the version of ProgramPIC";
const char s_cmdHelp[] PROGMEM = "HELP";
const char s_cmdHelpDesc[] PROGMEM =
    "Prints this help message";
const command_t commands[] PROGMEM = {
    {s_cmdRead, cmdRead, s_cmdReadDesc, s_cmdReadArgs},
    {s_cmdReadBinary, cmdReadBinary, s_cmdReadBinaryDesc, s_cmdReadArgs},
    {s_cmdWrite, cmdWrite, s_cmdWriteDesc, s_cmdWriteArgs},
    {s_cmdWriteBinary, cmdWriteBinary, s_cmdWriteBinaryDesc, s_cmdWriteBinaryArgs},
    {s_cmdErase, cmdErase, s_cmdEraseDesc, 0},
    {s_cmdDevice, cmdDevice, s_cmdDeviceDesc, 0},
    {s_cmdDevices, cmdDevices, s_cmdDevicesDesc, 0},
    {s_cmdSetDevice, cmdSetDevice, s_cmdSetDeviceDesc, s_cmdSetDeviceArgs},
    {s_cmdPowerOff, cmdPowerOff, s_cmdPowerOffDesc, 0},
    {s_cmdVersion, cmdVersion, s_cmdVersionDesc, 0},
    {s_cmdHelp, cmdHelp, s_cmdHelpDesc, 0},
    {0, 0}
};

// "HELP" command.
void cmdHelp(const char *args)
{
    Serial.println("OK");
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(commands[index].name)));
        if (!name)
            break;
        const prog_char *desc = (const prog_char *)
            (pgm_read_word(&(commands[index].desc)));
        const prog_char *args = (const prog_char *)
            (pgm_read_word(&(commands[index].args)));
        printProgString(name);
        if (args) {
            Serial.print(' ');
            printProgString(args);
        }
        Serial.println();
        Serial.print("    ");
        printProgString(desc);
        Serial.println();
        ++index;
    }
    Serial.println(".");
}

// Match a data-space string where the name comes from PROGMEM.
bool matchString(const prog_char *name, const char *str, int len)
{
    for (;;) {
        char ch1 = (char)(pgm_read_byte(name));
        if (ch1 == '\0')
            return len == 0;
        else if (len == 0)
            break;
        if (ch1 >= 'a' && ch1 <= 'z')
            ch1 = ch1 - 'a' + 'A';
        char ch2 = *str;
        if (ch2 >= 'a' && ch2 <= 'z')
            ch2 = ch2 - 'a' + 'A';
        if (ch1 != ch2)
            break;
        ++name;
        ++str;
        --len;
    }
    return false;
}

// Process commands from the host.
void processCommand(const char *buf)
{
    // Skip white space at the start of the command.
    while (*buf == ' ' || *buf == '\t')
        ++buf;
    if (*buf == '\0')
        return;     // Ignore blank lines.

    // Extract the command portion of the line.
    const char *cmd = buf;
    int len = 0;
    for (;;) {
        char ch = *buf;
        if (ch == '\0' || ch == ' ' || ch == '\t')
            break;
        ++buf;
        ++len;
    }

    // Skip white space after the command name and before the arguments.
    while (*buf == ' ' || *buf == '\t')
        ++buf;

    // Find the command and execute it.
    int index = 0;
    for (;;) {
        const prog_char *name = (const prog_char *)
            (pgm_read_word(&(commands[index].name)));
        if (!name)
            break;
        if (matchString(name, cmd, len)) {
            commandFunc func =
                (commandFunc)(pgm_read_word(&(commands[index].func)));
            (*func)(buf);
            return;
        }
        ++index;
    }

    // Unknown command.
    Serial.println("NOTSUPPORTED");
}

// Enter high voltage programming mode.
void enterProgramMode()
{
    // Bail out if already in programming mode.
    if (state != STATE_IDLE)
        return;

    // Lower MCLR, VDD, DATA, and CLOCK initially.  This will put the
    // PIC into the powered-off, reset state just in case.
    digitalWrite(PIN_MCLR, MCLR_RESET);
    digitalWrite(PIN_VDD, LOW);
    digitalWrite(PIN_DATA, LOW);
    digitalWrite(PIN_CLOCK, LOW);

    // Wait for the lines to settle.
    delayMicroseconds(DELAY_SETTLE);

    // Switch DATA and CLOCK into outputs.
    pinMode(PIN_DATA, OUTPUT);
    pinMode(PIN_CLOCK, OUTPUT);

    // Raise MCLR, then VDD.
    digitalWrite(PIN_MCLR, MCLR_VPP);
    delayMicroseconds(DELAY_TPPDP);
    digitalWrite(PIN_VDD, HIGH);
    delayMicroseconds(DELAY_THLD0);

    // Now in program mode, starting at the first word of program memory.
    state = STATE_PROGRAM;
    pc = 0;
}

// Exit programming mode and reset the device.
void exitProgramMode()
{
    // Nothing to do if already out of programming mode.
    if (state == STATE_IDLE)
        return;

    // Lower MCLR, VDD, DATA, and CLOCK.
    digitalWrite(PIN_MCLR, MCLR_RESET);
    digitalWrite(PIN_VDD, LOW);
    digitalWrite(PIN_DATA, LOW);
    digitalWrite(PIN_CLOCK, LOW);

    // Float the DATA and CLOCK pins.
    pinMode(PIN_DATA, INPUT);
    pinMode(PIN_CLOCK, INPUT);

    // Now in the idle state with the PIC powered off.
    state = STATE_IDLE;
    pc = 0;
}

// Send a command to the PIC.
void sendCommand(byte cmd)
{
    for (byte bit = 0; bit < 6; ++bit) {
        digitalWrite(PIN_CLOCK, HIGH);
        if (cmd & 1)
            digitalWrite(PIN_DATA, HIGH);
        else
            digitalWrite(PIN_DATA, LOW);
        delayMicroseconds(DELAY_TSET1);
        digitalWrite(PIN_CLOCK, LOW);
        delayMicroseconds(DELAY_THLD1);
        cmd >>= 1;
    }
}

// Send a command to the PIC that has no arguments.
void sendSimpleCommand(byte cmd)
{
    sendCommand(cmd);
    delayMicroseconds(DELAY_TDLY2);
}

// Send a command to the PIC that writes a data argument.
void sendWriteCommand(byte cmd, unsigned int data)
{
    sendCommand(cmd);
    delayMicroseconds(DELAY_TDLY2);
    for (byte bit = 0; bit < 16; ++bit) {
        digitalWrite(PIN_CLOCK, HIGH);
        if (data & 1)
            digitalWrite(PIN_DATA, HIGH);
        else
            digitalWrite(PIN_DATA, LOW);
        delayMicroseconds(DELAY_TSET1);
        digitalWrite(PIN_CLOCK, LOW);
        delayMicroseconds(DELAY_THLD1);
        data >>= 1;
    }
    delayMicroseconds(DELAY_TDLY2);
}

// Send a command to the PIC that reads back a data value.
unsigned int sendReadCommand(byte cmd)
{
    unsigned int data = 0;
    sendCommand(cmd);
    digitalWrite(PIN_DATA, LOW);
    pinMode(PIN_DATA, INPUT);
    delayMicroseconds(DELAY_TDLY2);
    for (byte bit = 0; bit < 16; ++bit) {
        data >>= 1;
        digitalWrite(PIN_CLOCK, HIGH);
        delayMicroseconds(DELAY_TDLY3);
        if (digitalRead(PIN_DATA))
            data |= 0x8000;
        digitalWrite(PIN_CLOCK, LOW);
        delayMicroseconds(DELAY_THLD1);
    }
    pinMode(PIN_DATA, OUTPUT);
    delayMicroseconds(DELAY_TDLY2);
    return data;
}

// Set the program counter to a specific "flat" address.
void setPC(unsigned long addr)
{
    if (addr >= dataStart && addr <= dataEnd) {
        // Data memory.
        addr -= dataStart;
        if (state != STATE_PROGRAM || addr < pc) {
            // Device is off, currently looking at configuration memory,
            // or the address is further back.  Reset the device.
            exitProgramMode();
            enterProgramMode();
        }
    } else if (addr >= configStart && addr <= configEnd) {
        // Configuration memory.
        addr -= configStart;
        if (state == STATE_IDLE) {
            // Enter programming mode and switch to config memory.
            enterProgramMode();
            sendWriteCommand(CMD_LOAD_CONFIG, 0);
            state = STATE_CONFIG;
        } else if (state == STATE_PROGRAM) {
            // Switch from program memory to config memory.
            sendWriteCommand(CMD_LOAD_CONFIG, 0);
            state = STATE_CONFIG;
            pc = 0;
        } else if (addr < pc) {
            // Need to go backwards in config memory, so reset the device.
            exitProgramMode();
            enterProgramMode();
            sendWriteCommand(CMD_LOAD_CONFIG, 0);
            state = STATE_CONFIG;
        }
    } else {
        // Program memory.
        if (state != STATE_PROGRAM || addr < pc) {
            // Device is off, currently looking at configuration memory,
            // or the address is further back.  Reset the device.
            exitProgramMode();
            enterProgramMode();
        }
    }
    while (pc < addr) {
        sendSimpleCommand(CMD_INCREMENT_ADDRESS);
        ++pc;
    }
}

// Sets the PC for "erase mode", which is activated by loading the
// data value 0x3FFF into location 0 of configuration memory.
void setErasePC()
{
    // Forcibly reset the device so we know what state it is in.
    exitProgramMode();
    enterProgramMode();

    // Load 0x3FFF for the configuration.
    sendWriteCommand(CMD_LOAD_CONFIG, 0x3FFF);
    state = STATE_CONFIG;
}

// Read a word from memory (program, config, or data depending upon addr).
// The start and stop bits will be stripped from the raw value from the PIC.
unsigned int readWord(unsigned long addr)
{
    setPC(addr);
    if (addr >= dataStart && addr <= dataEnd)
        return (sendReadCommand(CMD_READ_DATA_MEMORY) >> 1) & 0x00FF;
    else
        return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
}

// Read a word from config memory using relative, non-flat, addressing.
// Used by the "DEVICE" command to fetch information about devices whose
// flat address ranges are presently unknown.
unsigned int readConfigWord(unsigned long addr)
{
    if (state == STATE_IDLE) {
        // Enter programming mode and switch to config memory.
        enterProgramMode();
        sendWriteCommand(CMD_LOAD_CONFIG, 0);
        state = STATE_CONFIG;
    } else if (state == STATE_PROGRAM) {
        // Switch from program memory to config memory.
        sendWriteCommand(CMD_LOAD_CONFIG, 0);
        state = STATE_CONFIG;
        pc = 0;
    } else if (addr < pc) {
        // Need to go backwards in config memory, so reset the device.
        exitProgramMode();
        enterProgramMode();
        sendWriteCommand(CMD_LOAD_CONFIG, 0);
        state = STATE_CONFIG;
    }
    while (pc < addr) {
        sendSimpleCommand(CMD_INCREMENT_ADDRESS);
        ++pc;
    }
    return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
}

// Begin a programming cycle, depending upon the type of flash being written.
void beginProgramCycle(unsigned long addr, bool isData)
{
    switch (isData ? dataFlashType : progFlashType) {
    case FLASH:
    case EEPROM:
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        delayMicroseconds(DELAY_TDPROG + DELAY_TERA);
        break;
    case FLASH4:
        sendSimpleCommand(CMD_BEGIN_PROGRAM);
        delayMicroseconds(DELAY_TPROG);
        break;
    case FLASH5:
        sendSimpleCommand(CMD_BEGIN_PROGRAM_ONLY);
        delayMicroseconds(DELAY_TPROG5);
        sendSimpleCommand(CMD_END_PROGRAM_ONLY);
        break;
    }
}

// Write a word to memory (program, config, or data depending upon addr).
// Returns true if the write succeeded, false if read-back failed to match.
bool writeWord(unsigned long addr, unsigned int word)
{
    unsigned int readBack;
    setPC(addr);
    if (addr >= dataStart && addr <= dataEnd) {
        word &= 0x00FF;
        sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
        beginProgramCycle(addr, true);
        readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
        readBack = (readBack >> 1) & 0x00FF;
    } else if (!configSave || addr != (configStart + DEV_CONFIG_WORD)) {
        word &= 0x3FFF;
        sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
        beginProgramCycle(addr, false);
        readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
        readBack = (readBack >> 1) & 0x3FFF;
    } else {
        // The configuration word has calibration bits within it that
        // must be preserved when we write to it.  Read the current value
        // and preserve the necessary bits.
        readBack = (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
        word = (readBack & configSave) | (word & 0x3FFF & ~configSave);
        sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
        beginProgramCycle(addr, false);
        readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
        readBack = (readBack >> 1) & 0x3FFF;
    }
    return readBack == word;
}

// Force a word to be written even if it normally would protect config bits.
bool writeWordForced(unsigned long addr, unsigned int word)
{
    unsigned int readBack;
    setPC(addr);
    if (addr >= dataStart && addr <= dataEnd) {
        word &= 0x00FF;
        sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
        beginProgramCycle(addr, true);
        readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
        readBack = (readBack >> 1) & 0x00FF;
    } else {
        word &= 0x3FFF;
        sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
        beginProgramCycle(addr, false);
        readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
        readBack = (readBack >> 1) & 0x3FFF;
    }
    return readBack == word;
}

но и в программе управления

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

это версия 1.0. на их сайте в гите есть версия 1.8

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

MaksVV пишет:

на сколько помню не нажимал я ресет на ардуине. Все так шьётся, по клику в проге. 

пробовал через командную строку слить хекс файл. вышел файл почти весь в нулях размеров 47 кб. ОБратно он заливается, но если произвести изменения в файле (вставить строчки из компилированного кода), то при прошивке выдаётся ошибка. Причем по контрольной сумме всё правильно. Я даже пробовал через последовательное соединение , как  у них на сайте. Также отправляются команды на запись нулей по адресам, другие значения записать невозможно.  Единственное , что могу считать идентификатор устройства, который соответствует моему контроллеру. Пробовал даже менять формат хекс файла с int32 на int8 через hexmate. пробовал другой компилятор: мплабх, хитек. Подозрения, что считывает ,записывает и стирает он неправильно, учитывая, что он считывает только нулю со всех областей:программной памяти, еепром, конфигурационной памяти. Причем ,если отключить питание от МСЛР, то он также считывает нули, но вот конфигурацию устройства уже не покажет. Либо контроллер паленый либо в коде ошибка или всё-таки он не поддерживает прошивку этого устройства pic16f877, хотя он указан в ардуиновском файле,и автоматически определяется. Код верный в обоих случаях-проверял хекс файл через протеус на том же контроллере.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Eddy_cbix пишет:

это версия 1.0. на их сайте в гите есть версия 1.8

а киньте ссылкой пожалуйста

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Благодарю!

Посмотрел, из изменений добавили пяток чипов и компиляцию в IDE 1.8.7
PIC серии 18 в поддерживаемых нет, увы (((
 

Eddy_cbix
Offline
Зарегистрирован: 22.12.2018

Если вы хотите прошивать 18 серию, то советую такое решение с низковольтным программированием, но старые контроллеры он уже поддерживать не будет) https://hackaday.io/project/8559-microchip-pic-arduino-based-programmer/

Рафис
Offline
Зарегистрирован: 08.01.2019

https://sites.google.com/site/thehighspark/arduino-pic18f -есть пример прошивки микроконтроллеров  семейства pic18

Рафис
Offline
Зарегистрирован: 08.01.2019

всё на буржуйском языке, но рисунки хорошие и так понять можно

Paradox-2012
Offline
Зарегистрирован: 02.08.2018

Рафис пишет:

https://sites.google.com/site/thehighspark/arduino-pic18f -есть пример прошивки микроконтроллеров  семейства pic18

Спасибо за интересную статью и ресурс. Хочу попробовать этим методом прошить PIC18F24K22 прям на плате. На плате есть пять контактов для внутрисхемного программирования: 1. PROG (я так понимаю MCLR); 2. 5V (VDD); 3. GND (VSS); 4. PGD; 5. PGC.

В предложенном скетче для Ардуино используется ещё шестой контакт 6. PGM, так как он имеется на PIC18F2420 описанном в примере. А у микроконтроллера PIC18F24K22 такой контакт отсутствует! 

Вопрос, как Вы считаете нужно ли вносить изменения в скетч для Ардуино, для того чтобы корректно прошить PIC18F24K22?                                             

AlexIz
Offline
Зарегистрирован: 13.01.2016

Пытался запустить этот программатор. То прочитает чип, то нет. Стирать не получается. Плюнул буду искать готовое изделие...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

AlexIz пишет:

буду искать готовое изделие...

Найди TL866

qwerty31415
Offline
Зарегистрирован: 09.06.2022

Почему у меня при переходе по ссылке на статью автора пишет что отказано в доступе к серверу?

qwerty31415
Offline
Зарегистрирован: 09.06.2022

На сегодня ссылка вообще работает?

qwerty31415
Offline
Зарегистрирован: 09.06.2022

Или скиньте кто нибудь саму программу для прошивки

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

qwerty31415 пишет:

Или скиньте кто нибудь саму программу для прошивки

здесь посмотри

UFO 007
UFO 007 аватар
Offline
Зарегистрирован: 11.01.2018

DetSimen пишет:

Найди TL866

Это чудо я нашёл давно (при чём за "удвоенную" цену - 3,5 рубля сам агрегат и почти столько же 2 десятка адаптеров и с таким арсеналом прочитать/прошить любую из 15-ти с лихуем тысяч микросхему = не проблема). Проблема скомпилить *.hex для PICa (Arduino IDE складывает их в папке (например) h:\TEMP_P~1\arduino_build_261558\скетч_наме.ино.хекс). По умолчанию в Инструменты\Плата одни только Ардуинки: Уно, Нано и т. д. Но со временем туда "добавились" все AVRы: АтТини 12..2344 и АтМеги 8, 44. 48,...168, 328, 2560/61 а так же СТМ32, ЕСП8266/32 и даже W80x где-то надыбал, а вот из пиков только чипКИТ32, но железа такого нет. А вот где взять библиотеку для PIC12/16/18 - никто не подскажет?

З. Ы. Заранее благодарен

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

А всякие pinguino и так далее чем не устраивают? Я как бы pic-контроллерами никогда не занимался, но сейчас гугл открыл с запросом «pic arduino ide» и там море всего.