View previous topic :: View next topic |
Author |
Message |
wirelessage
Joined: 08 Aug 2012 Posts: 34
|
bootloader hex file corruption |
Posted: Fri Mar 22, 2013 11:02 am |
|
|
Hi all:
Environment is as follows:
-PIC18F2680
-Using ccs compiler v 4.092
-Using RS-485 for writing to program memory.
-Using ccsbootloader utility on the website for program download.
- I am using the bootloader.h,loader.c and ex_bootloader.c file provided by ccs.
I looked into forums, but I could not find what I am seeing. When I write to the PIC through the RS-485 line I am seeing all "ff" being written for some lines. I can't figure out why. Shouldn't the checksum catch it?
I don't have the greatest debugging environment to write it out a console. So, I am having to live with that.
The way I discovered this is I used the "ccs ICD-U64" programmer to read the chip after it is written and then do a diff with the original hex file.
a) I played with delay after write_program_memory() function in loader.c
What I find is that a delay of 90-100ms helps me reduce the number of corruptions to 1 or 2 lines.
Code: |
:10160000E111E21102E1006A0DD0D89001BE09D0CB
:10161000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA
:10162000F4D7019E0001000C09010251D8B4A5D0E5
|
Anyone seen this? Any ideas, thoughts?
I don't see this issue if I flash a small program.
Any help is appreciated..
Regards. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Mar 22, 2013 12:04 pm |
|
|
Do some tests with your RS485.
It is not writing FFFFFF. This is the erased value. It is rejecting the line.
The commonest problems with RS485, are poor termination (how essential this is, depends on the data rate involved), and lack of bias, when the bus is not driven. I'd suggest the loader is possibly receiving a low of garbage when the bus is not driven, and then having trouble identifying the start of the packet.
Best Wishes |
|
|
wirelessage
Joined: 08 Aug 2012 Posts: 34
|
|
Posted: Fri Mar 22, 2013 12:37 pm |
|
|
Thanks Ttelmah!
Makes sense. Shall look into it. |
|
|
wirelessage
Joined: 08 Aug 2012 Posts: 34
|
|
Posted: Sun Mar 24, 2013 3:25 pm |
|
|
Actually. It doesn't make sense what is going on
The checksum for the data turns out to be "DA". So, it cannot be data corruption over the wire.
Also, the location isn't the same. It changes on every write. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Mar 25, 2013 2:07 am |
|
|
Did you consider that CCS doesn't necessarily write full hex lines? To check for possible corruption of the binary image, you must compare the translated binary. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Mon Mar 25, 2013 2:10 am |
|
|
Of course it can (be data corruption over the wire).
Think about it. The hex file you are showing with the FF line, is generated by the ICD, so has a legitimate checksum for the line (since this is what is in the chip).
You are not seeing/showing what has actually been received.
You need to re-write the bootloader to do some diagnostics, or (simpler) write a program to emulate the bootloader. Have the same code as the bootloader, but have it when it receives a packet, instead of programming the chip, echo it out on another serial port. Then on your PC attach a second serial, and have it receive this data. You will then (hopefully) see what is being received.
Best Wishes
Last edited by Ttelmah on Mon Mar 25, 2013 3:25 am; edited 1 time in total |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Mar 25, 2013 2:59 am |
|
|
Just a general note:
Apart from your communication problems there is a fundamental feature missing from the CCS bootloader that will cause future problems.
As you have discovered there is a checksum on every line in the hex file, but what should the bootloader do when an error is discovered? I didn't check the source code, but I expect the line is dropped and that's why you see all 0xFF's (unprogrammed data). Now, the missing feature is that there is no mechanism available for the bootloader to request a retransmit of the corrupted line.
CCS can't be blamed for this, they built a small bootloader that will receive data from a simple text sending program like Hyperterm. Bootloaders from several other projects lack the same feature.
For a more robust bootloader a two-way protocol is needed. This can be done in many ways and even allows adding advanced features like memory read and verify. Disadvantage is that the user will have to install a dedicated bootloader program on his PC.
One of my favorites it the Tiny PIC Bootloader. The low level protocol is solid and bootloader code is tiny (about 100 words). Disadvantages are that you perhaps have to tweak the assembly code a bit to get it working for your processor and my main problem is that the PC program source code is not available (but you could always ask the author ...)
The protocol is simple and you could write your own PC host program, or searching the internet I found several other projects offering a PC host program using the same protocol. Here a first hit, aLinux port, but as it is written in Python it can easily be used on Windows as well.
Based on the above Linux code there is a new (January 2013) variant written in C# and offering complete source code: http://sourceforge.net/projects/tinypicbootload/ |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Mon Mar 25, 2013 4:48 am |
|
|
Quote: | Now, the missing feature is that there is no mechanism available for the bootloader to request a retransmit of the corrupted line. |
It's not actually missing, but probably not used by the loader tool.
The bootloader doesn't acknowledge packets with wrong checksum, it's up to the loader tool to retransmit it until getting an acknowledge, or cancel the download. |
|
|
wirelessage
Joined: 08 Aug 2012 Posts: 34
|
|
Posted: Wed Mar 27, 2013 9:08 am |
|
|
Here is what I have found so far:
- Like some of you have illustrated, there is an issue with loader.c code in terms of error handling. The code verifies the checksum ONLY AFTER SUCCESSFULLY PARSING the first 8 bytes. What if there is corruption in the first 8 bytes. The code I downloaded from ccs does not address that. Here is the modified code that seems to have helped me.
You have to set the do_ACKLOD flag to FALSE, and then set it to true ONLY after verifying the checksum (for line-type == 0).
I have run a couple of runs to see (through a serial sniffer) that now if there is a corruption the CCS client sees that there is no ACK, and so re-transmits (up to 3 times) which should be good if the baud rate is set right.
I shall run more tests and provide an update.. but initial tests look encouraging.
Code: |
do_ACKLOD = FALSE; //Set to TRUE in the original code.
//This is needed for ccsbootloader client. It first sends a ";HELLO" packet.
if( buffer[0] == ';')
{
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;
do_ACKLOD = 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 {
do_ACKLOD = TRUE;
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);
delay_ms(1);
}
else if (line_type == 4)
h_addr = make16(atoi_b16(&buffer[9]), atoi_b16(&buffer[11]));
}
}
}
if (do_ACKLOD)
fputc(ACKLOD,PC);
delay_ms(3);
fputc(XON,PC);
|
|
|
|
|