semihost server example program

Dependencies:   SWD mbed USBLocalFileSystem BaseDAP USBDAP

/media/uploads/va009039/kl46z-lpc800-360x480.jpg

LPCXpresso
LPC11U68
LPCXpresso
LPC1549
FRDM-KL46ZEA LPC4088 QSB
app-board
LPC1768
app-board
LPC810LPC1114FN28
serverserverserverserverserverclientclient
SWDIOD12D12D12p25p21p4(P0_2)p12
SWCLKD10D10D10p26p22p3(P0_3)p3
nRESET
*option
D6D6D6p34p30p1(P0_5)p23
GNDGNDGNDGNDp1p1p7p22
3.3VP3V3P3V3P3V3p44p40p6p21
flash writeSW2(P0_1)SW3(P1_9)SW1p14
joystick
center
p14
joystick
center

client example:

Import programlpc810-semihost_helloworld

semihost client example program

Flash.cpp

Committer:
va009039
Date:
2014-06-22
Revision:
18:5ed1759e863b
Parent:
14:e6acf863207e

File content as of revision 18:5ed1759e863b:

// Flash.cpp 2014/2/18
#include "Flash.h"
#include "Target2.h"
#include "mydebug.h"

// LPC1347,LPC1114,LPC812,LPC810
#define LPC_SYSCON_SYSMEMREMAP  0x40048000
#define LPC_SYSCON_MAINCLKSEL   0x40048070
#define LPC_SYSCON_MAINCLKUEN   0x40048074
#define LPC_SYSCON_SYSAHBCLKDIV 0x40048078

// LPC1768,LPC1769
#define LPC_SC_MEMMAP   0x400fc040
#define LPC_SC_PLL0CON  0x400fc080
#define LPC_SC_PLL0CFG  0x400fc084
#define LPC_SC_PLL0STAT 0x400fc088
#define LPC_SC_PLL0FEED 0x400fc08c

Flash::Flash(Target2* target, Serial* usbpc) :_target(target),_pc(usbpc)
{
    _setup();
}

void Flash::_setup()
{
    _target->halt();
    _target->wait_status(TARGET_HALTED);
    _target->prog_status();
}

bool Flash::init()
{
    _pc->printf("Initializing");
    ram_addr = 0x10000000;
    ram_size = 0x400;
    if (remoteIAP(READ_PART_ID) != CMD_SUCCESS) {
        _pc->printf("\nfaild. READ_PART_ID\n");
        return false;
    }               
    bool result = false;
    _pc->printf("(%08x).", part_id);
    switch(part_id) {
        case 0x08020543: // LPC1347
            result = flash_init_lpc1347();
            break;
        case 0x26113f37: // LPC1768,LPC1769
            result = flash_init_lpc1769();
            break;
        default:
            if (part_id >= 0x00008100 && part_id <= 0x000081ff) { // LOC810
                result = init_lpc1114fn28_lpc810(1024);
            } else { // part_id = 0x0a40902b or 0x1a40902b LPC1114FN28
                result = init_lpc1114fn28_lpc810(4096);
            }
            break;
    }            
    if (result) {
        _pc->printf("passed.\n");
    }    
    return result;
}

bool Flash::remoteREG(uint32_t addr, uint32_t value)
{
    _target->writeMemory(addr, value);
    return true;
}

bool Flash::init_lpc1114fn28_lpc810(int sector_size)
{
    cfg.iap_cclk = 12000;
    cfg.sector_size = sector_size;
    remoteREG(LPC_SYSCON_MAINCLKSEL, 0);  // Select Internal RC Oscillator
    remoteREG(LPC_SYSCON_MAINCLKUEN, 1);  // Update Main Clock Source
    remoteREG(LPC_SYSCON_MAINCLKUEN, 0);  // Toggle Update Register
    remoteREG(LPC_SYSCON_MAINCLKUEN, 1);
    uint32_t data = _target->readMemory(LPC_SYSCON_MAINCLKUEN); // Wait until updated
    if (!(data & 1)) {
        _pc->printf("\nerror MAINCLKUEN=%08x\n", data);
        return false;
    }
    remoteREG(LPC_SYSCON_SYSAHBCLKDIV, 1);// Set Main Clock divider to 1
    remoteREG(LPC_SYSCON_SYSMEMREMAP, 2); // User Flash Mode
    return true;
}

