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 support@ccsinfo.com

Write_program_memory and erase_program_memory in PCD

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



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

Write_program_memory and erase_program_memory in PCD
PostPosted: Sat Sep 27, 2008 4:06 am     Reply with quote

Hello,

I made a 24F bootloader (used parts of EX_PCD_Bootloader to implement an undestructable bootloader with a memory layout similar to Microchip AN1157). At the start, I stumbled over some issues with handling of flash routines.

EX_PCD_Bootloader.c respectively loader_pcd.c are using the built-in functions in this way:
- erasing the full code space below the loader residing at code top
- writing the data of each incoming hex-line separately

The first step fails with the most recent version (of Jul 08, 2008 shipped with 4.079), cause it's treating FLASH_ERASE_SIZE, which is actually meant as a byte count, as an address increment, erasing only each second code page. An easy correctable bug.

Write_program_memory() is said in the manual to do an embedded erase
Quote:
Whenever this function is about to write to a location that is a multiple of FLASH_ERASE_SIZE then an erase is performed on the whole block.

But this embedded erase never happens, unless a code page overflow within a call to write_program_memory occurs, not expectable with usual *.hex files. Cause programming must not necessarily start on a page boundary, the embedded erase wouldn't guarantee a complete erasure, thus the function behaviour may be regarded as a feature rather than a bug. But it's apparently undocumented. A separate erasure prior to programming is necessary however.

Write_program_memory() is writing full rows of 64 instructions internally. If a function call requests a partial write, the remaining locations are refreshed to have the data for writing a full row. Usual hex lines contain 16 code bytes respectively 4 instructions, thus each location is erased once and written 16 times.

Although divergent from the Microchip recommended programming algorithm, this method seems to work. Or works mostly, cause I experienced programming errors in one location using loader_pcd.c (Cause I didn't investigate this issue in detail, I'm not completely sure what actually caused it).

I didn't find a statement regarding mutiple write in Microchip documents, so I can't say if the method can be expected to achieve a reliable programming, normally. But specifications of other flash memory devices are suggesting, that erase once, write multiple may give unpredictable results.

The Microchip recommended method for partial writes is to use a page buffer, read the old page data, erase the page, update the buffer and write it completely. Cause 24F devices have plenty of RAM, this method is easy to implement.

As a special issue, PCD hex-files may be non-continuous in some cases, e. g. when binary data have been imported to the design.

Furthermore I found, that the Microchip documentation is incorrect and partly misleading regarding FLASH CONFIGURATION WORD 3. A different (and correct) explanation of protection fuses can be found in paragraph 24.4.2 CODE SEGMENT PROTECTION.

CCS programmers apparently made use of the wrong specification, thus #FUSES WPEND_HIGH has to be set to protect the bottom code. Also the existing CCS C #FUSES WPFPx aren't covering the full code area. It seems to me, that the 16K size had been misunderstood, it actuall means a 16 kBit code page. But the WPFPx fuses are sufficient for a small bottom bootloader.

Regards,
Frank
drdelphi



Joined: 22 Apr 2007
Posts: 22
Location: Romania

View user's profile Send private message Yahoo Messenger

PostPosted: Fri Oct 10, 2008 7:30 am     Reply with quote

hi

I tried to adapt the pcd bootloader example from ccs to make it work for 24FJ32GA002, but when I goto LOADER_ADDR, device resets.
My loader_pcd.c file looks like this:
Code:

#define LOADER_SIZE     0x3FF
#define LOADER_END      (getenv("PROGRAM_MEMORY") - 1)
#define LOADER_ADDR     (LOADER_END - LOADER_SIZE)

