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

Triggering serial bootloader

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



Joined: 06 May 2010
Posts: 22

View user's profile Send private message

Triggering serial bootloader
PostPosted: Thu Jun 03, 2010 4:19 am     Reply with quote

Hi,

I've been working with the serial bootloader that CCS have provided and it works well for my purposes. I'd like to extend this bootloader to be able to trigger it through the serial port.

The idea I've had is, while the main program is running, send a character sequence to the PIC which will set a flag in memory space somewhere that the bootloader can access. The device will then reset and the bootloader will test the condition of the flag. If the flag is set correctly, the bootloader will proceed to wait for the firmware image to be uploaded otherwise it will start the current image in memory.

Anyone have any ideas on how to set a flag in the main program that can be read by the bootloader?

Thanks
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jun 03, 2010 4:33 am     Reply with quote

Using #locate you can reserve a fixed memory address in RAM. By using the same address in both your bootloader and application you have established a mechanism for communication.

Another approach often used in bootloaders is that on reset the bootloader will wait for 1 second, scanning the serial port for a character (or sequence of characters) to receive. This has the advantage that your application doesn't have to know anything about the bootloader. Disadvantage is that your normal startup is delayed by 1 second (you can reduce this to 0.5 second or even lower depending on your baudrate).
adamp524



Joined: 06 May 2010
Posts: 22

View user's profile Send private message

PostPosted: Thu Jun 03, 2010 9:22 am     Reply with quote

Ok, well I tried modifying the CCS bootloader to add in a serial buffer but the code does not compile and gives an 'Invalid ORG range' error
Code:
#include "main.h"
#include "main_bootloader.h"
#include <string.h>

//BOOTLOADER AT START - Include Bootloader.h in your application - See sample application Ex_Bootload.c 
//BOOTLOADER AT END - Always include the projectname_bootloader.h file in future versions of the project
// Revector Interrupt table
#ORG default

#define charPattern "abc"
#define bootSize 5
char bootBuffer[bootSize];
int bufNext = 0;

#int_global
void isr(void) {
   jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}

#if defined(__PCM__)
 #org LOADER_END+1,LOADER_END+10
#elif defined(__PCH__)
 #org LOADER_END+2,LOADER_END+20
#endif
// NOTE - User must include bootloader.h in his final Application program
// if Bootloader is located at the start of memory
// Sample Application - Example Ex_Bootload.c

#int_RDA
void RDA_isr(void)
{
   bootBuffer[bufNext++] = getc();
   if(bufNext >= bootSize) { bufNext=0; }
}

void application(void) {
  while(TRUE);
}
// This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0x9F
#else
#org 0x20,0x7F
#endif
void main()
{
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   
   printf("Bootloader v1.0\r\n");
   delay_ms(1000);
   if(strstr(bootBuffer, charPattern) != null)
   {
      load_program();
   }
   application();
}

Have you any ideas what is wrong?

Thanks
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jun 03, 2010 11:27 am     Reply with quote

Don't use interrupts in the bootloader. It is possible but very difficult to implement because how does the interrupt know it belongs to the bootloader or your main application?

And why use interrupts? There is no need for the extra overhead created by interrupts, your bootloader is only doing one dedicated task. Keep your bootloader lean and mean; use getc.
adamp524



Joined: 06 May 2010
Posts: 22

View user's profile Send private message

PostPosted: Fri Jun 04, 2010 3:38 am     Reply with quote

Ok, well I now have this code for the main function:
Code:
// This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0x9F
#else
#org 0x20,0x7F
#endif
void main()
{
char charPattern[4] = "abc";
char bootBuffer[5] = "";
int bufNext = 0;

   long time =0;
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
   set_timer0(0);
   
   do
   {
      if(kbhit())
      {
         
         if(bufNext <= 4)
         {
            bootBuffer[bufNext++] = getc();
         }
         printf("a");
      }
      time = get_timer0();
   }while(time < 100);
     
   if(strstr(bootBuffer, charPattern) != null)
   {
      load_program();
   }
   application();
}