bool Flash::flash_init_lpc1347() {
    cfg.iap_cclk = 12000;
    cfg.sector_size = 4096;
    remoteREG(LPC_SYSCON_MAINCLKSEL, 0); // Select Internal RC Oscillator
    remoteREG(LPC_SYSCON_SYSAHBCLKDIV, 1);// Set Main Clock divider to 1
    if (!remoteREG(LPC_SYSCON_SYSMEMREMAP, 2)) { // User Flash Mode
        return false;
    }
    return true;
}

bool Flash::flash_init_lpc1769() {
    cfg.iap_cclk = 4000;
    cfg.sector_size = 4096;
    remoteREG(LPC_SC_PLL0CON, 0x00); // Select Internal RC Oscillator
    remoteREG(LPC_SC_PLL0FEED, 0xaa);
    remoteREG(LPC_SC_PLL0FEED, 0x55);
    if (!remoteREG(LPC_SC_MEMMAP, 0x01)) { // User Flash Mode
        return false;
    }
    return true;
}
 
bool Flash::write(const char* filename)
{
    const int chunk_size = 512;
    FILE* fp = fopen(filename, "rb");
    if (fp == NULL) {
        _pc->printf("file open error [%s]\n", filename);
        return false;
    }
    _pc->printf("Writing.");
    uint8_t buf[chunk_size];
    bool passed = false;
    for(int addr = 0; addr < 0x80000; addr += sizeof(buf)) {
        int ret = fread(buf, 1, sizeof(buf), fp);
        if (!_patch(buf, sizeof(buf), addr)) {
            break;
        }
        if (!write(addr, buf, sizeof(buf))) {
            break;
        }
        _pc->printf(".");
        if (ret < sizeof(buf)) {
            passed = true;
            break;
        }
    }
    fclose(fp);
    if (passed) {
        _pc->printf("passed.\n");
    }
    return passed;
}

int Flash::addr_to_sector(int addr) {
    if (addr < 0x10000) {
        return addr / cfg.sector_size;
    }
    return addr / 0x8000 + 0x10000/cfg.sector_size - 2;
}

bool Flash::sector_head(int addr) {
    if (addr < 0x10000) {
        return (addr%cfg.sector_size) == 0;
    }
    return (addr%0x8000) == 0;
}

bool Flash::write(int addr, const uint8_t* data, int size)
{
    int temp_addr = ram_addr + 44;
    int temp_size = 512;   
    for(int i = 0; i < size; i += temp_size) {
        update();
        if (!_write_to_ram(temp_addr, temp_size, data+i)) {
            _pc->printf("faild. write to ram %08x\n", temp_addr);
            return false;
        }
        int sector = addr_to_sector(addr + i);
        if (sector_head(addr + i)) {
            if (remoteIAP(PREPARE_SECTOR, sector, sector) != CMD_SUCCESS) {
                _pc->printf("faild. PREPARE_SECTOR %d %d\n", sector, sector);
                return false;
            }            
            if (remoteIAP(ERASE_SECTOR, sector, sector, cfg.iap_cclk) != CMD_SUCCESS) {
                _pc->printf("faild. ERASE_SECTOR %d %d %d\n", sector, sector, cfg.iap_cclk);
                return false;
            }
            if (remoteIAP(BLANK_CHECK, sector, sector, cfg.iap_cclk) != CMD_SUCCESS) {
                _pc->printf("faild. BLANK_CHECK %d %d %d\n", sector, sector, cfg.iap_cclk);
                return false;
            }
        }
        if (remoteIAP(PREPARE_SECTOR, sector, sector) != CMD_SUCCESS) {
            _pc->printf("faild. PREPARE_SECTOR %d %d\n", sector, sector);
            return false;
        }
        if (remoteIAP(COPY_RAM_TO_FLASH, addr+i, temp_addr, temp_size, cfg.iap_cclk) != CMD_SUCCESS) {
            _pc->printf("faild. COPY_RAM_TO_FLASH %d %d %d %dn", addr+i, temp_addr, temp_size, cfg.iap_cclk);
            return false;
        }
        if (remoteIAP(COMPARE, addr+i, temp_addr, temp_size) != CMD_SUCCESS) {
            _pc->printf("faild. COMPARE %d %d %d", addr+i, temp_addr, temp_size);
            return false;
        }
    }
    return true;
}