#org default
#org LOADER_ADDR, LOADER_END auto = 0 default
void real_load_program(void) {
   int crc, line_type, i, count, data[16];
   unsigned int16 addr, e;
   putc('S');
   putc('E');
   for(e = 0; e < (LOADER_ADDR - 0x401); e += 0x400)
      erase_program_memory(e);
   putc('L');
   for(;;) {
      count = getc();
      addr = make16(getc(), getc());
      addr /= 2;
      line_type = getc();
      if (line_type == 1) break;
      crc = 0;
      for (i = 0; i < count; i++) {
         data[i] = getc();
         crc ^= data[i];
      }
      crc ^= getc();
      if (crc) putc('e'); else
        if (line_type == 0) {
          write_program_memory(addr, data, count);
          putc('k');
        }
   }
   putc('F');
   reset_cpu();
}


Do you have any idea what am I doing wrong ?
Thanks.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Oct 10, 2008 11:45 am     Reply with quote

Hello,

I understand that your bootloader resets, before it places any messages at the serial interface? In this case, I would check the memory layout if the goto has a valid target. I've been using a different bootloader layout, as previously said. I see, that your using a different protocol, binary rather than hex as in loader_pcd.c, but I think, it should work too. Is it from a different bootloader example?

Generally, I suggest to trace a crashing application with the debugger to reveal the failure mechanism. I wouldn't have come far without this technique, particularly in PIC24F/PCD programming.

Regards,
Frank
drdelphi



Joined: 22 Apr 2007
Posts: 22
Location: Romania

View user's profile Send private message Yahoo Messenger

PostPosted: Fri Oct 10, 2008 11:52 am     Reply with quote

hi

I made it work, but only to reprogram the memory space after 0x400.
It was resetting when erasing the address 0.
Now I moved the bootloader at the top (0x400 - 0x7FF), and the main program starts at 0x800. Before 0x400, I only have left the interrupt vector and the #use delay ? I seem not to quite understand how memory is organized.
The problem is now that the write_program_memory and erase_program_memory routines are located at 0xA36 and 0xA56, which is outside of bootloader. So after I erase the first block between 0x800 and 0xC00, these routines are also erased and the bootloader gets stuck.

can you please tell me what method did you use ?
many thanks

FvM wrote:
Hello,

I understand that your bootloader resets, before it places any messages at the serial interaface? In this case, I would check the memory layout if the goto has a valid target. I've been using a different bootloader layout, as previously said. I see, that your using a different protocol, binary rather than hex as in loader_pcd.c, but I think, it should work too. Is it from a different bootloader example?

Generally, I sugest to trace a crashing application with the debugger to reveal the failure mechanism. I wouldn't have come far without this technique, particularly in PIC24F/PCD programming.

Regards,
Frank
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Oct 10, 2008 2:13 pm     Reply with quote

Hello,

as said, I've been using a memory layout according to Microchip AN1157, the bootloader example provided by Microchip. The basic idea is to have a failsafe bootloader, that can't be corrupted e. g. by a abnormal terminated update process (in which case the device needs programmer access respectively has to be returned to a service location).

The CCS PIC18 bootloader example meets this requirement, but the PCD bootloader doesn't, cause the reset and interrupt vector area is overwritten during each update.

Unfortunately, placing the bootloader in low flash and protecting the interrupt table, restricts the way, how an application can use interrupts. This problem is new to PIC24/dsPIC, cause previous PICs had only two interrupt vectors, that could be easily redirected to application space.

AN1157 is discussing two different techniques, how this issue can be handled. One approach is having fixed addresses for all used application interrupts and make the table pointing directly to these addresses. The other is moving the vector table to bottom of application flash and create interrupt stubs in bootloader code, that jump to the respective table addresses.

The second approach is more flexible in application programming, but PCD has some restrictions, that make it difficult to create the interrupt stubs in C code or #asm, as far as I see. Thus I used fixed ISR addresses. The bootloader has dummy ISR definitions like below to setup the interrupt table.
Code:
#org APP_BASE+0x100, APP_BASE+0x17f
#int_RDA
void  RDA1_isr(void)
{
}

#org APP_BASE+0x180, APP_BASE+0x1ff
#int_TBE
void  TBE1_isr(void)
{
}

