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

Updating firmware over RS232

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



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

Updating firmware over RS232
PostPosted: Fri Jun 05, 2009 7:45 am     Reply with quote

Hi all,

I'm trying to sort out a kind of a bootloader based on the CCS supplied loader.c but I'm having a problem. What I want to do is not have a bootloader as such but allow the user to select an option through the menu system of the main application where they can choose to update firmware.

I am using loader.c much as it is supplied and call load_program() and reset_cpu after the write has been done.

This works fine when I program the application with itself or with just a minor change like a value in a string. However, if I do a big change like add or remove some large library function it gets stuck in write_program_memory() after a short while. The point it gets stuck is fixed the same on repeated attempts and I am able to write past that point normally. I don't think it is a comms problem, I have no buffer overflows or anything.

I suspect I may be having some kind of writing over executing code problem but I don't think that should be the case as loader.c will not attempt to write over the load_program() functions. I have included my modified version below which basically just has changes to make it easier for me to read/understand and debug.

any thoughts would be most welcome.

cheers

ed

Code:

#pragma SEPARATE
unsigned int atoi_b16(char *s);

#pragma ORG LOADER_ADDR+10, LOADER_END 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] = fgetc(LOADER_STRM);
      } while ( (buffer[buffidx++] != 0x0D) && (buffidx <= BUFFER_LEN_LOD) );

      fputc(XOFF, LOADER_STRM);  // Suspend sender
      //fprintf(rda2_strm,"XF");
      output_low(LED1);
      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
         //fprintf(rda2_strm,"Got line, %u\r", count);
         // Get the lower 16 bits of address
         l_addr = make16(atoi_b16(&buffer[3]),atoi_b16(&buffer[5]));

         line_type = atoi_b16 (&buffer[7]);
         
         // At the first time through h_addr is zero as we are assuming the high bytes of the addr are zero
         // until we get a type 4 command
         addr = make32(h_addr,l_addr);

         // If the line type is 1, then data is done being sent
         if (line_type == 1)
         {
            done = TRUE;
            fprintf(rda2_strm,"Done\r");
         }
         else if ((addr < LOADER_ADDR || addr > LOADER_END) && addr < 0x300000)
         {
            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;
               fprintf(rda2_strm,"CS Fail\r");
            }
            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"))
                     fprintf(rda2_strm,"Erase\r");
                     if ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")/2-1)!=0))
                     {
                        erase_program_eeprom(addr);
                     }
                     next_addr = addr + 1;
                  #endif*/
                  fprintf(rda2_strm,"Write 0x%lx, %u, ", addr, count);
                  write_program_memory(addr, data, count);
                  fprintf(rda2_strm,"DN\r");
               }
               else if (line_type == 4)
               {
                  h_addr = make16(atoi_b16(&buffer[9]), atoi_b16(&buffer[11]));
                  fprintf(rda2_strm,"HAddr 0x%x\r", h_addr);
               }
            }
         }
      }

      if (do_ACKLOD)
      {
         fputc(ACKLOD, LOADER_STRM);
      }
      fputc(XON, LOADER_STRM);
      //fprintf(rda2_strm,"XO");
      output_high(LED1);
   }

   fputc(ACKLOD, LOADER_STRM);
   fputc(XON, LOADER_STRM);
   //fprintf(rda2_strm,"XO");
   // After writing a new program we always want to reset the CPU
   fprintf(rda2_strm,"Reset\r");
   reset_cpu();
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 05, 2009 1:16 pm     Reply with quote

1. Verify that your loader program is receiving and interpreting the
incoming data correctly.
Add printf statements to display the address and the bytes that come into
the loader routine. Comment out the code that erases and writes to
program memory. This will capture the entire incoming stream of
addresses and data. Copy and paste this information from the terminal
window, into MS Word and save it and print it. Now compare the
addresses and data that were received, to the original HEX file that
you sent to the PIC.