bool Flash::_write_to_ram(int addr, int size, const uint8_t* buf)
{
    _target->writeMemory(addr, (uint32_t*)buf, size / sizeof(uint32_t));
    return true;
}

static uint32_t LD32(uint8_t* buf)
{
    return (buf[0]) | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
}

bool Flash::_patch(uint8_t* buf, int size, int addr)
{
    const int crp_start = 0x2fc; // Code Read Protection location
    if (crp_start >= addr && crp_start < addr+size) {
        uint32_t pat = LD32(crp_start-addr+buf);
        if (pat != 0xffffffff) { // NO_CRP ?
            _pc->printf("\nCAUTION: CRP Pattern is not NO_CRP; %08x\n", pat);
            return false;
        }
    }
    return true;
}

Flash::IAP_STATUS Flash::remoteIAP(Flash::IAP_CMD cmd, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3)
{
    struct {
        uint32_t bkpt;       // +0       
        struct {             // IAP Structure
            uint32_t cmd;    // +4 Command
            uint32_t par[4]; // +8 Parameters
            uint32_t stat;   // +24 Status
            uint32_t res[4]; // +28 Result
        } IAP;               // +44
    } ram; 
    
    ram.bkpt = 0xe00abe00; // bpkt #00
    ram.IAP.cmd = cmd;
    ram.IAP.par[0] = p0;
    ram.IAP.par[1] = p1;
    ram.IAP.par[2] = p2;
    ram.IAP.par[3] = p3;
    _target->halt();
    _target->wait_status(TARGET_HALTED);

    _target->writeMemory(ram_addr, (uint32_t*)&ram, sizeof(ram)/sizeof(uint32_t));
    _target->r0 = ram_addr + 4;  // command addr
    _target->r1 = ram_addr + 24; // status addr
    _target->sp = 0x10000400-32; // IAP use ram top 32bytes
    _target->lr = ram_addr + 1; // return to bkpt
    _target->pc = 0x1fff1ff1; // IAP_Call
    _target->resume();
    _target->wait_status(TARGET_HALTED);
    if (cmd == READ_PART_ID) {
        part_id = _target->readMemory(ram_addr + 28);
    }
    return (IAP_STATUS)_target->readMemory(ram_addr + 24);  
}

bool Flash::verify(const char* filename)
{
    FILE* fp = fopen(filename, "rb");
    if (fp == NULL) {
        _pc->printf("file open error [%s]\n", filename);
        return false;
    }
    _pc->printf("Verifying.");
    uint8_t buf[256];
    bool passed = false;
    for(int addr = 0; addr < 0x80000; addr++) {
        int c = fgetc(fp);
        if (c == EOF) {
            passed = true;
            break;
        }
        if ((addr % sizeof(buf)) == 0) {
            _target->readMemory(addr, (uint32_t*)buf, sizeof(buf)/sizeof(uint32_t));
            _pc->printf(".");
        }
        if (c != buf[addr % sizeof(buf)]) {
            _pc->printf("\nError at %08x(%02x:%02x)\n", addr, c, buf[addr % sizeof(buf)]);
            break;
        }
    }
    fclose(fp);
    if (passed) {
        _pc->printf("passed.\n");
    }
    return passed;
}