CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PicProjects Serial Bootloader

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
davidd



Joined: 30 Sep 2010
Posts: 38

View user's profile Send private message

PicProjects Serial Bootloader
PostPosted: Wed Nov 18, 2015 1:30 am     Reply with quote

Hello,

Trying to implement picprojects serial bootloader.
http://www.picprojects.net/serialbootloader/

I am confused about the header...
Code:

/* ------------------------------------------------------------------------- */
/* Bootloader Address Mapping                                                */
/* ------------------------------------------------------------------------- */
#define BOOTLOADER_START        0x2A
#define BOOTLOADER_END          0x3FF
#define RESET_VECTOR            0x400
#define INTERRUPT_VECTOR_LOW    0x408
#define INTERRUPT_VECTOR_HIGH   0x418
#define APPLICATION_START       RESET_VECTOR

#ORG BOOTLOADER_START, BOOTLOADER_END auto=0 default

//__________________________Bootloader_________________________________________


Why is the APPLICATION START at the RESET VECTOR?

How do I set the Main() to ORG after the bootloader code?

Thanks.
jeremiah



Joined: 20 Jul 2010
Posts: 1349

View user's profile Send private message

PostPosted: Wed Nov 18, 2015 7:35 am     Reply with quote

It's basically mimicking the start of PIC memory at address 0x400.

It's placing a GOTO instruction at address 0x400 that will jump to your application main(). Additionally it is putting a table of GOTO's starting at address 0x408 to handle any interrupts your application will use.

You are not showing us the header file full code, but I expect that same file has something like:

#build(reset=RESET_VECTOR,interrupts=INTERRUPT_VECTOR_LOW)

which is the CCS preprocessor directive that says "Hey, when I make main(), can you place a GOTO at address RESET_VECTOR that jumps to main() for me?". That way, when the bootloader jumps to APPLICATION_START (0x400), it will hit the GOTO and automatically go to your main.

The same idea for interrupts, only using address INTERRUPT_VECTOR_LOW as your base address.

The #org you show will ensure main() and your other code won't occur in that address range, and the #build() directive (assuming it is in there) will tell the compiler to automatically link the addresses it uses for main and interrupts in correctly.

This system is used to help make it so you don't have to put main in a specific location. You can using #org, but if you feel you have to do that, then something is usually wrong in your header file. It should have the #build directive somewhere in there to setup the address linkage.
davidd



Joined: 30 Sep 2010
Posts: 38

View user's profile Send private message

PostPosted: Sun Nov 29, 2015 8:02 am     Reply with quote

Thanks Jeremiah,

Its been a few weeks but I finally got back to this...

I am having trouble with the structure of the bootloader -- I don't understand where to put Main() and where to ORG it.

I keep getting memory block conflicts.

Could someone guide me in the right direction?
Thanks!


Here is the Bootloader:



Code:


/* ========================================================================= */
/* get_hexbyte                                                               */
/* returns byte representation of 2 ASCII characters pointed to by *hex      */
/* ========================================================================= */
int8 get_hexbyte(int8 *hex)
{
    int8 i;
    int8 ret = 0;
    int8 ch;
   
    for (i=0; i < 2; i++)
    {
        /* take care of HEX files where lower case letters are used */
        #ifdef BOOTLOADER_HEX_LOWERCASE
        ch = toupper(*hex);
        #else
        ch = *hex;
        #endif
       
        /* convert character to integer value */
        if (ch >= 'A')
        {
            ch = ch - 'A' + 10;
        }
        else
        {
            ch = ch - '0';
        }
        ret = (ret << 4) | ch;
        hex++;
    }
   
    return (ret);
}


/* ========================================================================= */
/* check_checksum                                                            */
/* calculates checksum for the received Intel HEX file line                  */
/* return: 0 = checksum ok                                                   */
/*         1 = checksum error                                                */
/* ========================================================================= */
#ifdef BOOTLOADER_HEX_CHECKSUM
int8 check_checksum(int8 *hex, int8 reclen)
{
    int8 checksum = 0;
    int8 i;

    // add all byte values, incl. checksum!
    for (i=0; i <= (reclen + HEX_HEADER_LEN); i++)
    {
        checksum += get_hexbyte(hex);
        hex += 2;
    }

    // checksum is zero if checksum is correct
    return (checksum);
}
#endif /* BOOTLOADER_HEX_CHECKSUM */


