|
|
View previous topic :: View next topic |
Author |
Message |
adamp524
Joined: 06 May 2010 Posts: 22
|
Triggering serial bootloader |
Posted: Thu Jun 03, 2010 4:19 am |
|
|
Hi,
I've been working with the serial bootloader that CCS have provided and it works well for my purposes. I'd like to extend this bootloader to be able to trigger it through the serial port.
The idea I've had is, while the main program is running, send a character sequence to the PIC which will set a flag in memory space somewhere that the bootloader can access. The device will then reset and the bootloader will test the condition of the flag. If the flag is set correctly, the bootloader will proceed to wait for the firmware image to be uploaded otherwise it will start the current image in memory.
Anyone have any ideas on how to set a flag in the main program that can be read by the bootloader?
Thanks |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 03, 2010 4:33 am |
|
|
Using #locate you can reserve a fixed memory address in RAM. By using the same address in both your bootloader and application you have established a mechanism for communication.
Another approach often used in bootloaders is that on reset the bootloader will wait for 1 second, scanning the serial port for a character (or sequence of characters) to receive. This has the advantage that your application doesn't have to know anything about the bootloader. Disadvantage is that your normal startup is delayed by 1 second (you can reduce this to 0.5 second or even lower depending on your baudrate). |
|
|
adamp524
Joined: 06 May 2010 Posts: 22
|
|
Posted: Thu Jun 03, 2010 9:22 am |
|
|
Ok, well I tried modifying the CCS bootloader to add in a serial buffer but the code does not compile and gives an 'Invalid ORG range' error
Code: | #include "main.h"
#include "main_bootloader.h"
#include <string.h>
//BOOTLOADER AT START - Include Bootloader.h in your application - See sample application Ex_Bootload.c
//BOOTLOADER AT END - Always include the projectname_bootloader.h file in future versions of the project
// Revector Interrupt table
#ORG default
#define charPattern "abc"
#define bootSize 5
char bootBuffer[bootSize];
int bufNext = 0;
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}
#if defined(__PCM__)
#org LOADER_END+1,LOADER_END+10
#elif defined(__PCH__)
#org LOADER_END+2,LOADER_END+20
#endif
// NOTE - User must include bootloader.h in his final Application program
// if Bootloader is located at the start of memory
// Sample Application - Example Ex_Bootload.c
#int_RDA
void RDA_isr(void)
{
bootBuffer[bufNext++] = getc();
if(bufNext >= bootSize) { bufNext=0; }
}
void application(void) {
while(TRUE);
}
// This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0x9F
#else
#org 0x20,0x7F
#endif
void main()
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
printf("Bootloader v1.0\r\n");
delay_ms(1000);
if(strstr(bootBuffer, charPattern) != null)
{
load_program();
}
application();
} |
Have you any ideas what is wrong?
Thanks |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 03, 2010 11:27 am |
|
|
Don't use interrupts in the bootloader. It is possible but very difficult to implement because how does the interrupt know it belongs to the bootloader or your main application?
And why use interrupts? There is no need for the extra overhead created by interrupts, your bootloader is only doing one dedicated task. Keep your bootloader lean and mean; use getc. |
|
|
adamp524
Joined: 06 May 2010 Posts: 22
|
|
Posted: Fri Jun 04, 2010 3:38 am |
|
|
Ok, well I now have this code for the main function:
Code: | // This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0x9F
#else
#org 0x20,0x7F
#endif
void main()
{
char charPattern[4] = "abc";
char bootBuffer[5] = "";
int bufNext = 0;
long time =0;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
set_timer0(0);
do
{
if(kbhit())
{
if(bufNext <= 4)
{
bootBuffer[bufNext++] = getc();
}
printf("a");
}
time = get_timer0();
}while(time < 100);
if(strstr(bootBuffer, charPattern) != null)
{
load_program();
}
application();
} |
But it's giving this error:
*** Error 71 "main.c" Line 66(0,1): Out of ROM, A segment or the program is too large MAIN
Seg 00040-0009E, 0060 left, need 00B4
Seg 000A0-000FE, 0060 left, need 00B4
Seg 00100-00108, 0006 left, need 00B4
Seg 0010A-004FE, 015C left, need 00B4
Seg 00500-00512, 0010 left, need 00B4
Note, line 66 does not exist in my main.c
Do you know how to increase the space given to main() in this bootloader? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Jun 04, 2010 6:00 am |
|
|
All the information is there!
Quote: | *** Error 71 "main.c" Line 66(0,1): Out of ROM, A segment or the program is too large MAIN
Seg 00040-0009E, 0060 left, need 00B4 | Here the compiler says that the reserved memory for the program is too small. You have reserved address 00040 to 0009E which is a total of 0060 addresses. The required size is 00B4 program words.
Now look at the top of your posted program: Code: | // This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0x9F
#else
#org 0x20,0x7F
#endif | This reserves for the PCH compiler the memory range 0x40 to 0x9F (The CCS error says 0x9E because memory words start at even byte addresses).
The compiler said it needs 0xB4 bytes, so fix it by changing the 0x9F to 0xF4 (0x40+0xB4). |
|
|
adamp524
Joined: 06 May 2010 Posts: 22
|
|
Posted: Mon Jun 07, 2010 2:48 am |
|
|
Ok, I've changed the hex values of the #org statements in line with what the compiler suggests. The code now compiles but when I load an image onto the PIC through the bootloader, it does not boot after a reset.
Here is my current main.c code:
Code: | #include "main.h"
#include "main_bootloader.h"
#include <string.h>
//BOOTLOADER AT START - Include Bootloader.h in your application - See sample application Ex_Bootload.c
//BOOTLOADER AT END - Always include the projectname_bootloader.h file in future versions of the project
// Revector Interrupt table
#ORG default
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}
#if defined(__PCM__)
#org LOADER_END+1,LOADER_END+10
#elif defined(__PCH__)
#org LOADER_END+2,LOADER_END+20
#endif
// NOTE - User must include bootloader.h in his final Application program
// if Bootloader is located at the start of memory
// Sample Application - Example Ex_Bootload.c
void application(void) {
while(TRUE);
}
// This defines space available for main() -Keep this code small so that it compiles
// then use Ex_Bootload.c to load application
#if defined(__PCH__)
#org 0x40,0xFE
#else
#org 0x20,0xEC
#endif
void main()
{
char bootBuffer[4] = "";
int bufNext = 0;
long time =0;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
set_timer0(0);
do
{
if(kbhit())
{
if(bufNext <= 4)
{
bootBuffer[bufNext++] = getc();
}
}
time = get_timer0();
}while(time < 50000);
if(strstr(bootBuffer, "abc") != null)
{
printf("a");
load_program();
}
printf("b");
application();
} |
The included file "main_bootloader.h":
Code: | //bootloader code
// LOADER_SIZE - Define the size of the bootloader code
// LOADER_END - Define the end of the general purpose bootload code.
// NOTE : LOADER_SIZE will changes depending on Compiler optimization
// Change these values in case of Out of ROM error.
#if defined(__PCM__)
#define LOADER_END 0x2FF
#define LOADER_SIZE 0x1E0
#elif defined(__PCH__)
#define LOADER_END 0x4FF
#define LOADER_SIZE 0x3FF
#endif
#define _bootloader
#ifndef _bootloader
#if defined(__PCM__)
#build(reset=LOADER_END+1, interrupt=LOADER_END+5)
#elif defined(__PCH__)
#build(reset=LOADER_END+1, interrupt=LOADER_END+9)
#endif
#org 0, LOADER_END {}
#endif
#define LOADER_ADDR LOADER_END-LOADER_SIZE
#define BUFFER_LEN_LOD 64
int buffidx;
char buffer[BUFFER_LEN_LOD];
#define ACKLOD 0x06
#define XON 0x11
#define XOFF 0x13
#SEPARATE
unsigned int atoi_b16(char *s);
#ORG LOADER_ADDR+10, LOADER_END auto=0 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] = getc();
} while ( (buffer[buffidx++] != 0x0D) && (buffidx <= BUFFER_LEN_LOD) );
putchar (XOFF); // Suspend sender
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;
#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 {
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);
}
else if (line_type == 4)
h_addr = make16(atoi_b16(&buffer[9]), atoi_b16(&buffer[11]));
}
}
}
if (do_ACKLOD)
putchar (ACKLOD);
putchar(XON);
}
putchar (ACKLOD);
putchar(XON);
#ifndef _bootloader
reset_cpu();
#endif
}
unsigned int atoi_b16(char *s) { // Convert two hex characters to a int8
unsigned int result = 0;
int i;
for (i=0; i<2; i++,s++) {
if (*s >= 'A')
result = 16*result + (*s) - 'A' + 10;
else
result = 16*result + (*s) - '0';
}
return(result);
}
#ORG default
#ORG LOADER_ADDR, LOADER_ADDR+9
void load_program(void)
{
real_load_program();
} |
Thanks for your help |
|
|
|
|
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
|