How to place a GOTO at a specific address in a dsPIC33EV flash program? - Page 1
Forum section: electronics / general

author: ggchab
author_rank: Frequent Contributor
timestamp: September 07, 2018, 01:37:03 pm
content: I am trying to write a simple bootloader for a dsPIC33EV256GM002 (hex file simply sent over a serial port - XON/XOFF flow control).It should be located at 0x02A000. I modified the default project settings and the code is correctly loaded at that location.After 1 sec of no activity on the serial port, the loader jumps to 0x200. But if no user code is loaded yet, I would like to have a "GOTO 0x2A000" at that location (the entry point to the bootloader console).I copied the instruction in a .s file but I don't know how to tell the linker to place it at the right addressThanks for any idea.

author: mikerj
author_rank: Super Contributor
timestamp: September 07, 2018, 01:52:55 pm
content: Why not have the bootloader examine the instruction at 0x0200 before jumping to it? Presumably if the device is blank (apart from the bootloader) this will be 0xFFFF or similar. Even better would be to include a length and checksum in your application code (at fixed addresses) so that the bootloader can check the application in intact before executing it.

author: ggchab
author_rank: Frequent Contributor
timestamp: September 07, 2018, 02:05:43 pm
content: That's another simple option. Thanks.But for curiosity, I also would like to know if there is a simple way to force an instruction at a specific location. If that's too complex, then let's forget it. (I am new to C and used to do this type of things in assembly on a PC18F. That was so easy)

author: NorthGuy
author_rank: Super Contributor
timestamp: September 07, 2018, 02:30:09 pm
content: If you look at the memory structure, there's a reset vector at 0x000, IVT which spans to 0x200, then program memory starting at 0x200.The flash memory needs to be erased in pages. One page spans 0x400 addresses. Thus, the first page spans from 0x000 to 0x400. If you erase this page, the reset vector gets erased. If something happens at this time, the reset vector will no longer jump to the bootloader and the PIC is bricked (needs to be re-programmed through ICSP). Therefore, erasing the first page is not a good idea.If you never erase the first page, the addresses between 0x200 and 0x400 cannot be changed, and hence cannot be used by the application. Therefore, it'a a good idea to put the bootloader code into this space.Not erasing the first page also means that you cannot erase IVT. Therefore, it's a good idea to reserve IVT for the bootloader and use AIVT for the application.You can avoid all these problems altogether if you define aboot segmentwhich is the space in the beginning of the memory where the bootloader resides. Then application memory will start where the boot segment ends, beginning from AIVT. See the datasheet for details.

author: ggchab
author_rank: Frequent Contributor
timestamp: September 07, 2018, 03:45:19 pm
content: Thank you, I knew that. Except that I have never done any research on the use of AIVT. As this is an hobbyist project, I simply wanted to reuse the approach I used for many years with the PIC18F. But true, the PIC24 / dsPIC33 has many more options for bootloaders and it's always a pleasure to learn new techniques

author: rstofer
author_rank: Super Contributor
timestamp: September 07, 2018, 04:46:10 pm
content: Using GCC, you would define a .section, presumably in the startup code (crt0.s?) and assemble a GOTO (branch or whatever). Remember, you probably have to branch through an indirect address pool because the ARM can't always include a full memory address in a single instruction word and it doesn't do multi-word instructions.Then in the linker script you would change the memory map to add the section at a specific location.

author: JPortici
author_rank: Super Contributor
timestamp: September 07, 2018, 04:51:52 pm
content: You don't need interrupts for the bootloader, you have a fifo buffer on the uart and the dspic can run pretty fast. Just poll the RX data available flag and use some kind of protocol that tells the host to wait/resume.I don't remember if there is a builtin function, otherwise to insert a goto just addCode:volatile asm ("GOTO #0x2A000");

author: ggchab
author_rank: Frequent Contributor
timestamp: September 07, 2018, 05:40:07 pm
content: QuoteTo force the GOTO at a specific address, I remember that I tried something likeCode:_at(0x200) void dummy(void){asm("GOTO 0x2A000");}but the compiler is producing some additional code before and after the GOTO

author: ggchab
author_rank: Frequent Contributor
timestamp: September 07, 2018, 05:44:47 pm
content: QuoteI am still looking for a good tutorial to learn how to create sections and define them in the linker scriptOn the PIC24, there is a GOTO that can go anywhere in the addressable memory.

author: rstofer
author_rank: Super Contributor
timestamp: September 09, 2018, 03:06:43 pm
content: Quote from: ggchab on September 07, 2018, 05:40:07 pmSee if the 'naked' attribute will eliminate the prologue and epilogue code:http://www.keil.com/support/man/docs/armclang_ref/armclang_ref_jhg1476893564298.htm