/* ========================================================================= */
/* bootloader                                                                */
/* the bootloader itself.                                                    */
/* ========================================================================= */
void bootloader(void)
{
    int32 addr;
    int16 addr_low;
    int8 addr_high = 0;
    int8 reclen;
    int8 rectype;
    int8 idx;
    int8 buffer[HEX_LINE_LEN_MAX];
    int8 ch;
    int1 hexend = 0;
   
    #if getenv("FLASH_ERASE_SIZE")>2
    int16 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 */
        #ifdef BOOTLOADER_HEX_CHECKSUM
       
        if (check_checksum(&buffer[HEX_LEN_START], reclen) != 0)
        {
            /* checkum error - send negative acknowledge */
            putc(NAK);
        }
        else
        #endif /* BOOTLOADER_HEX_CHECKSUM */
        {
            /* 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);
        }
    }
}


/* ========================================================================= */
/* application                                                               */
/* dummy application.                                                        */
/* ========================================================================= */
#ORG APPLICATION_START, APPLICATION_START+0x100
void application(void)
{
    while(1);
}


/* ========================================================================= */
/* main                                                                      */
/* checks if bootloader shall be invoked or if it shall start the            */
/* application program.                                                      */
/* ========================================================================= */
#ORG BOOTLOADER_START
void main()
{
    setup_adc(ADC_OFF);
   
    if (input(!BOOTLOADER_PIN))
    {
        //Show_Text("Firmware Update...  ");
        bootloader();
    }

    #asm
    goto RESET_VECTOR
    #endasm
}


/* ========================================================================= */
/* isr_low                                                                   */
/* remap interrupt vector low.                                               */
/* ========================================================================= */
#ORG 0x08, 0x17
void isr_low(void)
{
    #asm
    goto INTERRUPT_VECTOR_LOW
    #endasm
}


/* ========================================================================= */
/* isr_high                                                                  */
/* remap interrupt vector high.                                              */
/* ========================================================================= */
#ORG 0x18, 0x29
void isr_high(void)
{
    #asm
    goto INTERRUPT_VECTOR_HIGH
    #endasm
}




And here is my Main code:

Code:


#include <18F44K22.H>
//#device ADC=16
 
//_____________________________________________________________________________

//#FUSES NOWDT
#FUSES NOPROTECT
#FUSES PUT
#FUSES NOBROWNOUT
#FUSES NOLVP
#FUSES nopbaden
#FUSES INTRC_IO
#FUSES PLLEN                                                             

#FUSES MCLR
#FUSES NOIESO
#FUSES NOFCMEN                     
#FUSES NOXINST   

#USE DELAY(clock= 32000000)

#use standard_io(A)
#use standard_io(B)
#use standard_io(C)


#USE i2c(master,sda=PIN_A6, scl=PIN_A7, FORCE_SW, FAST )

#USE RS232(BAUD=9600,RCV=PIN_D7, XMIT=PIN_D6)


//___________________map reset vector and interrupt vector  __________________

// 0x000-0x3FF is used by the bootloader. The bootloader maps the original   
// reset vector (0x000) to 0x400 and the interrupt vector (0x008) to 0x408. 
// ----------------------------------------------------------------------------
#build (reset=0x400, interrupt=0x408)
// ----------------------------------------------------------------------------
// reserve boot block area                                                   
// This memory range is used by the bootloader, so the application must not 
// use this area.

#org 0, 0x3FF {}


//__________________________Bootloader_________________________________________

/* enable the following line to support lower case charachters in HEX file */
//#define BOOTLOADER_HEX_LOWERCASE

/* the following line enables the checksum check, disable to decrease the */
/* bootloader size */
//#define BOOTLOADER_HEX_CHECKSUM

/* pin for booloader activation */
#define BOOTLOADER_PIN      PIN_B0


/* ------------------------------------------------------------------------- */
/* Intel HEX file record types                                               */
/* ------------------------------------------------------------------------- */
#define HEX_DATA_REC        0   /* data record */
#define HEX_EOF_REC         1   /* end of file record */
#define HEX_EXTADDR_REC     4   /* extened linear address record */


/* ------------------------------------------------------------------------- */
/* Intel HEX file section start offsets                                      */
/* ------------------------------------------------------------------------- */
#define HEX_LEN_START       1   /* start of record length */
#define HEX_ADDR_START      3   /* start of address */
#define HEX_TYPE_START      7   /* start of record type */
#define HEX_DATA_START      9   /* start of data */

#define HEX_HEADER_LEN      4   /* lenght of lenght-, address- and type field in byte */

#define HEX_LINE_LEN_MAX    50  /* maximum length a line in the HEX file */


#define ACK                 0x06    /* positive acknowledge (ACK) */
#define NAK                 0x15    /* negative acknowledge (NAK) */


/* ------------------------------------------------------------------------- */
/* Bootloader Address Mapping                                                */
/* ------------------------------------------------------------------------- */
#define BOOTLOADER_START        0x2A
#define BOOTLOADER_END          0x3FF
#define RESET_VECTOR            0x400
#define INTERRUPT_VECTOR_LOW    0x408
#define INTERRUPT_VECTOR_HIGH   0x418
#define APPLICATION_START       RESET_VECTOR



#ORG BOOTLOADER_START, BOOTLOADER_END //auto=0 //default

#include <Bootloader.c>
 
 

//__________________________Bootloader_________________________________________




//************* MAIN ************************************************

#ORG APPLICATION_START

void application()

    {
 
   while (1)
   {
   
   printf ("BootLoader Test Program...  /n/r");
   
   delay_ms(1000);
   
   }

}
//*******************************************************************

jeremiah



Joined: 20 Jul 2010
Posts: 1349

View user's profile Send private message

PostPosted: Sun Nov 29, 2015 5:13 pm     Reply with quote

As I said in my previous post, you don't need to #org main at all. Just put in

Code:

void main(void){
    //do stuff
    while(TRUE){

   }
}


And since your application code has a

Code:

#build (reset=0x400, interrupt=0x408)


in it, it will place your main() in the right place automatically.

The only things in your application code that concern me are:
1. You include bootloader.c...I don't think you are supposed to do that in the application code. Normally, all the bootloader functions are just for the bootloader, not the application.
2. You don't put in a void main(void) like you should...you have an void application(), which is not going to tell the compiler anything.

You might consider taking a step back and actually looking at the example provided with the compiler and starting with those. I know you want to implement a specific one, but until you understand how a bootloader is laid out and how it works with the compiler settings, it is better to start with the provided examples.


EDIT:
From the website you linked, here are the only changes you need to add to your application:
http://www.picprojects.net/serialbootloader/#CODE_RELOCATION

look at the CCS section...just two lines:
Code:

/* ------------------------------------------------------------------------- */
/* map reset vector and interrupt vector                                     */
/* 0x000-0x3FF is used by the bootloader. The bootloader maps the original   */
/* reset vector (0x000) to 0x400 and the interrupt vector (0x008) to 0x408.  */
/* ------------------------------------------------------------------------- */
#build (reset=0x400, interrupt=0x408)
/* ------------------------------------------------------------------------- */
/* reserve boot block area                                                   */
/* This memory range is used by the bootloader, so the application must not  */
/* use this area.                                                            */
/* ------------------------------------------------------------------------- */
#org 0, 0x3FF {}


I also suggest #FUSES NONE

So all you need for a small program is:
Code:

#FUSES NONE

/* ------------------------------------------------------------------------- */
/* map reset vector and interrupt vector                                     */
/* 0x000-0x3FF is used by the bootloader. The bootloader maps the original   */
/* reset vector (0x000) to 0x400 and the interrupt vector (0x008) to 0x408.  */
/* ------------------------------------------------------------------------- */
#build (reset=0x400, interrupt=0x408)
/* ------------------------------------------------------------------------- */
/* reserve boot block area                                                   */
/* This memory range is used by the bootloader, so the application must not  */
/* use this area.                                                            */
/* ------------------------------------------------------------------------- */
#org 0, 0x3FF {}

void main(void){
      //this is your main code

    while(TRUE){

    }
}


From there you can add other things you need like the #use delay, #use rs232, etc.
davidd



Joined: 30 Sep 2010
Posts: 38

View user's profile Send private message

PostPosted: Sun Nov 29, 2015 7:35 pm     Reply with quote

Then bootloader.c should go here?

Code:


#org 0, 0x3FF {}

#include <bootloader.c>

void main(void){
      //this is your main code

    while(TRUE){

    }



Do I have to compile 2 hex files one with the bootloader and one without? or Is there a #define bootloader?

Thanks
jeremiah



Joined: 20 Jul 2010
Posts: 1349

View user's profile Send private message

PostPosted: Sun Nov 29, 2015 10:30 pm     Reply with quote

You don't put bootloader.c in your application at all.

You have two hex files:
1. your bootloader hex, which you load using a programmer
2. your application hex, which you load using the serial interface and the program that website provides.

You don't put your bootloader into the application at all.
Ttelmah



Joined: 11 Mar 2010
Posts: 19512

View user's profile Send private message

PostPosted: Mon Nov 30, 2015 2:47 am     Reply with quote

You do put _bootloader.h_ in the application. Not bootloader.c.

Look at the examples. The key thing is that bootloader.h changes what it does, based on a #declare If you have a "#declare _bootloader_", then load bootloader.h, it behaves to locate things correctly for the bootloader code. However if you include it without this declare, it instead locates things for the program to be loaded.

So if your main code is compiled like:
Code:

//processor define
//Fuses etc.
//clock settings
#define LOADER_END 0x3FF
#include "bootloader.h"

void main(void)
{
    //your code to run

}


The 'bootloader.h', automatically sets up the build command etc., to suit the defined 'LOADER_END'. In this case putting the main entry point at 0x400.
jeremiah



Joined: 20 Jul 2010
Posts: 1349

View user's profile Send private message

PostPosted: Mon Nov 30, 2015 8:39 am     Reply with quote

Just as a note, the bootloader.h that comes from their bootloader website isn't setup the same as the CCS bootloader.h. One must take care to use the CCS bootloader.h instead of the supplied one for that suggestion to work.
davidd



Joined: 30 Sep 2010
Posts: 38

View user's profile Send private message

PostPosted: Mon Nov 30, 2015 11:15 am     Reply with quote

Thanks everyone!

It is starting to make sense now!

I kept trying to insert my main code into the bootloader code --
So that it was all in a single HEX file.


Now I understand the reason for the Main() placeholder. I kept wondering why there was 2 Mains(), then I was Re-naming one Application().
Ttelmah



Joined: 11 Mar 2010
Posts: 19512

View user's profile Send private message

PostPosted: Mon Nov 30, 2015 11:19 am     Reply with quote

That is actually quite hard to do.

Personally, the easiest way, is to build the two parts separately, then import the bootloader into MPLAB, then import the runtime. Then save the result as a hex file. Result a single file that can be programmed into a blank chip, and includes the bootloader, and the default code.
davidd



Joined: 30 Sep 2010
Posts: 38

View user's profile Send private message

PostPosted: Mon Jan 18, 2016 7:47 am     Reply with quote

Finally got this boot-loader working on 18F44k22
http://www.picprojects.net/serialbootloader/


Thanks to all CCS members who helped out on this.

Some insight for others struggling with this:

Understand the concept that you will have 2 separate HEX files. The bootloader.hex gets programmed into your micro first. Upon reset, the bootloader.hex runs first and it checks the trigger pin, then it will either jump to the Main function OR load myapp.hex serially into the micro.

The "dummy" application is there to create a stub -- that is, the compiler will create the jump code to this point. So if you have the bootloader.hex programmed with no myapp.hex loaded yet, if you reset the micro and do not invoke the bootloader, it will jump to main() which is the dummy code. So it will sit in a do nothing loop, but what you can do is add a beeper to let the person know it is waiting, then do a reset_CPU(); when the button is pressed again.

The bootloader overwrites the dummy main() with myapp main() when myapp.hex is loaded into the micro.

what you need to know about the memory addresses is based on the bootloader code size. LOOK AT THE BOOTLOADER ASM LIST file. find the highest address used in bootloader.hex and choose your myapp.hex to start after that.

It is important to know that for
#ORG ADR1, ADR2 the following code starts at ADR1 and the space is reserved up to ADR2.

#ORG ADR1, ADR2 {} NOTE THE BRACKETS there is no code placed within this memory range.

HERE IS WHERE THE ISSUE ARISES

For example, say bootload.hex resides within 2FF, so you would choose your main function to start at 300. BUT this doesn't work -- there is additional code which is placed after 300. So the solution is to add some address space for that. Starting at 400 resolves this issue. The ASM file shows all the bootload.hex under 400.
Code:

/*------------------------------------------------------------------------- */
/* Bootloader Address Mapping                                                  */
/* -------------------------------------------------------------------------*/
#define BOOTLOADER_START   0x2A

#define BOOTLOADER_END       0x2FF

(ADDRESS SPACE HERE IS FOR ADDITIONAL CODE...)

#define RESET_VECTOR            0x400
#define INTERRUPT_VECTOR_LOW    0x408
#define INTERRUPT_VECTOR_HIGH   0x418
#define APPLICATION_START       RESET_VECTOR

#ORG BOOTLOADER_START, BOOTLOADER_END  auto=0 default



(If anyone has a better fix for this pls let us know.)

ALL THE ABOVE IS FOR THE bootloader.c file

Next the myapp.c needs to be setup to be stored at 400,
Code:

//_____________________________________________________________________________
/* ------------------------------------------------------------------------- */
/* map reset vector and interrupt vector                                     */
/* 0x000-0x2FF (PLUS I ADDED 100) is used by the bootloader. The bootloader maps the original   */
/* reset vector (0x000) to 0x400 and the interrupt vector (0x008) to 0x408.  */
/* ------------------------------------------------------------------------- */
#build (reset=0x400, interrupt=0x408)
/* ------------------------------------------------------------------------- */
/* reserve boot block area NEED TO RESERVE EVERYTHING UNDER400 (NOT just 'til 2FF)                                                  */
/* This memory range is used by the bootloader, so the application must not  */
/* use this area.                                                            */
/* ------------------------------------------------------------------------- */
#org 0, 0x3FF {}
//_____________________________________________________________________________


Lastly, I had issues with reset pin acting flaky.

keeping it short, #FUSE NOPBADEN Places PORT B in TTL I/O mode at power-up.

to use the bootloader invoke button,
Use #FUSE PBADEN to set port B as Inputs on Power-up.

If anyone has any questions, feel free to ask...
Thanks,
Dave
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group