Skip to main content
Visitor II
December 26, 2008
Question

Need some help creating an IAP app

  • December 26, 2008
  • 108 replies
  • 21463 views
Posted on December 26, 2008 at 23:44

Need some help creating an IAP app

#iap #bootloader #upsd3253
    This topic has been closed for replies.

    108 replies

    jmullaneyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    I cannot quite grasp the IAP fucntionality yet. I'm a newbie working with the DK3200. I am familiar with the general mapping of an IAP program as follows:

    Boot to secondary flash which contains the IAP program. The IAP program can perform various validity checks on primary flash sectors to determine good/bad status of main program. The IAP can then modify the VM and page register and ''jump'' to the page of the main program.

    Can someone please give some specifics on the VM and page register modifications. :-[

    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    IAP can be tricky. Before I even get started, do you plan to use this with an ICE (in-circuit emulator). Neither the one made by Nohau or by Manley support the most efficient means of performing IAP since it involves ''swapping out'' the entire code space. Let me know that and I'll be able to answer your question more effectively.

    jmullaneyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    No emulators. simply using the DK3200.

    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    Alright... here's the way to do it that I found most accomodating:

    1. Create a memory map that has one page with secondary flash mapped in the lower 32kB of code memory and main flash mapped into the upper 32kB (or whatever) of data memory (with your RAM and the like in the lower 32kB of data memory). This map should have another page with main flash mapped into the lower 32kB of code memory and secondary flash not mapped anywhere.

    2. Create a project for some compiler (I use Keil) to contain your IAP routines. Make sure to copy and include the STARTUP.A51 code from Keil if that's what you're using. In this project, write the various routines for programming the main flash, etc.

    3. Create another project to contain your main application. Find an open block of fixed code memory and define some constants there that are all FF's, like so:

    const unsigned int code statusbytes = 0xFFFF;

    4. Modify the STARTUP.A51 file for BOTH projects to be IDENTICAL. This assembly code should, at startup, check the status bytes of the main application and if they're equal to some predetermined value (OTHER than FF), run the application. Otherwise, it should just run the IAP routines. The way the code runs the application is by changing the VM register to let it fetch code from EITHER main or secondary flash, THEN swapping to a page which places main flash in the space previously held by secondary flash. A final note is that you have to tell the linker to place this startup code (in Keil, the routine is C_C51STARTUP) at the EXACT same memory address. Just look at the memory map and pick someplace that looks convenient.

    Notes:

    - When you finish programming the main flash application, you should set the status bytes to whatever value you want to be your ''good'' indicator. For examples, I use 0xFE

    - Your startup assembly code also needs to check if you're trying to switch into IAP mode. I do this by writing a long key sequence into RAM from the main application when IAP is initiated and then letting the watchdog reset the processor. I have my startup code check this BEFORE seeing if the application is valid, and if it's there I run the IAP routines. Make sure it's a long enough key sequence that random RAM contents at startup couldn't accidentally prevent you from running the application.

    - When you start reprogramming flash, the very FIRST thing you should do is program your status bytes to 0x0000, that way if anything goes wrong, your startup code will know NOT to try and run a corrupted application.

    There are some other nifty things you could do. With as much memory as the DK3200 has, it's possible to have multiple application images and have the startup code just run whichever one is valid. This way, you avoid ever having no application to run after a failed download.

    Hopefully some of that will help. It took me quite a while to wrap my head around what's involved in doing all this manual paging.

    jmullaneyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    Wow! Lots of work ahead of me.

    Thanks for taking the time to explain that to me. It has been a real help. I'm sure that I'll have followup Q's eventually, but until then, good day sir.

    jmullaneyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    I ask hesitantly as I do not want to bite the hand that feeds me.

    Could you possibly attach/paste an example of the startup.a51 routine which provides the following functionality: checks main flash validity, looks for the IAP key pattern in RAM, and jumps to either main or IAP routines?

    An example would put me further along the path of comprehension much faster.

    I will understand if you choose not to disclose such information.

    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    Sure, I can post some code that will give you a basic idea without divulging anything that I shouldn't. Also, the basic methodology I use here is from an app note I found somewhere on either this forum or another ST site. Finally, there will be no mocking my hideously inefficient assembly code. I'm normally a C-only guy.

    MOV DPTR, VMREG

    MOV A, (VM_REG_RD_MAIN_FLASH OR VM_REG_PSEN_MAIN_FLASH OR VM_REG_PSEN_BOOT_FLASH)

    MOVX @DPTR, A

    CHECKPAGE: MOV DPTR, pageval

    MOVX A, @DPTR

    JNZ RUNAPP ;If pageval doesn't point to bootloader, check and run app

    MOV DPTR, PAGEREG

    MOV A, BOOTLOADER_PAGE

    MOVX @DPTR, A

    ;If we're here, the pageval appears to point to the bootloader. We check the checkcode

    ;in RAM against the key value to make sure that it's not just a random occurrence on

    ;startup. If they match, we run the bootloader.

    CHECKRAM: MOV R0, KEY_LENGTH - 1 ;R0 = Loop index

    CHECKLOOP: MOV DPTR, key

    MOV A, R0

    MOVC A, @A+DPTR

    MOV R1, A ;Store next byte from key in R1

    MOV A, LOW(checkcode) ;Add R0 to location of checkcode and load

    ADD A, R0 ;into DPTR

    MOV DPL, A

    MOV A, HIGH(checkcode)

    ADDC A, 00H

    MOV DPH, A

    MOVX A, @DPTR ;Fetch next byte of check code

    MOV R2, A

    MOV A, 'x'

    MOVX @DPTR, A ;Wipe checkcode as we process it so we can get back to app

    MOV A, R2

    XRL A, R1 ;XOR with key byte in R1

    JNZ RUNAPP ;If bytes don't match, check and run application

    DJNZ R0, CHECKLOOP ;Otherwise, decrement loopcounter and jump

    JMP RUNBOOT ;pageval =0 and key sequence good, so run bootloader

    RUNAPP: MOV DPTR, (08000H + APPBITS)

    MOVX A, @DPTR

    CJNE A, 0FEH, RUNBOOT ;Make sure we don't run an invalid application

    MOV DPTR, VMREG

    MOV A, (VM_REG_PSEN_MAIN_FLASH OR VM_REG_PSEN_BOOT_FLASH)

    MOVX @DPTR, A

    MOV DPTR, PAGEREG

    MOV A, APPLICATION_PAGE

    MOVX @DPTR, A

    MOV DPTR, VMREG

    MOV A, VM_REG_PSEN_MAIN_FLASH

    MOVX @DPTR, A

    JMP DONE

    RUNBOOT: MOV DPTR, VMREG

    MOV A, (VM_REG_PSEN_BOOT_FLASH OR VM_REG_PSEN_MAIN_FLASH)

    MOVX @DPTR, A

    MOV DPTR, PAGEREG

    MOV A, BOOTLOADER_PAGE

    MOVX @DPTR, A

    MOV DPTR, VMREG

    MOV A, (VM_REG_PSEN_BOOT_FLASH OR VM_REG_RD_MAIN_FLASH)

    MOVX @DPTR, A

    DONE:

    Hope some of that helps... let me know if anything's unclear, but I think it's lack of efficiency makes it pretty easy to understand.

    jmullaneyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    Thank you. I am also primarily a C-guy, so please don't appologize for knowing more Assembly than me. ;)

    I've got a meeting w/ GE this morning so I won't be able to perform any tests until afternoon'ish. But I'm sure your example code will answer many of my questions.

    Thanks again!

    jmullaneyAuthor
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    Your example startup.a51 has helped tremendously. I have some questions though that I was hoping that you could answer before I get myself into trouble.

    -----------------------------------------------

    1:How do I locate the main app's statusbytes (0xFFFF) once defined? Do I simply open the .hex file in a hex viewer and look for it's location?

    -----------------------------------------------

    Previously, you had written:

    Modify the STARTUP.A51 file for BOTH projects to be IDENTICAL.

    2:Can you explain your reasoning behind using identical startup.a51's for both programs.

    -----------------------------------------------

    Previously, you had written:

    The way the code runs the application is by changing the VM register to let it fetch code from EITHER main or secondary flash, THEN swapping to a page which places main flash in the space previously held by secondary flash.

    3.I can see this in your startup.a51 example. There is a VM change,Page change,and then VM change again. Could you explain each change in a bit more detail?

    4.What pages are you using for #APPLICATION_PAGE & #BOOTLOADER_PAGE ?

    -----------------------------------------------

    Previously, you had written:

    A final note is that you have to tell the linker to place this startup code (in Keil, the routine is C_C51STARTUP) at the EXACT same memory address. Just look at the memory map and pick someplace that looks convenient.

    5.Is this why the same startup.a51 is used for both app's?; So that address of C_C51STARTUP is the same in both pages?

    6.How exaclty do I 'tell' the linker to place startup code at a specific mem address?

    -----------------------------------------------

    7.My main application will take up more than 32k code space. I am familiar with banking as I have successfully created a bank-switching app which calls routines in all 8 banks. What concerns and/or modifications should I make to allow this multi-page mapping to my main application, without disrupting the IAP architecture?

    -----------------------------------------------

    8.Could you provide a sample key sequence used to switch to IAP mode from main app? Im not sure that I understand your CHECKLOOP.

    -----------------------------------------------

    FYI: I too am using Keil.

    Wow, thats alot of Q's. I have been reading up on the uPSD for well over 2 weeks now. It really helps having someone with experience who can fill in the blanks for me. Especially with IAP development which has been the hardest to find help on.

    Thanks for all of your help

    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 12:04

    mulls14,

    Wow... that is alot of questions. As far as two weeks goes, imagine how I felt when there wasn't anyone on here who seemed to have tried what I was doing. I'll try to take this point by point:

    1. You basically have to TELL the linker where to put the statusbytes, because otherwise every code change could move them around and you wouldn't be able to find them (there'd certainly be other FFFF's in there somewhere). If you put the following in your Keil project (under project->options for target XXX, BL51 locate tab) in the ''Code'' line on the dialog, it will locate if for you:

    ?CO?STATUSBITS(0xXXXX)

    where ''statusbits'' is whatever you named the C file with the definition and 0xXXXX is where in code space you want it placed (oh yeah, the ?C0? part tells it you want to locate the ''constant'' segment from this module.)

    2. The reasoning is complicated, but goes like this. 8051's don't know anything about pages. They just know about code memory fetches and data memory fetches. What ST has done is provide some internal logic to allow you to activate different chip selects on different chips based on the contents of the VM register. When the 8051 is running a program, it just keeps fetching opcodes from code memory. So... imagine that both startup files are exactly the same and the uPSD is initially running out of secondary flash. When you change the VM register, the next thing the 8051 is going to do is try to grab the next bit of code and it will use whatever code address would have been next in the secondary flash file (because it's just incrementing the PC). If the code WASN'T identical and located at the same spot when you redirect the chip select to main flash, it might try loading in the middle of an opcode or some other random place. Basically, the idea is to get some KNOWN CODE at that exact location in main flash so that it can continue fetching and will never be the wiser. Since you still have to finish your startup and variable initialization, etc. anyway, the easiest way to do this is to make the startup code identical and locate them both to the same place. I hope that makes it clearer.

    3. It has a bit to do with the way I initialize the uPSD. In my project, at reset, the uPSD has secondary flash in code space only from 0 - 7FFF and main flash in DATA space only from 8000-FFFF. So, if I just changed the page, then it would try to load from main flash, but that wouldn't be allowed because of the VM register (still in data space). So... first, I make the VM change. This leaves secondary flash in code space in the lower 32kB, but now shifts main flash to CODE space in the upper 32kB. I have to still leave it able to execute from secondary flash, because it's running out of the lower 32kB and if I took that away, it again wouldn't be able to fetch opcodes. Next, I change the page. This swaps in main flash for BOTH the lower 32kB and upper 32kB. But remember, the code at the location of the program counter in main flash is IDENTICAL to what was in the secondary flash, so the 8051 core is still fat dumb and happy. The final VM change is just there for safety really, but it tells the uPSD to only execute code now from main flash (since I'll only want to run from secondary flash again if I try to switch over to do IAP).

    4. Doesn't really matter. I use different pages depending on whether it's production code or code for use on my emulator. Since the uPSD resets to page 0, however, it's probably a good idea for you to use that for secondary flash and then some other page for your first page of main flash.

    5. Yes... that's the reasoning. Refer to the previous long-winded description for why.

    6. Just like above, you put another directive in the ''code'' line under the BL51 locate tab in options. This time the directive would be:

    ?C_C51STARTUP(0xXXXX)

    again, 0xXXXX is just some address you happen to like that's convenient. and C_C51STARTUP is the name Keil's startup.a51 file gives to that segment. You could change it if you like.

    7. My app is larger than 32kB as well. What is do is map fs0 into the LOWER 32kB of code space and fs1 into the UPPER 32kB of code space for a total of 64kB of code space. I haven't configured actual code banking since it's not needed for me. If all you want to do is store some code tables or something in the other flash pages, then you can probably handle that manually. Otherwise, you'll have to do some dancing to get the linker to understand how your code pages are laid out. You'd have to chart a course on that one yourself, but once you get the gist of how the above is working, I think it'll click for you.

    8. A good key sequency (albeit a long one) would be a string like: ''This could not occur by random chance''. The basic idea is that you need some string long enough that the odds of it happening because of random contents of memory at startup are essentially zero. Also, you'll notice in my checkloop that I destroy it as I check it so that if there's a reset, it's not still hanging around in there. I use this all to tell the processor to run IAP. As in, imagine something happens in the application that makes me want to run IAP to reprogram the application. I write a page value to a specified location in memory (the one that's checked by startup.a51). Next, I write this key sequence in memory. Then I let the watchdog reset the processor. Since it didn't power down, the contents of ram are preserved. At startup, I see that the page value points to the bootloader, but keep in mind that there's still a 1/255 chance that this byte is just random junk from a powerup. So... if THAT matches, I check this long key sequence and if it's all there, I say the only reason it would be is if the application is asking me to run the bootloader and so I stay in secondary flash and get ready for reprogramming. Is that clearer?

    Well... hope that helps. I agree the lack of practical IAP stuff is frustrating, but that seems to be the case for every processor manufacturer, not just ST. Typically I guess they figure the people working on this have very specific stuff that their hardware has to do, so they have to hash out the details on their own.