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.

TM4C1290NCPDT: Problem with RTOS task firing when base application address is changed.

Part Number: TM4C1290NCPDT
Other Parts Discussed in Thread: SYSBIOS

Hi everyone,

I am pretty new to TI RTOS and am working through a problem right now where a timer interrupt callback is not firing once I change the application code base address. I have a heartbeat callback function that toggles an LED every 500ms. When the binary is flashed at 0x00, everything works no problem. 

I then try to bundle the above binary with a bootstrap and a couple other things which requires the application binary to start at 0x44100. I set the reset vector address appropriately "m3Hwi.resetVectorAddress = 0x44100" in the RTOS config file and can correctly see it placed there when observing the binary. When launched, the bootstrap successfully jumps to the application code and runs (some expected LED activity before heartbeat proves this). However, my heartbeat never runs. If I debug and put a breakpoint in the callback function, it never hits. Conversely, if I do the same with the binary at 0x00, the callback hits and heartbeat executes.

To me this indicates a timer issue or interrupt configuration issue in the version that is not working (changed application base address). It would also indicate to me that whatever the problem is, is directly related to the application address change. I was wondering if anyone had any ideas as to what the problem could be. Is there anything related to the interrupts that needs to be changed outside of m3Hwi.resetVectorAddress? Is there something that the RTOS, clock, or interrupts take for granted when at 0x00 that needs to be set or configured when it is not at 0x00?

