main.c

Bootloader for PIC16F87X (by Niklas Langmaack).



/**************************************************************
  Description: Bootloader Program
  Author:      Niklas Langmaack
  
  for problems, bugs, questions and good ideas
  mailto:Niklas@Langmaack-IZ.de

===============================================================

  This bootloader uses the hardware rs232 capability of the
  PICmicro to load the program as fast as possible. It is
  configured for 1200 baud, maybe it works even faster.
  
  The loader is located at the end of the program memory and
  uses 512 words.
  I've written two sample "custom.h" files:
     16F876 with 8K words
     16F870 with 2K words
  It should be no problem to change the values in these files
  for your specific application...
  
  The bootloader should work with any Flash PICmicro, that has a
  hardware rs232, self-programming capability and at least 1K memory ;-)
  At the moment, thats only the PIC16F87x family, but Microchip is
  already planing new cool flash devices....we'll C
  
===============================================================

  History:


05.07.2003
   v1.1  lots of changes, half the code size of v1.0
      changes in detail:
            new read_flash() function
            optimized save_boot_sect()
            some optimization in load_from_pc()
            removed main_menu()
            rs232 in assembler, no more pointers, shorter texts
            one included file for all changes

14.06.2003
   v1.0  first final version
            
**************************************************************/

#include <system.h>
#include "main.h"
#include "custom_16F870.h"



//======================== defs =======================
// var
char a;
char b;
char c;
char i;

//====================== init ==========================
void init()
{
   //pragmas
   #pragma RESERVE_ADDR_0 goto _main__code
   #pragma BOOTLOADER start_adr

   //init Hardware RS232
   txsta = 00100010b;
   rcsta = 10010000b;
   spbrg = baud_rate;
}

//=============== functions ========================
void write_flash( char adH, char adL, char datH, char datL )
{
   eeadrh = adH;                    //this function writes one
   eeadr  = adL;                    //word of code to the
   eedath = datH;                   //PIC's flash program mem
   eedata = datL;
   set_bit(eecon1, EEPGD);
   set_bit(eecon1, WREN);
   eecon2 = 0x55;
   eecon2 = 0xAA;
   set_bit(eecon1, WR);
   nop();
   nop();
   nop();
}

char read_flash( char adH, char adL, char byte )   //reads one byte (0=lower, 1=upper)
{                                      //from the given location
   eeadrh = adH;                          //in flash program mem
   eeadr  = adL;
   set_bit(eecon1, EEPGD);
   set_bit(eecon1, RD);
   nop();
   nop();
   if (byte == 0)
      return eedata;
   else
      return eedath;
}


/*
copies the first three opcodes of the loaded program to a special adress,
from where the program can be started then
*/
void save_boot_sect()
{
   for(i=0; i<3; i++)
   {
      write_flash(save_boot_adr,0xFC+i,read_flash(0,i,1),read_flash(0,i,0));
   }
}

void rep_boot_sect()                   //this function repairs the boot
{                                   //sector, so that after a reset
   write_flash(0,0,rep1,rep2);               //the bootloader will be started
   write_flash(0,1,rep3,rep4);
   write_flash(0,2,rep5,rep6);
   write_flash(0,3,rep7,rep8);
}

void load_from_pc()                       //the main loading function!
{
   char finished;
   char adrH;
   char adrL;
   char dataH;
   char dataL;
   char length;

   put_CR_LF();
   put_CR_LF();

   asm
   {
   putchr 'S'
   putchr 'u'
   putchr 'r'
   putchr 'e'
   putchr '?'
   putchr ' '
   putchr 'y'
   putchr '/'
   putchr 'n'
   }

   put_CR_LF();
   asm putchr '>'

load_loop:
   a = getchr();
   if (a == 'n')
      goto abort;
   if (a == 'y')
   {
      asm
      {
      putchr 'S'
      putchr 'e'
      putchr 'n'
      putchr 'd'
      putchr ' '
      putchr 'f'
      putchr 'i'
      putchr 'l'
      putchr 'e'
      putchr '!'
      }

      finished = 0;
      while(finished == 0)
      {
         a = getchr();
         if (a == ':')
         {
            length = hex2char(getchr(),getchr());
            adrH = hex2char(getchr(),getchr());
            adrL = hex2char(getchr(),getchr());
            getchr();
            getchr();
            adrL = (adrL >> 1) + ((adrH & 1)*128);
            adrH = adrH >> 1;

            if (adrH < max_adr)
            {
               i = 0;
               while (i < length)
               {
                  dataL = hex2char(getchr(),getchr());
                  dataH = hex2char(getchr(),getchr());
                  write_flash(adrH, adrL, dataH, dataL);
                  i = i + 2;
                  adrL++;
                  if (adrL == 0) adrH++;
               }
            }
            else
               finished = 1;
         }
      }
      save_boot_sect();
      rep_boot_sect();
      put_CR_LF();
      asm putchr 'O'
      asm putchr 'K'
      put_CR_LF();

      asm
      {
      putchr 'R'
      putchr 'e'
      putchr 's'
      putchr 'e'
      putchr 't'
      putchr '!'
      }

      while(1) nop();
   }
   else
      goto loop;
abort:

}

void run_current()                     //starts the current program
{
   asm goto boot_sect
}

//============================== Main program entry ======================

void main()                      //in this function, you could think about
{                             //writing some code, that tests a pin connected
   init();                       //to a jumper to automatically start the current
                              //program...
menu:
   put_menu_txt();

loop:
   switch( getchr() )
   {
      case '1': load_from_pc();  break;
      case '2': run_current();   break;
      case ' ': goto menu;    break;
   }
   goto loop;
}



http://www.sourceboost.com/home.html

Copyright © 2002-2006 SourceBoost Technologies