As one implication, the ISR code has to fit a predefined space, or must be extended by function calls. (Or a new, incompatible bootloader version has to be created). Another implication is, that you can't extend the application by new interrupts not considered in the bootloader. As a last resort, #INT_DEFAULT can be mapped to an application ISR.

Regards,
Frank
drdelphi



Joined: 22 Apr 2007
Posts: 22
Location: Romania

View user's profile Send private message Yahoo Messenger

PostPosted: Fri Oct 10, 2008 10:20 pm     Reply with quote

thanks a lot for the info.
now in the middle of my efforts to make this BL work, look what I get :
Internal Error - Contact CCS LABEL SCR=511
Mad
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sat Oct 11, 2008 2:06 am     Reply with quote

I sometimes got Internal Errors, but they never stayed for long. Although its occurence can be actually regarded as compiler bugs, they may appear in the end due to an error in your code, that hasn't been foreseen by CCS and isn't handled by a qualified error message. Thus, I would check, which code change produced it.
drdelphi



Joined: 22 Apr 2007
Posts: 22
Location: Romania

View user's profile Send private message Yahoo Messenger

PostPosted: Sat Oct 11, 2008 6:57 am     Reply with quote

Code:
#define METHOD1 0x400

unsigned int16 METHOD2 = 0x400;

// The following compiles ok
#asm
  goto METHOD1
#endasm

// The following raises internal error
#asm
  goto METHOD2
#endasm


so yes, it was my code.
drdelphi



Joined: 22 Apr 2007
Posts: 22
Location: Romania

View user's profile Send private message Yahoo Messenger

PostPosted: Sat Oct 11, 2008 12:59 pm     Reply with quote

It seems to work now. Here is how I did it.

When the BL starts, it checks if it is running for the first time (right after it has been programmed to the device). It checks the flash address 0x0004. If it is 0xFFFFFF then it reprograms the first 0x100 words like this :
0x00 - 0x5400 (BL start address)
0x02 - 0x0000
0x04 - 0x5010
0x06 - 0x5018
0x08 - 0x5020
...
0xFE - 0x53F8

Then, it checks the address 0x5000, where it puts the original contents of address 0x0000 from a loaded HEX (the reset). If it is 0xFFFFFF, it means it never loaded a HEX, so it waits forever for an incoming HEX. Otherwise he waits only for a few seconds then it executes a GOTO 0x5000.

The PC side software parses each line in the HEX and eliminates the fourth byte of each value to be programmed (which is always 0) to decrease the programming time. Then it rearranges the data in 384 bytes blocks (128 three-bytes words). This takes about 530 bytes of RAM for the BL's buffer. It ignores blocks that have addresses higher than 0x5000 (where the new IVT is located), to avoid BL overwriting. In the program to be loaded, you must include "#org 0x200, 0x3FF", so the code will always start at address 0x0400. Assuming you don't use the ALTIVT, then the HEX will contain only one block above 0x400, and that is between 0x0000 and 0x0100 (reset and IVT - 384 bytes).

The PC software will transform this block (I will call it the B block) in 4 blocks located at 0x5000, 0x5100, 0x5200 and 0x5300 like this :

B[0x00] -> 0x5000
B[0x02] -> 0x5002
B[0x04] + 0x020000 -> 0x5010 // add a call instruction
0x000000 -> 0x5012
0x064000 -> 0x5014 // RETFIE
B[0x06] + 0x020000 -> 0x5018
0x000000 -> 0x501A
0x064000 -> 0x501C
...
B[0xFE] + 0x020000 -> 0x53F8
0x000000 -> 0x53FA
0x064000 -> 0x53FC

Finally, it will search the entire HEX for the value 0x064000 (RETFIE) and replace it with 0x060000 (RETURN). It sends the data to the BL, the BL writes it into the flash and everything seems to work just fine and it achieves the goal of being an undestructable bootloader, not having any limitation regarding the interrupts.

Maybe I did some mistakes, but I tested it a few times and it works ok.

Thanks a lot for your help.

Best regards.
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