Any help is appreciated. Thanks.

  • Hello Mike,

    The issue I think is that your Vector Table would not be aligned with a Page Boundary based on how you've described the application binary address.

    See the following excerpt from our Flash boot loader in TivaWare that gives good background here:

    //*****************************************************************************
    //
    // The address at which the application locates its exception vector table.
    // This must be a multiple of 1024 bytes (making it aligned to a page
    // boundary).  Typically, an application will start with its vector table and
    // this value should be set to APP_START_ADDRESS.  This option is provided to
    // cater for applications which run from external memory which may not be
    // accessible by the NVIC (the vector table offset register is only 30 bits
    // long).
    //
    // Depends on: None
    // Exclusive of: None
    // Requires: None
    //
    //*****************************************************************************
    #define VTABLE_START_ADDRESS    0x4000

    If you really can't set the application to be at 0x44000, then you will need to set it to load into and start at 0x48000. I believe that should resolve your problem.

    Best Regards,

    Ralph Jacobi

  • Hi Jacobi,

    First off I really appreciate the response. I like your idea. While it very well could be true, it would be odd as this is the same structure that is used for other correctly working firmware on other TI chips we have (same addresses, bootloader, etc. different application though). I would think if that was the problem here, we would see it everywhere. I will still try this though.

    Some new things I have noticed. When the binary is loaded at 0x00, everything runs as expected. When loaded at our custom address, when I step through the code, everything seems initialized correctly (using RTOS object viewer) however nothing ever changes. Upon further inspection, the code is running the Idle task indefinitely. Which once again seems like maybe an interrupt issue, as if nothing is changing the flow from the idle task.

    However the HWI in ROV looks the exact same as the list when it is working.

    One curious thing I noticed is we have our halHwi.checkStackFlag = true in our RTOS config. Every so often, the flow breaks off from the idle task to run ti_sysbios_hal_HWI_checkstack() and it seems to be indicating there is an overflow every time.

    Stack size in the picture is 2048 and I have tried increasing to 4096 with no success. I doubt the stack size is the actual problem, once again as the same configuration works at 0x00. Does this finding raise any antennas? I'm assuming the HWI stack overflow would certainly mess up HWI functionality and therefore timing/callbacks.

    Once again, thank you for the help.

  • If you really can't set the application to be at 0x44000, then you will need to set it to load into and start at 0x48000. I believe that should resolve your problem.

    TM4C1294NCPDT: RTOS: BIOS not working was a different investigation which showed TI-RTOS working with a m3Hwi.resetVectorAddress of 0x8100 which only has 256 byte alignment.

    Is there something that the RTOS, clock, or interrupts take for granted when at 0x00 that needs to be set or configured when it is not at 0x00?

    Does the bootstrap use interrupts, or any of the peripherals which the application uses?

    If so, what does the bootstrap do before calling the application?

    Just try to rule out the change of m3Hwi.resetVectorAddress as being the issue.

    In the thread referenced above one issue found was that if the boot loader called IntMasterDisable() prior to starting the application, the SYS/BIOS application will start with all interrupts disabled which is different to the the initial state on a processor reset.

  • Hi Mike,

    I'll be honest that these kind of advanced RTOS topics are difficult to help with because our teams knowledge is centered heavily on the TM4C hardware itself in terms of peripherals etc. so when it comes to elements of the RTOS that are more BIOS related, we don't have a broad depth of knowledge to draw upon. You have been investigating for the root cause using all the right tools already. The stack overflow issue is certainly something I would imagine is impacting things, but I am not sure of the root cause yet. I will try and search for similar issues and see if I can find something of value that way.

    In the meantime, Chester has better memory than I do and dug up a similar thread where he was able to help resolve the customers issue. I would recommend checking if the same situation might apply for your application.

    Best Regards,

    Ralph Jacobi

  • Hi Chester. Thank you for the thoughtful response.

    First off, I agree with you're first point. I am aware of other firmware running on the same chipset using the same bootloader/flash address setup. Theoretically the only thing that is different is the application code itself. The wrapping bootloader and flash structure is the same. And I have seen other applications successfully run when loaded at a non page aligned address.

    Unfortunately, this is somewhat a double edged sword because the bootloader is considered "golden" as it successfully loads and jumps to other TI-RTOS based firmware at the same address. Nevertheless, I went back and looked at the bootloader code and it does not do anything major such as disabling the interrupts. Essentially just minimal clock initialization, basic code verification (CRC), and then jump to code.

    I realize what I've said above screams "application code problem", and I am not ruling that out. Being new to this firmware and TI-RTOS has been a lot to digest especially when facing a weird problem like this. I am going to look into the Idle loop/HWI overflow error I replied with above for now, as that seems like it would affect the clock module/timing ability to function properly. And somehow relate this to the address change since I don't see that error at 0x00. I'll also look at the linked thread for ideas.

    In all honesty, this problem has been a great way to jump into learning TI-RTOS and refresh my low level memory skills :). Appreciate the feedback.

  • No worries Ralph I understand. These topics are complex and made even harder trying to convey the problem over forum posts :). I'll look through the posts and also keep digging, I get a little further each day. Thanks for the help!

  • ------------------UPDATE---------------

    I wanted to give an update as to what was causing this issue after I have found a workaround. 

    After reading the link Chester referred me to: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1024278/tm4c1294ncpdt-rtos-bios-not-working/3787593#3787593

    I decided to check my PRIMASK register at application entry. For some reason this was set to 1. I verified in both cases where the application was loaded at 0x00 and completely different firmware on a different chip (using same bootloader and flash structure) that PRIMASK was 0 at program entry.

    To test it out, I put a call to IntMasterEnable(); at the very beginning of my non-working application code scenario and the code/heartbeat started executing. This makes sense as when PRIMASK was 1, it disabled all interrupts which grounds your RTOS system.

    The question I am now looking into is why PRIMASK is being set to 1 (presumably by the bootloader) in this case, but is set to 0 and works fine using the same bootloader in other cases. If PRIMASK being set to 1 is happening before the application code (which it appears is the case), why is this not the case if the same bootloader, flash setup, and chip is being used for other firmware that works without modification.

    If someone stumbles upon this thread with the same problem, check your PRIMASK value at your application start and make sure it is not 1.

  • Hi Mike,

    I would look for either an IntMasterDisable call or a CPUcpsid in either your boot loader or inside of your application just prior to jumping to the boot loader.

    I believe you have looked for the former in the boot loader already so maybe it is the later being called instead, but I think perhaps it is inside of the application itself that it is being called. It is not unusual to see someone call IntMasterDisable before jumping to the boot loader. 

    Best Regards,

    Ralph Jacobi

  • Hi Ralph. Thanks for the suggestion. Since this post I have discovered that PRIMASK is actually being set by our bootloader somewhere. It is still not clear where. We actually just got lucky that our firmware that "worked" did an enable interrupts call for an unrelated reason before the BIOS kicked off.

    I think this will have to be the permanent "workaround" as the bootloader is used in many placed and would be complicated to update. Out of curiosity I am trying to figure out where the bootloader is setting PRIMASK. Like I said before it just does some basic oscillator setup. 

    I do notice that we write to the SYSCTL_MISC and SYSCTL_RIS registers that have to deal with interrupts. But from the datasheet, I didn't see any bitfield in these registers that explicitly called out changing PRIMASK value as a result. Other than that it is a lot of RCC register writes, which doesn't seem like it would matter. The bootloader is not cooperating when trying to be step through debugged.

    I think it's safe to say the original problem is solved, it is just continuing out of curiosity at this point. Thank you for your's and Chester's help.

  • Hi Mike,

    Maybe you can do a blanket search across the source code for PRIMASK. Even the CPUcpsid API uses that for assembly code:

    uint32_t
    CPUcpsid(void)
    {
        //
        // Read PRIMASK and disable interrupts.
        //
        __asm("    mrs     r0, PRIMASK\n"
              "    cpsid   i\n"
              "    bx      lr\n");
    
        //
        // The following keeps the compiler happy, because it wants to see a
        // return value from this function.  It will generate code to return
        // a zero.  However, the real return is the "bx lr" above, so the
        // return(0) is never executed and the function returns with the value
        // you expect in R0.
        //
        return(0);
    }

    Best Regards,

    Ralph Jacobi