//////////////////////////////////////////////////////////////////////// // // boot: Pico-2 ram-boot program // version 2.0 for Linux/Mac/Windows (August 31, 2009) // // (c) Hideki Kozima (xkozima@myu.ac.jp), subject to GPLv2 // // usage: boot --dev /dev/ttyUSB0 file.sr (Linux) // boot --dev /dev/tty.KeySerial1 file.sr (Mac) // boot --dev COM3 file.sr (Windows) // // Functions: // This program transfers an SR file to RAM on Pico-2. The SR file // should be an executable program of SH2, which will be fed into // the RAM (from 0xffffd800) of SH2 (S7046F). You need to reset // Pico-2 with BOOT mode (switch #6 and #7 are on) before load. // //////////////////////////////////////////////////////////////////////// // // 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); } //////////////////////////////////////////////////////////////////////// // // boot #include #if defined(linux) // Linux #define DEF_DEV "/dev/ttyUSB0" // example // #elif defined(__APPLE__) && defined(__MACH__) // Mac OS X #define DEF_DEV "/dev/cu.KeySerial1" // example // #elif defined(_WIN32) // Windows #define DEF_DEV "COM3" // example #define usleep(a) Sleep((a)/1000) // #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: S3 // tail: S7 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_readline (char *line, 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; 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 NEGOMAX 32 #define MAXSIZE 100000 #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 data, length_hi, length_lo; unsigned char memory[MAXSIZE]; // reading options // -d/--dev if (argc == 1) { printf("boot: download a ram-program to Pico-2\n"); printf(" boot [-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("error in option -d/--dev (main)"); dev = argv[i + 1]; i++; } else filename = argv[i]; } if (! filename) error_exit("filename is missing (main)"); // read S-data printf("Reading s-file (%s) ...", filename); fflush(stdout); file = fopen(filename, "r"); if (file == NULL) error_exit("boot: s-file not found (main)"); while (fgets(line, LINELEN, file)) { if (strlen(line) < 6) error_exit("boot: format error in s-file (main)"); if (line[0] != 'S') error_exit("boot: line format error in s-file (main)"); if (line[1] == '0') continue; // header (ignore) if (line[1] == '7') continue; // tailer (ignore) if (line[1] == '3') length += sr_readline(line, memory+length); } fclose(file); printf(" done. (%d bytes)\n", length); if (length > 9984) error_exit("boot: program size exceeds the ram size (main)"); // open serial port com_init(dev); printf("Opened serial port (%s at 19200 bps)\n", dev); // negotiation // host: 0x00 // pico: ---- // host: 0x00 // pico: ---- // host: 0x00 // pico: 0x00 printf("Negotiating "); fflush(stdout); res = 0; for (i = 0; i < NEGOMAX; i++) { com_send_byte(0x00); res = com_rec_byte(&data); if (res != 0) break; printf("."); fflush(stdout); } if (res == 0) error_exit("boot: negotiation timeout (main)"); if (data != 0x00) error_exit("boot: negotiation failed (main)"); printf(" done. (0x%02x)\n", data); // acknowledge // host: 0x55 // pico: 0xaa com_send_byte(0x55); com_rec_byte(&data); if (data != 0xaa) error_exit("boot: acknowledgment failed (main)"); printf("Acknowledged to start downloading. (0x%02x)\n", data); // send and check byte length // host: length_hi // host: length_lo // pico: length_hi (echo) // pico: length_lo (echo) length_hi = length / 256; length_lo = length % 256; com_send_byte(length_hi); com_send_byte(length_lo); com_rec_byte(&data); if (data != length_hi) error_exit("boot: byte length (high) mismatch (main)"); com_rec_byte(&data); if (data != length_lo) error_exit("boot: byte length (low) mismatch (main)"); // feed the program to Pico-2's ram! // host: byte // pico: byte (echo) printf("Downloading "); fflush(stdout); for (i = 0; i < length; i++) { com_send_byte(memory[i]); com_rec_byte(&data); if (memory[i] != data) error_exit("boot: echoback data mismatch (main)"); if (i % 100 == 0) { printf("."); fflush(stdout); } } printf(" done.\n"); // check if flash is erased // pico: 0xaa (on success) or 0xff (on failure) i = 0; res = com_rec_byte(&data); while (res == 0) { if (++i > 10) error_exit("boot: flash erase check timeout (main)"); res = com_rec_byte(&data); } if (data == 0xff) error_exit("boot: flash erase failed (main)"); else if (data != 0xaa) error_exit("boot: flash erase probably failed (main)"); printf("Flash memory is successfully erased.\n"); printf("*** Now your Pico-2 starts the program. ***\n"); // epilogue com_quit(); printf("Press ENTER to end this program: "); fflush(stdout); getchar(); return 0; }