But it's giving this error:

*** Error 71 "main.c" Line 66(0,1): Out of ROM, A segment or the program is too large MAIN
Seg 00040-0009E, 0060 left, need 00B4
Seg 000A0-000FE, 0060 left, need 00B4
Seg 00100-00108, 0006 left, need 00B4
Seg 0010A-004FE, 015C left, need 00B4
Seg 00500-00512, 0010 left, need 00B4

Note, line 66 does not exist in my main.c

Do you know how to increase the space given to main() in this bootloader?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Jun 04, 2010 6:00 am     Reply with quote

All the information is there!
Quote:
*** Error 71 "main.c" Line 66(0,1): Out of ROM, A segment or the program is too large MAIN
Seg 00040-0009E, 0060 left, need 00B4
Here the compiler says that the reserved memory for the program is too small. You have reserved address 00040 to 0009E which is a total of 0060 addresses. The required size is 00B4 program words.

Now look at the top of your posted program:
Code:
// This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0x9F
#else
#org 0x20,0x7F
#endif
This reserves for the PCH compiler the memory range 0x40 to 0x9F (The CCS error says 0x9E because memory words start at even byte addresses).
The compiler said it needs 0xB4 bytes, so fix it by changing the 0x9F to 0xF4 (0x40+0xB4).
adamp524



Joined: 06 May 2010
Posts: 22

View user's profile Send private message

PostPosted: Mon Jun 07, 2010 2:48 am     Reply with quote

Ok, I've changed the hex values of the #org statements in line with what the compiler suggests. The code now compiles but when I load an image onto the PIC through the bootloader, it does not boot after a reset.

Here is my current main.c code:
Code:
#include "main.h"
#include "main_bootloader.h"
#include <string.h>

//BOOTLOADER AT START - Include Bootloader.h in your application - See sample application Ex_Bootload.c 
//BOOTLOADER AT END - Always include the projectname_bootloader.h file in future versions of the project
// Revector Interrupt table
#ORG default

#int_global
void isr(void) {
   jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}

#if defined(__PCM__)
 #org LOADER_END+1,LOADER_END+10
#elif defined(__PCH__)
 #org LOADER_END+2,LOADER_END+20
#endif
// NOTE - User must include bootloader.h in his final Application program
// if Bootloader is located at the start of memory
// Sample Application - Example Ex_Bootload.c

void application(void) {
  while(TRUE);
}
// This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0xFE
#else
#org 0x20,0xEC
#endif
void main()
{
   char bootBuffer[4] = "";
   int bufNext = 0;
   long time =0;
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
   set_timer0(0);
   
   do
   {
      if(kbhit())
      {         
         if(bufNext <= 4)
         {
            bootBuffer[bufNext++] = getc();
         }
      }
      time = get_timer0();
   }while(time < 50000);
   
   if(strstr(bootBuffer, "abc") != null)
   {
      printf("a");
      load_program();
   }
   printf("b");
   application();
}


The included file "main_bootloader.h":
Code:
//bootloader code
// LOADER_SIZE - Define the size of the bootloader code
// LOADER_END - Define the end of the general purpose bootload code.
// NOTE : LOADER_SIZE will changes depending on Compiler optimization
// Change these values in case of Out of ROM error.
#if defined(__PCM__)
   #define LOADER_END   0x2FF
   #define LOADER_SIZE   0x1E0
#elif defined(__PCH__)
   #define LOADER_END   0x4FF
   #define LOADER_SIZE   0x3FF
#endif

#define _bootloader

#ifndef _bootloader

#if defined(__PCM__)
   #build(reset=LOADER_END+1, interrupt=LOADER_END+5)
#elif defined(__PCH__)
   #build(reset=LOADER_END+1, interrupt=LOADER_END+9)
#endif

#org 0, LOADER_END {}

#endif

