View previous topic :: View next topic |
Author |
Message |
Fabri
Joined: 22 Aug 2005 Posts: 275
|
|
Posted: Sun Nov 29, 2020 1:53 pm |
|
|
About eeprom write I have zero crossing signal so, in case it miss for more than 50 ms I stop eeprom write. I'll rise up VBOR to 2,5V. I'll try to understand if this change is possible by firmware so I can update devices with new release.
About test I have reprogrammed devices working from month without any problem. I also tested again with burst generator.
What do you think about bootloader ? Maybe something happens in case program counter jumps to bootloader routine ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19254
|
|
Posted: Mon Nov 30, 2020 1:20 am |
|
|
This is down to how the bootloader is actually designed. The obvious
possibility is that some code 'overruns', and drops off the end, allowing
the top of memory loader to be reached. Does the bootloader contain the
ZCD detection code as well?. What would happen if you arrived at the
bootloader without the serial data arriving that it requires?. Could it do
some form of partial write?. |
|
|
Fabri
Joined: 22 Aug 2005 Posts: 275
|
|
Posted: Mon Nov 30, 2020 3:24 am |
|
|
Bootloader is based on example code of CCS. After received serial command firmware jump to routine waiting for serial string checking start bit and checksum. This is routine of boot.
Code: |
void boot (void)
{
uint1_t do_ACKLOD, done=FALSE;
uint8_t checksum, line_type, dataidx, i, count, buffidx;
uint16_t l_addr, h_addr=0;
uint32_t addr;
// Buffers
uint8_t data[32];
uint8_t buffer[BUFFER_LEN_LOD];
// Only required for parts where the flash erase and write sizes are different
#if (getenv("FLASH_ERASE_SIZE") > getenv("FLASH_WRITE_SIZE"))
uint32_t next_addr = 0;
#endif
disable_interrupts(global);
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);
do_ACKLOD = TRUE; // Flag to indicate this is a sentence we should acknowledge
// Only process data blocks that start with ':'
if (buffer[0] == ':')
{
count = atoi_b16(&buffer[1]); // Get the number of bytes from the buffer
l_addr = make16(atoi_b16(&buffer[3]),atoi_b16(&buffer[5])); // Get the lower 16 bits of address
line_type = atoi_b16(&buffer[7]); // Get the line type code from the string
addr = make32(h_addr,l_addr); // 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
if (line_type == 1) // If the line type is 1, then data is done being sent
{
done = TRUE;
// do_ACKLOD = FALSE; //tolto ?
}
else if ((addr < LOADER_ADDR || addr > LOADER_END) && addr < 0x300000) // Don't try to overwrite the loader
{
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 ((addr!=next_addr)&&(addr&(getenv("FLASH_ERASE_SIZE")/2-1)!=0))
erase_program_eeprom(addr);
next_addr = addr + 1;
#endif
write_program_memory(addr, data, count); // Attempt a write to the program memory
// do_ACKLOD = FALSE; // tolto ?
}
else if (line_type == 4)
h_addr = make16(atoi_b16(&buffer[9]), atoi_b16(&buffer[11]));
}
}
}
if (do_ACKLOD) // Only do this for sentences we have not already responded to
putchar(ACKLOD);
putchar(XON);
}
putchar(ACKLOD);
putchar(XON);
reset_cpu(); // After writing a new program we always want to reset the CPU
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9130 Location: Greensville,Ontario
|
|
Posted: Mon Nov 30, 2020 6:21 am |
|
|
Ok, I'm really confused now.....
earlier you posted that the oscillator stopped working,so the program can't run.
there's NO way the 'bootloader' code can STOP the clock, least none I know of.
the only software that I know that CAN stop the clock is the sleep() command according to a diagram in the datasheet.
Now there's a possiblity that the PIC is seeing 'EMI' as you have some sort of ZCD @ 50ms. I assume that's european line voltage ? A line voltage 'glitch' could randomly stop a PIC.
Again, use the internal osicallator for at least test. This eliminates any external clock hardware(xtal/caps/PCB) . I've got PIC with 1,000s of hours on them, using the internal osc, and none have ever 'stopped'. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19254
|
|
Posted: Mon Nov 30, 2020 7:48 am |
|
|
Also the bootloader you show is different in two key ways.
First you have said that this is at the top of memory. This implies it is
possible for code 'walking' up the memory to reach it. Then it has no form
of testing when entered for the code actually wanting to do a bootload. You
should be adding a test for something (possibly a 'flag' byte set in the main
code, when you do want a bootload to occur, which if it is not set, results
in the bootloader calling a reset, instead of executing). Currently if you walk
into the bootloader you will be stuck.
Also there is a huge difference in terms of the protection that the actual
bootloader code needs to apply. The CCS code by default ensures that a
write cannot occur to a location where the bootloader is, or to the config
registers. This modified bootloader needs the same protections for it's
addresses.
There is another nastier difference. The CCS code is designed so that
'worst case', if a bootload fails, the bootloader itself is still left intact.
Since this bootloader is dependant on the main code calling it, this
protection is lost. A failed write will result in a chip that has to be
reprogrammed. Think again. Work out how to keep the bootloader like
the standard one so it launches at 'boot'..... |
|
|
Fabri
Joined: 22 Aug 2005 Posts: 275
|
|
Posted: Mon Nov 30, 2020 8:36 am |
|
|
I'm working on test with internal oscillator but issue is quite rare so it can take months or years. About bootloader I'll work around as you suggest. I can introduce a flag in order to check if call to bootloader is serial comunication or just a noise or program counter error. In this last case I can go out with reset. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9130 Location: Greensville,Ontario
|
|
Posted: Mon Nov 30, 2020 10:30 am |
|
|
The 'flag' for serial bootloading should be at least 3 unique characters long to prevent 'random' bootloading....
Also it'd be best to have 2 'partitions' for storing two programs, the 'current' one and the 'new' one. That way if the downloading fails, for ANY reason, the PIC can still use the 'current' version of the program. This scheme is similar to how some PC BIOS EEPROMs are unpgraded over the Internet. If this wasn't done the PC could become a 'brick'. |
|
|
Fabri
Joined: 22 Aug 2005 Posts: 275
|
|
Posted: Mon Nov 30, 2020 11:18 am |
|
|
yes, two partition is best solution but I haven't space. Bootload is used in production from customers so, in case something gone wrong with boot, they return back board. This isn't a a big problem. |
|
|
|