ISP example program.

Dependencies:   SLCD mbed USBLocalFileSystem

/media/uploads/va009039/lpc81isp-360x240.jpg

FRDM-KL46ZLPC810
UART RXDPTE23p2(P0_4)
UART TXDPTE22p8(P0_0)
nRESETD6p1(P0_5)
nISPD8p5(P0_1)
GNDGNDp7
3.3VP3V3p6

Copy binary image to the disk called LPC81ISP.
Push sw1 or sw3, start write to LPC810 flash.

BaseLpcIsp.cpp

Committer:
va009039
Date:
2014-05-04
Revision:
2:eafc1c6787c7
Parent:
src/BaseLpcIsp.cpp@ 0:ad2b1fc04955

File content as of revision 2:eafc1c6787c7:

#include "BaseLpcIsp.h"
#include <algorithm>

#if (DEBUG2 > 3)
#define ISP_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\r\n");} while(0);
#else
#define ISP_DBG(...) while(0);
#endif

#define ISP_ERR() isp_error(__LINE__)

#define RAM 0x10000300
#define ROM_SIZE 0x10000

void BaseLpcIsp::Reset(bool isp)
{
    _nisp = isp ? 0 : 1;
    _nreset = 0;
    wait_ms(50);
    _nreset = 1;
    wait_ms(100);
}

bool BaseLpcIsp::Sync()
{
    putc('?');
    if (waitln("Synchronized")) { // Synchronized
        sendln("Synchronized");
        if (waitln("OK")) {
            sendln("14748");
            if (waitln("OK")) {
                if (_cmd("A 0")) { // echo off
                    return true;
                }
            }
        }
    }
    ISP_ERR();
    return false;
}

bool BaseLpcIsp::_cmd(const char* format, ...)
{
    char buf[128];
    va_list args;
    va_start(args, format);
    vsprintf(buf, format, args);
    va_end(args);
    sendln(buf);

    if (waitln("0")) { // CMD_SUCCESS ?
        return true;
    }
    ISP_ERR();
    return false;
}

void BaseLpcIsp::sendln(const char* s)
{
    infoLED(LED_TX, tx_sw++ & 1);
    ISP_DBG("send:[%s]", s);
    puts(s);
    puts(CRLF);
}

bool BaseLpcIsp::waitln(const char* s)
{
    char buf[64];
    while(recvln(buf, sizeof(buf))) {
        if (strcmp(buf, s) == 0) {
            ISP_DBG("recv:[%s]", buf);
            return true;
        }
        ISP_DBG("skip:[%s]", buf);
    }
    ISP_ERR();
    return false;
}

bool BaseLpcIsp::recvln(mystring& s)
{
    Timer t;
    t.reset();
    t.start();
    while(t.read_ms() < 900) {
        if (readable()) {
            int c = getc();
            if (c == LF) {
                return true;
            } else if (c >= ' ') {
                s.append(c);
            }
        }
    }
    ISP_ERR();
    return false;
}

bool BaseLpcIsp::recvln(char* buf, int size)
{
    Timer t;
    t.reset();
    t.start();
    int pos = 0;
    while(t.read_ms() < 900) {
        if (readable()) {
            int c = getc();
            if (c == LF) {
                buf[pos] = '\0';
                return true;
            } else if (c >= ' ') {
                if (pos < size-1) {
                    buf[pos++] = c;
                }
            }
        }
    }
    return false;
}

bool BaseLpcIsp::FlashWrite(const char* filename)
{
    infoLED(LED_TX, 0);
    if (!_cmd("J")) {
        return false;
    }
    char lineBuf[16];
    if (!recvln(lineBuf, sizeof(lineBuf))) {
        ISP_ERR();
        return false;
    }
    ISP_DBG("recv:[%s]", lineBuf);

    part_code = strtoul(lineBuf, NULL, 10);
    if (part_code >= 0x8100 && part_code <= 0x81ff) { // LPC8XX
        chunk_size = 64;
        sector_size = 1024;
        plan_binary = true;
        infoSLCD("810 ");
    } else {
        chunk_size = 256;
        sector_size = 4096;
        plan_binary = false;
        infoSLCD("1114");
    }
    
    if (!_cmd("U 23130")) { // Unlock
        ISP_ERR();
        return false;
    }

    FILE* fp = fopen(filename, "rb");
    if (fp == NULL) {
        ISP_ERR();
        return false;
    }

    int bin_size = 0;
    Timer t;
    t.reset();
    t.start();
    uint8_t buf[chunk_size];
    int sector = 0;
    bool result = false;
    for(int addr = 0; addr < ROM_SIZE; addr += sizeof(buf)) {
        if (feof(fp)) {
            result = true;
            break;
        }
        fread(buf, sizeof(buf), 1, fp);
        if (!_patch(addr, buf, sizeof(buf))) {
            break;
        }
        bin_size += sizeof(buf);
        if (!_write_to_ram(RAM, buf, sizeof(buf))) {
            break;
        }
        if ((addr % sector_size) == 0) {
            sector = addr / sector_size;
            if (!_cmd("P %u %u", sector, sector)) {
                break;
            }
            if (!_cmd("E %u %u", sector, sector)) { // Erase
                break;
            }
            if (!_cmd("I %u %u", sector, sector)) { // Blank check
                break;
            }
        }
        if (!_cmd("P %u %u", sector, sector)) {
            break;
        }
        if (!_cmd("C %u %u %u", addr, RAM, sizeof(buf))) { // copy
            break;
        }
        if (!_cmd("M %u %u %u", addr, RAM, sizeof(buf))) { // compare
            break;
        }
    }
    fclose(fp);
    infoLED(LED_TX, 0);
    if (result) {
        t.stop();
        ISP_DBG("bin size: %d bytes, %d ms, %d bytes/sec", 
            bin_size, t.read_ms(), bin_size*1000/t.read_ms());
        infoSLCD("OK  ");
    }   
    return result;
}

extern void uuencode(const void* src, int srcsize, char* dst); //utils.cpp

bool BaseLpcIsp::_write_to_ram(int addr, uint8_t* buf, int size)
{
    if (!_cmd("W %u %u", addr, size)) {
        return false;
    }
    if (plan_binary) {
        for(int i = 0; i < size; i++) {
            _target.putc(buf[i]);
        }
        return true;
    }
    int sum = 0;
    int line = 0;
    for(int n = 0; n < size; n += 45) {
        char tmp[61+1];
        int size2 = std::min(45, size - n);
        uuencode(buf+n, size2, tmp);
        sendln(tmp);
        for(int i = 0; i < size2; i++) {
            sum += buf[n+i];
        }
        if (++line >= 20 || (n + size2) >= size) {
            snprintf(tmp, sizeof(tmp), "%u", sum);
            sendln(tmp);
            if (!waitln("OK")) {
                return false;
            }
            line = 0;
            sum = 0;
        }
    }
    return true;
}

bool BaseLpcIsp::_patch(int addr, uint8_t* buf, int size)
{
    const int crp_start = 0x2fc; // Code Read Protection location
    if (crp_start >= addr && crp_start < addr+size) {
        uint32_t pat = *reinterpret_cast<uint32_t*>(crp_start-addr+buf);
        if (pat != 0xffffffff) { // NO_CRP ?
            ISP_ERR();
            return false;
        }
    }
    return true;
}