2. Determine the address at which it locks up.
Re-enable the erase and write program memory routines. Run the
above test again. You said it locks up at one point. Note the address.
Look at the .LST file for your original program (that's in the PIC). Look
at the code at the address where the problem occurs. This may
give you a clue.

You may be over-writing CCS library routines that are called by the
loader routine. The library code (putc, getc, delays, etc.) is not
guaranteed to be placed at the same ROM address by the compiler every
time you compile your program. So the loader may be calling library
routines that no longer exist at the addresses that its calling. One solution
is to make versions of the library code that are only for the loader
routine, so they can't be over-written.
EdWaugh



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

cheers
PostPosted: Sat Jun 06, 2009 4:52 am     Reply with quote

thanks for the great answer, I hadn't considered the routines I am linking in. I will give that all a try.

cheers

ed
EdWaugh



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

Making a second copy of library routines
PostPosted: Mon Jun 08, 2009 10:19 am     Reply with quote

I had more of a think about it and your suggestion about library functions sounds like the problem to me. It's not clear to me how to do as you suggest however, is there a trick to it?

I have a memory of an old post I think by Ttelmah where the math routines for use in an interrupt are duplicated by putting a #org statement around that interrupt, my memory is tho that the math routine copies are not then stored inside the #org just two copies are created (otherwise wouldn't what I have already work as I am calling the functions inside a #org).

I could also use multiple #use functions for fputc (I will eliminate fprintf as two copies would be silly). I guess if I just create a new stream this shouldn't affect my other code.

I feel like I should be able to figure out the solution but it is eluding me, sorry if I've missed something obvious!

cheers

ed
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 08, 2009 10:38 am     Reply with quote

I created my own versions of the CCS library routines. Here is my
version of putc(). This code will reside in the "bootloader" area along
with the rest of the bootloader code. It can't be overwritten by new
firmware.
Code:
void putbyte(char c)
{
while(!TXIF_BIT);
TXREG_REG = c;
}


Here is my version of getc().
Code:
char getbyte(void)
{
long timer;

timer = 0xffff;     // A count of 65,535 gives timeout of approx. 0.65 seconds

// This loop takes 10 usec

while((char)(timer >> 8))    // Only check the MSB, for speed
  {
   if(RCIF_BIT)
     {
      return(RCREG_REG);
     }
   timer--;
  }

return(0);
}


This is what I mean when I said to create your own library routines.
There might be some other way to do it. I worked on this project
back in 2001.
EdWaugh



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

Got it working
PostPosted: Mon Jun 08, 2009 10:43 am     Reply with quote

After making that last post i had a go with just creating a new RS232 stream inside the #org directive and once I remembered to disable interrupts in the second application I was testing it all started to work very nicely. Tiny app loads giant app and then giant app loads tiny app.

I guess the CCS compiler must already be making second copies of those functions and placing them in the #org region for me.

I will tidy up the code tomorrow and post it here and in the completed code forum in case anyone finds it useful.

thanks

ed
EdWaugh



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

Finally
PostPosted: Tue Jun 09, 2009 7:55 am     Reply with quote

Hi all,

I have tidyed up and made a few modifications and posted my final code here:

http://www.ccsinfo.com/forum/viewtopic.php?p=116730#116730

It seems to work fine, I hand checked the .lst file and have confirmed there are no CALL, RCALL or GOTO statements that point outside of the #org defined area. Hopefully this means it is all self contained.

I have left it very big and very verbose as I think it makes it a nice demo for people trying to figure this out. The CCS built in functions all seem to get inlined, like:

make8()
make16()
make32()
reset_cpu()
write_program_memory()
read_program_memory()

C library functions like strncmp however had to be copied into the code. Putting the #use RS232 statement inside the #org seems to mean all serial port statements are also included in this code.

I am a bit concerned that a change in optimisation level might break this, so I may have a play with that now. Thanks to PCM Programmer for the suggestions.

Cheers

ed
EdWaugh



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

Optimisation levels
PostPosted: Tue Jun 09, 2009 8:04 am     Reply with quote

Hi again,

I just tried opt 0 and opt 10 and apart from getting a bit fatter the loader worked fine and when I checked the lst there were no references outside the #org.

I suspect this is because the built in functions aren't real C functions but just bits of asm that are pasted in at compile time. As long as this doesn't change there should be no problem.

ed
jesconsa



Joined: 21 Jun 2010
Posts: 3

View user's profile Send private message

PostPosted: Mon Jun 21, 2010 6:07 am     Reply with quote

Try to put WRT on the FUSES!!!!!!!!!!!.........It works for me!!!!!!!!!! Ciao. Jesus
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