From 9fbb6337b663e89a11b448049f8bde6cdeca4cd7 Mon Sep 17 00:00:00 2001 From: Michael Corcoran Date: Thu, 28 Jan 2016 21:53:17 +1300 Subject: [PATCH] DFU: Support STM32F4 --- _locales/en/messages.json | 2 +- js/protocols/stm32usbdfu.js | 127 ++++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 1e11d78c..3fae72e4 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -213,7 +213,7 @@ "message": "Erased $1 kB of flash successfully" }, "dfu_device_flash_info": { - "message": "Detected device with $1*$2 kiB pages, total size $3 kiB" + "message": "Detected device with total flash size $1 kiB" }, "dfu_error_image_size": { "message": "Error: Supplied image is larger then flash available on the chip! Image: $1 kiB, limit = $2 kiB" diff --git a/js/protocols/stm32usbdfu.js b/js/protocols/stm32usbdfu.js index 403013e1..2fcb872d 100644 --- a/js/protocols/stm32usbdfu.js +++ b/js/protocols/stm32usbdfu.js @@ -62,9 +62,7 @@ var STM32DFU_protocol = function () { dfuERROR: 10 // An error has occurred. Awaiting the DFU_CLRSTATUS request. }; - this.page_size = 0; - this.available_flash_size = 0; - this.start_address = 0; + this.flash_layout = { 'start_address': 0, 'total_size': 0, 'sectors': []}; }; STM32DFU_protocol.prototype.connect = function (device, hex, options, callback) { @@ -257,40 +255,65 @@ STM32DFU_protocol.prototype.getFlashInfo = function (_interface, callback) { return; } - //@Internal Flash /0x08000000/128*0002Kg + // F303: "@Internal Flash /0x08000000/128*0002Kg" + // F407: "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" + // split main into [location, start_addr, sectors] var tmp1 = str.split('/'); - if (tmp1.length != 3) { + if (tmp1.length != 3 || !tmp1[0].startsWith("@Internal Flash")) { callback({}, -1); return; } - var tmp2 = tmp1[2].split('*'); - if (tmp2.length != 2 || tmp2[1].length != 6) { + var type = tmp1[0].trim().replace('@', ''); + var start_address = parseInt(tmp1[1]); + + // split sectors into array + var sectors = []; + var total_size = 0; + var tmp2 = tmp1[2].split(','); + if (tmp2.length < 1) { callback({}, -2); return; } - - var page_size = parseInt(tmp2[1].substr(0, 4)); - if (!page_size) { - callback({}, -3); - return; - } - var unit = tmp2[1].substr(4, 1); - switch (unit) { - case 'M': - page_size *= 1024; // fall through to K as well - case 'K': - page_size *= 1024; - break; - default: + for (var i = 0; i < tmp2.length; i++) { + // split into [num_pages, page_size] + var tmp3 = tmp2[i].split('*'); + if (tmp3.length != 2) { + callback({}, -3); + return; + } + var num_pages = parseInt(tmp3[0]); + var page_size = parseInt(tmp3[1]); + if (!page_size) { callback({}, -4); return; + } + var unit = tmp3[1].slice(-2, -1); + switch (unit) { + case 'M': + page_size *= 1024; // fall through to K as well + case 'K': + page_size *= 1024; + break; + default: + callback({}, -4); + return; + } + + sectors.push({ + 'num_pages' : num_pages, + 'start_address': start_address + total_size, + 'page_size' : page_size, + 'total_size' : num_pages * page_size + }); + + total_size += num_pages * page_size; } var flash = { - 'start_address': parseInt(tmp1[1]), - 'num_pages' : parseInt(tmp2[0]), - 'page_size' : page_size, - 'total_size' : parseInt(tmp2[0]) * page_size + 'type' : type, + 'start_address': start_address, + 'sectors' : sectors, + 'total_size' : total_size } callback(flash, resultCode); @@ -424,12 +447,10 @@ STM32DFU_protocol.prototype.upload_procedure = function (step) { console.log('Failed to detect chip flash info, resultCode: ' + resultCode); self.upload_procedure(99); } else { - self.page_size = flash.page_size; - self.start_address = flash.start_address; - self.available_flash_size = flash.total_size - (self.hex.start_linear_address - self.start_address); + self.flash_layout = flash; + self.available_flash_size = flash.total_size - (self.hex.start_linear_address - flash.start_address); - GUI.log(chrome.i18n.getMessage('dfu_device_flash_info', [flash.num_pages.toString(), - (flash.page_size / 1024).toString(), (flash.total_size / 1024).toString()])); + GUI.log(chrome.i18n.getMessage('dfu_device_flash_info', (flash.total_size / 1024).toString())); if (self.hex.bytes_total > self.available_flash_size) { GUI.log(chrome.i18n.getMessage('dfu_error_image_size', @@ -475,17 +496,41 @@ STM32DFU_protocol.prototype.upload_procedure = function (step) { } else { // local erase - var max_address = self.hex.data[self.hex.data.length - 1].address + self.hex.data[self.hex.data.length - 1].bytes - 0x8000000, - erase_pages_n = Math.ceil(max_address / self.page_size), - page = 0; + // find out which pages to erase + var erase_pages = []; + for (var i = 0; i < self.flash_layout.sectors.length; i++) { + for (var j = 0; j < self.flash_layout.sectors[i].num_pages; j++) { + var page_start = self.flash_layout.sectors[i].start_address + j * self.flash_layout.sectors[i].page_size; + var page_end = page_start + self.flash_layout.sectors[i].page_size - 1; + for (var k = 0; k < self.hex.data.length; k++) { + var starts_in_page = self.hex.data[k].address >= page_start && self.hex.data[k].address <= page_end; + var end_address = self.hex.data[k].address + self.hex.data[k].bytes - 1; + var ends_in_page = end_address >= page_start && end_address <= page_end; + var spans_page = self.hex.data[k].address < page_start && end_address > page_end; + if (starts_in_page || ends_in_page || spans_page) { + var idx = erase_pages.findIndex(function (element, index, array) { + return element.sector == i && element.page == j; + }); + if (idx == -1) + erase_pages.push({'sector': i, 'page': j}); + } + } + } + } $('span.progressLabel').text('Erasing ...'); - console.log('Executing local chip erase'); - console.log('Erasing. page: 0x00 - 0x' + erase_pages_n.toString(16)); + console.log('Executing local chip erase'); + + var page = 0; + var total_erased = 0; // bytes var erase_page = function() { - var page_addr = page * self.page_size + self.hex.start_linear_address; + var page_addr = erase_pages[page].page * self.flash_layout.sectors[erase_pages[page].sector].page_size + + self.flash_layout.sectors[erase_pages[page].sector].start_address; var cmd = [0x41, page_addr & 0xff, (page_addr >> 8) & 0xff, (page_addr >> 16) & 0xff, (page_addr >> 24) & 0xff]; + total_erased += self.flash_layout.sectors[erase_pages[page].sector].page_size; + console.log('Erasing. sector ' + erase_pages[page].sector + + ', page ' + erase_pages[page].page + ' @ 0x' + page_addr.toString(16)); self.controlTransfer('out', self.request.DNLOAD, 0, 0, 0, cmd, function () { self.controlTransfer('in', self.request.GETSTATUS, 0, 0, 6, 0, function (data) { @@ -496,24 +541,24 @@ STM32DFU_protocol.prototype.upload_procedure = function (step) { self.controlTransfer('in', self.request.GETSTATUS, 0, 0, 6, 0, function (data) { if (data[4] == self.state.dfuDNLOAD_IDLE) { // update progress bar - self.progress_bar_e.val((page + 1) / erase_pages_n * 100); + self.progress_bar_e.val((page + 1) / erase_pages.length * 100); page++; - if(page == erase_pages_n) { + if(page == erase_pages.length) { console.log("Erase: complete"); - GUI.log(chrome.i18n.getMessage('dfu_erased_kilobytes', (erase_pages_n * self.page_size / 1024).toString())); + GUI.log(chrome.i18n.getMessage('dfu_erased_kilobytes', (total_erased / 1024).toString())); self.upload_procedure(4); } else erase_page(); } else { - console.log('Failed to erase page 0x' + self.current_page.toString(16)); + console.log('Failed to erase page 0x' + page_addr.toString(16)); self.upload_procedure(99); } }); }, delay); } else { - console.log('Failed to initiate page erase, page 0x' + self.current_page.toString(16)); + console.log('Failed to initiate page erase, page 0x' + page_addr.toString(16)); self.upload_procedure(99); } });