//////////////////////////////////////////////////////////////////////// // // pc-flash: Pico-2 flash memory writer (PC program) // version 2.0 for Linux/Mac/Windows (August 31, 2009) // // (c) Hideki Kozima (xkozima@myu.ac.jp), subject to GPLv2 // // usage: pc-flash --dev /dev/ttyUSB0 file.sr (Linux) // pc-flash --dev /dev/tty.KeySerial1 file.sr (Mac) // pc-flash --dev COM3 file.sr (Windows) // // Functions: // This program writes an SR file to the flash memory on Pico-2 // (SH2). The SR file should be an executable program of SH2, // which will be baked into the flash memory (from 0x00000000 to // 0003ffff). // // Direction: // 1. Reset Pico-2 with BOOT mode (switch #6 and #7 are on). // 2. With "pc-boot" program, transfer "pico-flash.sr" to Pico-2. // $ pc-boot --dev /dev/ttyUSB0 pico-flash.sr // 3. Type "pc-flash ", and see what happens. // $ pc-flash --dev /dev/ttyUSB0 your-program.sr // //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // serial port interface // void com_init (char *dev); // void com_quit (); // void com_send (unsigned char *data, int n) // int com_rec_byte (unsigned char *data); #ifdef _WIN32 // Windows #include #include HANDLE ComFH; // file handle void com_error (char *func, char *mess) { fprintf(stderr, "*** com_%s: %s\n", func, mess); fprintf(stderr, "Press ENTER to exit: "); fflush(stderr); getchar(); exit(1); } void com_init (char *dev) { DCB dcb; // device settings COMMTIMEOUTS t_out; // timeout settings int ret; // open serial port ComFH = CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (ComFH == INVALID_HANDLE_VALUE) com_error("init", "cannot CreateFile"); // set attribute (baud, etc.) FillMemory(&dcb, sizeof(dcb), 0); dcb.DCBlength = sizeof(dcb); ret = BuildCommDCB("38400,n,8,1", &dcb); if (ret == 0) com_error("init", "cannot BuildCommDCB"); dcb.fRtsControl = RTS_CONTROL_DISABLE; ret = SetCommState(ComFH, &dcb); if (ret == 0) com_error("init", "cannot SetCommState"); // set timeout (100ms) t_out.ReadIntervalTimeout = MAXDWORD; t_out.ReadTotalTimeoutMultiplier = MAXDWORD; t_out.ReadTotalTimeoutConstant = 500; t_out.WriteTotalTimeoutMultiplier = MAXDWORD; t_out.WriteTotalTimeoutConstant = 500; ret = SetCommTimeouts(ComFH, &t_out); if (ret == 0) com_error("init", "cannot SetCommTimeouts"); } void com_quit () { int ret; ret = CloseHandle(ComFH); if (ret == 0) com_error("quit", "cannot CloseHandle"); } void com_send (unsigned char *data, int n) { int ret; DWORD n_done; ret = WriteFile(ComFH, data, n, &n_done, NULL); if (ret == 0) com_error("send", "cannot WriteFile"); if ((int) n_done < n) { // still some data to send Sleep(10); com_send(data + n_done, n - n_done); } } int com_rec_byte (unsigned char *data) { int ret; DWORD n_done; // read data from the port ret = ReadFile(ComFH, data, 1, &n_done, NULL); if (ret == 0) com_error("rec_byte", "cannot ReadFile"); // return 1 on success // return 0 on timeout return n_done; } // enf of Windows #else // Linux/Mac #include #include #include #include #include #include #include #include static int ComFD = -1; // file descriptor void com_error (char *func, char *mess) { fprintf(stderr, "*** com_%s: %s\n", func, mess); fprintf(stderr, "Press ENTER to exit: "); fflush(stderr); getchar(); exit(1); } void com_init (char *dev) { static struct termios termios_data; int ret; // open serial port ComFD = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); if (ComFD < 0) com_error("init", "can't open the port"); // set attribute (settings and baud) ret = tcgetattr(ComFD, &termios_data); termios_data.c_iflag = 0; termios_data.c_oflag = 0; termios_data.c_lflag = 0; termios_data.c_cflag = CS8 | CREAD | CLOCAL; termios_data.c_cc[VMIN] = 0; // "read" byte by byte termios_data.c_cc[VTIME] = 5; // timeout 500ms ret = cfsetspeed(&termios_data, B38400); if (ret < 0) com_error("init", "cannot set speed"); ret = tcsetattr(ComFD, TCSANOW, &termios_data); if (ret < 0) com_error("init", "cannot set attribute"); // turn off "NONBOLCK" ret = fcntl(ComFD, F_SETFL, 0); if (ret < 0) com_error("init", "can't fcntl (to unset NONBLOCK)"); // flush input/output ret = tcflush(ComFD, TCIOFLUSH); if (ret < 0) com_error("init", "cannot flush"); } void com_quit () { int ret; // close the port ret = close(ComFD); if (ret < 0) com_error("quit", "cannot close the port"); } void com_send (unsigned char *data, int n) { int ret, ret_drain; // write data to the port ret = write(ComFD, data, n); if (ret < 0) com_error("send", "cannot write data to the port"); // drain out the write-buffer ret_drain = tcdrain(ComFD); if (ret_drain < 0) com_error("send", "cannot drain the data"); // incomplete? if (ret < n) { // still some data to send usleep(10000); com_send(data + ret, n - ret); } } int com_rec_byte (unsigned char *data) { int ret; // read data from the port ret = read(ComFD, data, 1); if (ret < 0) com_error("rec_byte", "cannot read byte from the port"); // return 1 on success // return 0 on timeout return ret; } // end of Linux/Mac #endif // // com_send_byte (for Linux/Mac/Windows) void com_send_byte (unsigned char data) { com_send(&data, 1); } //////////////////////////////////////////////////////////////////////// // // flash #include #if defined(linux) // Linux #define LINUX #define DEF_DEV "/dev/ttyUSB0" // example // #elif defined(__APPLE__) && defined(__MACH__) // Mac OS X #define MAC_OS_X #define DEF_DEV "/dev/cu.KeySerial1" // example // #elif defined(_WIN32) // Windows #define WINDOWS #define DEF_DEV "COM3" // example // #endif static void error_exit (char *message) { fprintf(stderr, "*** boot: %s\n", message); exit(1); } //////////////////////////////////////////////////////////////////////// // // Motorola S format interpreter (for word-address) // head: S0 0000 // body: S1 <2-byte-address> // S2 <3-byte-address> // S3 <4-byte-address> // tail: S7 <4-byte-entry-address> // S8 <3-byte-entry-address> // S9 <2-byte-entry-address> // means # of bytes
to . static int sr_h2d (char c1, char c2) { int d1, d2; if ('0' <= c1 && c1 <= '9') d1 = c1 - '0'; else if ('A' <= c1 && c1 <= 'F') d1 = (c1 - 'A') + 10; else return -1; if ('0' <= c2 && c2 <= '9') d2 = c2 - '0'; else if ('A' <= c2 && c2 <= 'F') d2 = (c2 - 'A') + 10; else return -1; return d1*16 + d2; } int sr_readline1 (char *line, unsigned int *addr, unsigned char *data) { char s1, s2, b1, b2, a1, a2, a3, a4, c1, c2; int len, i; sscanf(line, "%c%c%c%c%c%c%c%c", &s1, &s2, &b1, &b2, &a1, &a2, &a3, &a4 ); len = sr_h2d(b1, b2) - 3; *addr = sr_h2d(a1, a2) * 0x100 + sr_h2d(a3, a4); for (i = 0; i < len; i++) { int val; sscanf(line+8+i*2, "%c%c", &c1 ,&c2); val = sr_h2d(c1, c2); if (val < 0) error_exit("SR: hex data required (SR_readline)"); data[i] = val; } return len; } int sr_readline2 (char *line, unsigned int *addr, unsigned char *data) { char s1, s2, b1, b2, a1, a2, a3, a4, a5, a6, c1, c2; int len, i; sscanf(line, "%c%c%c%c%c%c%c%c%c%c", &s1, &s2, &b1, &b2, &a1, &a2, &a3, &a4, &a5, &a6 ); len = sr_h2d(b1, b2) - 4; *addr = sr_h2d(a1, a2) * 0x10000 + sr_h2d(a3, a4) * 0x100 + sr_h2d(a5, a6); for (i = 0; i < len; i++) { int val; sscanf(line+10+i*2, "%c%c", &c1 ,&c2); val = sr_h2d(c1, c2); if (val < 0) error_exit("SR: hex data required (SR_readline)"); data[i] = val; } return len; } int sr_readline3 (char *line, unsigned int *addr, unsigned char *data) { char s1, s2, b1, b2, a1, a2, a3, a4, a5, a6, a7, a8, c1, c2; int len, i; sscanf(line, "%c%c%c%c%c%c%c%c%c%c%c%c", &s1, &s2, &b1, &b2, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8 ); len = sr_h2d(b1, b2) - 5; *addr = sr_h2d(a1, a2) * 0x1000000 + sr_h2d(a3, a4) * 0x10000 + sr_h2d(a5, a6) * 0x100 + sr_h2d(a7, a8); for (i = 0; i < len; i++) { int val; sscanf(line+12+i*2, "%c%c", &c1 ,&c2); val = sr_h2d(c1, c2); if (val < 0) error_exit("SR: hex data required (SR_readline)"); data[i] = val; } return len; } //////////////////////////////////////////////////////////////////////// // // main #define MEMSIZE 262144 #define LINELEN 1000 int main (int argc, char **argv) { char *dev = DEF_DEV, *filename = NULL; FILE *file; char line[LINELEN]; int length = 0, i, res; unsigned char ack; unsigned char memory[MEMSIZE]; unsigned char memtag[2048]; // tag for 128-byte blocks // reading options // -d/---dev if (argc == 1) { printf("pc-flash: download an S-file to the flash memory\n"); printf(" fpc-lash [-d/-dev ] \n"); printf(" default : %s\n", dev); return 0; } for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dev") == 0) { if (i == argc - 1) error_exit("pc-flash: error in option -d/--dev (main)"); dev = argv[i + 1]; i++; } else filename = argv[i]; } if (! filename) error_exit("pc-flash: filename is missing (main)"); // clear the memory & memtag for (i = 0; i < MEMSIZE; i++) memory[i] = 0xff; for (i = 0; i < 2048; i++) memtag[i] = 0; // read S-data printf("Reading s-file (%s) ... ", filename); fflush(stdout); file = fopen(filename, "r"); if (file == NULL) error_exit("pc-flash: s-file not found (main)"); while (fgets(line, LINELEN, file)) { unsigned int len, addr, j; if (strlen(line) < 6) error_exit("pc-flash: format error in s-file (main)"); if (line[0] != 'S') error_exit("pc-flash: line format error in s-file (main)"); switch (line[1]) { case '1': len = sr_readline1(line, &addr, memory+length); break; case '2': len = sr_readline2(line, &addr, memory+length); break; case '3': len = sr_readline3(line, &addr, memory+length); break; default: continue; } if (addr >= 0x00040000 || addr < 0) error_exit("pc-flash: address out of range (main)"); for (j = 0; j < len; j++) memtag[(addr + j) / 128] = 1; length += len; } fclose(file); printf(" done (%d bytes)\n", length); // open serial port com_init(dev); printf("Opened serial port (%s at 38400)\n", dev); // write to flash memory // host: ... // pico: 0x00 // host: ... // pico: 0x00 // ... // host: <0xffffffff> // pico: 0xff printf("Writing flash "); fflush(stdout); for (i = 0; i < 2048; i++) { if (memtag[i]) { unsigned int addr; unsigned char ack = 0x55; int j, res; // send address addr = i * 128; com_send_byte((addr >> 24) & 0xff); com_send_byte((addr >> 16) & 0xff); com_send_byte((addr >> 8) & 0xff); com_send_byte( addr & 0xff); // send data block for (j = 0; j < 128; j++) com_send_byte(*(memory+addr+j)); // receive ack res = com_rec_byte(&ack); if (res == 0) error_exit("pc-flash: acknowledge timeout (main)"); if (ack != 0x00) error_exit("pc-flash: failed in writing data block (main)"); printf("."); fflush(stdout); } } printf(" done\n"); // send end mark and receive ack com_send_byte(0xff); com_send_byte(0xff); com_send_byte(0xff); com_send_byte(0xff); res = com_rec_byte(&ack); if (res == 0) error_exit("pc-flash: final acknowledge timeout (main)"); if (ack != 0xff) error_exit("pc-flash: failed in finising flash memory (main)"); printf("Program has been successfully written!\n"); // epilogue com_quit(); printf("Press ENTER to end this program: "); fflush(stdout); getchar(); return 0; }