//Write to Flash ROM. // // location - flash program memory address // src - pointer to data to write // size - number of bytes to write to flash // // Here is the sequence of events: // 1.) Goes to the beginning of the first erase block for this address // 2.) Reads n records to ram, where n is the PIC's flash erase size // 3.) Erases block in flash // 4.) Modifies block in RAM // 5.) Writes changed block back to FLASH. Writes in chunks defined by PIC's flash write size // 6.) Goes back to step1 if there is still more data to be written void rom_w(int32 location, char *src, int16 size) { #define EEPROM_ERASE_SIZE getenv("FLASH_ERASE_SIZE") #define EEPROM_WRITE_SIZE getenv("FLASH_WRITE_SIZE") int8 block[EEPROM_ERASE_SIZE]; int32 block_start; int8 i; int8 num; block_start = location & (~((int32)EEPROM_ERASE_SIZE-1)); i=location-block_start; while (size) { read_program_memory(block_start, block, sizeof(block)); //read entire block to ram buffer if (size>(EEPROM_ERASE_SIZE-i)) {num=EEPROM_ERASE_SIZE-i;} else {num=size;} memcpy(&block[i],src,num); //modify ram buffer erase_program_eeprom(block_start); //erase entire block write_program_memory(block_start, block, sizeof(block)); //write modified block src+=num; block_start+=EEPROM_ERASE_SIZE; i=0; size-=num; } }
/* ========================================================================= */ void bootloader(void) { uint32 addr; uint16 addr_low; uint8 addr_high = 0; uint8 reclen; uint8 rectype; uint8 idx; uint8 buffer[HEX_LINE_LEN_MAX]; uint8 ch; bool hexend = 0; #if getenv("FLASH_ERASE_SIZE")>2 uint16 next_addr = 0; #endif /* until end of HEX file */ while(hexend == 0) { /* get one line of the HEX file via RS232 until we receive CR or */ /* we reached the end of the buffer */ idx = 0; do { /* get one byte */ ch = getch(); /* save to buffer */ buffer[idx] = ch; /* increment buffer index */ idx++; } while(ch != 0x0A); /* get record length */ reclen = get_hexbyte(&buffer[HEX_LEN_START]); /* check for proper checksum */ if (check_checksum(&buffer[HEX_LEN_START], reclen) != 0) { /* checkum error - send negative acknowledge */ putc(NAK); } else { /* checkum ok */ /* get address */ addr_low = make16(get_hexbyte(&buffer[HEX_ADDR_START]), get_hexbyte(&buffer[HEX_ADDR_START+2])); /* make 32 bit address */ addr = make32(addr_high, addr_low); /* get record type */ rectype = get_hexbyte(&buffer[HEX_TYPE_START]); if (rectype == HEX_DATA_REC) { /* only program code memory */ if ((addr_high < 0x30) && (addr >= RESET_VECTOR)) { for (idx=0; idx < reclen; idx++) { buffer[idx] = get_hexbyte(&buffer[HEX_DATA_START+(idx*2)]); } #if getenv("FLASH_ERASE_SIZE") > getenv("FLASH_WRITE_SIZE") #if defined(__PCM__) if ((addr_low!=next_addr)&&(addr_low&(getenv("FLASH_ERASE_SIZE")-1)!=0)) #else if ((addr_low!=next_addr)&&(addr_low&(getenv("FLASH_ERASE_SIZE")/2-1)!=0)) #endif erase_program_eeprom(addr); next_addr = addr_low + 1; #endif write_program_memory(addr, buffer, reclen); } } else if (rectype == HEX_EOF_REC) { hexend = 1; } else if (rectype == HEX_EXTADDR_REC) { /* to save resources, only take lower byte - this */ /* allows 24 bit addresses => enough for PIC18F */ //addr_high = make16(get_hexbyte(&buffer[HEX_DATA_START]), // get_hexbyte(&buffer[HEX_DATA_START+2])); addr_high = get_hexbyte(&buffer[HEX_DATA_START+2]); } /* send positive acknowledge */ putc(ACK); } } }