|
|
View previous topic :: View next topic |
Author |
Message |
manisha
Joined: 03 Feb 2012 Posts: 29
|
Need help for bootloader code with pic18f6723 |
Posted: Sat Nov 30, 2013 1:31 am |
|
|
Hello everyone...
I need some clarification regarding the code ex_bootloader.c present in the examples folder of PICC. Please help me..
My code is as follows:
main bootloader code :
Code: | /*
#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12
*/
//#elif defined(__PCH__)
//#include <18F452.h>
#include <18F6723.h>
#fuses WDT,PUT,PROTECT,BROWNOUT,HS
#use delay(clock=20000000)
#use rs232(baud=9600, ERRORS,xmit=PIN_C6, rcv=PIN_C7) // Jumpers: 8 to 11, 7 to 12
//#endif
#define _bootloader
#include <codebootload.h> //bootloader.h
#include <codeloader.c> //loader.c
/*#if defined(__PCM__)
#org LOADER_END+1,LOADER_END+10
#elif defined(__PCH__)*/
#org LOADER_END+2,LOADER_END+20
//#endif
void application(void) {
//printf("E");
while(TRUE);
}
//#if defined(__PCH__)
#org 0x40,0x9F
/*#else
#org 0x20,0x3F
#endif*/
void main(void) {
if(!input(PIN_G5)) //MCLR to check with reset
{
printf("E");
load_program();
printf("R");
}
application();
}
#ORG default
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
} |
second is bootloader.h renamed as codebootload.h:
Code: | /*#if defined(__PCM__)
#define LOADER_END 0x1FF
#define LOADER_SIZE 0x1BF
#elif defined(__PCH__)
*/
#define FLASH_SIZE getenv("FLASH_ERASE_SIZE")
#warning FLASH_SIZE
#if ((0x500 % FLASH_SIZE) == 0 ) //IF 0x500 is even flash boundary
#define LOADER_END 0x4FF //difference of 256
#define LOADER_SIZE 0x3FF
// #define LOADER_END 0x100FF //difference of 256
// #define LOADER_SIZE 0xFFFF
#else //ELSE, goto next even boundary
#define LOADER_END ((0x500+FLASH_SIZE-(0x500%FLASH_SIZE))-1)
#define LOADER_SIZE (LOADER_END-0x100)
#endif
//#endif
#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 |
Below is loader.c: renamed in code as codeloader.c
Code: |
#ifndef LOADER_END
#define LOADER_END getenv("PROGRAM_MEMORY")-1
/*#if defined(__PCM__)
#define LOADER_SIZE 0x17F
#elif defined(__PCH__)*/
//#define LOADER_SIZE 0x3FF
#define LOADER_SIZE 0x3FF
//#endif
#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();
} |
First I have loaded the above code as bootloader,then when I have checked for the execution of the main & it is seen that printf("E"); presnt in the main code is executed on hyperterminal and it is struck in the load program() and the next printf i.e R is not executed. I think there is a concern with loader_size and loader_end... When E is displayed on serial port monitor when I have dumped the hex of below file it is received by the controller but no result..
The application file is:
Code: | #include <18F6723.h>
#fuses WDT,PUT,PROTECT,BROWNOUT,HS
#use delay(clock=20000000,restart_wdt)
#USE RS232(baud=9600,xmit=pin_c6,rcv=pin_c7,ERRORS)
#byte PORTA = 0xF80
#byte PORTB = 0xF81
#byte PORTC = 0xF82
#byte PORTD = 0xF83
#byte PORTE = 0xF84
#byte PORTF = 0xF85
#byte PORTG = 0xF86
#include<stdio.h>
#include<math.h>
#include<stddef.h>
#include<string.h>
#include<stdlib.h>
#include<LCDLEDOP.c>
#define _bootloader
#include <codebootload.h>
#SEPARATE
VOID init_io()
{
set_tris_a(0X00);
set_tris_b(0x00);
set_tris_c(0x80); //1000 0010
set_tris_d(0x00); //
set_tris_e(0x00);
set_tris_f(0x00); //1001 0000
set_tris_g(0x14);
}
void display()
{
lcd_gotoxy(1,4);
printf (lcd_putc, " From bootloader ");
delay_ms (100);
}
void main(){
init_io(); // UC Intializing
lcd_init(); // LCD Intializing
delay_ms(500);
SETUP_WDT(WDT_ON);
while(TRUE)
{
restart_wdt();
printf("hello");
display();
}
} |
want the solution for above code i.e to dump code into controller via bootloader. Please help me in solving this problem..
Waiting for a quick reply... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sat Nov 30, 2013 11:49 am |
|
|
one problem I see is in the if/else processor type statements
I'd delete the conditional if/else and 'hardcode' for the PIC you're using.
Also check to be sure the memory configuring is correct.
and.. always add 'errors' to the use rs232(...options...) when using the hardware UART.
hth
jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sat Nov 30, 2013 1:29 pm |
|
|
The key thing is that if you change the size of the bootloader, you have to change the sizes to match.
You compile the bootloader, look at it's size, round it 'up' to the next page boundary, and put this into the sizes.
Printf statements are quite large, so it'll need to grow quite a bit.
However, you don't say what compiler version you are using?. There were a number of problems with the program memory write routine, a little while ago (very little...). If you are adding the printf's because the actual bootloader won't work, these may be your problem.
Best Wishes |
|
|
manisha
Joined: 03 Feb 2012 Posts: 29
|
|
Posted: Sun Dec 01, 2013 11:30 pm |
|
|
Quote: | The key thing is that if you change the size of the bootloader, you have to change the sizes to match.
You compile the booloader, look at it's size, round it 'up' to the next page boundary, and put this into the sizes.
Printf statements are quite large, so it'll need to grow quite a bit.
However, you don't say what compiler version you are using?. |
I am using version 4.120 and can you please tell me how to decide the LOADER_SIZE and LOADER_END values?
I have also added the ERRORS for uart... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 02, 2013 12:13 am |
|
|
Quote: | can you please tell me how to decide the LOADER_SIZE and LOADER_END values? |
Read this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=45044&start=6
Especially read the 2nd half of the post, which starts like this:
Quote: | ---------------------
To fix the problem we need to increase the ROM segment size |
If you have questions, ask them here in this thread, not in that one. |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Mon Dec 02, 2013 4:57 pm |
|
|
This thread is rather fortuitous, since I am just looking into a boot loader for the 18F87J60.
I read through the recommended post on how to modify ex_bootloader.c to compile for a different PIC. First, I don't get any compiler errors for either the default PIC (18F4522) or the 18F87J60. Does that mean I can use ex_bootloader.c as is, with some minor changes? I don't have to adjust segment sizes or #org locations?
I also have question about the memory map. When I compile for the default PIC (18F4522) I get the following:
Code: |
ROM Allocation:
000008 isr
00001E @const724.call
00003A @const726.call
000054 @PSTRINGC_9600_31766_31767
000076 @PUTCHARI_BIU_1
00007E atoi_b16
0000E4 @FLASHWR
000104 @WRITE_PROGRAM_MEMORY
000148 real_load_program
00031A load_program
000320 MAIN
000320 @cinit1
000354 @cinit2
000500 application
|
And the following defines are produced:
Code: |
#define LOADER_END 0x4ff
#define LOADER_SIZE 0x4ff
// 0x00 0x4ff 0x4ff
#define LOADER_ADDR (LOADER_END - LOADER_SIZE)
|
The loader address doesn't seem right to me. Is that correct? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 02, 2013 4:59 pm |
|
|
Explain to us how you got those numbers (0x4ff everywhere).
And post your compiler version. |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Mon Dec 02, 2013 5:25 pm |
|
|
I printed out the values of LOADER_END, LOADER_SIZE, and LOADER_ADDR.
Code: |
#warning Loader end: LOADER_END
#warning Loader size: LOADER_SIZE
#warning Loader addr: LOADER_ADDR
|
I' using v5.015 of PCWHD. |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Mon Dec 02, 2013 6:03 pm |
|
|
As I look at the code, it appears that LOADER_ADDR is not used if BOOTLOADER_AT_START is defined. And it is defined right at the top of bootloader.h. So maybe it doesn't matter what the value of LOADER_ADDR is.
The more interesting question for me is, what does the isr in ex_bootloader.c do?
Code: |
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}
|
First, I don't see where any interrupts are enabled anywhere. And even if interrupts managed to get enabled, what is the isr jumping to? I don't see its purpose. |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Tue Dec 03, 2013 12:10 pm |
|
|
Still trying to understand how the bootloader works. I compiled the example program ex_bootloader.c for the 18F87J60.
In function real_load_program() in file loader.c, there is this block of code:
Code: |
if (addr == (getenv("PROGRAM_MEMORY") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE"))))
{
read_program_memory(getenv("PROGRAM_MEMORY"), buffer, getenv("FLASH_ERASE_SIZE") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")));
write_program_memory(addr, data, count);
write_program_memory(getenv("PROGRAM_MEMORY"), buffer, getenv("FLASH_ERASE_SIZE") - (getenv("PROGRAM_MEMORY") % getenv("FLASH_ERASE_SIZE")));
}
|
with "buffer" declared as:
The values of the various macros are:
PROGRAM_MEMORY: 131064
FLASH_ERASE_SIZE: 1024
FLASH_WRITE_SIZE: 64
as determined by using the warning directive to print out the values.
Code: |
#warning Flash erase size: getenv("FLASH_ERASE_SIZE")
#warning Flash write size: getenv("FLASH_WRITE_SIZE")
#warning Program mem: getenv("PROGRAM_MEMORY")
|
Now look at the function read_program_memory() above.
The starting address is 131064. It starts reading at the end of memory? Does it then read down, or does the address wrap to 0, or does it read from non-existent memory?
Then after writing a line of data to program memory, it writes the array in 'buffer' back to program memory. How do we know that it didn't just overwrite what was written? |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Tue Dec 03, 2013 1:32 pm |
|
|
Ok, I think I see what is happening. The block of code I posted before is saving the last 8-bytes of program memory, writing data, then writing back the 8-bytes of saved program memory. I'm guessing there must be some special information saved in the last 8-bytes of program memory that must be protected/preserved at all costs.
Anyway, I guess I'm talking to myself here. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Tue Dec 03, 2013 3:52 pm |
|
|
SeeCwriter wrote: | As I look at the code, it appears that LOADER_ADDR is not used if BOOTLOADER_AT_START is defined. And it is defined right at the top of bootloader.h. So maybe it doesn't matter what the value of LOADER_ADDR is.
The more interesting question for me is, what does the isr in ex_bootloader.c do?
Code: |
#int_global
void isr(void) {
jump_to_isr(LOADER_END+5*(getenv("BITS_PER_INSTRUCTION")/8));
}
|
First, I don't see where any interrupts are enabled anywhere. And even if interrupts managed to get enabled, what is the isr jumping to? I don't see its purpose. |
This 're-vectors' the interrupts to work with the main code.
The bootloader does not use interrupts, but the main code may. Interrupts physically always call addresses right where the bootloader sits. When you compile with the main code set to start just after the LOADER_END, the interrupt code is put the required number of instructions after this point, and this code then makes the physical interrupt jump to _this_ address.
Best Wishes |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Wed Dec 04, 2013 5:00 pm |
|
|
Thank you for the explanation.
I compiled ex_bootloader.c for the 18F6722, which is the PIC on the development board I'm using. This is what the .sym file reports:
Code: |
ROM Allocation:
000008 isr
00001E @const724.call
00003A @const726.call
000054 @PSTRINGC_9600_31766_31767
00007E @PUTCHARI_BIU_1
000086 atoi_b16
0000EC @FLASHWR
00010C @WRITE_PROGRAM_MEMORY
000150 real_load_program
00031E load_program
000324 MAIN
000324 @cinit1
000346 @cinit2
000500 application
|
The org statement for function application() is:
Code: |
#org LOADER_END+2,LOADER_END+4
|
Where LOADER_END = 0x4ff
How does function application() end up 0x500, because my calculator says 0x4ff + 2 = 0x501?
Next I compiled ex_bootload.c. The .sym file reports the following:
Code: |
ROM Allocation:
000508 @const705.call
000524 @delay_ms1
00054E @PSTRINGC_9600_31766_31767
00057A @DIV88
0005A2 @PRINTF_U_9600_31766_31767
000610 main
000610 @cinit1
000632 @cinit2
|
Doesn't main() need to be at 0x500 for this to work? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Thu Dec 05, 2013 2:15 am |
|
|
The second number in the #ORG, is the end of the space allocated for the 'application'. Nothing to do with the ISR. The ISR, is placed in the _default_ memory space, which starts (for the bootloader) at address zero, and is always (by default) eight bytes (for a PIC18) 'up' in this space. So the #INT_GLOBAL is placed at address 0008. Jump to ISR, for a PIC 18, generates _two_ jumps. One located where the ISR sits, and one 0x10 bytes higher, going to a point 0x10 bytes higher. These are in case interrupt hardware priorities are used.
'Main' is _not_ the code entry point.
Compile a program without the bootloader. Look where 'main' sits.
On the PIC, you have a single 'jump' at the start of memory, which jumps 'to' main. Main is then the 'main' routine.
There has to be this jump, because your main code cannot sit at the start of memory, because it is followed just four instructions (8 bytes) latter by the interrupt entry point. So the memory layout on standard PIC18 code is:
0000 jump to main
0008 jump to high priority ISR
0018 jump to low priority ISR or ISR code
system routines
main etc..
or if interrupt priorities are not used
0000 jump to main
0008 ISR code
system routines
main etc..
With the build at 0x500, add 500 to each of these addresses. Note that 'main' does not sit at 500. It is the jump _to_ it that sits at 500.
Best Wishes |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Thu Dec 05, 2013 9:29 am |
|
|
I didn't explained myself very well. I will try again.
My understanding of how the bootloader works is, the bootloader code gets programmed into flash between addresses 0 and 0x4ff. And this code never changes. Address 0, the "jump to main" instruction, jumps to the bootloader's main function where it decides whether to enter the loader function or the application. The application is located at 0x500, the first memory address outside the bootloader region. The downloaded application goes into address 0x500 and up. So when the PIC boots up and decides to run the application it calls the function at address 0x500, which is where the downloaded application starts. If the application is put somewhere else, how is the bootloader going to know where it is so it can run it? |
|
|
|
|
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
|