Hi,
I'm trying to create bootloader in main memory. How to prepare linker scripts for BOOT and APP? How to do jump to APP from BOOT?
I'm using msp430f6659 and CCS 6
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi,
I'm trying to create bootloader in main memory. How to prepare linker scripts for BOOT and APP? How to do jump to APP from BOOT?
I'm using msp430f6659 and CCS 6
Hi Rafal,
The MSP-BOOT app note has a description of how to use the included Perl script MSPBootLinkerGen.pl to generate your linker files in section 4.2.3 Generating Linker Files. This shows you the syntax required by the script. You need to specify about the device you are using, and also provide parameters based on the part that you are using - like what address memory starts on the device, where the interrupt vector starts, and at what address you want your bootloader to begin, etc. These will be device and application specific. Please note you'll also need a Perl interpreter to run the script if you don't already have one.
Once you have run the script, you should have linker files that you can use for the APP and BOOT projects.
For how to jump to APP - in the example MSP-BOOT projects, after verifying the application image, the application manager decides whether to go on to the bootloader or main application. Section 2.2.1 Boot and Application Detection describes the decision flow concerning this.
If the application image is valid, then TI_MSPBoot_APPMGR_JUMPTOAPP() is called - see for example main.c inside the MSP-BOOT software package under Target\FR5739_I2C\Src\MSPBoot\AppMgr. In this main.c you can see in main_boot():
// Validate the application and jump if needed if (TI_MSPBoot_AppMgr_ValidateApp() == TRUE_t) TI_MSPBoot_APPMGR_JUMPTOAPP();
And in the AppMgr folder, in TI_MSPBoot_AppMgr.h, you'll see the definition of this macro:
/*! Jumps to application using its reset vector address */ #define TI_MSPBoot_APPMGR_JUMPTOAPP() {((void (*)()) _App_Reset_Vector) ();}
So what happens is that there is a jump to the application's reset vector in the main code area's proxy table, and then your application will run as if from reset.
Lets back up and say that the application manager determined that the image was not valid, or some other predefined external condition was met to force bootloader entry. In this case, it continues to the bootloader mode, and starts loading a new application image into the part. After the loading is complete, it calls the function TI_MSPBoot_AppMgr_JumpToApp() (note how this is different from the macro above). This issues a software BOR using the PMMSWBOR bit - this will force the code to reset back to the beginning of boot.c again, and validate the app again. However this time, the app manager will see that the app is valid and boot is not forced - at this point it will call TI_MSPBoot_APPMGR_JUMPTOAPP() just as above to finally jump into the app code that was just loaded at its proxy table reset vector.
I hope this helps to explain how it works.
Regards,
Katie
Thank you.
First problem which I see is memory map of msp430F6659 (512kB flash, 16kB ram), from orginal linker script we have:
RAM : origin = 0x2400, length = 0x4000
RAM2 : origin = 0xF0000, length = 0xC000
FLASH : origin = 0x8000, length = 0x7F80
FLASH2 : origin = 0x10000,length = 0x78000
So which adresses should be used as input parameter for perl script?
I used these parameters:
perl MSPBootLinkerGen.pl -file lnk_msp430F6659 -dev MSP430F6659 -params 0x8000 0xFF80 0xDF80 116 0 0x2400 0x63FF 0x80 0x1800 0x19FF
where:
- params = Defines ten necessary parameters used to defined the memory configuration of the
target device.
<mem_start> = Start address of Flash/FRAM (0xC000 for G2553)
<int_vect> = Address of interrupt vector table (0xFFE0 for G2553)
<boot_start> = Start address of Bootloader (0xFC00 for 1KB)
<proxy_size> =Size of the proxy table (48 for 12 vectors using 4B each)
<sv_size> = Size of shared vectors (4 for 2 vectors of 2B each)
<RAM_start> = Start address of RAM (0x200 for G2553)
<RAM_end> = End address of RAM (0x3FF for G2553)
<stack_size> = Size of the stack (0x50 for G2553)
<info_start> = Start address of info memory used for bootloader (0x1000)
<info_start> = End address of info memory used for bootloader (0x10BF)
but perl script generates me linker scripts with adresses like below:
/* RAM Memory Addresses */
__RAM_Start = 0x2400; /* RAM Start */
__RAM_End = 0x63FF; /* RAM End */
/* Flash memory addresses */
__Flash_Start = 0x8000; /* Start of Flash */
__Flash_End = 0xFFFF; /* End of Flash */
So the problem is that for APP flash size is limited to 0xFFFF. How to solve this problem?
Hi Rafal,
I had not realized you responded with further questions until now, because you edited your original response that just said you'd take a look at it (so I got no additional notification). Sorry for the delay. We're looking into your issue with the script now.
-Katie
Hi Katie,
Now I'm trying to do my own bootloader with adresses up to 0xFFFF. Next step will be increase adresses for application because for bootloader 24kB is enough.
How to program flash if address is wider that 16 bit? Now I'm using this procedure:
uint8_t FIRMW_WriteByteTouCFlash(uint16_t addr, uint8_t data) { if ((addr < APP_START_ADDR) || (addr > APP_END_ADDR)) return 1; FCTL3 = FWKEY; FCTL1 = FWKEY + WRT; // Enable flash write *(unsigned char*) addr = data; // Write data to flash FCTL1 = FWKEY; // Disable flash write FCTL3 = FWKEY + LOCK; return 0; }
But this is only for adresses uint16_t. How use bigger adresses? Just tu use uint32_t as addr parameter?
Thanks,
Rafal
Hi Katie,
Thank you for links. Next question is about proxy table in APP. In example there is:
const uint16_t ProxyVectorTable[] = { 0x4030, (uint16_t) Dummy_Isr, // APP_PROXY_VECTOR(0) }
But compiler told me:
#770-D conversion from pointer to smaller integer blink.c /TinyAppWithInterrupts line 89 C/C++ Problem
So I assume that Function pointer is higher than U16. What size should be reserved in linker for proxy table in APP? 4 bytes for function pointer and the table should looks like (6 bytes for one entry):
0x4030, (uint32_t) Dummy_Isr,
Regards,
Rafal
Hi Rafal,
Uint32_t (anything 20-bit or longer) would allow you to have code for your ISRs at locations above 0xFFFF if you want that option (MSP430 addresses can be up to 20-bits).
However, I would think you could leave your proxy table the same size, with uint16_t as long as you have some way to ensure that the application code will build with all ISRs below 0xFFFF. Indeed, that is actually the case by default already in the standard MSP430 linker files, because the actual interrupt vector table entries in the device can only hold 16-bit addresses anyway. You can see that in the normal MSP430 linker file for MSP430F6659 for example in CCS, it forces all ISRs to be in the lower memory by using this line for placement:
.text:_isr : {} > FLASH /* ISR Code space */
Compare this to the placement of other code:
.text : {}>> FLASH2 | FLASH /* Code */
And note the definitions of FLASH and FLASH2 earlier in the file:
FLASH : origin = 0x8000, length = 0x7F80 FLASH2 : origin = 0x10000,length = 0x78000
As you can see, all ISRs then are placed in FLASH which is 0x8000-0xFF80. Other code is then placed in either FLASH or FLASH2 0x10000-0x88000.
Another thing to make sure of, is that you must ensure that the proxy table itself is below 0xFFFF. This is because the actual vector table in the device only has room for 16-bit addresses - since the actual vector table is pointing to the proxy vector table location, you also have to make sure the proxy vector table gets placed in lower memory.
Regards,
Katie
Hi Katie,
Ok, I think that I understand. But in this case when proxy table is using size uint16 how to force compiler to not show warnings about conversion from pointer to smaller size? It's looks bad when during compilation many warning are displayed.
Probably I can block these warnings in CCS but I don't want to do this because of this kind of problems in other cases.
And second is a linker script modification.
For bootloader I think that I don't need to modify script, seems to be ok. But for application I have to to use FLASH2 area. So what should I modify in current script which works OK to use FLASH2 ? I attached current APP script. How to skip bootloader area started from 0xA000 and proxy table started 0x9F8E
/* RAM Memory Addresses */ __RAM_Start = 0x2400; /* RAM Start */ __RAM_End = 0x63FF; /* RAM End */ /* RAM shared between App and Bootloader, must be reserved */ PassWd = 0x2400; /* Password sent by App to force boot mode */ StatCtrl = 0x2402; /* Status and Control byte used by Comm */ CI_State_Machine = 0x2403; /* State machine variable used by Comm */ CI_Callback_ptr = 0x2404; /* Pointer to Comm callback structure */ /* Unreserved RAM used for Bootloader or App purposes */ _NonReserved_RAM_Start = 0x2406; /* Non-reserved RAM */ /* Flash memory addresses */ __Flash_Start = 0x8000; /* Start of Flash */ __Flash_End = 0xFFFF; /* End of Flash */ /* Reserved Flash locations for Bootloader Area */ __Boot_Start = 0xA000; /* Boot flash */ __Boot_Reset = 0xFFFE; /* Boot reset vector */ __Boot_VectorTable = 0xFFC6; /* Boot vector table */ __Boot_SharedCallbacks_Len = 4; /* Length of shared callbacks (2 calls =4B(msp430) or 8B(msp430x) */ __Boot_SharedCallbacks = 0xFFC2; /* Start of Shared callbacks */ _BOOT_APPVECTOR = __Boot_SharedCallbacks; /* Definition for application table */ /* Reserved Flash locations for Application Area */ _AppChecksum = (__Flash_Start); /* CRC16 of Application */ _AppChecksum_8 = (__Flash_Start+2); /* CRC8 of Application */ _App_Start = (__Flash_Start+3); /* Application Area */ _App_End = (__Boot_Start-1); /* End of application area (before boot) */ _CRC_Size = (_App_End - _App_Start +1); /* Number of bytes calculated for CRC */ _App_Reset_Vector = (__Boot_Start-2); /* Address of Application reset vector */ _App_Proxy_Vector_Start = 0x9F8E; /* Proxy interrupt table */ /* MEMORY definition, adjust based on definitions above */ MEMORY { SFR : origin = 0x0000, length = 0x0010 PERIPHERALS_8BIT : origin = 0x0010, length = 0x00F0 PERIPHERALS_16BIT : origin = 0x0100, length = 0x0100 // RAM from _NonReserved_RAM_Start - __RAM_End RAM : origin = 0x2406, length = 0x3FFA INFOBOOT : origin = 0x1800, length = 0x200 // Flash from _App_Start -> (APP_PROXY_VECTORS-1) FLASH : origin = 0x8003, length = 0x1F8B // Interrupt Proxy table from _App_Proxy_Vector_Start->(RESET-1) APP_PROXY_VECTORS : origin = 0x9F8E, length = 112 // App reset from _App_Reset_Vector RESET : origin = 0x9FFE, length = 0x0002 } /****************************************************************************/ /* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY */ /****************************************************************************/ SECTIONS { .bss : {} > RAM /* GLOBAL & STATIC VARS */ .data : {} > RAM /* GLOBAL & STATIC VARS */ .sysmem : {} > RAM /* DYNAMIC MEMORY ALLOCATION AREA */ .stack : {} > RAM (HIGH) /* SOFTWARE SYSTEM STACK */ .text : {} >> FLASH |INFOBOOT /* CODE */ .cinit : {} > FLASH |INFOBOOT /* INITIALIZATION TABLES*/ .const : {} >> FLASH |INFOBOOT /* CONSTANT DATA */ .cio : {} > RAM /* C I/O BUFFER */ .APP_PROXY_VECTORS : {} > APP_PROXY_VECTORS /* INTERRUPT PROXY TABLE */ .reset : {} > RESET /* MSP430 RESET VECTOR */ }
Regards,
Rafal
Hi Rafal,
For the pointers - unfortunately I do not know a good way to get rid of that warning, because using this large code model all that the compiler knows is that addresses are 20-bit. Now, you as the designer know that you forced this ISR address to be in the 16-bit area so that address in this case will always be 16-bit with preceding 0's for the other bits up to 20, so truncation is ok, but I don't know any way to get rid of the warning. I don't know if someone in the compiler forum could help with that or not.
Here's what I think you need to do (note that I haven't tested this myself, this is just from looking at it):
For the linker, to allow you to use the upper flash for your APP - you need to add a section like FLASH2 defined for starting at 0x10000 up to the ending address of your device's memory, and add this in the MEMORY portion of the linker file. For example, if you use MSP430F6659, I think you could add this line straight from the normal linker file for that part:
FLASH2 : origin = 0x10000,length = 0x78000
Then later in the SECTIONS part of the linker file, you will have to say what can go into this FLASH2 area. You'll allow normal code and constants here, but not ISRs or c-initialization tables - you can take your cues here from looking at the standard lnk_msp430f6659.cmd file: https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/166/lnk_5F00_msp430f6659.cmd
See how in the SECTIONS area, it has statements regarding where to put things in large data model. For normal ".text" (normal code) and ".const" constants, you will tell it to put these in either FLASH or FLASH2
.text : {} >> FLASH | FLASH2 | INFOBOOT /* CODE */
and
.const : {} >> FLASH | FLASH2 | INFOBOOT /* CONSTANT DATA */
But for things you want to be forced to 16-bit addresses like your ISRs, you'll want this:
.text:_isr : {} > FLASH /* ISR Code space */ .cinit : {} > FLASH /* Initialization tables */
Note the .text:_isr section - we use this on large memory model to ensure that the ISRs go into the lower 16-bit address range by setting it only to go into FLASH and not FLASH2. .cinit is c-initialization tables and this also goes in the lower range.
I'm not sure if there's anything else you'd need to change - I think you should try this out and look at the .map file and see where it places things when you have large code.
I hope that this helps give some more guidance on what to do next!
-Katie
Hi Katie,
I modified liker script:
/* MEMORY definition, adjust based on definitions above */ MEMORY { SFR : origin = 0x0000, length = 0x0010 PERIPHERALS_8BIT : origin = 0x0010, length = 0x00F0 PERIPHERALS_16BIT : origin = 0x0100, length = 0x0100 // RAM from _NonReserved_RAM_Start - __RAM_End RAM : origin = 0x2406, length = 0x3FFA RAM2 : origin = 0xF0000, length = 0xC000 /* Added by Uni-Tec manually */ INFOBOOT : origin = 0x1800, length = 0x200 // Flash from _App_Start -> (APP_PROXY_VECTORS-1) FLASH : origin = 0x8003, length = 0x1F8B FLASH2 : origin = 0x10000,length = 0x78000 /* Added by Uni-Tec manually */ // Interrupt Proxy table from _App_Proxy_Vector_Start->(RESET-1) APP_PROXY_VECTORS : origin = 0x9F8E, length = 112 // App reset from _App_Reset_Vector RESET : origin = 0x9FFE, length = 0x0002 } /****************************************************************************/ /* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY */ /****************************************************************************/ SECTIONS { .bss : {} > RAM | RAM2 /* GLOBAL & STATIC VARS */ .data : {} > RAM | RAM2 /* GLOBAL & STATIC VARS */ .sysmem : {} > RAM /* DYNAMIC MEMORY ALLOCATION AREA */ .stack : {} > RAM (HIGH) /* SOFTWARE SYSTEM STACK */ .text : {} >> FLASH2 | INFOBOOT /* CODE */ .text:_isr : {} > FLASH /* ISR Code space */ .cinit : {} > FLASH /* INITIALIZATION TABLES*/ .const : {} >> FLASH | FLASH2 | INFOBOOT /* CONSTANT DATA */ .cio : {} > RAM /* C I/O BUFFER */ .APP_PROXY_VECTORS : {} > APP_PROXY_VECTORS /* INTERRUPT PROXY TABLE */ .reset : {} > RESET /* MSP430 RESET VECTOR */ }
but all interrupts are send to FLASH2 not FLASH. In map file I have
000100ec TIMER1_A0_ISR 00010104 memcpy 00010118 __TI_decompress_none 0001012a __TI_decompress_rle24 00010130 Dummy_Isr
where TIMER1_A0_ISR and Dummy_Isr should be located in FLASH not FLASH2. The same behaviour is for standard linker script (not modified by me) that interrupts are in FLASH2, although in linker script there is
.text:_isr : {} > FLASH
Hi Rafal,
Sorry to hear this - Can you send over the project you used with the standard linker file for F6659 that put the timer ISR in 0x10000+ area of memory (you can send it to me in a private message if you don't want to post it for some reason)?
I tried for example building this code example linked here, but there it put it at 0x8000 area for me. dev.ti.com/tirex
In the comments near the top of the default linker file, what Version number is listed? Mine is 1.173.
Also what compiler version do you use?
Regards,
Katie
I have tools like below:
Code Composer Studio
Version: 6.0.0.00190
Project is attached.Program_uC_Tiny_APP_INTERRUPT.zip
Hi Rafal,
Thanks for attaching the project - I see what your issue is.
You have this for your timer interrupt, for example:
//============================================================================= //============================================================================= __interrupt void TIMER1_A0_ISR(void) { SecondTmpCounter--; if (!SecondTmpCounter) { SecondTmpCounter = 1000; P4OUT ^= 0x02; // Toggle P4.1 using exclusive-OR } TA1CCR0 += TIMER_A_RELOAD_1MSEC; // Add Offset to CCR0 }
When you make an ISR for one of the interrupts in the MSP430 device, you have to use a #pragma vector directive to tell the compiler which interrupt vector to associate with it. So you need to add a line and make it:
//============================================================================= //============================================================================= #pragma vector=TIMER1_A0_VECTOR __interrupt void TIMER1_A0_ISR(void) { SecondTmpCounter--; if (!SecondTmpCounter) { SecondTmpCounter = 1000; P4OUT ^= 0x02; // Toggle P4.1 using exclusive-OR } TA1CCR0 += TIMER_A_RELOAD_1MSEC; // Add Offset to CCR0 }
This tells it that this ISR goes with the TIMER1_A0_VECTOR. Now, when you build you will see that the ISR has correctly been placed only in the lower areas of memory, because the compiler + linker knows that this goes with one of the hardware interrupts and needs to therefore be in lower memory.
You can find more examples of declaring interrupts in our other code examples for this device: dev.ti.com/tirex
Regards,
Katie
Hi Katie,
Thanks it works. But what "#pragma vector" should I use for Dummy_Isr() to do it in nice way? I can use vector of interrupt which is never use in APP but maybe you now better way to "mask" dummy isr?
Regards,
Rafal
Hi Rafal,
I'm not sure what you are using Dummy_Isr() for - is it to trap/catch all unused interrupts and so you will fill the unused entries of the proxy table with the address of this Dummy_Isr()?
CCS in fact normally by default creates a trap ISR for catching all unused interrupts (__TI_TRAP_ISR if you look in the map file) but I think this is defined in the isr_trap.asm file in the run-time support library, so I don't know if you can very easily write your table to point to this address without hard-coding the address, which is probably not a good idea.
To make Dummy_Isr() be used for all of your unused interrupts, you can do something like this:
//============================================================================= //============================================================================= #pragma vector = ADC12_VECTOR, UNMI_VECTOR, PORT1_VECTOR, PORT2_VECTOR, \ TIMER0_A0_VECTOR, TIMER0_A1_VECTOR, WDT_VECTOR __interrupt void Dummy_Isr(void) { while(1) ; }
Simply list all interrupt vectors for the part that are not used by your code, separated by ",".
Regards,
Katie
Hi Katie,
I have a problem with erasing FLASH2. I have method:
static uint16_t FIRMW_EraseSector(uint32_t addr) { unsigned long * Flash_ptr; Flash_ptr = (unsigned long *)addr; __disable_interrupt(); // Check address to be not in bootloader area if (addr < APP_START_ADDR) { DEBUG("FIRMW: Erase ERROR at 0x%04X\r\n", addr); return 1; } DEBUG("FIRMW: Erase 0x%04X%04X\r\n", (uint16_t)(addr>>16), (uint16_t)addr); FCTL1 = FWKEY + ERASE; // Enable flash erase FCTL3 = FWKEY; // Disable lock *Flash_ptr = 0; // Dummy write to erase flash FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; // Diasble flash write return 0; }
And compiler throws me warning "invalid type conversion" for line:
Flash_ptr = (unsigned long *)addr;
And next when program is executing, program hangs up. I suppose that this warning is a reason that erasing is done wrong and damage flash area of bootloader. Have I wrong implementation of erase method?
Magic address is 0x00010600. If erasing this sector than application hungs up.
Regards,
Rafal
Hi Rafal,
I was looking to see what our BSL from SLAA450 does to do an erase on F5xx devices, which can have up to 20-bit addresses. I found that instead of using the flash_ptr method like you are doing above to create a pointer and do a dummy write, instead it uses this:
__data20_write_char(addr, 0);
If you check the TI C compiler user guide www.ti.com/lit/pdf/slau132 chapter 6.8.1 MSP430 Intrinsics, you'll find that this basically gives you access to the 20-bit assembly functions available in the device's instruction set. So this lets you do a character dummy write with a 20-bit address.
So you may want to try:
FCTL1 = FWKEY + ERASE; // Enable flash erase FCTL3 = FWKEY; // Disable lock __data20_write_char(addr,0); FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; // Diasble flash write
and completely comment out the lines where you set up the flash pointer since you're doing this instead.
As a note, another intrinsic __data20_write_short(addr, data) is used by the writeWord functions of the SLAA450 BSL source code as well, with __data20_read_short(addr) being used to read back word data for memory checking. __data20_write_char and __data20_read_char are used to read/write single bytes.
Regards,
Katie
**Attention** This is a public forum