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.

Jumping to a function pointer

I am working with an LM4F232 using CCS 5.1. I previously posted this under the compiler area and they sent me to Stellaris.

I have a custom bootloader in the first 12KB of memory and use it to load an application into FLASH starting at 0x3000.
I am now trying to figure out how to jump to the application and start running.

I have the application loading and running in CSS at 0x3000. I have the bootloader loading and running in CSS at 0x0000.

For the application, I have in startup_css.c:

#pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((unsigned long)&__STACK_TOP),
                                            // The initial stack pointer
    ResetISR,                               // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    MPU_fault_ISR,                          // The MPU fault handler
    Bus_fault_ISR,                          // The bus fault handler
    Usage_fault_ISR,                        // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
 ...

In memory for both the application running out of CCS and after using the bootloader to download the app to 0x3000:

Hex 32 Bit - TI Style g_pfnVectors 20001050 00008631 00007F5F 00007537 00008479 000082F1 000085B1 00000000 00000000 00000000 00000000 000084F9 00008309 00000000 000084B9 00008229 00008339 00008341

The first word is the top of the stack. The second word is the address of the ResetISR. Am I correct? Why are all the addresses seem to be

the address of the function + 1? They are all odd. I would expect something modulo 4. If I look at the disassmbly at 0x8630, I see I am at the

ResetISR.

So I am trying to jump to this code while running the bootloader in CSS and after downloading the application to flash:

        void (*funcptr)( void );  // Set up function pointer to application
        //
        unsigned long funcptrAddress = *((unsigned long *)0x3004);
        funcptrAddress--;  // TODO: explain, why is entry into table an odd number and not modulo 4?
        funcptr = (void (*)())funcptrAddress;
        funcptr();

But I end up jumping into the weeds and end up in the FaultISR.

The Disassembly at 0x8630 is (and I do not understand it, is the code branching to the address in R14, if so where was R14 loaded?):

          ResetISR:
00008630:   F7FFB918 B.W             _c_int00
372       }
00008634:   4770     BX              R14
          SysCtlDelay:

It is when I execute 0x8630 that I jump to FaultISR.

When I debug the application, execution starts at main(), so the initialization code is already run and

I am not able to set a breakpoint in ResetISR to see how this operates.

