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

PIC24 Bootloader jump to Applicaton

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



Joined: 20 Apr 2012
Posts: 9

View user's profile Send private message

PIC24 Bootloader jump to Applicaton
PostPosted: Tue May 22, 2012 3:26 am     Reply with quote

Hi,

I'm working on the bootloader for PIC24HJ128. The compiler version I have is PCD 4.132.
The bootloader reset vector is at 0x0000, the application reset vector is mapped by the bootloader (not using #build in the application) to address 0x0200 (and 0x0202). I've confirmed that it really is placing all the code in the right spot including reset vector.
The bootloader excludes memory space
Code:
#ORG 0x200,0xFFFE{}

The application excludes memory space
Code:
#ORG 0x200,0x202{}                                                                                          // application reset vector (re-mapped)
#ORG 0xF800,0xFFFE{}                                                                                       // EEPROM
#ORG 0x10000,0x157FE{}                                                                                       // bootloader

The last lines of code before jump in the bootloader are
Code:
   debugmsgraw(dbgBootloaderLevel_Main,"DEVICE RESET\r\n");
   delay_ms(1000);
   #asm
      GOTO new_reset_vector_addr
   #endasm
The debugmsgraw is a macro for debug messages print depending on the level. I've noticed that most of the time the bootloader works fine, but I've had situations when it apparently jumped to application reset vector and suddenly went straight into either address error interrupt trap or just recently had oscillator interrupt trap. Also, if I restart the bootloader the same situation happens with the same code, so it's not a random thing, it seems to be code specific, so if I change the application code and re-compile it starts working fine.
I've also noticed that restart_cause() finds it sometimes as POWER-UP restart and sometimes as UNKNOWN.

Any ideas?
Thanks
jeremiah



Joined: 20 Jul 2010
Posts: 1346

View user's profile Send private message

PostPosted: Tue May 22, 2012 8:15 am     Reply with quote

Address error trap can occur if your application reset vector isn't using 4 program words (8 bytes) like it should. So say you want to have your application reset vector be 0x800 for whatever reason

Simply writing 0x00040800 to 0x200 could cause an address trap because the 2 program words after that might be 0xFFFFFFFF, which would be an invalid address. You don't really specify how you are doing your application reset vector since you aren't using #build. Here is how I recommend doing it (well, actually, I recommend using #build...):

Code:

#org 0x0200,0x0203
void application_reset(){
   #asm
      GOTO 0x0800  //or whatever address you need.
   #endasm
}


but never call that function. That just places a GOTO statement for you. and makes sure the address is correct.

Still, #build is much simpler:
Code:

#build (reset=0x0200)


and is more flexible

EDIT:
Just noticed all your #ORG statements end on even addresses...That's usually not good form.
I would suggest
#org <even_address>,<odd_address>{}

otherwise statements like #org 0x0200,0x202{} leave 0x203 open to be used by random things and who knows what the compiler might toss in there.
koofelek



Joined: 20 Apr 2012
Posts: 9

View user's profile Send private message

PostPosted: Tue May 22, 2012 11:45 am     Reply with quote

The ORG is a good point, thanks. I must have thought compiler would make sure 0x203 would not be used but I was wrong.
The way the bootloader re-maps the reset vector is:
- the hex file is modified to have separate ROM pages (this also reduces the file size from 300k hex to 80k)
- when reading 1st page the reset vector from the file (which is the application reset vector) is stored into RAM temporarily, also the reset vector from ROM (bootloader reset vector) is stored to RAM
- when it comes to writing the 1st page to ROM, the bootloader reset vector is put at 0x0000 and 0x0002 and application reset vector is put at 0x0200 and 0x0202. This is why application has #ORG 0x200,0x203{} which excludes anything to be put there.
jeremiah



Joined: 20 Jul 2010
Posts: 1346

View user's profile Send private message

PostPosted: Tue May 22, 2012 5:09 pm     Reply with quote

The interrupts Family Reference document on the Microchip website has a pretty decent list of causes of both of those traps. That would be my first step to debug with. Since you are storing it in RAM, how are you guaranteeing that those 8 bytes per restart vector aren't getting overwritten by other variables in the same ram location? Using #locate?
koofelek



Joined: 20 Apr 2012
Posts: 9

View user's profile Send private message

PostPosted: Tue May 22, 2012 5:28 pm     Reply with quote

I've used global static variables to store both reset vectors, i.e.
Code:
static ureg32   uBootResetVec0;                                                                                 // bootloader reset vector value 0 (at address 0x000000)
static ureg32   uBootResetVec1;                                                                                 // bootloader reset vector value 1 (at address 0x000002)
static ureg32   uNewResetVec0;                                                                                 // new firmware reset vector value 0
static ureg32   uNewResetVec1;                                                                                 // new firmware reset vector value 1


where ureg32 is
Code:
typedef union                                                                                             // create union
{                                                                                                      // only 1 value valid at any particular moment
   uint32 Val32;                                                                                          // 32-bit unsigned integer
   struct                                                                                                //
   {                                                                                                   //
      uint16 LW;                                                                                          // 16-bit unsigned integer
      uint16 HW;                                                                                          //
   } word;                                                                                                //
   uint8 Val[4];                                                                                          // 8-bit unsigned integer array
} ureg32;                                                                                                //

uint... are also my own typedefs
koofelek



Joined: 20 Apr 2012
Posts: 9

View user's profile Send private message

PostPosted: Wed May 23, 2012 5:27 pm     Reply with quote

Could this be also a compiler bug or problems with jumps? I had a bit weird behaviour going on, not sure that it was i.e. when I increased the stack from 256 bytes to 512 bytes, the top RAM usage jumped from 74% to a 100%. I've reduced the RAM usage to 61% with 512 bytes of stack and what I'm getting now is the PIC hangs when it tries to do the jump to application reset vector, the whole bootloader goes through fine. I've also commented out the function to write configuration registers (the same for both application and bootloader). I've confirmed the correct reset vector being written to the 0x200 and 0x202 addresses.
jeremiah



Joined: 20 Jul 2010
Posts: 1346

View user's profile Send private message

PostPosted: Wed May 23, 2012 6:32 pm     Reply with quote

Can you show the code you use to verify the correct reset vector is being set as well as the output that leads you to that conclusion? Not that I don't believe you, but sometimes we miss small things, so I figure a second set of eyes might show something.
koofelek



Joined: 20 Apr 2012
Posts: 9

View user's profile Send private message

PostPosted: Wed May 23, 2012 7:11 pm     Reply with quote

I know exactly what you mean. Here's the function to copy the bootloader reset vector and application reset vector from an incoming file into global variables
Code:

   if(uSourceAddr.Val32 == 0)                                                                                 // find reset vectors only if 1st page
   {                                                                                                   //
      read_program_memory(0x00000000, uBootResetVec0.Val, 4);                                                         //    
      read_program_memory(0x00000002, uBootResetVec1.Val, 4);                                                         //   
      uNewResetVec0.Val[0] = iDatabuffer[6];                                                                     // find the reset vector of the new firmware to be re-mapped 1st address
      uNewResetVec0.Val[1] = iDatabuffer[7];                                                                     //
      uNewResetVec0.Val[2] = iDatabuffer[8];                                                                     //
      uNewResetVec0.Val[3] = 0;                                                                               //
      uNewResetVec1.Val[0] = iDatabuffer[9];                                                                     // find the reset vector of the new firmware to be re-mapped 2nd address
      uNewResetVec1.Val[1] = iDatabuffer[10];                                                                     //
      uNewResetVec1.Val[2] = iDatabuffer[11];                                                                     //
      uNewResetVec1.Val[3] = 0;                                                                               //

And here is the code for writing the memory
Code:

   uTempAddr.Val32 = uSourceAddr.Val32;                                                                        // copy current page base address
   debugmsgraw(dbgBootloaderLevel_Main,"Write user page to PIC memory\r\n");                                             //
   for(iBufferCount = 0; iBufferCount < (user_page_instr_length * bytes_per_instr); iBufferCount = iBufferCount + bytes_per_instr)      //
   {                                                                                                   //
      if(uTempAddr.Val32 == 0)                                                                              // check if bootloader reset vector lower register
      {                                                                                                //
         uTempWord.Val[0] = uBootResetVec0.Val[0];                                                               // copy bootloader reset vector to temp
         uTempWord.Val[1] = uBootResetVec0.Val[1];                                                               //
         uTempWord.Val[2] = uBootResetVec0.Val[2];                                                               //
         uTempWord.Val[3] = 0;                                                                              //
      }                                                                                                //
      else if((uTempAddr.word.HW == 0) && (uTempAddr.word.LW == 2))                                                   // check if bootloader reset vector higher register
      {                                                                                                //
         uTempWord.Val[0] = uBootResetVec1.Val[0];                                                               // copy bootloader reset vector to temp
         uTempWord.Val[1] = uBootResetVec1.Val[1];                                                               //
         uTempWord.Val[2] = uBootResetVec1.Val[2];                                                               //
         uTempWord.Val[3] = 0;                                                                              //
      }                                                                                                //
      else if((uTempAddr.word.HW == 0) && (uTempAddr.word.LW == new_reset_vector_addr))                                    // check if firmware reset vector lower register
      {                                                                                                //
         uTempWord.Val[0] = uNewResetVec0.Val[0];                                                               // copy firmware reset vector to temp
         uTempWord.Val[1] = uNewResetVec0.Val[1];                                                               //
         uTempWord.Val[2] = uNewResetVec0.Val[2];                                                               //
         uTempWord.Val[3] = 0;                                                                              //
      }                                                                                                //
      else if((uTempAddr.word.HW == 0) && (uTempAddr.word.LW == (new_reset_vector_addr + 2)))                                 // check if firmware reset vector higher register
      {                                                                                                //
         uTempWord.Val[0] = uNewResetVec1.Val[0];                                                               // copy firmware reset vector to temp
         uTempWord.Val[1] = uNewResetVec1.Val[1];                                                               //
         uTempWord.Val[2] = uNewResetVec1.Val[2];                                                               //
         uTempWord.Val[3] = 0;                                                                              //
      }                                                                                                //
      else                                                                                             // if any other address
      {                                                                                                //
         uTempWord.Val[0] = iDatabuffer[iBufferCount + 6];                                                         // copy to temp
         uTempWord.Val[1] = iDatabuffer[iBufferCount + 7];                                                         //
         uTempWord.Val[2] = iDatabuffer[iBufferCount + 8];                                                         //
         uTempWord.Val[3] = 0;                                                                              //
      }                                                                                                //
                                                                                                      //
      debugmsgrawnum2(dbgBootloaderLevel_Wr,"Address: %6x, Data %6x\r\n",uTempAddr.Val32,uTempWord.Val32);                     //
      write_program_memory(uTempAddr.Val32,uTempWord.Val,4);
      uTempAddr.Val32 += 2;                                                                                 // increment address



I don't have the code to check the reset vector after it's been written to flash but there is a CRC for each page while it's being read, just before programming flash. I checked reset vector after being written manually with pickit.
jeremiah



Joined: 20 Jul 2010
Posts: 1346

View user's profile Send private message

PostPosted: Thu May 24, 2012 6:34 am     Reply with quote

Nothing jumps out from that for me.

I still think you should at least do some print statements on certain areas, specifically:

1. The program memory that holds the GOTO instruction called by the bootloader to go to the application

2. The reset vector for the application

it would be nice to see those printed values after they have been written but before the GOTO in the bootloader is executed.

The family reference manual lists the following causes for address trap:
Quote:

6.2.2.3 ADDRESS ERROR TRAP (HARD TRAP, LEVEL 13)
Operating conditions that can generate an address error trap include:
• A misaligned data word fetch is attempted. This condition occurs when an instruction
performs a word access with the Least Significant bit (LSb) of the effective address set to
‘1’. The PIC24H CPU requires all word accesses to be aligned to an even address
boundary
• A bit manipulation instruction uses the Indirect Addressing mode with the LSb of the
effective address set to ‘1’
• A data fetch is attempted from unimplemented data address space
• Execution of a BRA #literal instruction or a GOTO #literal instruction, where
literal is an unimplemented program memory address
• Execution of instructions after the Program Counter has been modified to point to
unimplemented program memory addresses. The Program Counter can be modified by
loading a value into the stack and executing a RETURN instruction


So it would be good to try to eliminate those one by one. The print statements I mentioned earlier would help root out potential candidates.

Aside from that, the best I could suggest is try to whittle down your program to a really small bootloader program that just uses your write to memory routine with some preloaded variables to see if you can get the same problem happening with a smaller subset of code and debug from there.

Mind you this is pseudo code, but wanted to give you an idea:

Code:

void main(){
   unsigned int32 address = 0x0200;
   unsigned int8 iBuffer[] = {
                              0x00,0x08,0x04,0x00,
                              0x00,0x00,0x00,0x00
                              //blah blah blah
                             };
   unsigned int8 oBuffer[16];
   unsigned int16 iBuffer_len = sizeof(iBuffer);

   your_write_to_mem_func(address,iBuffer,iBuffer_len);

   read_program_memory(....,&(oBuffer[0]),8);  //this needs to be the address of the GOTO coming up
   read_program_memory(0x0200,&(oBuffer[8]),8);

   print_read_results(oBuffer,16)

   #ASM
      GOTO 0x0200  //need to figure out the ROM address of this line for the first read_program_memory() call
   #ENDASM
}


Of course change the addresses/data to fit what you usually use. See if you can get the same failure with something basic.
koofelek



Joined: 20 Apr 2012
Posts: 9

View user's profile Send private message

PostPosted: Tue Jun 05, 2012 7:35 pm     Reply with quote

Sorry for a long delay, no time at all. The program was working fine, my colleague removed all debug from the main so after the debug in the bootloader about the device resetting, there was nothing else which had lead me to the thought something was wrong with the jump. All fine now, physically hooked up to uart receive and transmit lines to view real data without the impact on the program.
Thanks for all 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