int main(int argc, char* argv[]) { struct port_interface *port = NULL; int ret = 1; stm32_err_t s_err; parser_err_t perr; FILE *diag = stdout; fprintf(diag, "stm32flash " VERSION "\n\n"); fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n"); if (parse_options(argc, argv) != 0) goto close; if (rd && filename[0] == '-') { diag = stderr; } if (wr) { /* first try hex */ if (!force_binary) { parser = &PARSER_HEX; p_st = parser->init(); if (!p_st) { fprintf(stderr, "%s Parser failed to initialize\n", parser->name); goto close; } } if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) { if (force_binary || perr == PARSER_ERR_INVALID_FILE) { if (!force_binary) { parser->close(p_st); p_st = NULL; } /* now try binary */ parser = &PARSER_BINARY; p_st = parser->init(); if (!p_st) { fprintf(stderr, "%s Parser failed to initialize\n", parser->name); goto close; } perr = parser->open(p_st, filename, 0); } /* if still have an error, fail */ if (perr != PARSER_ERR_OK) { fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); if (perr == PARSER_ERR_SYSTEM) perror(filename); goto close; } } fprintf(diag, "Using Parser : %s\n", parser->name); } else { parser = &PARSER_BINARY; p_st = parser->init(); if (!p_st) { fprintf(stderr, "%s Parser failed to initialize\n", parser->name); goto close; } } if (port_open(&port_opts, &port) != PORT_ERR_OK) { fprintf(stderr, "Failed to open port: %s\n", port_opts.device); goto close; } fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port)); if (init_flag && init_bl_entry(port, gpio_seq) == 0) goto close; stm = stm32_init(port, init_flag); if (!stm) goto close; fprintf(diag, "Version : 0x%02x\n", stm->bl_version); if (port->flags & PORT_GVR_ETX) { fprintf(diag, "Option 1 : 0x%02x\n", stm->option1); fprintf(diag, "Option 2 : 0x%02x\n", stm->option2); } fprintf(diag, "Device ID : 0x%04x (%s)\n", stm->pid, stm->dev->name); fprintf(diag, "- RAM : %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000); fprintf(diag, "- Flash : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps); fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1); fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024); uint8_t buffer[256]; uint32_t addr, start, end; unsigned int len; int failed = 0; int first_page, num_pages; /* * Cleanup addresses: * * Starting from options * start_addr, readwrite_len, spage, npages * and using device memory size, compute * start, end, first_page, num_pages */ if (start_addr || readwrite_len) { start = start_addr; if (is_addr_in_flash(start)) end = stm->dev->fl_end; else { no_erase = 1; if (is_addr_in_ram(start)) end = stm->dev->ram_end; else end = start + sizeof(uint32_t); } if (readwrite_len && (end > start + readwrite_len)) end = start + readwrite_len; first_page = flash_addr_to_page_floor(start); if (!first_page && end == stm->dev->fl_end) num_pages = 0xff; /* mass erase */ else num_pages = flash_addr_to_page_ceil(end) - first_page; } else if (!spage && !npages) { start = stm->dev->fl_start; end = stm->dev->fl_end; first_page = 0; num_pages = 0xff; /* mass erase */ } else { first_page = spage; start = flash_page_to_addr(first_page); if (start > stm->dev->fl_end) { fprintf(stderr, "Address range exceeds flash size.\n"); goto close; } if (npages) { num_pages = npages; end = flash_page_to_addr(first_page + num_pages); if (end > stm->dev->fl_end) end = stm->dev->fl_end; } else { end = stm->dev->fl_end; num_pages = flash_addr_to_page_ceil(end) - first_page; } if (!first_page && end == stm->dev->fl_end) num_pages = 0xff; /* mass erase */ } if (rd) { unsigned int max_len = port_opts.rx_frame_max; fprintf(diag, "Memory read\n"); perr = parser->open(p_st, filename, 1); if (perr != PARSER_ERR_OK) { fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); if (perr == PARSER_ERR_SYSTEM) perror(filename); goto close; } fflush(diag); addr = start; while (addr < end) { uint32_t left = end - addr; len = max_len > left ? left : max_len; s_err = stm32_read_memory(stm, addr, buffer, len); if (s_err != STM32_ERR_OK) { fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr); goto close; } if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) { fprintf(stderr, "Failed to write data to file\n"); goto close; } addr += len; fprintf(diag, "\rRead address 0x%08x (%.2f%%) ", addr, (100.0f / (float)(end - start)) * (float)(addr - start) ); fflush(diag); } fprintf(diag, "Done.\n"); ret = 0; goto close; } else if (rp) { fprintf(stdout, "Read-Protecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; stm32_readprot_memory(stm); fprintf(stdout, "Done.\n"); } else if (ur) { fprintf(stdout, "Read-UnProtecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; stm32_runprot_memory(stm); fprintf(stdout, "Done.\n"); } else if (eraseOnly) { ret = 0; fprintf(stdout, "Erasing flash\n"); if (num_pages != 0xff && (start != flash_page_to_addr(first_page) || end != flash_page_to_addr(first_page + num_pages))) { fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); ret = 1; goto close; } s_err = stm32_erase_memory(stm, first_page, num_pages); if (s_err != STM32_ERR_OK) { fprintf(stderr, "Failed to erase memory\n"); ret = 1; goto close; } } else if (wu) { fprintf(diag, "Write-unprotecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; stm32_wunprot_memory(stm); fprintf(diag, "Done.\n"); } else if (wr) { fprintf(diag, "Write to memory\n"); off_t offset = 0; ssize_t r; unsigned int size; unsigned int max_wlen, max_rlen; max_wlen = port_opts.tx_frame_max - 2; /* skip len and crc */ max_wlen &= ~3; /* 32 bit aligned */ max_rlen = port_opts.rx_frame_max; max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen; /* Assume data from stdin is whole device */ if (filename[0] == '-' && filename[1] == '\0') size = end - start; else size = parser->size(p_st); // TODO: It is possible to write to non-page boundaries, by reading out flash // from partial pages and combining with the input data // if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) { // fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); // goto close; // } // TODO: If writes are not page aligned, we should probably read out existing flash // contents first, so it can be preserved and combined with new data if (!no_erase && num_pages) { fprintf(diag, "Erasing memory\n"); s_err = stm32_erase_memory(stm, first_page, num_pages); if (s_err != STM32_ERR_OK) { fprintf(stderr, "Failed to erase memory\n"); goto close; } } fflush(diag); addr = start; while (addr < end && offset < size) { uint32_t left = end - addr; len = max_wlen > left ? left : max_wlen; len = len > size - offset ? size - offset : len; if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK) goto close; if (len == 0) { if (filename[0] == '-') { break; } else { fprintf(stderr, "Failed to read input file\n"); goto close; } } again: s_err = stm32_write_memory(stm, addr, buffer, len); if (s_err != STM32_ERR_OK) { fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr); goto close; } if (verify) { uint8_t compare[len]; unsigned int offset, rlen; offset = 0; while (offset < len) { rlen = len - offset; rlen = rlen < max_rlen ? rlen : max_rlen; s_err = stm32_read_memory(stm, addr + offset, compare + offset, rlen); if (s_err != STM32_ERR_OK) { fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr + offset); goto close; } offset += rlen; } for (r = 0; r < len; ++r) if (buffer[r] != compare[r]) { if (failed == retry) { fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n", (uint32_t)(addr + r), buffer [r], compare[r] ); goto close; } ++failed; goto again; } failed = 0; } addr += len; offset += len; fprintf(diag, "\rWrote %saddress 0x%08x (%.2f%%) ", verify ? "and verified " : "", addr, (100.0f / size) * offset ); fflush(diag); } fprintf(diag, "Done.\n"); ret = 0; goto close; } else if (crc) { uint32_t crc_val = 0; fprintf(diag, "CRC computation\n"); s_err = stm32_crc_wrapper(stm, start, end - start, &crc_val); if (s_err != STM32_ERR_OK) { fprintf(stderr, "Failed to read CRC\n"); goto close; } fprintf(diag, "CRC(0x%08x-0x%08x) = 0x%08x\n", start, end, crc_val); ret = 0; goto close; } else ret = 0; close: if (stm && exec_flag && ret == 0) { if (execute == 0) execute = stm->dev->fl_start; fprintf(diag, "\nStarting execution at address 0x%08x... ", execute); fflush(diag); if (stm32_go(stm, execute) == STM32_ERR_OK) { reset_flag = 0; fprintf(diag, "done.\n"); } else fprintf(diag, "failed.\n"); } if (stm && reset_flag) { fprintf(diag, "\nResetting device... "); fflush(diag); if (init_bl_exit(stm, port, gpio_seq)) fprintf(diag, "done.\n"); else fprintf(diag, "failed.\n"); } if (p_st ) parser->close(p_st); if (stm ) stm32_close (stm); if (port) port->close(port); fprintf(diag, "\n"); return ret; }
int main(int argc, char* argv[]) { int ret = 1; parser_err_t perr; FILE *diag = stdout; fprintf(diag, "stm32flash " VERSION "\n\n"); fprintf(diag, "http://stm32flash.googlecode.com/\n\n"); if (parse_options(argc, argv) != 0) goto close; if (rd && filename[0] == '-') { diag = stderr; } if (wr) { /* first try hex */ if (!force_binary) { parser = &PARSER_HEX; p_st = parser->init(); if (!p_st) { fprintf(stderr, "%s Parser failed to initialize\n", parser->name); goto close; } } if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) { if (force_binary || perr == PARSER_ERR_INVALID_FILE) { if (!force_binary) { parser->close(p_st); p_st = NULL; } /* now try binary */ parser = &PARSER_BINARY; p_st = parser->init(); if (!p_st) { fprintf(stderr, "%s Parser failed to initialize\n", parser->name); goto close; } perr = parser->open(p_st, filename, 0); } /* if still have an error, fail */ if (perr != PARSER_ERR_OK) { fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); if (perr == PARSER_ERR_SYSTEM) perror(filename); goto close; } } fprintf(diag, "Using Parser : %s\n", parser->name); } else { parser = &PARSER_BINARY; p_st = parser->init(); if (!p_st) { fprintf(stderr, "%s Parser failed to initialize\n", parser->name); goto close; } } serial = serial_open(device); if (!serial) { fprintf(stderr, "Failed to open serial port: "); perror(device); goto close; } if (serial_setup( serial, baudRate, serial_get_bits(serial_mode), serial_get_parity(serial_mode), serial_get_stopbit(serial_mode) ) != SERIAL_ERR_OK) { perror(device); goto close; } fprintf(diag, "Serial Config: %s\n", serial_get_setup_str(serial)); if (init_flag && init_bl_entry(serial, gpio_seq) == 0) goto close; if (!(stm = stm32_init(serial, init_flag))) goto close; fprintf(diag, "Version : 0x%02x\n", stm->bl_version); fprintf(diag, "Option 1 : 0x%02x\n", stm->option1); fprintf(diag, "Option 2 : 0x%02x\n", stm->option2); fprintf(diag, "Device ID : 0x%04x (%s)\n", stm->pid, stm->dev->name); fprintf(diag, "- RAM : %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000); fprintf(diag, "- Flash : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps); fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1); fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024); uint8_t buffer[256]; uint32_t addr, start, end; unsigned int len; int failed = 0; if (rd) { fprintf(diag, "\n"); if ((perr = parser->open(p_st, filename, 1)) != PARSER_ERR_OK) { fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); if (perr == PARSER_ERR_SYSTEM) perror(filename); goto close; } if (start_addr || readwrite_len) { start = start_addr; if (readwrite_len) end = start_addr + readwrite_len; else end = stm->dev->fl_end; } else { start = stm->dev->fl_start + (spage * stm->dev->fl_ps); end = stm->dev->fl_end; } addr = start; if (start < stm->dev->fl_start || end > stm->dev->fl_end) { fprintf(stderr, "Specified start & length are invalid\n"); goto close; } fflush(diag); while(addr < end) { uint32_t left = end - addr; len = sizeof(buffer) > left ? left : sizeof(buffer); if (!stm32_read_memory(stm, addr, buffer, len)) { fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr); goto close; } if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) { fprintf(stderr, "Failed to write data to file\n"); goto close; } addr += len; fprintf(diag, "\rRead address 0x%08x (%.2f%%) ", addr, (100.0f / (float)(end - start)) * (float)(addr - start) ); fflush(diag); } fprintf(diag, "Done.\n"); ret = 0; goto close; } else if (rp) { fprintf(stdout, "Read-Protecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; stm32_readprot_memory(stm); fprintf(stdout, "Done.\n"); } else if (ur) { fprintf(stdout, "Read-UnProtecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; stm32_runprot_memory(stm); fprintf(stdout, "Done.\n"); } else if (eraseOnly) { ret = 0; fprintf(stdout, "Erasing flash\n"); if (start_addr || readwrite_len) { if ((start_addr % stm->dev->fl_ps) != 0 || (readwrite_len % stm->dev->fl_ps) != 0) { fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); ret = 1; goto close; } spage = (start_addr - stm->dev->fl_start) / stm->dev->fl_ps; if (readwrite_len) npages = readwrite_len / stm->dev->fl_ps; else npages = (stm->dev->fl_end - stm->dev->fl_start) / stm->dev->fl_ps; } if (!spage && !npages) npages = 0xff; /* mass erase */ if (!stm32_erase_memory(stm, spage, npages)) { fprintf(stderr, "Failed to erase memory\n"); ret = 1; goto close; } } else if (wu) { fprintf(diag, "Write-unprotecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; stm32_wunprot_memory(stm); fprintf(diag, "Done.\n"); } else if (wr) { fprintf(diag, "\n"); off_t offset = 0; ssize_t r; unsigned int size; /* Assume data from stdin is whole device */ if (filename[0] == '-') size = stm->dev->fl_end - stm->dev->fl_start; else size = parser->size(p_st); if (start_addr || readwrite_len) { start = start_addr; spage = (start_addr - stm->dev->fl_start) / stm->dev->fl_ps; if (readwrite_len) { end = start_addr + readwrite_len; npages = (end - stm->dev->fl_start + stm->dev->fl_ps - 1) / stm->dev->fl_ps - spage; } else { end = stm->dev->fl_end; if (spage) npages = (end - stm->dev->fl_start) / stm->dev->fl_ps - spage; else npages = 0xff; /* mass erase */ } } else if (!spage && !npages) { start = stm->dev->fl_start; end = stm->dev->fl_end; npages = 0xff; /* mass erase */ } else { start = stm->dev->fl_start + (spage * stm->dev->fl_ps); if (npages) end = start + npages * stm->dev->fl_ps; else end = stm->dev->fl_end; } addr = start; if (start < stm->dev->fl_start || end > stm->dev->fl_end) { fprintf(stderr, "Specified start & length are invalid\n"); goto close; } // TODO: It is possible to write to non-page boundaries, by reading out flash // from partial pages and combining with the input data // if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) { // fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); // goto close; // } // TODO: If writes are not page aligned, we should probably read out existing flash // contents first, so it can be preserved and combined with new data if (!stm32_erase_memory(stm, spage, npages)) { fprintf(stderr, "Failed to erase memory\n"); goto close; } fflush(diag); while(addr < end && offset < size) { uint32_t left = end - addr; len = sizeof(buffer) > left ? left : sizeof(buffer); len = len > size - offset ? size - offset : len; if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK) goto close; if (len == 0) { if (filename[0] == '-') { break; } else { fprintf(stderr, "Failed to read input file\n"); goto close; } } again: if (!stm32_write_memory(stm, addr, buffer, len)) { fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr); goto close; } if (verify) { uint8_t compare[len]; if (!stm32_read_memory(stm, addr, compare, len)) { fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr); goto close; } for(r = 0; r < len; ++r) if (buffer[r] != compare[r]) { if (failed == retry) { fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n", (uint32_t)(addr + r), buffer [r], compare[r] ); goto close; } ++failed; goto again; } failed = 0; } addr += len; offset += len; fprintf(diag, "\rWrote %saddress 0x%08x (%.2f%%) ", verify ? "and verified " : "", addr, (100.0f / size) * offset ); fflush(diag); } fprintf(diag, "Done.\n"); ret = 0; goto close; } else ret = 0; close: if (stm && exec_flag && ret == 0) { if (execute == 0) execute = stm->dev->fl_start; fprintf(diag, "\nStarting execution at address 0x%08x... ", execute); fflush(diag); if (stm32_go(stm, execute)) { reset_flag = 0; fprintf(diag, "done.\n"); } else fprintf(diag, "failed.\n"); } if (stm && reset_flag) { fprintf(diag, "\nResetting device... "); fflush(diag); if (init_bl_exit(stm, serial, gpio_seq)) fprintf(diag, "done.\n"); else fprintf(diag, "failed.\n"); } if (p_st ) parser->close(p_st); if (stm ) stm32_close (stm); if (serial) serial_close (serial); fprintf(diag, "\n"); return ret; }