So what is wrong with this approach?

  • Hi,

    ARM Cortex micro controllers require  that interrupt vectors to be at odd address always, this is to indicate the need for Thumb-2 instructions; providing an even address results always in Fault ISR; this may occur in cases as yours and when the interrupts are not declared properly.

    To setup an interrupt in ResetISR routine you must modify the behavior of the debugger - depending on your toolchain you must be able to find out in debugger configuration some indication that after rest the first breakpoint is o main() - you can easily modify to ResetISR and then you will be able to use another breakpoint in the same routine.

    Petrei.

  • I am not sure what I am supposed to conclude from your first paragraph.  If ISR routines are at odd addresses, am I able to call them directly?

    I have taken the functptrAddress-- statement out.  I now end up in some infinite loop in the _c_int00 code, which is impossible to figure out why.

    I do not understand what you are suggesting in the second paragraph.  I am not setting an interrupt in any ISR.  I do not understand what is meant by "after rest the first breakpoint is o main()".  I assume you mean after reset, but what does 'o main()' mean?  I am using CCS, where is the debugger configuration file and how do I modify it?    Getting a breakpoint working in the ResetISR is not critical.

    My basic question is: I have two applications in flash, each with its own interrupt table, initialization code and code itself.  I start running with the application that is in flash 0-12KB, this application then flashes the second application, getting its flash image off of the CAN bus.  The first application then needs to jump to the second application in a way that the second applications initialization code is executed. 

    How do I do that?

  • First I apologize about "o main" - I intended to be "to main" - a typo mistake, just very tired after a long and ugly day... To get debugger configuration in CCS, you must go to Project | Properties | CCSDebug and access the Target tab - there you will find out an item "Target: Auto Run Options: Run to symbol: main" is the usual; you can change it to ResetISR and from there you can single step.

    Now about odd addresses: the odd address is set up by the linker only for interrupt vectors, although all functions are at even address (and must remain at even everywhere in the project). You are interested in even/odd address at least for a single reason: to access your application you need an entry point marked as ResetISR by  the linker and this is an odd address.

    You can check/verify all these by running the examples in StellarisWare - but make also a global listing and take a look at the code and addresses.

    Petrei

  • Petrei,

    Thanks for taking the time to answer my questions during a tough day.  Your inputs made my day better.  I hope today is better for you.

    Thanks for  getting me to look at Project | Properties | Debug.  I have been all over the compiler and linker pages, but not the debugger.  There are some quite useful things on the debugger page.  Things that will save me time right now - like not clearing all of memory, so I have to keep downloading the target app everytime I change the bootloader.

    I have another question on the odd addressed ISR functions.  Does this mean you cannot call an ISR function directly as if it were any other function?  Will setting the PC to an odd address cause a processor fault?

    I am starting to think I have to read the branch instruction at the ResetISR location to get the offset to _c_int00, then jump to that address.

    [On another note, I have found that some of my downloaded program have been corrupted by the FlashErase function.  You ask for a block at 0x3C00 to be erased and both blocks at 0x3800 and 0x3C00 are erased.  Or at least I think the one at 0x3C00 is erased.  I have started a thread on that issue seperately.] 

    John

  • John Osen said:
    [On another note, I have found that some of my downloaded program have been corrupted by the FlashErase function.  You ask for a block at 0x3C00 to be erased and both blocks at 0x3800 and 0x3C00 are erased.  Or at least I think the one at 0x3C00 is erased.  I have started a thread on that issue seperately.] 

    This depends on which specific processor you have.  The flash block size is different for different devices in the Stellaris family.  This is one of the reasons that it's very important when asking any questions in these forums to state what device you are using - there are many differences between all of the different devices.

    As for whether you can call an ISR directly as a function, in general the answer is yes.  All functions in your code actually start on even addresses, but because the processor is operating in extended thumb instruction mode at all times, the LSB of the PC must always be set.  The compiler will adjust any branch instructions to guarantee that the LSB is set.  The only issue is that when branching through a vector table or pointer, you need to make sure that the LSB of the function address in the vector table or pointer is set.  This is why all addresses in the interrupt vector table are odd addresses.  If an entry in the vector table points to location 0xc001, the code that will be branched to can be found at 0xc000.

    As to whether it's a good idea to call an ISR directly as a function, that's another story.  Code that can be called both from within and outside of interrupt context needs special attention to be paid to it to make sure that it won't generate race conditions or other problems.  If the code needs to be operating in a privileged context, special steps may need to be taken when called directly from a user context.

  • slandrum

    I specify processor and toolchain in: "FlashErase erase and ROM_FlashErase erasing wrong memory on LM4F232".

    Regardless, I am using an LM45232 on the EKS board using CCS 5.1.

    Thanks for your time.

  • John Osen said:
    I specify processor and toolchain in: "FlashErase erase and ROM_FlashErase erasing wrong memory on LM4F232".

    The title of the thread I'm posting in is just "Jumping to a function pointer".  I can't tell where the thread originates from, and its title may have been changed if it was split from another thread.  And something I find very annoying on this forum that even trips up TI employees is that when replying to a post, the title of the thread is not shown, so even if important information is there, it will often get missed in the reply.

    I do now see that the device is specified in the beginning of this thread - I looked before and didn't notice it.  The first post is mangled by all of the code tags and makes it much harder to read.

  • slandrum said:
    post is mangled by all of the code tags and makes it much harder to read.

    Absolutely!   You need to somewhat "market" your numerous post requests...  (obscuring the code is sub-optimal)

  • My apologies for the readability of this post.

    I have just started to paste using "Insert Code" button.  There are some problems with it - it changes the formatting for the text thereafter and the formatting in the editor is not what is seen in the final post.  So what looks readable during editing is not readable in the post.  The confirming email TI sends is yet a different format which looks quite readable.

  • Nobody seeks apology - suggest you kill "insert code" and simply "cut/paste"  (notepad has worked for many).   Once you see that your posting is illegible - over-write w/Plan "B." 

    BTW - slandrum is clear tech powerhouse this forum - has helped/solved issues for many.  Perhaps bit hasty to challenge his comments/observations - they are constructive!   Just as he says - the unfortunate loss of subject proves harmful - suggest that you "top-line" each post w/subject summary - inefficient to expect responders (even hallowed official ones) to scroll far backward.  (and I bet they will "lose" some/much on the return scroll)

    Perfection not my strong suit - yet free, fast, experienced/seasoned support is rare and should be perhaps - more, "welcomed..."  (my $ 0.02)

  • I am neither challenging nor disrespecting any response, just trying to get the subject straight in my own head. 

    This is a sidebar...

    I have posted on another forum the question "How do you paste efficiently into a forum post?"  It was never answered.  I always get a "paste from word" pop up when I ctrl-v or right-click-paste that can paste the most unreadable text.  It looks more like a hostage note with changing fonts, spacings and colors.  I have found no simple way of pasting into a forum post.  If you would be so kind as to educate me on how to paste, that would be much appreciated :)

  • A "Notepad" paste into the TI forum:

        // Configure the processor to run at 50 MHz.
        //
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_25MHZ |
                           SYSCTL_OSC_MAIN);
        //
        // Enable the peripherals used by the application.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    I pulled this code directly from our paid IAR - pasted into Notepad - then pasted here.  (We past used notepad as it avoided "format" complexities - which plagued Word)  You/others can judge if this is more readable and/or acceptable.

    Believe you will benefit from earlier suggestion, "Top each post with key Subject/Issue/MCU/IDE etc."  Especially as your subjects bend from "mainstream" - better managing/maintaining the responder's focus can only be to your advantage.   (how our group took small tech firm public...)

     

  • How to paste sidebar...

    Thanks for taking the time to identify a less than obvious path to pasting on a completely unrelated thread.  Copying from any editor that supports formatting seems to cause problems: CSS, Notepad++, VS2010, Internet Explorer.  But Notepad works and I will happily start using it.  I will update my original post on how to paste.

  • Indeed would be nice if you'd credit cb1 for the "less than obvious" Notepad Forum Pasting suggestion...  

    (and you truly/assuredly will benefit by "re-focusing" your responders via "top-line" subject repetition.   You "know" just what you seek - your remote "assistants" - not so much...)

  • Getting an LM4F to download and jump to a different "app".

    With help on this thread, another thread on FlashErase and muddling around in FLASH with no disassembly data, I have this working.  The issues were:

    • FlashErase on the EKS LM4F is Rev A1, which has a problem with FlashErase, this was clearing most, but not all of the odd blocks
    • Need to disable interrupts before jumping
    • Need to get you interrupt table in the target app set correctly

    Thanks all.