/**** BootLoader for PIC16F887Ussage:ascii-xfr -s -v -l 110 ./bltest.hex > /dev/ttyUSB0ascii-xfr is part of 'minicom' packageAdd "uf\n\r" to the first line of .HEX. or use this script:echo uf > /dev/ttyUSB$1ascii-xfr -s -v -l 100 ./bltest.hex > /dev/ttyUSB$1Or add "uf\n\r" and add some dummy characters at the end or begin of each line (for 100 ms delay) and use:cp ./bltest.hex > /dev/ttyUSB0For adding characters you can use this:sed -i 's/^/pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp/' ./bltest.hexsed -i 1i"uf" ./bltest.hexWindows script:mode com1 baud=9600 parity=n data=8 stop=1 rts=off dtr=off xon=offecho uf > com1ping 1.1.1.1 -n 1 -w 100 > nulFOR /F "tokens=1*" %%i in (bltest.hex) do @echo %%i > com1 & ping 1.1.1.1 -n 1 -w 100 > nul*/#define ID "$Id: bloader.c 2898 2013-04-09 22:15:55Z kakl $"#CASE // Case sensitive compiler#define ERR_BUFFER_OVERRUN 1 // Error 1 - Buffer Overrun#define ERR_CHECKSUM 2 // Error 2 - Bad CheckSum#define ERR_TOO_MANY_BYTES 3 // Error 3 - Too many bytes in one line#define ERR_UNSUPORTED_LINETYPE 4 // Error 4 - Unsuported Line type#define BUFFER_LEN_LOD 46 // Length of Working buffer for HEX#include "..\common\bloader_defs.h"#include "bloader.h"#include <string.h>#INT_RDAvoid rs232_handler() // Test of interrupt{putchar(getc()); // Just echo for test}void welcome(void) // Welcome message{char REV[50]=ID; // Buffer for concatenate of a version stringif (REV[strlen(REV)-1]=='$') REV[strlen(REV)-1]=0;printf("\r\n\r\n# BLoader 887 (C) 2013 KAKL\r\n"); // Welcome messageprintf("#%s\r\n",&REV[4]);}/*-------------------------------- MAIN --------------------------------------*/#SEPARATEvoid real_main() // Main of loaded program{int8 i=0;i=rs232_errors; // Just for compiler pleasure (supress Warning)welcome();printf("# Reserved: %Lu\r\n", RESERVED_BLOCKS*FLASH_BLOCK_SIZE);printf("# FLASH_ERASE_SIZE: %Lu\r\n",getenv("FLASH_ERASE_SIZE"));printf("# FLASH_WRITE_SIZE: %Lu\r\n",getenv("FLASH_WRITE_SIZE"));printf("# Boot Loader Test >>>\r\n# ");enable_interrupts(INT_RDA);enable_interrupts(GLOBAL);while(TRUE){printf("%u|",i++); // Do somethingdelay_ms(100);}}/*------------------- BOOT LOADER --------------------------------------------*/#BUILD(INTERRUPT=FLASH_BLOCK_SIZE) // Redirect Interrupt routine above first flash block#ROM 0x0004={0,0,0,0,0,0,0,0,0,0,0,0} // 12x NOP from interrupt vector to interrupt routine#ORG LOADER_RESERVED,LOADER_RESERVED+FLASH_BLOCK_SIZE-1 auto=0#SEPARATEvoid dummy_main() // Main on the fix position. It will be overwriten by downloaded program reset vector.{real_main();}#ORG LOADER_RESERVED+FLASH_BLOCK_SIZE,getenv("PROGRAM_MEMORY")-1 auto=0 default //Start of BootLoader#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,ERRORS) //RS232 control routine for BootLoader#SEPARATEunsigned int8 atoi_b16(char *s) // Convert two hex characters to an int8{unsigned int8 result = 0;int i;for (i=0; i<2; i++,s++) {if (*s >= 'A')result = 16*result + (*s) - 'A' + 10;elseresult = 16*result + (*s) - '0';}return(result);}void assert(int1 Condition, int8 ErrorCode) // Send error number to the serial line{if(Condition){putchar('e');putchar(ErrorCode+'0');reset_cpu();}}void pause(){int16 timeout;for(timeout=0; timeout<65535; timeout++); // Delay cca 300ms}#SEPARATEvoid boot_loader() // Loads a new program{/*:100240001F2999000A300C1E232999006430A4004C10 = 16 bytes0249 = address 0x0120 (0x240/2 because of words)00 = data...data...4C = checksum:00000001FF00 = 0 bytes0000 = address 001 = ENDFF = checksumhttp://cs.wikipedia.org/wiki/Intel_HEX*/int buffidx;char buffer[BUFFER_LEN_LOD]; // Buffer for HEX lineint8 checksum, num_of_bytes, line_type; // Extracted values from HEX lineint16 l_addr,h_addr=0;int16 addr; // Address of word in PICint32 next_addr; // Helper variable for forint8 dataidx, i; // Buffer for program bytes and pointersunion program_data {int8 i8[16];int16 i16[8];} data;disable_interrupts(GLOBAL);putchar('@'); //Start Erase/*//Erase program memory is not necessary.{int8 i;for(i=0;i<32;i++)buffer[i]=0xFF;}for(addr=FLASH_BLOCK_SIZE;addr<LOADER_RESERVED+FLASH_BLOCK_SIZE;addr+=FLASH_BLOCK_SIZE){write_program_memory(addr, &buffer[0], 32);putchar('.');restart_wdt();}*/putchar('!'); //Erase completed//---WDTwhile(!kbhit()) restart_wdt(); //Wait for HEXputc('\r'); putc('\n');while(TRUE){//---WDTwhile (getc()!=':') restart_wdt(); // Only process data blocks that starts with ':'putchar(':');buffidx = 0; // Read into the buffer until CR is received or buffer is fulldo{buffer[buffidx] = getc();putc(buffer[buffidx]);} while ( (buffer[buffidx] != '\r') && (buffer[buffidx] != '\n') && (buffer[buffidx] != ' ') && (++buffidx < BUFFER_LEN_LOD) );assert(buffidx == BUFFER_LEN_LOD, ERR_BUFFER_OVERRUN); // Error 1 - Buffer Overrun//---WDTrestart_wdt();checksum = 0; // Sum the bytes to find the check sum valuefor (i=0; i<(buffidx-1); i+=2){checksum += atoi_b16 (&buffer[i]);//!!! printf(".%x",checksum);}assert(checksum != 0, ERR_CHECKSUM); // Error 2 - Bad CheckSum// Get the lower 16 bits of addressl_addr = make16(atoi_b16(&buffer[2]),atoi_b16(&buffer[4]));line_type = atoi_b16 (&buffer[6]);num_of_bytes = atoi_b16 (&buffer[0]);assert (num_of_bytes > 16, ERR_TOO_MANY_BYTES); // Error 3 - Too many bytes in one lineaddr = make32(h_addr,l_addr);addr /= 2; // PIC16 uses word addresses// If the line type is 1 then ENDif (line_type == 1){putchar('#');reset_cpu();}assert (line_type != 0, ERR_UNSUPORTED_LINETYPE); // Error 4 - Unsuported Line type{// Read old program memory contentfor (i=0,next_addr=addr;i<8;i++)data.i16[i]=read_program_eeprom(next_addr++);// Loops through all of the data and stores it in data// The last 2 bytes are the check sum, hence buffidx-4for (i=8,dataidx=0; i < (buffidx-3); i += 2)data.i8[dataidx++]=atoi_b16(&buffer[i]);if (addr == 0){// Write 8 words to the Loader location (jump to the main())addr=LOADER_RESERVED;write_program_memory(addr, &data.i8[0], 16); // It works only with 16 !!!putchar('%');}elseif ( (addr >= FLASH_BLOCK_SIZE) && (addr <= (LOADER_RESERVED-16)) ) // Do not overwrite BootLoader{// Write programwrite_program_memory(addr, &data.i8[0], 16); // It works only with 16 !!!putchar('$');}else putchar('.'); // Possibly there was prevented write to the location of BootLoaderputc('\r'); putc('\n');//---WDTrestart_wdt();}}}void main(){int8 timeout;disable_interrupts(GLOBAL);setup_wdt(WDT_2304MS); // Setup Watch Dogsetup_adc_ports(NO_ANALOGS);setup_adc(ADC_OFF);setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);setup_timer_1(T1_DISABLED);setup_timer_2(T2_DISABLED,0,1);setup_comparator(NC_NC_NC_NC);setup_vref(FALSE);setup_oscillator(OSC_8MHZ|OSC_INTRC);for(timeout=0; timeout<255; timeout++) //cca 50s{if (kbhit())if (getc()=='u') // Send "uf" for Update Firmware{putchar('*');if (getc()=='f'){restart_wdt();boot_loader(); // Update Firmware starter}}else break;putchar('u'); putchar('f'); putchar('?');pause();restart_wdt();};restart_wdt();goto_address(LOADER_RESERVED); // Jump to the location where is the jump to the main}#ORG default // End of BootLoader