void write_flash_memory_block(unsigned char *src, uint32_t start_addr,unsigned short num_bytes) { // 1. Write the 2 DMA descriptors to RAM write_xdata_memory_block(ADDR_DMA_DESC_0, dma_desc_0, 8); write_xdata_memory_block(ADDR_DMA_DESC_1, dma_desc_1, 8); // 2. Update LEN value in DUP's DMA descriptors unsigned char len[2] = {HIBYTE(num_bytes), LOBYTE(num_bytes)}; write_xdata_memory_block((ADDR_DMA_DESC_0+4), len, 2); // LEN, DBG => ram write_xdata_memory_block((ADDR_DMA_DESC_1+4), len, 2); // LEN, ram => flash // 3. Set DMA controller pointer to the DMA descriptors write_xdata_memory(DUP_DMA0CFGH, HIBYTE(ADDR_DMA_DESC_0)); write_xdata_memory(DUP_DMA0CFGL, LOBYTE(ADDR_DMA_DESC_0)); write_xdata_memory(DUP_DMA1CFGH, HIBYTE(ADDR_DMA_DESC_1)); write_xdata_memory(DUP_DMA1CFGL, LOBYTE(ADDR_DMA_DESC_1)); // 4. Set Flash controller start address (wants 16MSb of 18 bit address) start_addr >>= 2; write_xdata_memory(DUP_FADDRH, HIBYTE( start_addr )); write_xdata_memory(DUP_FADDRL, LOBYTE( start_addr )); // 5. Arm DBG=>buffer DMA channel and start burst write write_xdata_memory(DUP_DMAARM, CH_DBG_TO_BUF0); burst_write_block(src, num_bytes); // 6. Start programming: buffer to flash write_xdata_memory(DUP_DMAARM, CH_BUF0_TO_FLASH); write_xdata_memory(DUP_FCTL, 0x06); // 7. Wait until flash controller is done while (read_xdata_memory(DUP_FCTL) & 0x80); }
//============================================================================== uint16_t CC_UnitDriver::calc_block_crc() { write_xdata_memory(reg_info_.rndl, 0xFF); write_xdata_memory(reg_info_.rndl, 0xFF); write_xdata_memory(reg_info_.dma_arm, 0x01); write_xdata_memory(reg_info_.dma_req, 0x01); while (!(read_xdata_memory(reg_info_.dma_irq) & 0x01)); ByteVector xsfr; read_xdata_memory(reg_info_.rndl, 2, xsfr); return xsfr[0] | (xsfr[1] << 8); }
//============================================================================== void CC_UnitDriver::write_flash_slow(const DataSectionStore §ion_store) { const size_t WRITE_BLOCK_SIZE = reg_info_.write_block_size; // Channel 0: Xdata buffer -> Flash controller uint8_t dma_desc[8] = { HIBYTE(reg_info_.dma_data_offset),// src[15:8] LOBYTE(reg_info_.dma_data_offset),// src[7:0] HIBYTE(reg_info_.fwdata), // dest[15:8] LOBYTE(reg_info_.fwdata), // dest[7:0] HIBYTE(WRITE_BLOCK_SIZE), // block size[15:8] LOBYTE(WRITE_BLOCK_SIZE), // block size[7:0] 18, // trigger FLASH 0x42 // increment source }; // Load dma descriptors write_xdata_memory(reg_info_.dma0_cfg_offset, dma_desc, sizeof(dma_desc)); // Set the pointer to the DMA descriptors write_xdata_memory(reg_info_.dma0_cfgl, LOBYTE(reg_info_.dma0_cfg_offset)); write_xdata_memory(reg_info_.dma0_cfgh, HIBYTE(reg_info_.dma0_cfg_offset)); size_t faddr = 0xFFFF; ByteVector data; section_store.create_image(0xFF, data); data.resize((section_store.upper_address() + (WRITE_BLOCK_SIZE - 1)) & ~(WRITE_BLOCK_SIZE - 1), 0xFF); pw_.write_start(data.size()); ByteVector empty_block; empty_block.resize(WRITE_BLOCK_SIZE, 0xFF); for (size_t i = 0; i < (data.size() / WRITE_BLOCK_SIZE); i++) { pw_.write_progress(WRITE_BLOCK_SIZE); size_t offset = WRITE_BLOCK_SIZE * i; if (!memcmp(&data[offset], &empty_block[0], WRITE_BLOCK_SIZE)) continue; size_t new_faddr = WRITE_BLOCK_SIZE * i / reg_info_.flash_word_size; if (new_faddr != faddr) { faddr = WRITE_BLOCK_SIZE * i / reg_info_.flash_word_size; write_xdata_memory(reg_info_.faddrl, LOBYTE(faddr)); write_xdata_memory(reg_info_.faddrh, HIBYTE(faddr)); faddr += WRITE_BLOCK_SIZE / reg_info_.flash_word_size; } write_xdata_memory(reg_info_.dma_data_offset, &data[offset], WRITE_BLOCK_SIZE); write_xdata_memory(reg_info_.dma_arm, 0x01); write_xdata_memory(reg_info_.fctl, reg_info_.fctl_write); while ((read_xdata_memory(reg_info_.fctl) & 0x80)); } pw_.write_finish(); }
//============================================================================== void CC_UnitDriver::flash_read(size_t offset, size_t size, ByteVector &flash_data) { uint8_t flash_bank = 0xFF; while (size) { size_t bank_offset = offset % FLASH_BANK_SIZE; size_t count = std::min(size, (size_t)0x8000); uint8_t flash_bank_0 = offset / FLASH_BANK_SIZE; uint8_t flash_bank_1 = (offset + count) / FLASH_BANK_SIZE; if (flash_bank_0 != flash_bank_1) size_t count = ((offset + count) % FLASH_BANK_SIZE); if (flash_bank != flash_bank_0) { flash_bank = flash_bank_0; write_xdata_memory(reg_info_.fmap, flash_bank); bank_offset = offset % FLASH_BANK_SIZE; } flash_read_near(bank_offset + reg_info_.xbank_offset, count, flash_data); size -= count; offset += count; } }
//============================================================================== bool CC_UnitDriver::erase_page(uint_t page_offset) { page_offset /= reg_info_.flash_word_size; write_xdata_memory(reg_info_.faddrl, 0); write_xdata_memory(reg_info_.faddrh, HIBYTE(page_offset)); // erase write_xdata_memory(reg_info_.fctl, FCTL_ERASE); // wait for write to finish uint8_t reg; while ((reg = read_xdata_memory(reg_info_.fctl)) & FCTL_BUSY); return !(reg & FCTL_ABORT); }
void read_flash_memory_block(unsigned char bank,unsigned short flash_addr,unsigned short num_bytes, unsigned char *values) { unsigned char instr[3]; unsigned short i; unsigned short xdata_addr = (0x8000 + flash_addr); // 1. Map flash memory bank to XDATA address 0x8000-0xFFFF write_xdata_memory(DUP_MEMCTR, bank); // 2. Move data pointer to XDATA address (MOV DPTR, xdata_addr) instr[0] = 0x90; instr[1] = HIBYTE(xdata_addr); instr[2] = LOBYTE(xdata_addr); HM10SendDebugCommand(instr, 3); for (i = 0; i < num_bytes; i++) { // 3. Move value pointed to by DPTR to accumulator (MOVX A, @DPTR) instr[0] = 0xE0; values[i] = HM10SendDebugCommand(instr, 1); // 4. Increment data pointer (INC DPTR) instr[0] = 0xA3; HM10SendDebugCommand(instr, 1); } }
//============================================================================== bool CC_UnitDriver::flash_verify_by_crc(const DataSectionStore §ion_store) { // Channel 0: Flash mapped to Xdata -> CRC shift register uint8_t dma_desc[8] = { HIBYTE(reg_info_.xbank_offset), // src[15:8] LOBYTE(reg_info_.xbank_offset), // src[7:0] HIBYTE(reg_info_.rndh), // dest[15:8] LOBYTE(reg_info_.rndh), // dest[7:0] HIBYTE(reg_info_.verify_block_size),// block size[15:8] LOBYTE(reg_info_.verify_block_size),// block size[7:0] 0x20, // no trigger event, block mode 0x42, // increment source }; write_xdata_memory(reg_info_.dma_arm, 0x00); // set the pointer to the DMA descriptors write_xdata_memory(reg_info_.dma0_cfgl, LOBYTE(reg_info_.dma0_cfg_offset)); write_xdata_memory(reg_info_.dma0_cfgh, HIBYTE(reg_info_.dma0_cfg_offset)); size_t flash_bank = 0xFF; // correct flash bank will be set later pw_.read_start(section_store.actual_size()); foreach (const DataSection §ion, section_store.sections()) { size_t section_offset = section.address; size_t total_size = section.size(); size_t bank_offset = section_offset % FLASH_BANK_SIZE; while (total_size) { size_t count = std::min(total_size, reg_info_.verify_block_size); size_t flash_bank_0 = section_offset / FLASH_BANK_SIZE; size_t flash_bank_1 = (section_offset + count) / FLASH_BANK_SIZE; if (flash_bank_0 != flash_bank_1) count = FLASH_BANK_SIZE - (section_offset % FLASH_BANK_SIZE); if (flash_bank != flash_bank_0) { flash_bank = flash_bank_0; if (reg_info_.memctr) write_xdata_memory(reg_info_.memctr, flash_bank); bank_offset = section_offset % FLASH_BANK_SIZE; } dma_desc[0] = HIBYTE(bank_offset + reg_info_.xbank_offset); dma_desc[1] = LOBYTE(bank_offset + reg_info_.xbank_offset); dma_desc[4] = HIBYTE(count); dma_desc[5] = LOBYTE(count); write_xdata_memory(reg_info_.dma0_cfg_offset, dma_desc, sizeof(dma_desc)); CrcCalculator crc_calc; crc_calc.process_bytes(§ion.data[section.size() - total_size], count); if (calc_block_crc() != crc_calc.checksum()) return false; total_size -= count; section_offset += count; bank_offset += count; pw_.read_progress(count); } } pw_.read_finish(); return true; }
//============================================================================== void CC_UnitDriver::write_xdata_memory(uint16_t address, const ByteVector &data) { write_xdata_memory(address, &data[0], data.size()); }
//============================================================================== void CC_UnitDriver::write_xdata_memory(uint16_t address, uint8_t data) { write_xdata_memory(address, &data, 1); }