public virtual Tuple <FlashBuilderConsts.flash_page, UInt32> _next_nonsame_page(UInt32 i) { if (i >= this.page_list.Count) { return(new Tuple <FlashBuilderConsts.flash_page, UInt32>(null, i)); } FlashBuilderConsts.flash_page page = this.page_list[(int)i]; while ((bool)page.same) { i += 1; if (i >= this.page_list.Count) { return(new Tuple <FlashBuilderConsts.flash_page, UInt32>(null, i)); } page = this.page_list[(int)i]; } return(Tuple.Create(page, i + 1)); }
// // Determine fastest method of flashing and then run flash programming. // // Data must have already been added with addData // public virtual FlashBuilderConsts.ProgrammingInfo program(bool?chip_erase = null, Action <double> progress_cb = null, bool smart_flash = true, bool fast_verify = false) { // Assumptions // 1. Page erases must be on page boundaries ( page_erase_addr % page_size == 0 ) // 2. Page erase can have a different size depending on location // 3. It is safe to program a page with less than a page of data // Examples // - lpc4330 -Non 0 base address // - nRF51 -UICR location far from flash (address 0x10001000) // - LPC1768 -Different sized pages DateTime program_start = DateTime.Now; progress_cb = progress_cb ?? FlashBuilderConsts._stub_progress; // There must be at least 1 flash operation if (this.flash_operation_list.Count == 0) { Trace.TraceWarning("No pages were programmed"); return(null); } // Convert the list of flash operations into flash pages UInt32 program_byte_count = 0; UInt32 flash_addr = this.flash_operation_list[0].addr; FlashConsts.PageInfo info = this.flash.getPageInfo(flash_addr); UInt32 page_addr = flash_addr - flash_addr % (UInt32)info.size; var current_page = new FlashBuilderConsts.flash_page(page_addr, (UInt32)info.size, new List <byte>(), (double)info.erase_weight, (double)info.program_weight); this.page_list.Add(current_page); foreach (FlashBuilderConsts.flash_operation flash_op in this.flash_operation_list) { UInt32 pos = 0; while (pos < flash_op.data.Count) { // Check if operation is in next page flash_addr = flash_op.addr + pos; if (flash_addr >= current_page.addr + current_page.size) { info = this.flash.getPageInfo(flash_addr); page_addr = flash_addr - flash_addr % (UInt32)info.size; current_page = new FlashBuilderConsts.flash_page(page_addr, (UInt32)info.size, new List <byte>(), (double)info.erase_weight, (double)info.program_weight); this.page_list.Add(current_page); } // Fill the page gap if there is one UInt32 page_data_end = current_page.addr + (UInt32)current_page.data.Count; if (flash_addr != page_data_end) { List <byte> old_data = this.flash.target.readBlockMemoryUnaligned8(page_data_end, flash_addr - page_data_end); current_page.data.AddRange(old_data); } // Copy data to page and increment pos UInt32 space_left_in_page = (UInt32)(info.size - current_page.data.Count); UInt32 space_left_in_data = (UInt32)flash_op.data.Count - pos; UInt32 amount = Math.Min(space_left_in_page, space_left_in_data); current_page.data.AddRange(flash_op.data.GetRange((int)pos, (int)amount)); program_byte_count += amount; //increment position pos += amount; } } // If smart flash was set to false then mark all pages // as requiring programming if (!smart_flash) { this._mark_all_pages_for_programming(); } // If the first page being programmed is not the first page // in ROM then don't use a chip erase if (this.page_list[0].addr > this.flash_start) { if (chip_erase == null) { chip_erase = false; } else if (chip_erase == true) { Trace.TraceWarning("Chip erase used when flash address 0x{0:X} is not the same as flash start 0x{1:X}", this.page_list[0].addr, this.flash_start); } } this.flash.init(); var _tup_1 = this._compute_chip_erase_pages_and_weight(); var chip_erase_count = _tup_1.Item1; TimeSpan chip_erase_program_time = TimeSpan.FromSeconds(_tup_1.Item2); TimeSpan page_erase_min_program_time = TimeSpan.FromSeconds(this._compute_page_erase_pages_weight_min()); // If chip_erase hasn't been specified determine if chip erase is faster // than page erase regardless of contents if (chip_erase == null && chip_erase_program_time < page_erase_min_program_time) { chip_erase = true; } TimeSpan page_program_time = TimeSpan.Zero; UInt32 sector_erase_count = 0; // If chip erase isn't True then analyze the flash if (!(bool)chip_erase) { DateTime analyze_start = DateTime.Now; if ((bool)this.flash.getFlashInfo().crc_supported) { var _tup_2 = this._compute_page_erase_pages_and_weight_crc32(fast_verify); sector_erase_count = _tup_2.Item1; page_program_time = TimeSpan.FromSeconds(_tup_2.Item2); this.perf.analyze_type = FlashBuilder.FLASH_ANALYSIS_CRC32; } else { var _tup_3 = this._compute_page_erase_pages_and_weight_sector_read(); sector_erase_count = _tup_3.Item1; page_program_time = TimeSpan.FromSeconds(_tup_3.Item2); this.perf.analyze_type = FlashBuilder.FLASH_ANALYSIS_PARTIAL_PAGE_READ; } DateTime analyze_finish = DateTime.Now; this.perf.analyze_time = analyze_finish - analyze_start; Trace.TraceInformation(String.Format("Analyze time: {0}", analyze_finish - analyze_start)); } // If chip erase hasn't been set then determine fastest method to program if (chip_erase == null) { Trace.TraceInformation(String.Format("Chip erase count {0}, Page erase est count {1}", chip_erase_count, sector_erase_count)); //Trace.TraceInformation(String.Format("Chip erase weight {0}, Page erase weight {2}", chip_erase_program_time, page_program_time)); chip_erase = chip_erase_program_time < page_program_time; } byte?flash_operation = null; if ((bool)chip_erase) { if (this.flash.isDoubleBufferingSupported() && this.enable_double_buffering) { Trace.TraceInformation("Using double buffer chip erase program"); flash_operation = this._chip_erase_program_double_buffer(progress_cb); } else { flash_operation = this._chip_erase_program(progress_cb); } } else if (this.flash.isDoubleBufferingSupported() && this.enable_double_buffering) { Trace.TraceInformation("Using double buffer page erase program"); flash_operation = this._page_erase_program_double_buffer(progress_cb); } else { flash_operation = this._page_erase_program(progress_cb); } this.flash.target.resetStopOnReset(); DateTime program_finish = DateTime.Now; this.perf.program_time = program_finish - program_start; this.perf.program_type = flash_operation.ToString(); Trace.TraceInformation("Programmed {0} bytes ({1} pages) at {2:0.00} kB/s", program_byte_count, this.page_list.Count, program_byte_count / 1024 / ((TimeSpan)this.perf.program_time).TotalSeconds); return(this.perf); }