USB composite device example program, drag-and-drop flash writer.
Dependencies: SWD USBDevice mbed BaseDAP
Diff: Flash.cpp
- Revision:
- 0:2385683c867a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Flash.cpp Tue Sep 17 04:33:44 2013 +0000 @@ -0,0 +1,216 @@ +// Flash.cpp 2013/9/16 +#include "Flash.h" +#include "Target2.h" +#include "mydebug.h" + +#define SYSMEMREMAP 0x40048000 +#define MAINCLKSEL 0x40048070 +#define MAINCLKUEN 0x40048074 +#define SYSAHBCLKDIV 0x40048078 + +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."); + if (_target->idcode == 0x0bb11477) { // LPC1114FN28 + _target->writeMemory(MAINCLKSEL, 0); // Select Internal RC Oscillator + _target->writeMemory(MAINCLKUEN, 1); // Update Main Clock Source + _target->writeMemory(MAINCLKUEN, 0); // Toggle Update Register + _target->writeMemory(MAINCLKUEN, 1); + uint32_t data = _target->readMemory(MAINCLKUEN); // Wait until updated + if (!(data & 1)) { + _pc->printf("\nerror MAINCLKUEN=%08x\n", data); + return false; + } + _target->writeMemory(SYSAHBCLKDIV, 1);// Set Main Clock divider to 1 + _target->writeMemory(SYSMEMREMAP, 2); // User Flash Mode + } else { + _pc->printf("\nerror idcode=%08x\n", _target->idcode); + return false; + } + _pc->printf("passed.\n"); + return true; +} + +bool Flash::write(const char* filename) +{ + FILE* fp = fopen(filename, "rb"); + if (fp == NULL) { + _pc->printf("file open error [%s]\n", filename); + return false; + } + _pc->printf("Writing."); + uint8_t buf[512]; + bool passed = false; + for(int addr = 0; addr < 0x8000; 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; +} + +bool Flash::write(int addr, const uint8_t* data, int size) +{ + const int ram = 0x10000200; + const int ram_size = 256; + for(int i = 0; i < size; i += ram_size) { + if (!_write_to_ram(ram, ram_size, data+i)) { + _pc->printf("faild. write to ram %08x\n", ram); + return false; + } + if (remoteIAP(PREPARE_SECTOR, _sector(addr+i), _sector(addr+i)) != CMD_SUCCESS) { + _pc->printf("faild. PREPARE_SECTOR %d %d\n", _sector(addr+i), _sector(addr+i)); + return false; + } + if (remoteIAP(COPY_RAM_TO_FLASH, addr+i, ram, ram_size, IAP_CCLK) != CMD_SUCCESS) { + _pc->printf("faild. COPY_RAM_TO_FLASH %d %d %d %dn", addr+i, ram, ram_size); + return false; + } + if (remoteIAP(COMPARE, addr+i, ram, ram_size) != CMD_SUCCESS) { + _pc->printf("faild. COMPARE %d %d %d", addr+i, ram, ram_size); + return false; + } + } + return true; +} + +bool Flash::eraseAll() +{ + _pc->printf("Erasing."); + for(int sector = 0; sector <= 7; sector++) { + IAP_STATUS status = remoteIAP(PREPARE_SECTOR, sector, sector); + if (status != CMD_SUCCESS) { + _pc->printf("faild. PREPARE_SECTOR %d %d status=%d\n", sector, sector, status); + return false; + } + if (remoteIAP(ERASE_SECTOR, sector, sector, IAP_CCLK) != CMD_SUCCESS) { + _pc->printf("faild. ERASE_SECTOR %d %d %d\n", sector, sector, IAP_CCLK); + return false; + } + if (remoteIAP(BLANK_CHECK, sector, sector, IAP_CCLK) != CMD_SUCCESS) { + _pc->printf("faild. BLANK_CHECK %d %d %d\n", sector, sector, IAP_CCLK); + return false; + } + _pc->printf("."); + } + _pc->printf("passed.\n"); + 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; +} + +int Flash::_sector(int addr) +{ + return addr / 4096; +} + +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); + const uint32_t ram_addr = 0x10000100; + _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); + 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 < 0x8000; 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; +}