author: ggchab
author_rank: Frequent Contributor
timestamp: September 09, 2018, 04:30:18 pm
content: QuoteThank you

author: TomS_
author_rank: Frequent Contributor
timestamp: September 09, 2018, 06:21:19 pm
content: Quote from: ggchab on September 07, 2018, 01:37:03 pmIf the application has not been loaded, and presumably all of the lower memory addresses are erased such that their value is "all 1's", then according to the datasheet the lower memory space should be full of NOPR instructions.Therefore, if the bootloader jumps to 0x200 and an application is not loaded, the CPU should execute NOPRs all the way back in to the bootloader. No problem.

author: JPortici
author_rank: Super Contributor
timestamp: September 09, 2018, 06:41:56 pm
content: should! what if it's only partially erased? at some point you may be excecuting random codeAnyway, in my 33EV bootloader the MCU enter the bootloader at startup.A Program memory read at address XXX is performedif the memory location is "free" -> 0xFFFFFF stay in bootloader, otherwise go to application

author: ggchab
author_rank: Frequent Contributor
timestamp: September 09, 2018, 08:00:38 pm
content: That's also what I am doing now. Thank youQuote from: JPortici on September 09, 2018, 06:41:56 pmEnvoyé de mon SM-G920F en utilisant Tapatalk

author: rstofer
author_rank: Super Contributor
timestamp: September 09, 2018, 09:23:08 pm
content: Quote from: ggchab on September 09, 2018, 08:00:38 pmThe NXP 2xxx series uCs did a checksum over the interrupt vectors. If the checksum was 0x00000000 then the bootloader branched to the reset interrupt.To make this happen, one of the vectors was reserved and a value was calculated and placed in that location. There are a number of ways this happened but mostly it was just a well known constant.Keil had the device programmer calculate the value.http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka11381.htmlThere's a lot of information about this on the web.It wasn't as simple as 0x00000000 or 0xffffffff, it actually forced the checksum to 0.

author: westfw
author_rank: Super Contributor
timestamp: September 11, 2018, 12:54:01 am
content: QuoteFor gcc in general, You don't need a linker script to locate a particular section at a particular address. You can specify a section attribute in the source code:Code:void default_code() __attribute__((section("normstart"))) __attribute__((naked));void default_code() {main();}int main() {while (1);}and a --section-start option in the link command:Code:/Applications/microchip/xc16/v1.35/bin/xc16-gcc -O1 -Wl,--section-start=.text=0x2A000 -Wl,--section-start=normstart=0x200 pic33.cIn theory, anyway. It works fine for an AVR, but I couldn't get it to work with xc16. :-((The section-start for .text works fine. The ".section normstart" shows up fine in the .s file, but ... default_code() ends up in the same .text section with everything else :-( )However, it seems that xc16 has a separate attribute that lets you position functions:Code:void default_code() __attribute__((address(0x200))) __attribute__((naked));(viahttps://www.microchip.com/forums/m887082.aspx)And that works fine. (no, not quite. It put main() itself in a separate section at 0x100. Sigh. I have no more clues...)Code::**** crt code all goes to 0x2a000 like it's supposed to...0002a0c8 <__crt_start_mode>:2a0c8: 00 00 05 retlw.w #0x0, w0Disassembly of section .reset:00000000 <.reset>:0: 00 a0 04 goto 0x2a000 <__reset>2: 02 00 00Disassembly of section _0x4187dd00_at_address_0x200:***** default_code goes at 0x200 like I asked it to.00000200 <_default_code>:200: 81 ff 07 rcall 0x104 <_main> <.L2>202: 00 00 06 returnDisassembly of section .isr:00000100 <__DefaultInterrupt>:100: 00 40 da break102: 00 00 fe resetDisassembly of section .text:***** But WTF?00000104 <_main>:104: ff ff 37 bra .

author: JPortici
author_rank: Super Contributor
timestamp: September 11, 2018, 06:11:05 am
content: if you want to reserve space that the compiler shouldn't have access to for this particular firmware the linker method is the best and easiest.even if you relocate a function you are merely changing the starting address of the function, you have to isolate it into a section to make sure...Then there's the startup code, it will be placed wherever the compiler feels like it. When i experimented with repositioning the main it did happen at one point that part of the startup code was before the main, in the "restricted" area, and part of it was somewhere else.And even then, constants could be placed in the area you want to preserve.Infact, one of the ways could be to declare an array of constants of the size you want to preserve, at the address of the start of the block.Otherwise, changing the linker file so that one area of memory just isn't there is rather easy