825 lines
16 KiB
C
825 lines
16 KiB
C
|
/*
|
||
|
* iceprogduino -- simple programming tool for FTDI-based Lattice iCE programmers
|
||
|
* and Olinuxino based programmers for iCE40HX1K-EVB
|
||
|
*
|
||
|
* Copyright (C) 2015 Clifford Wolf <clifford@clifford.at>
|
||
|
* Olimexino Nano edition by Chris B. <chris@protonic.co.uk> @ Olimex Ltd. <c> 2016
|
||
|
*
|
||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||
|
* purpose with or without fee is hereby granted, provided that the above
|
||
|
* copyright notice and this permission notice appear in all copies.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*
|
||
|
* Relevant Documents:
|
||
|
* -------------------
|
||
|
* http://www.latticesemi.com/~/media/Documents/UserManuals/EI/icestickusermanual.pdf
|
||
|
* http://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_32mb_3v_65nm.pdf
|
||
|
* https://www.olimex.com/ iCE40HX1K-EVB
|
||
|
*/
|
||
|
|
||
|
//#define Olinuxino
|
||
|
//#define FTDI
|
||
|
#define Nano
|
||
|
|
||
|
#define READ_ID 0x9F
|
||
|
#define PWR_UP 0xAB
|
||
|
#define PWR_DOWN 0xB9
|
||
|
#define WR_EN 0x06
|
||
|
#define BULK_ERASE 0xC7
|
||
|
#define SEC_ERASE 0xd8
|
||
|
#define PROG 0x02
|
||
|
#define READ 0x03
|
||
|
#define READY 0x44
|
||
|
#define READ_ALL 0x83
|
||
|
#define EMPTY 0x45
|
||
|
|
||
|
|
||
|
#define _GNU_SOURCE
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
|
||
|
|
||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void serial_read(int x);
|
||
|
|
||
|
#define FEND 0xc0
|
||
|
#define FESC 0xdb
|
||
|
#define TFEND 0xdc
|
||
|
#define TFESC 0xdd
|
||
|
bool newframe;
|
||
|
bool timeout;
|
||
|
bool escaped;
|
||
|
#include <termios.h>
|
||
|
#define SerialPort "/dev/ttyACM0"
|
||
|
int fd;
|
||
|
uint8_t rxframe[512], txframe[512], fcs, tfcs;
|
||
|
uint16_t txp,rxp;
|
||
|
uint8_t membuf[0x200000];
|
||
|
uint8_t pages[0x2000];
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
bool verbose = false;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
int set_interface_attribs (int fd, int speed, int parity)
|
||
|
{
|
||
|
struct termios tty;
|
||
|
memset (&tty, 0, sizeof tty);
|
||
|
if (tcgetattr (fd, &tty) != 0)
|
||
|
{
|
||
|
fprintf(stderr,"error %d from tcgetattr", errno);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
cfsetospeed (&tty, speed);
|
||
|
cfsetispeed (&tty, speed);
|
||
|
|
||
|
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
|
||
|
tty.c_iflag &= ~IGNBRK; // disable break processing
|
||
|
tty.c_lflag = 0; // no signaling chars, no echo,
|
||
|
// no canonical processing
|
||
|
tty.c_oflag = 0; // no remapping, no delays
|
||
|
tty.c_cc[VMIN] = 0; // read doesn't block
|
||
|
tty.c_cc[VTIME] = 0; // no read timeout
|
||
|
|
||
|
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
|
||
|
|
||
|
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
|
||
|
// enable reading
|
||
|
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
|
||
|
tty.c_cflag |= parity;
|
||
|
tty.c_cflag |= parity;
|
||
|
tty.c_cflag &= ~CSTOPB;
|
||
|
tty.c_cflag &= ~CRTSCTS;
|
||
|
|
||
|
if (tcsetattr (fd, TCSANOW, &tty) != 0)
|
||
|
{
|
||
|
fprintf(stderr,"error %d from tcsetattr", errno);
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void set_blocking (int fd, int should_block)
|
||
|
{
|
||
|
struct termios tty;
|
||
|
memset (&tty, 0, sizeof tty);
|
||
|
if (tcgetattr (fd, &tty) != 0)
|
||
|
{
|
||
|
fprintf(stderr,"error %d from tggetattr", errno);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
tty.c_cc[VMIN] = should_block ? 1 : 0;
|
||
|
tty.c_cc[VTIME] = 0;
|
||
|
|
||
|
if (tcsetattr (fd, TCSANOW, &tty) != 0)
|
||
|
fprintf(stderr,"error %d setting term attributes", errno);
|
||
|
}
|
||
|
|
||
|
void startframe(uint8_t command){
|
||
|
txframe[0]=FEND;
|
||
|
txframe[1]=command;
|
||
|
tfcs = command;
|
||
|
txp = 2;
|
||
|
}
|
||
|
|
||
|
void addbyte(uint8_t newbyte){
|
||
|
tfcs+=newbyte;
|
||
|
|
||
|
switch(newbyte){
|
||
|
case FEND:
|
||
|
txframe[txp++] = FESC;
|
||
|
txframe[txp++] = TFEND;
|
||
|
break;
|
||
|
case FESC:
|
||
|
txframe[txp++] = FESC;
|
||
|
txframe[txp++] = TFESC;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
txframe[txp++] = newbyte;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void sendframe(){
|
||
|
tfcs=0xff-tfcs;
|
||
|
addbyte(tfcs);
|
||
|
txframe[txp++] = FEND;
|
||
|
#ifdef frdebug
|
||
|
printf("%02X-L:%04X/%02X\n",txframe[txp-1],txp,tfcs);
|
||
|
#endif
|
||
|
if (fd>=0)
|
||
|
write(fd,txframe,txp);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void error()
|
||
|
{
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
bool waitframe(uint8_t cmd)
|
||
|
{
|
||
|
rxp = 0;
|
||
|
newframe = false;
|
||
|
fcs = 0;
|
||
|
|
||
|
uint32_t addr;
|
||
|
|
||
|
for (uint32_t to=0;to<5000;to++)
|
||
|
{
|
||
|
serial_read(0);
|
||
|
usleep(50);
|
||
|
|
||
|
if (newframe){
|
||
|
// int rxpp = rxp;
|
||
|
rxp = 0;
|
||
|
newframe = false;
|
||
|
usleep(10);
|
||
|
|
||
|
|
||
|
if ((rxframe[0]==READ_ID) && (cmd == READ_ID)){
|
||
|
|
||
|
if (rxframe[1]==0xef) fprintf(stderr, "Winbond Serial Flash ");
|
||
|
else fprintf(stderr, "Manufacturer ID: 0x%02X",rxframe[1]);
|
||
|
if ((rxframe[2]==0x40) && (rxframe[3]==0x15)) fprintf(stderr, "- W25Q16BV\n");
|
||
|
else fprintf(stderr, " / Device ID: 0x%02X%02X\n",rxframe[2],rxframe[3]);
|
||
|
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (rxframe[0]==READ)
|
||
|
|
||
|
{
|
||
|
|
||
|
addr = (rxframe[1]<<16) | (rxframe[2]<<8);
|
||
|
pages[addr>>8]=0;
|
||
|
|
||
|
for (int x=3; x < 259;x++)
|
||
|
{
|
||
|
|
||
|
membuf[addr++]=rxframe[x];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (rxframe[0]==READY) if (cmd==READY) return true; else to = 0;
|
||
|
|
||
|
if (rxframe[0]==EMPTY) pages[(rxframe[1]<<8) | rxframe[2]]=0;
|
||
|
|
||
|
if ((rxframe[0]==READ)||(rxframe[0]==EMPTY)) if (cmd==READ) return true; else to = 0;
|
||
|
rxframe[0]=0;
|
||
|
fcs = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void flash_read_id()
|
||
|
{
|
||
|
startframe(READ_ID);
|
||
|
sendframe();
|
||
|
waitframe(READ_ID);
|
||
|
return;
|
||
|
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
void flash_bulk_erase()
|
||
|
{
|
||
|
fprintf(stderr, "\nbulk erase..");
|
||
|
|
||
|
|
||
|
startframe(BULK_ERASE);
|
||
|
sendframe();
|
||
|
waitframe(BULK_ERASE);
|
||
|
fprintf(stderr, "\rbulk erased\n");
|
||
|
|
||
|
}
|
||
|
|
||
|
void flash_64kB_sector_erase(int addr)
|
||
|
{
|
||
|
fprintf(stderr, "erase 64kB sector at 0x%06X..", addr);
|
||
|
|
||
|
startframe(SEC_ERASE);
|
||
|
addbyte(addr>>16);
|
||
|
addbyte(addr>>8);
|
||
|
sendframe();
|
||
|
waitframe(READY);
|
||
|
fprintf(stderr, "erased\n");
|
||
|
|
||
|
}
|
||
|
|
||
|
void flash_read_all(void){
|
||
|
|
||
|
fprintf(stderr, "read 0x%06X +0x%06X..\n", 0, 0x200000);
|
||
|
memset(&membuf,0xff,sizeof(membuf));
|
||
|
memset(&pages,0xff,sizeof(pages));
|
||
|
startframe(READ_ALL);
|
||
|
sendframe();
|
||
|
if (!waitframe(READY))
|
||
|
{
|
||
|
error();
|
||
|
|
||
|
}
|
||
|
|
||
|
fprintf(stderr, "Requesting missmatched frames...");
|
||
|
bool notready=false;
|
||
|
while (1){
|
||
|
notready = false;
|
||
|
int s = 0;
|
||
|
for(int x = 0; x < 0x2000;x++)
|
||
|
{
|
||
|
|
||
|
if (pages[x]>0){
|
||
|
if (s++ > 25)
|
||
|
{
|
||
|
fprintf(stderr, "ERROR Reading..\n");
|
||
|
notready = false;
|
||
|
break;
|
||
|
}
|
||
|
notready=true;
|
||
|
fprintf(stderr, ".");
|
||
|
startframe(READ);
|
||
|
addbyte(x >> 8);
|
||
|
addbyte(x >> 0);
|
||
|
sendframe();
|
||
|
waitframe(READ);
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (!notready) break;
|
||
|
|
||
|
|
||
|
}
|
||
|
fprintf(stderr, "\n");
|
||
|
uint32_t i;
|
||
|
if (verbose)
|
||
|
for (i = 0; i < 1024; i++)
|
||
|
fprintf(stderr, "%02x%c", membuf[i], i == 0 || i % 32 == 31 ? '\n' : ' ');
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void help(const char *progname)
|
||
|
{
|
||
|
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, "iceprog -- simple programming tool for Olinuxino Nano-based Lattice iCE programmers\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, "Usage: %s [options] <filename>\n", progname);
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -e\n");
|
||
|
fprintf(stderr, " bulk erase entire flash only\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -w\n");
|
||
|
fprintf(stderr, " write only, do not verify\n\n");
|
||
|
fprintf(stderr, " -f\n");
|
||
|
fprintf(stderr, " write all data, including 0xFF's pages\n\n");
|
||
|
fprintf(stderr, " -I<serialport>\n");
|
||
|
fprintf(stderr, " port to connect Arduino (default /dev/ttyACM0)\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -r\n");
|
||
|
fprintf(stderr, " read entire flash (2MB) and write to file\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
|
||
|
|
||
|
fprintf(stderr, " -c\n");
|
||
|
fprintf(stderr, " do not write flash, only verify (check)\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -b\n");
|
||
|
fprintf(stderr, " bulk erase entire flash before writing\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -n\n");
|
||
|
fprintf(stderr, " do not erase flash before writing\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -o <offset in bytes> start address for write [default: 0]\n");
|
||
|
fprintf(stderr, " (append 'k' to the argument for size in kilobytes,\n");
|
||
|
fprintf(stderr, " or 'M' for size in megabytes)\n");
|
||
|
fprintf(stderr, " this feature works not with all options.\n");
|
||
|
fprintf(stderr, " tested with -b, -v\n");
|
||
|
fprintf(stderr, " -t\n");
|
||
|
fprintf(stderr, " just read the flash ID sequence\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
fprintf(stderr, " -v\n");
|
||
|
fprintf(stderr, " verbose output\n");
|
||
|
fprintf(stderr, "\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void serial_read(int x)
|
||
|
{
|
||
|
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
if (rxp>512)
|
||
|
{
|
||
|
newframe = 0;
|
||
|
rxp = 0;
|
||
|
escaped = false;
|
||
|
fcs = 0;
|
||
|
break;
|
||
|
}
|
||
|
usleep(5);
|
||
|
uint8_t buf[1];
|
||
|
int n;
|
||
|
|
||
|
if (fd < 0)
|
||
|
{
|
||
|
printf(".");
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
n=read(fd, buf, 1);
|
||
|
if (n==1){
|
||
|
|
||
|
switch(buf[0]){
|
||
|
case FEND:
|
||
|
if (fcs==0xff)
|
||
|
{
|
||
|
newframe = 1;
|
||
|
return;
|
||
|
}
|
||
|
newframe = 0;
|
||
|
rxp = 0;
|
||
|
escaped = false;
|
||
|
fcs = 0;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case FESC:
|
||
|
escaped = true;
|
||
|
break;
|
||
|
|
||
|
case TFESC:
|
||
|
if (escaped)
|
||
|
{
|
||
|
rxframe[rxp++]=FESC;
|
||
|
fcs+=FESC;
|
||
|
escaped = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rxframe[rxp++]=TFESC;
|
||
|
fcs += TFESC;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case TFEND:
|
||
|
if (escaped)
|
||
|
{
|
||
|
rxframe[rxp++]=FEND;
|
||
|
fcs += FEND;
|
||
|
escaped=false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rxframe[rxp++]=TFEND;
|
||
|
fcs += TFEND;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
escaped=false;
|
||
|
rxframe[rxp++]=buf[0];
|
||
|
fcs+=buf[0];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
int addr;
|
||
|
int max_read_size = 0x200000;
|
||
|
bool read_mode = false;
|
||
|
bool check_mode = false;
|
||
|
bool bulk_erase = false;
|
||
|
bool dont_erase = false;
|
||
|
bool prog_sram = false;
|
||
|
bool test_mode = false;
|
||
|
|
||
|
bool noverify = true; // verify performs by arduino board
|
||
|
bool ff_mode = false;
|
||
|
bool bulk_erase_only = false;
|
||
|
const char *filename = NULL;
|
||
|
const char *devstr = NULL;
|
||
|
int rw_offset = 0;
|
||
|
|
||
|
int opt;
|
||
|
char *endptr;
|
||
|
|
||
|
|
||
|
char *portname = SerialPort;
|
||
|
while ((opt = getopt(argc, argv, "I:o:rcbntvwfeh")) != -1)
|
||
|
|
||
|
|
||
|
{
|
||
|
switch (opt)
|
||
|
{
|
||
|
case 'd':
|
||
|
devstr = optarg;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 'I':
|
||
|
portname = optarg;
|
||
|
break;
|
||
|
|
||
|
case 'r':
|
||
|
read_mode = true;
|
||
|
noverify=false;
|
||
|
break;
|
||
|
case 'e':
|
||
|
bulk_erase_only = true;
|
||
|
break;
|
||
|
case 'f':
|
||
|
ff_mode = true;
|
||
|
break;
|
||
|
case 'R':
|
||
|
read_mode = true;
|
||
|
max_read_size = 256 * 1024;
|
||
|
break;
|
||
|
case 'c':
|
||
|
check_mode = true;
|
||
|
noverify=false;
|
||
|
break;
|
||
|
case 'b':
|
||
|
bulk_erase = true;
|
||
|
break;
|
||
|
case 'n':
|
||
|
|
||
|
dont_erase = true;
|
||
|
break;
|
||
|
case 'S':
|
||
|
prog_sram = true;
|
||
|
break;
|
||
|
case 't':
|
||
|
test_mode = true;
|
||
|
printf("\nTest mode\n");
|
||
|
break;
|
||
|
case 'v':
|
||
|
verbose = true;
|
||
|
break;
|
||
|
case 'w':
|
||
|
noverify = true;
|
||
|
break;
|
||
|
case 'o': /* set address offset */
|
||
|
rw_offset = strtol(optarg, &endptr, 0);
|
||
|
if (*endptr == '\0')
|
||
|
/* ok */;
|
||
|
else if (!strcmp(endptr, "k"))
|
||
|
rw_offset *= 1024;
|
||
|
else if (!strcmp(endptr, "M"))
|
||
|
rw_offset *= 1024 * 1024;
|
||
|
else {
|
||
|
fprintf(stderr, "'%s' is not a valid offset\n", optarg);
|
||
|
return EXIT_FAILURE;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
help(argv[0]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if (read_mode + check_mode + prog_sram + test_mode > 1)
|
||
|
help(argv[0]);
|
||
|
|
||
|
if (bulk_erase && dont_erase)
|
||
|
help(argv[0]);
|
||
|
|
||
|
if (optind+1 != argc && !test_mode && !bulk_erase_only)
|
||
|
help(argv[0]);
|
||
|
|
||
|
filename = argv[optind];
|
||
|
|
||
|
//bulk_erase = true; // comment this line if you do not want to bulk erase by default
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/* open serial port */
|
||
|
fd = open(portname, O_RDWR | O_NOCTTY);
|
||
|
// fd = open(portname, O_RDWR | O_ASYNC | O_NDELAY);
|
||
|
if (fd < 0)
|
||
|
{
|
||
|
fprintf(stderr,"error %d opening %s: %s\n", errno, portname, strerror (errno));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
set_interface_attribs (fd, B57600, 0); // set speed to 57600 bps, 8n1 (no parity)
|
||
|
set_blocking (fd, 0); // set no blocking
|
||
|
|
||
|
|
||
|
|
||
|
fprintf(stderr,"Serial: %s: %s\n", portname, strerror (errno));
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
rxp = 0;
|
||
|
|
||
|
if (test_mode)
|
||
|
{
|
||
|
|
||
|
|
||
|
flash_read_id();
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
else if (prog_sram)
|
||
|
{
|
||
|
fprintf(stderr, "\nprogramming SRAM is not supported!\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// ---------------------------------------------------------
|
||
|
// Program
|
||
|
// ---------------------------------------------------------
|
||
|
|
||
|
if (!read_mode && !check_mode && !bulk_erase_only)
|
||
|
{
|
||
|
|
||
|
FILE *f = (strcmp(filename, "-") == 0) ? stdin :
|
||
|
fopen(filename, "r");
|
||
|
if (f == NULL) {
|
||
|
fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
|
||
|
error();
|
||
|
}
|
||
|
|
||
|
if (!dont_erase)
|
||
|
{
|
||
|
if (bulk_erase)
|
||
|
{
|
||
|
|
||
|
flash_bulk_erase();
|
||
|
sleep(1);
|
||
|
flash_read_id();
|
||
|
usleep(10000);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
struct stat st_buf;
|
||
|
if (stat(filename, &st_buf)) {
|
||
|
fprintf(stderr, "Error: Can't stat '%s': %s\n", filename, strerror(errno));
|
||
|
error();
|
||
|
}
|
||
|
|
||
|
fprintf(stderr, "file size: %d\n", (int)st_buf.st_size);
|
||
|
/* 64 k */
|
||
|
int begin_addr = rw_offset & ~0xffff;
|
||
|
int end_addr = (rw_offset + st_buf.st_size + 0xffff) & ~0xffff;
|
||
|
for (addr = begin_addr; addr < end_addr; addr += 0x10000) {
|
||
|
|
||
|
flash_64kB_sector_erase(addr);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fprintf(stderr, "\nprogramming..\n");
|
||
|
int ccc;
|
||
|
|
||
|
flash_read_id();
|
||
|
|
||
|
|
||
|
/* page is 256 */
|
||
|
for (int rc, addr = 0; true; addr += rc) {
|
||
|
uint8_t buffer[256];
|
||
|
int page_size = 256 - (rw_offset + addr) % 256;
|
||
|
rc = fread(buffer, 1, page_size, f);
|
||
|
|
||
|
int offset_addr = addr + rw_offset;
|
||
|
if (rc <= 0) break;
|
||
|
if (verbose)
|
||
|
fprintf(stderr, "prog 0x%06X +0x%03X..\n", offset_addr, rc);
|
||
|
else
|
||
|
fprintf(stderr, "\rprog 0x%06X +0x%03X..", offset_addr, rc);
|
||
|
for (ccc=0;ccc<rc;ccc++){
|
||
|
if ((buffer[ccc] != 0xFF) || (ff_mode))
|
||
|
{
|
||
|
int x;
|
||
|
|
||
|
|
||
|
while(1){
|
||
|
|
||
|
startframe(PROG);
|
||
|
addbyte(offset_addr>>16);
|
||
|
addbyte(offset_addr>>8);
|
||
|
for (x=0;x<rc;x++)
|
||
|
addbyte(buffer[x]);
|
||
|
|
||
|
sendframe();
|
||
|
|
||
|
//if (verbose)
|
||
|
fprintf(stderr, ".");
|
||
|
|
||
|
//usleep(1000);
|
||
|
if (waitframe(READY)) break;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
fprintf(stderr, "\n");
|
||
|
|
||
|
|
||
|
if (f != stdin)
|
||
|
fclose(f);
|
||
|
}
|
||
|
|
||
|
if (!noverify && !bulk_erase_only)
|
||
|
{
|
||
|
// ---------------------------------------------------------
|
||
|
// Read/Verify
|
||
|
// ---------------------------------------------------------
|
||
|
|
||
|
if (read_mode)
|
||
|
{
|
||
|
FILE *f = (strcmp(filename, "-") == 0) ? stdout :
|
||
|
fopen(filename, "w");
|
||
|
if (f == NULL) {
|
||
|
fprintf(stderr, "Error: Can't open '%s' for writing: %s\n", filename, strerror(errno));
|
||
|
error();
|
||
|
}
|
||
|
|
||
|
fprintf(stderr, "\nreading..\n");
|
||
|
|
||
|
|
||
|
|
||
|
flash_read_id();
|
||
|
flash_read_all();
|
||
|
printf("\nWriting data to file %s\n",filename);
|
||
|
fwrite(membuf, 0x200000, 1, f);
|
||
|
|
||
|
if (f != stdout)
|
||
|
fclose(f);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FILE *f = (strcmp(filename, "-") == 0) ? stdin :
|
||
|
fopen(filename, "r");
|
||
|
if (f == NULL) {
|
||
|
fprintf(stderr, "Error: Can't open '%s' for reading: %s\n", filename, strerror(errno));
|
||
|
error();
|
||
|
}
|
||
|
|
||
|
fprintf(stderr, "\nreading..\n");
|
||
|
|
||
|
flash_read_id();
|
||
|
flash_read_all();
|
||
|
uint8_t buffer_file[0x200000];
|
||
|
int rc = fread(buffer_file, 1, 0x200000, f);
|
||
|
|
||
|
if (memcmp(buffer_file, membuf, rc))
|
||
|
{
|
||
|
fprintf(stderr, "Found difference between flash and file!\n");
|
||
|
error();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
fprintf(stderr, "\nVERIFY OK\n");
|
||
|
|
||
|
if (f != stdin)
|
||
|
fclose(f);
|
||
|
}
|
||
|
}
|
||
|
if (bulk_erase_only)
|
||
|
{
|
||
|
|
||
|
|
||
|
flash_bulk_erase();
|
||
|
|
||
|
fprintf(stderr, "Flash erased!\n");
|
||
|
}
|
||
|
// ---------------------------------------------------------
|
||
|
// Reset
|
||
|
// ---------------------------------------------------------
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------
|
||
|
// Exit
|
||
|
// ---------------------------------------------------------
|
||
|
|
||
|
fprintf(stderr, "Bye.\n");
|
||
|
|
||
|
|
||
|
|
||
|
close(fd);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|