#define LOADER_ADDR LOADER_END-LOADER_SIZE
#define BUFFER_LEN_LOD 64

int  buffidx;
char buffer[BUFFER_LEN_LOD];

#define ACKLOD 0x06
#define XON    0x11
#define XOFF   0x13

#SEPARATE
unsigned int atoi_b16(char *s);

#ORG LOADER_ADDR+10, LOADER_END auto=0 default
void real_load_program (void)
{
   int1  do_ACKLOD, done=FALSE;
   int8  checksum, line_type;
   int16 l_addr,h_addr=0;
   int32 addr;
   #if getenv("FLASH_ERASE_SIZE")>2
      int32 next_addr;
   #endif
   int8  dataidx, i, count;
   int8  data[32];

   while (!done)  // Loop until the entire program is downloaded
   {
      buffidx = 0;  // Read into the buffer until 0x0D ('\r') is received or the buffer is full
      do {
         buffer[buffidx] = getc();
      } while ( (buffer[buffidx++] != 0x0D) && (buffidx <= BUFFER_LEN_LOD) );

      putchar (XOFF);  // Suspend sender

      do_ACKLOD = TRUE;

      // Only process data blocks that start with ':'
      if (buffer[0] == ':') {
         count = atoi_b16 (&buffer[1]);  // Get the number of bytes from the buffer

         // Get the lower 16 bits of address
         l_addr = make16(atoi_b16(&buffer[3]),atoi_b16(&buffer[5]));

         line_type = atoi_b16 (&buffer[7]);

         addr = make32(h_addr,l_addr);

         #if defined(__PCM__)  // PIC16 uses word addresses
            addr /= 2;
         #endif

         // If the line type is 1, then data is done being sent
         if (line_type == 1) {
            done = TRUE;
         #if defined(__PCM__)
         } else if ((addr < LOADER_ADDR || addr > LOADER_END) && addr < 0x2000){
         #elif defined(__PCH__)
         } else if ((addr < LOADER_ADDR || addr > LOADER_END) && addr < 0x300000){
         #endif
            checksum = 0;  // Sum the bytes to find the check sum value
            for (i=1; i<(buffidx-3); i+=2)
               checksum += atoi_b16 (&buffer[i]);
            checksum = 0xFF - checksum + 1;

            if (checksum != atoi_b16 (&buffer[buffidx-3]))
               do_ACKLOD = FALSE;
            else   {
               if (line_type == 0) {
                  // Loops through all of the data and stores it in data
                  // The last 2 bytes are the check sum, hence buffidx-3
                  for (i = 9,dataidx=0; i < buffidx-3; i += 2)
                     data[dataidx++]=atoi_b16(&buffer[i]);

                  #if getenv("FLASH_ERASE_SIZE") > getenv("FLASH_WRITE_SIZE")
                     #if defined(__PCM__)
                        if ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")-1)!=0))
                     #else
                        if ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")/2-1)!=0))
                     #endif
                           erase_program_eeprom(addr);
                     next_addr = addr + 1;
                  #endif
                  write_program_memory(addr, data, count);
               }
               else if (line_type == 4)
                  h_addr = make16(atoi_b16(&buffer[9]), atoi_b16(&buffer[11]));
            }
         }
      }

      if (do_ACKLOD)
         putchar (ACKLOD);

      putchar(XON);
   }

   putchar (ACKLOD);
   putchar(XON);
   #ifndef _bootloader
   reset_cpu();
   #endif
}

unsigned int atoi_b16(char *s) {  // Convert two hex characters to a int8
   unsigned int result = 0;
   int i;

   for (i=0; i<2; i++,s++)  {
      if (*s >= 'A')
         result = 16*result + (*s) - 'A' + 10;
      else
         result = 16*result + (*s) - '0';
   }

   return(result);
}

#ORG default


#ORG LOADER_ADDR, LOADER_ADDR+9
void load_program(void)
{
   real_load_program();
}


Thanks for your help
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