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.

TM4C1294NCPDT: Compilation Error - for flash memory protection with FreeRTOS

Part Number: TM4C1294NCPDT

FreeRTOS Version: v9.0

Tivaware version: TivaWare_C_Series-2.2.0.295

CCS version: 12.1.0.00007

Issue: Compilation error    "[E0002] PC-relative access violates disabling of embedded constants".   

@ file portasm.asm and

             @ line 99: ldr r0, ulMaxSyscallInterruptPriorityConst 

             @ line 112: ldr r3, pxCurrentTCBConst

             @ line 127: ldr r0, ulMaxSyscallInterruptPriorityConst

             @ line 160: ldr r3, pxCurrentTCBConst

             @ line 177: ldr r0, NVICOffsetConst

             @ line 195: ldr.w r0, CPACRConst

Background: 

We enabled "execute-only" flash protection for the simple freeRTOS project. But we are getting compilation error as mentioned above.

Infact Memory protection without FreeRTOS is working fine.

 

As pe the forum suggestion we did following changes:

1. chosen "OFF" for --embedded_constants

2. Done memory section changes as below.

SECTIONS
{
.intvecs: > 0x00000000
.libraries : > FLASH
{
--library=rtsv7M4_T_le_v4SPD16_eabi.lib(.text)
}
.text : > CODE_FLASH
.const : > FLASH
.cinit : > FLASH
.pinit : > FLASH
.init_array : > FLASH

.vtable : > 0x20000000
.data : > SRAM
.bss : > SRAM
.sysmem : > SRAM
.stack : > SRAM
}

With Regards

Velliyangiri Palanisamy

  • Hi,

      Please refer to this app note about integrating FreeRTOS for TM4C. Software collaterals are provided in this app note. 

    https://www.ti.com/lit/pdf/spma085

  • Hi Charles ,

    Thank you for the document.  Infact, we had already used the same document for project setup.

    Actually, the setup of the FreeRTOS project is flawless.

    1. Without flash memory protection, the FreeRTOS project was successfully compiled and is currently working.

    2. Memory flash protection for projects without FreeRTOS is also functional.


    We are having problem in compiling with Memory protection for the FreeRTOS project. i.e  when chosen "OFF" for --embedded_constants.

    if we choose "ON" for --embedded constants then FreeRTOS project will compile successfully but getting Fault ISR while run time.

    With Regards

    Velliyangiri Palanisamy

  • You can review the FreeRTOS portasm.asm file and check if there are any PC-relative constant accesses that could be causing the compilation error.

  • Hi Zain Nasir,

    Yes, when "OFF" is selected for "--embedded constants", the compilation of the four constants below fails in portasm.asm.

    Why do these errors are appearing and how can they be fixed?


    Since the default FreeRTOS portasm.asm file produces an error, the question of whether memory protection has been verified with FreeRTOS on TM4C arises.



    With Regards

    Velliyangiri Palanisamy

  • We are having problem in compiling with Memory protection for the FreeRTOS project. i.e  when chosen "OFF" for --embedded_constants.

    if we choose "ON" for --embedded constants then FreeRTOS project will compile successfully but getting Fault ISR while run time.

    I'm not an expert in compiler and don't know exactly what the switch embedded_constants will do? What are you trying to accomplish for memory protection? According to the compiler user's guide it is ON by default already. I will need to forward your question to our compiler for clarification what this switch actually does. 

    If the processor jumps to faultISR, it normally means the processor is accessing an invalid/illegal memory location or you are trying to access a peripheral register for which the peripheral is not yet enabled. In your case, it most likely has to do with the invalid memory location. You can use this app note to diagnose the cause of the fault. https://www.ti.com/lit/pdf/spma043

    TM4C129 contains hardware flash protection that you can configure such that a given flash page is protected for execute-only. This is always the way our customers use in order to protection the flash memory. Refer to the datasheet under 8.2.3.4 for Protected Flash Memory Registers for details. 

  • Hi ,

    We want to add "Read protection" for the FreeRTOS application code. 

    In the below forum discussion please find the answer for the question why "--embedded constants" need to make it OFF.

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/807063/ccs-sw-tm4c-tiva-c-flash-memory-read-out-protection

  • Hi,

    Thanks for sharing the link. I'm learning something new for myself about --embedded constants. As I mentioned, I support MCU. Compiler is not my expertise. What Bob in the thread was saying is that by using --embedded constants, the constants will not be allocated to the flash section that is meant to be protected for Execute-Only. In the linker command file, you will need to create a memory section that is to be protected. Reading your .cmd file, I only see CODE_FLASH but there is not telling where in flash memory CODE_FLASH would occupy. 

    We want to add "Read protection" for the FreeRTOS application code. 

    If all you want is 'Read Protection' then why do you need --embedded constants? All you need to is FlashProtectSet(YourAddrRangeFlashReadOnly). Read Only protection is meant to prevent the flash from being erased or re-programmed. See below datasheet description. 

    8.2.3.6 Read-Only Protection


    Read-only protection prevents the contents of the flash block from being re-programmed, while still
    allowing the content to be read by processor or the debug interface. Note that if a FMPREn bit is
    cleared, all read accesses to the Flash memory block are disallowed, including any data accesses.
    Care must be taken not to store required data in a Flash memory block that has the associated
    FMPREn bit cleared.


    The read-only mode does not prevent read access to the stored program, but it does provide
    protection against accidental (or malicious) erasure or programming. Read-only is especially useful
    for utilities like the boot loader when the debug interface is permanently disabled. In such
    combinations, the boot loader, which provides access control to the Flash memory, is protected
    from being erased or modified.

    12.2.2.14 FlashProtectSet


    Sets the protection setting for a block of flash.


    Prototype:
    int32_t
    FlashProtectSet(uint32_t ui32Address,
    tFlashProtection eProtect)


    Parameters:
    ui32Address is the start address of the flash block to be protected.
    eProtect is the protection to be applied to the block. Can be one of FlashReadWrite,
    FlashReadOnly, or FlashExecuteOnly.

    Description:
    This function sets the protection for the specified block of flash. Refer to the device data sheet
    to determine the granularity for each protection option. Blocks that are read/write can be made
    read-only or execute-only. Blocks that are read-only can be made execute-only. Blocks that
    are execute-only cannot have their protection modified. Attempts to make the block protection
    less stringent (that is, read-only to read/write) result in a failure (and are prevented by the
    hardware).


    Changes to the flash protection are maintained only until the next reset. This protocol allows
    the application to be executed in the desired flash protection environment to check for inappropriate
    flash access (via the flash interrupt). To make the flash protection permanent, use the
    FlashProtectSave() function.


    Returns:
    Returns 0 on success, or -1 if an invalid address or an invalid protection was specified.

  • Hi,

    In actual use, we're going to create a USB-DFU class firmware update facility.
    Instead of using the ROM boot loader, we intend to flash a custom USB-DFU bootloader at location 0x0000000.

    Bootloader will be "Execute-only protection (FMPPEn=0 FMPREn=0). Hence it will be read-write protected and will be erased or update only in the factory through debugger.

    Where FreeRTOS Application will be loadable image. This application code will be updated on-the-fly via the bootloader in the filed; for this reason, "Execute-only protection" is not appropriate. Hence, we intend to implement "Read protection" (FMPPEn=1 FMPREn=0 i.e The block may be written, erased or executed, but not read.) for the freeRTOS application code in order to protect it from unauthorized access.

    We made these below observations:



    Please confirm whether 
    1. embedded constants should be turned OFF or ON for "Read protection"(FMPPEn=1 FMPREn=0) ?
    2. if it should be turned OFF , how do I resolve the compilation error?


    Note :

    1.To get the clarity, we just created simple FreeRTOS project and tested all possible flash security combinations. 

    2. "Read Protection (FMPPEn=1 FMPREn=0) , we created enum and done required changes in driverlib/flash.c
    Please find the attached code below. I added the flashprotectionset() @line no: 124 of main.c file and made OFF for --embedded_constants in this project.

    blinky_queue.zip


    With Regards

    Velliyangiri Palanisamy

  • Hi,

    Where FreeRTOS Application will be loadable image. This application code will be updated on-the-fly via the bootloader in the filed; for this reason, "Execute-only protection" is not appropriate. Hence, we intend to implement "Read protection" (FMPPEn=1 FMPREn=0 i.e The block may be written, erased or executed, but not read.) for the freeRTOS application code in order to protect it from unauthorized access.

    You seem to choose a combination (FMPPEn =1, FMPREn =0 ) that is unlikely to be used. Despite what is said in the datasheet, I don't see an issue if you insist to use this combination. What is important is that constants and literal pool data must be stored in the flash pages that are readable by the processor. Reading constants and literal pools will use LDR instruction. When these constants, literal pool data are read from a flash page that is protected from read, the flash controller will assert a bus error signal to the processor resulting in processor fault. 

    Please confirm whether 
    1. embedded constants should be turned OFF or ON for "Read protection"(FMPPEn=1 FMPREn=0) ?
    2. if it should be turned OFF , how do I resolve the compilation error?

    Yes, embedded-constants should be turned off so that constants, literal pool data do not reside in the .text section. You can verify this in .map file. Below is what I see in your .map file. At first glance, your .intvecs, .const, .libraries and .cinit are not in the CODE_FLASH section where you allocate from 0xc000 - 0x2c000. Your .text section starts from 0xc000 as indicated in the .map file. 

    SEGMENT ALLOCATION MAP

    run origin load origin length init length attrs members
    ---------- ----------- ---------- ----------- ----- -------
    00000000 00000000 00001598 00001598 r-x
    00000000 00000000 00000200 00000200 r-- .intvecs
    00000200 00000200 00000f84 00000f84 r-- .const
    00001184 00001184 000003ca 000003ca r-x .libraries
    00001550 00001550 00000048 00000048 r-- .cinit
    0000c000 0000c000 0000274a 0000274a r-x
    0000c000 0000c000 0000274a 0000274a r-x .text

    2. if it should be turned OFF , how do I resolve the compilation error?

    I'm confused. Are you getting compilation issue during compile time or are you getting an runtime error? If you are getting a compilation issue then how did you build the blinky_queue project successfully?

    Note :

    1.To get the clarity, we just created simple FreeRTOS project and tested all possible flash security combinations. 

    2. "Read Protection (FMPPEn=1 FMPREn=0) , we created enum and done required changes in driverlib/flash.c
    Please find the attached code below. I added the flashprotectionset() @line no: 124 of main.c file and made OFF for --embedded_constants in this project.

    I do see one issue with your code snippet below where you are marking address range from 0xc000 - 0x2c000 to be FlashExecuteOnly. 

    #if 1
    uint32_t count = 0;
    
    /* Memory Protection for Code. i.e, Flash Address range: 0xC000 - 0x2BFFF
    * All memory allocations are mentioned in blinky_queue_ccs.cmd file*/
    for(count=0;count<0x20000;count++)
    {
    //
    //Protecting 128KB of Code flash from the address of 0xC000
    //to 0x2C000.
    //
    FlashProtectSet(0xC000+count, FlashExecuteOnly);
    
    //FlashProtectSet(0xC000+count, FlashReadProtection);
    }
    
    FlashProtectSave();
    
    

    The issue I see is that you call FlashProtectSave(). This call will make the PFPPEn and FMPREn registers permanent. These are non-volatile registers. Once you program them once, they will not change when you try to program them again with a different value such as changing the value from 0 to 1. For example, you first  call FlashProtectSet to set up certain address range for Execute-Only. If you simply just modify your program to change a new address range or the protection mode in the API call, it will result in attempting to change FMPPEn and FMPREn from one setting to another, but it will not work after you rebuild the project. The FMPPEn and FMPREn register will not change to the new values. These are non-volatile registers that must go through a full unlock operation before they can be programmed with new values again. See below notes from the datasheet as well as peripheral driver user's guide. Perhaps you can confirm if you perform an unlock operation each time before you change the FMPPEn and FMPREn settings. 

    If you have never perform an unlock operation to the processor, here is what I will suggest you do. 

    1. Perform an unlock operation to restore the device to its factory setting. 

    2. Comment out FlashProtectSave until you are absolutely sure that you want the permanent setting to take effect. Without FlashProtectSave, the new settings in FMPPEn and FMPREn settings will take effect the next POR cycle. Read datasheet description.  This means you can not just reload the code in the debugger. You must first reset the device before reloading the new code. 

    The factory settings for the FMPREn and FMPPEn registers are a value of 1 for all implemented
    banks. These settings create a policy of open access and programmability. The register bits may
    be changed by clearing the specific register bit. The changes are not permanent until the register
    is committed (saved), at which point the bit change is permanent. If a bit is changed from a 1 to a
    0 and not committed, it may be restored by executing a any simulated power-on-reset (SIM_POR)
    event. The changes are committed using the Flash Memory Control (FMC) register. Details on
    programming these bits are discussed in “Non-Volatile Register Programming-- Flash Memory
    Resident Registers” on page 613.

    By committing the register values using the COMT bit in the Flash Memory Control (FMC) register,
    the register contents become non-volatile and are therefore retained following power cycling. Once
    the register contents are committed, the only way to restore the factory default values is to perform
    the sequence described in “Recovering a "Locked" Microcontroller” on page 213.


    All of the FMPREn, FMPPEn and USER_REGn registers, in addition to the BOOTCFG register can
    be committed in non-volatile memory. The FMPREn, FMPPEn, and USER_REGn registers can be
    tested before being committed; the BOOTCFG register cannot. To program the BOOTCFG register,
    the value must be written into the Flash Memory Data (FMD) register before it is committed. The
    BOOTCFG configuration cannot be tried and verified before committing to non-volatile memory.


    Important: All Flash memory resident registers can only have bits changed from 1 to 0 by user
    programming. The FMPREn, FMPPEn and BOOTCFG registers can be committed
    multiple times, but the USER_REGn registers can only be committed once, after the
    entire register has been set to 1s. After being committed, the USER_REGn registers
    can only be returned to their factory default values of all 1s by performing the sequence
    described in “Recovering a "Locked" Microcontroller” on page 213. The mass erase of
    the main Flash memory array caused by the sequence is performed prior to restoring
    these registers.

    Finally, please do use this app note to diagnose the cause of the fault. https://www.ti.com/lit/pdf/spma043

  • Hi,

    Let me explain this once again, in short. So, now I take the "execute-only" protection (FMPPEn=0 FMPREn=0) first for your clear understanding, and then we will discuss the other protection options like read-out protection (FMPPEn=1 FMPREn=0) and read-only protection (FMPPEn=0 FMPREn=1).

    In fact, we started to test the flash memory protection functionality with the basic example projects such as project0, Hello from Tivaware (TivaWare_C_Series-2.2.0.295), which are not using FreeRTOS. There, we used three very important things in the code.

    1. We made Flash memory allocations in the .cmd file. We gave a region of flash memory for data and another region for code.

    2. We took the same range of code memory and used the function FlashProtectSet(Address, FlashExecuteOnly), which will protect the code memory from read, write, and erase operations. We also used the function FlashProtectSave() to make that permanent. 

    When these constants, literal pool data are read from a flash page that is protected from read, the flash controller will assert a bus error signal to the processor resulting in processor fault. 

    3. While testing, we saw the same error signal that you have described precisely, and we understood the importance of --embedded_constants. Then we selected OFF for --embedded_constants to tell the compiler to embed the constants in a readable flash region like data memory (as mentioned in the .cmd file).

     

    Eventually, we tested the project0 code with "Execute-only" protection and verified the results with the TM4C1294NCPDT microcontroller. The code was running successfully (LEDs were blinking) without any bus errors or faults. We could not erase, rewrite, or read the code region in Flash. Then we unlocked the microcontroller by doing the "Recovering locked microcontroller" procedure. Finally, we succeeded, and there were no issues with Flash Memory Protection.

     

    Then, we moved further to test the "Execute-only" protection functionality with a FreeRTOS (v9.0) example project "blinky_queue".

    First, we downloaded and tested the blinky_queue without making any changes. It was perfect and worked fine.

    Then we added the same 3 steps for memory protection in blinky_queue and compiled the blinky_queue project. But here we found compilation errors like "[E0002] PC-relative access violates disabling of embedded constants" in the Portable/CCS/ARM_CM4F/portasm.asm file. Particularly, I see these errors whenever I choose OFF for --embedded_constants. 

    Please check these error lines from portasm.asm when --embedded_constants=OFF
    @ line 99: ldr r0, ulMaxSyscallInterruptPriorityConst
    @ line 112: ldr r3, pxCurrentTCBConst
    @ line 127: ldr r0, ulMaxSyscallInterruptPriorityConst
    @ line 160: ldr r3, pxCurrentTCBConst
    @ line 177: ldr r0, NVICOffsetConst
    @ line 195: ldr.w r0, CPACRConst

     

    Here we are structed up now and need help to solve this issue. We are getting questions like,

    1. What does the compiler error "[E0002] PC-relative access violates disabling of embedded constants" mean? and how to solve this?

    2. What are these mentioned lines from the portasm.asm file doing?

    3. Why does the compiler (ti-cgt-arm_20.2.7.LTS) list this error in the portasm.asm file after selecting off --embedded_constants?

    4. Relation between --embedded_constants and the mentioned lines from the portasm.asm file

    5. Where do I need to focus to solve this error, either compiler settings or FreeRTOS files?

    6. Is there any different method to achieve this "Execute-only" flash protection for FreeRTOS projects?

     

    Help us to perform this memory protection functionality in FreeRTOS projects. 

  • Hi,

    Please check these error lines from portasm.asm when --embedded_constants=OFF
    @ line 99: ldr r0, ulMaxSyscallInterruptPriorityConst
    @ line 112: ldr r3, pxCurrentTCBConst
    @ line 127: ldr r0, ulMaxSyscallInterruptPriorityConst
    @ line 160: ldr r3, pxCurrentTCBConst
    @ line 177: ldr r0, NVICOffsetConst
    @ line 195: ldr.w r0, CPACRConst

     

    Here we are structed up now and need help to solve this issue. We are getting questions like,

    1. What does the compiler error "[E0002] PC-relative access violates disabling of embedded constants" mean? and how to solve this?

    2. What are these mentioned lines from the portasm.asm file doing?

    3. Why does the compiler (ti-cgt-arm_20.2.7.LTS) list this error in the portasm.asm file after selecting off --embedded_constants?

    4. Relation between --embedded_constants and the mentioned lines from the portasm.asm file

    5. Where do I need to focus to solve this error, either compiler settings or FreeRTOS files?

    6. Is there any different method to achieve this "Execute-only" flash protection for FreeRTOS projects?

    I will need help from our compiler expert and see if there is a workaround for the compilation error. I will forward your question to them. Based on the complier error, we need to first understand what is PC-relative addressing. PC-relative addressing is a way of specifying the address of an operand by adding or subtracting a signed offset to the PC register. The offset is usually encoded as an immediate value in the instruction, and it represents the number of bytes from the current instruction to the target location. The error may be saying that the PC-relative address of the target location is too far away from the current instruction when you set the embedded-constants to OFF. However, you might argue why doesn't the compiler choose not to use PC-relative addressing when embedded-constants is set to OFF. For this, I want to know myself too. Hopefully, there are some switches in the compiler setting to workaround the error you see. I will let our complier expert comment on it. 

  • Hi Charles,

    It's great to receive your responses and see how involved you are regarding the issue.

    Looking forward to a great discussion and hopefully a solution to the issue.

    Thank you.

  • Hi,

      Can you attach the portasm.asm file so our compiler expert can investigate?

  • Hi,

    Yes, I can. Here I have attached the portasm.asm file from the third_party\FreeRTOS\Source\portable\CCS\ARM_CM4F folder. Its version is v9.0.0.

    portasm.asm

    You can download the full "blinky_queue" project from the previous reply for further verification if you want to refer to the full project.

    Thank you.

  • When you build with --embedded_constants=off, you tell the compiler tools not to allow the use of embedded constants inside a section that has executable code.  But code in portasm.asm does exactly that.  You have to change the code.  Here is one example ...

    	; ldr r0, ulMaxSyscallInterruptPriorityConst
    	movw r0, ulMaxSyscallInterruptPriorityConst
    	movt r0, ulMaxSyscallInterruptPriorityConst

    The problem instruction is commented out, and replaced by the two new instructions.  This same change needs to be made a few other places in the file.  

    I'm a bit outside my expertise on this next change.  I think these lines ...

    NVICOffsetConst:					.word 	0xE000ED08
    CPACRConst:							.word 	0xE000ED88
    pxCurrentTCBConst:					.word	pxCurrentTCB
    ulMaxSyscallInterruptPriorityConst: .word ulMaxSyscallInterruptPriority

    ... have to be changed so they do not appear inside a section that contains executable code.  Put them inside a section with another name by using the .sect directive.  I lack expertise as to what section to use or where it should be allocated in memory.

    Thanks and regards,

    -George

  • Hi George,

    As per your suggestions, I first replaced every error line with the other two lines, each with MOVW and MOVT instructions.

    Then I made a .sect directive with those constants. I gave them a memory space (0x0000–0xC000) where code constants are placed in Flash.

    You can check out these images for reference.

    Initially, I planned to test the code with the above changes and without any memory protection, and I chose --embedded_constants = off.

    After these changes, I compiled the project. Now, I am not getting those errors. Then, I uploaded the FreeRTOS application code (Blinky_queue) into the TM4C1294 microcontroller. There was no response from the LEDs. I checked the .map file for the .sect directive, and it was there.

    I confirmed that the ".pc_const" directive is placed in the data region rather than the code region. Then I went through the debugging option. Here is the FaultISR issue. The microcontroller is executing the code until the "BaseType_t xPortStartScheduler( void )" function of the port.c file from FreeRTOS. After executing the line, the microcontroller goes to the FaultISR function.

    At last, the compilation error is fixed with "--embedded_constants = off", but the application is not working due to some fault. I tried to fix this, but I could not. Please help me here. Why am I facing this problem? Did I miss anything, or did I do something wrong?

    You can check these files.

    7065.portasm.asm

    /*
        FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
        All rights reserved
    
        VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
    
        This file is part of the FreeRTOS distribution.
    
        FreeRTOS is free software; you can redistribute it and/or modify it under
        the terms of the GNU General Public License (version 2) as published by the
        Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
    
        ***************************************************************************
        >>!   NOTE: The modification to the GPL is included to allow you to     !<<
        >>!   distribute a combined work that includes FreeRTOS without being   !<<
        >>!   obliged to provide the source code for proprietary components     !<<
        >>!   outside of the FreeRTOS kernel.                                   !<<
        ***************************************************************************
    
        FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
        WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
        FOR A PARTICULAR PURPOSE.  Full license text is available on the following
        link: http://www.freertos.org/a00114.html
    
        ***************************************************************************
         *                                                                       *
         *    FreeRTOS provides completely free yet professionally developed,    *
         *    robust, strictly quality controlled, supported, and cross          *
         *    platform software that is more than just the market leader, it     *
         *    is the industry's de facto standard.                               *
         *                                                                       *
         *    Help yourself get started quickly while simultaneously helping     *
         *    to support the FreeRTOS project by purchasing a FreeRTOS           *
         *    tutorial book, reference manual, or both:                          *
         *    http://www.FreeRTOS.org/Documentation                              *
         *                                                                       *
        ***************************************************************************
    
        http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
        the FAQ page "My application does not run, what could be wrong?".  Have you
        defined configASSERT()?
    
        http://www.FreeRTOS.org/support - In return for receiving this top quality
        embedded software for free we request you assist our global community by
        participating in the support forum.
    
        http://www.FreeRTOS.org/training - Investing in training allows your team to
        be as productive as possible as early as possible.  Now you can receive
        FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
        Ltd, and the world's leading authority on the world's leading RTOS.
    
        http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
        including FreeRTOS+Trace - an indispensable productivity tool, a DOS
        compatible FAT file system, and our tiny thread aware UDP/IP stack.
    
        http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
        Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
    
        http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
        Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
        licenses offer ticketed support, indemnification and commercial middleware.
    
        http://www.SafeRTOS.com - High Integrity Systems also provide a safety
        engineered and independently SIL3 certified version for use in safety and
        mission critical applications that require provable dependability.
    
        1 tab == 4 spaces!
    */
    
    /*-----------------------------------------------------------
     * Implementation of functions defined in portable.h for the ARM CM4F port.
     *----------------------------------------------------------*/
    
    /* Scheduler includes. */
    #include "FreeRTOS.h"
    #include "task.h"
    
    #ifndef __TI_VFP_SUPPORT__
    	#error This port can only be used when the project options are configured to enable hardware floating point support.
    #endif
    
    #if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0
    	#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
    #endif
    
    #ifndef configSYSTICK_CLOCK_HZ
    	#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
    	/* Ensure the SysTick is clocked at the same frequency as the core. */
    	#define portNVIC_SYSTICK_CLK_BIT	( 1UL << 2UL )
    #else
    	/* The way the SysTick is clocked is not modified in case it is not the same
    	as the core. */
    	#define portNVIC_SYSTICK_CLK_BIT	( 0 )
    #endif
    
    /* Constants required to manipulate the core.  Registers first... */
    #define portNVIC_SYSTICK_CTRL_REG			( * ( ( volatile uint32_t * ) 0xe000e010 ) )
    #define portNVIC_SYSTICK_LOAD_REG			( * ( ( volatile uint32_t * ) 0xe000e014 ) )
    #define portNVIC_SYSTICK_CURRENT_VALUE_REG	( * ( ( volatile uint32_t * ) 0xe000e018 ) )
    #define portNVIC_SYSPRI2_REG				( * ( ( volatile uint32_t * ) 0xe000ed20 ) )
    /* ...then bits in the registers. */
    #define portNVIC_SYSTICK_INT_BIT			( 1UL << 1UL )
    #define portNVIC_SYSTICK_ENABLE_BIT			( 1UL << 0UL )
    #define portNVIC_SYSTICK_COUNT_FLAG_BIT		( 1UL << 16UL )
    #define portNVIC_PENDSVCLEAR_BIT 			( 1UL << 27UL )
    #define portNVIC_PEND_SYSTICK_CLEAR_BIT		( 1UL << 25UL )
    
    #define portNVIC_PENDSV_PRI					( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
    #define portNVIC_SYSTICK_PRI				( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
    
    /* Constants required to check the validity of an interrupt priority. */
    #define portFIRST_USER_INTERRUPT_NUMBER		( 16 )
    #define portNVIC_IP_REGISTERS_OFFSET_16 	( 0xE000E3F0 )
    #define portAIRCR_REG						( * ( ( volatile uint32_t * ) 0xE000ED0C ) )
    #define portMAX_8_BIT_VALUE					( ( uint8_t ) 0xff )
    #define portTOP_BIT_OF_BYTE					( ( uint8_t ) 0x80 )
    #define portMAX_PRIGROUP_BITS				( ( uint8_t ) 7 )
    #define portPRIORITY_GROUP_MASK				( 0x07UL << 8UL )
    #define portPRIGROUP_SHIFT					( 8UL )
    
    /* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
    #define portVECTACTIVE_MASK					( 0xFFUL )
    
    /* Constants required to manipulate the VFP. */
    #define portFPCCR							( ( volatile uint32_t * ) 0xe000ef34 ) /* Floating point context control register. */
    #define portASPEN_AND_LSPEN_BITS			( 0x3UL << 30UL )
    
    /* Constants required to set up the initial stack. */
    #define portINITIAL_XPSR					( 0x01000000 )
    #define portINITIAL_EXEC_RETURN				( 0xfffffffd )
    
    /* The systick is a 24-bit counter. */
    #define portMAX_24_BIT_NUMBER				( 0xffffffUL )
    
    /* A fiddle factor to estimate the number of SysTick counts that would have
    occurred while the SysTick counter is stopped during tickless idle
    calculations. */
    #define portMISSED_COUNTS_FACTOR			( 45UL )
    
    /* For strict compliance with the Cortex-M spec the task start address should
    have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
    #define portSTART_ADDRESS_MASK		( ( StackType_t ) 0xfffffffeUL )
    
    /* Required to allow portasm.asm access the configMAX_SYSCALL_INTERRUPT_PRIORITY
    setting. */
    const uint32_t ulMaxSyscallInterruptPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;
    
    /* Each task maintains its own interrupt status in the critical nesting
    variable. */
    static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
    
    /*
     * Setup the timer to generate the tick interrupts.  The implementation in this
     * file is weak to allow application writers to change the timer used to
     * generate the tick interrupt.
     */
    void vPortSetupTimerInterrupt( void );
    
    /*
     * Exception handlers.
     */
    void xPortSysTickHandler( void );
    
    /*
     * Start first task is a separate function so it can be tested in isolation.
     */
    extern void vPortStartFirstTask( void );
    
    /*
     * Turn the VFP on.
     */
    extern void vPortEnableVFP( void );
    
    /*
     * Used to catch tasks that attempt to return from their implementing function.
     */
    static void prvTaskExitError( void );
    
    /*-----------------------------------------------------------*/
    
    /*
     * The number of SysTick increments that make up one tick period.
     */
    #if configUSE_TICKLESS_IDLE == 1
    	static uint32_t ulTimerCountsForOneTick = 0;
    #endif /* configUSE_TICKLESS_IDLE */
    
    /*
     * The maximum number of tick periods that can be suppressed is limited by the
     * 24 bit resolution of the SysTick timer.
     */
    #if configUSE_TICKLESS_IDLE == 1
    	static uint32_t xMaximumPossibleSuppressedTicks = 0;
    #endif /* configUSE_TICKLESS_IDLE */
    
    /*
     * Compensate for the CPU cycles that pass while the SysTick is stopped (low
     * power functionality only.
     */
    #if configUSE_TICKLESS_IDLE == 1
    	static uint32_t ulStoppedTimerCompensation = 0;
    #endif /* configUSE_TICKLESS_IDLE */
    
    /*
     * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
     * FreeRTOS API functions are not called from interrupts that have been assigned
     * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
     */
    #if ( configASSERT_DEFINED == 1 )
    	 static uint8_t ucMaxSysCallPriority = 0;
    	 static uint32_t ulMaxPRIGROUPValue = 0;
    	 static const volatile uint8_t * const pcInterruptPriorityRegisters = ( uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16;
    #endif /* configASSERT_DEFINED */
    
    /*-----------------------------------------------------------*/
    
    /*
     * See header file for description.
     */
    StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
    {
    	/* Simulate the stack frame as it would be created by a context switch
    	interrupt. */
    
    	/* Offset added to account for the way the MCU uses the stack on entry/exit
    	of interrupts, and to ensure alignment. */
    	pxTopOfStack--;
    
    	*pxTopOfStack = portINITIAL_XPSR;	/* xPSR */
    	pxTopOfStack--;
    	*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;	/* PC */
    	pxTopOfStack--;
    	*pxTopOfStack = ( StackType_t ) prvTaskExitError;	/* LR */
    
    	/* Save code space by skipping register initialisation. */
    	pxTopOfStack -= 5;	/* R12, R3, R2 and R1. */
    	*pxTopOfStack = ( StackType_t ) pvParameters;	/* R0 */
    
    	/* A save method is being used that requires each task to maintain its
    	own exec return value. */
    	pxTopOfStack--;
    	*pxTopOfStack = portINITIAL_EXEC_RETURN;
    
    	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4. */
    
    	return pxTopOfStack;
    }
    /*-----------------------------------------------------------*/
    
    static void prvTaskExitError( void )
    {
    	/* A function that implements a task must not exit or attempt to return to
    	its caller as there is nothing to return to.  If a task wants to exit it
    	should instead call vTaskDelete( NULL ).
    
    	Artificially force an assert() to be triggered if configASSERT() is
    	defined, then stop here so application writers can catch the error. */
    	configASSERT( uxCriticalNesting == ~0UL );
    	portDISABLE_INTERRUPTS();
    	for( ;; );
    }
    /*-----------------------------------------------------------*/
    
    /*
     * See header file for description.
     */
    BaseType_t xPortStartScheduler( void )
    {
    	#if( configASSERT_DEFINED == 1 )
    	{
    		volatile uint32_t ulOriginalPriority;
    		volatile uint8_t * const pucFirstUserPriorityRegister = ( uint8_t * ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
    		volatile uint8_t ucMaxPriorityValue;
    
    		/* Determine the maximum priority from which ISR safe FreeRTOS API
    		functions can be called.  ISR safe functions are those that end in
    		"FromISR".  FreeRTOS maintains separate thread and ISR API functions to
    		ensure interrupt entry is as fast and simple as possible.
    
    		Save the interrupt priority value that is about to be clobbered. */
    		ulOriginalPriority = *pucFirstUserPriorityRegister;
    
    		/* Determine the number of priority bits available.  First write to all
    		possible bits. */
    		*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
    
    		/* Read the value back to see how many bits stuck. */
    		ucMaxPriorityValue = *pucFirstUserPriorityRegister;
    
    		/* Use the same mask on the maximum system call priority. */
    		ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
    
    		/* Calculate the maximum acceptable priority group value for the number
    		of bits read back. */
    		ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
    		while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
    		{
    			ulMaxPRIGROUPValue--;
    			ucMaxPriorityValue <<= ( uint8_t ) 0x01;
    		}
    
    		/* Shift the priority group value back to its position within the AIRCR
    		register. */
    		ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
    		ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
    
    		/* Restore the clobbered interrupt priority register to its original
    		value. */
    		*pucFirstUserPriorityRegister = ulOriginalPriority;
    	}
    	#endif /* conifgASSERT_DEFINED */
    
    	/* Make PendSV and SysTick the lowest priority interrupts. */
    	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
    	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
    
    	/* Start the timer that generates the tick ISR.  Interrupts are disabled
    	here already. */
    	vPortSetupTimerInterrupt();
    
    	/* Initialise the critical nesting count ready for the first task. */
    	uxCriticalNesting = 0;
    
    	/* Ensure the VFP is enabled - it should be anyway. */
    	vPortEnableVFP();
    
    	/* Lazy save always. */
    	*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
    
    	/* Start the first task. */
    	vPortStartFirstTask();
    
    	/* Should not get here! */
    	return 0;
    }
    /*-----------------------------------------------------------*/
    
    void vPortEndScheduler( void )
    {
    	/* Not implemented in ports where there is nothing to return to.
    	Artificially force an assert. */
    	configASSERT( uxCriticalNesting == 1000UL );
    }
    /*-----------------------------------------------------------*/
    
    void vPortEnterCritical( void )
    {
    	portDISABLE_INTERRUPTS();
    	uxCriticalNesting++;
    
    	/* This is not the interrupt safe version of the enter critical function so
    	assert() if it is being called from an interrupt context.  Only API
    	functions that end in "FromISR" can be used in an interrupt.  Only assert if
    	the critical nesting count is 1 to protect against recursive calls if the
    	assert function also uses a critical section. */
    	if( uxCriticalNesting == 1 )
    	{
    		configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
    	}
    }
    /*-----------------------------------------------------------*/
    
    void vPortExitCritical( void )
    {
    	configASSERT( uxCriticalNesting );
    	uxCriticalNesting--;
    	if( uxCriticalNesting == 0 )
    	{
    		portENABLE_INTERRUPTS();
    	}
    }
    /*-----------------------------------------------------------*/
    
    void xPortSysTickHandler( void )
    {
    	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
    	executes all interrupts must be unmasked.  There is therefore no need to
    	save and then restore the interrupt mask value as its value is already
    	known. */
    	( void ) portSET_INTERRUPT_MASK_FROM_ISR();
    	{
    		/* Increment the RTOS tick. */
    		if( xTaskIncrementTick() != pdFALSE )
    		{
    			/* A context switch is required.  Context switching is performed in
    			the PendSV interrupt.  Pend the PendSV interrupt. */
    			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
    		}
    	}
    	portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
    }
    /*-----------------------------------------------------------*/
    
    #if configUSE_TICKLESS_IDLE == 1
    
    	#pragma WEAK( vPortSuppressTicksAndSleep )
    	void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
    	{
    	uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL;
    	TickType_t xModifiableIdleTime;
    
    		/* Make sure the SysTick reload value does not overflow the counter. */
    		if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
    		{
    			xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
    		}
    
    		/* Stop the SysTick momentarily.  The time the SysTick is stopped for
    		is accounted for as best it can be, but using the tickless mode will
    		inevitably result in some tiny drift of the time maintained by the
    		kernel with respect to calendar time. */
    		portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
    
    		/* Calculate the reload value required to wait xExpectedIdleTime
    		tick periods.  -1 is used because this code will execute part way
    		through one of the tick periods. */
    		ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
    		if( ulReloadValue > ulStoppedTimerCompensation )
    		{
    			ulReloadValue -= ulStoppedTimerCompensation;
    		}
    
    		/* Enter a critical section but don't use the taskENTER_CRITICAL()
    		method as that will mask interrupts that should exit sleep mode. */
    		__asm( "	cpsid i" );
    		__asm( "	dsb" );
    		__asm( "	isb" );
    
    
    		/* If a context switch is pending or a task is waiting for the scheduler
    		to be unsuspended then abandon the low power entry. */
    		if( eTaskConfirmSleepModeStatus() == eAbortSleep )
    		{
    			/* Restart from whatever is left in the count register to complete
    			this tick period. */
    			portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
    
    			/* Restart SysTick. */
    			portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
    
    			/* Reset the reload register to the value required for normal tick
    			periods. */
    			portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
    
    			/* Re-enable interrupts - see comments above __disable_interrupt()
    			call above. */
    			__asm( "	cpsie i" );
    		}
    		else
    		{
    			/* Set the new reload value. */
    			portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
    
    			/* Clear the SysTick count flag and set the count value back to
    			zero. */
    			portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
    
    			/* Restart SysTick. */
    			portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
    
    			/* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
    			set its parameter to 0 to indicate that its implementation contains
    			its own wait for interrupt or wait for event instruction, and so wfi
    			should not be executed again.  However, the original expected idle
    			time variable must remain unmodified, so a copy is taken. */
    			xModifiableIdleTime = xExpectedIdleTime;
    			configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
    			if( xModifiableIdleTime > 0 )
    			{
    				__asm( "	dsb" );
    				__asm( "	wfi" );
    				__asm( "	isb" );
    			}
    			configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
    
    			/* Stop SysTick.  Again, the time the SysTick is stopped for is
    			accounted for as best it can be, but using the tickless mode will
    			inevitably result in some tiny drift of the time maintained by the
    			kernel with respect to calendar time. */
    			ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
    			portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
    
    			/* Re-enable interrupts - see comments above __disable_interrupt()
    			call above. */
    			__asm( "	cpsie i" );
    
    			if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
    			{
    				uint32_t ulCalculatedLoadValue;
    
    				/* The tick interrupt has already executed, and the SysTick
    				count reloaded with ulReloadValue.  Reset the
    				portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
    				period. */
    				ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
    
    				/* Don't allow a tiny value, or values that have somehow
    				underflowed because the post sleep hook did something
    				that took too long. */
    				if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
    				{
    					ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
    				}
    
    				portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
    
    				/* The tick interrupt handler will already have pended the tick
    				processing in the kernel.  As the pending tick will be
    				processed as soon as this function exits, the tick value
    				maintained by the tick is stepped forward by one less than the
    				time spent waiting. */
    				ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
    			}
    			else
    			{
    				/* Something other than the tick interrupt ended the sleep.
    				Work out how long the sleep lasted rounded to complete tick
    				periods (not the ulReload value which accounted for part
    				ticks). */
    				ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
    
    				/* How many complete tick periods passed while the processor
    				was waiting? */
    				ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
    
    				/* The reload value is set to whatever fraction of a single tick
    				period remains. */
    				portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
    			}
    
    			/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
    			again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
    			value.  The critical section is used to ensure the tick interrupt
    			can only execute once in the case that the reload register is near
    			zero. */
    			portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
    			portENTER_CRITICAL();
    			{
    				portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
    				vTaskStepTick( ulCompleteTickPeriods );
    				portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
    			}
    			portEXIT_CRITICAL();
    		}
    	}
    
    #endif /* #if configUSE_TICKLESS_IDLE */
    /*-----------------------------------------------------------*/
    
    /*
     * Setup the systick timer to generate the tick interrupts at the required
     * frequency.
     */
    #pragma WEAK( vPortSetupTimerInterrupt )
    void vPortSetupTimerInterrupt( void )
    {
    	/* Calculate the constants required to configure the tick interrupt. */
    	#if configUSE_TICKLESS_IDLE == 1
    	{
    		ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
    		xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
    		ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
    	}
    	#endif /* configUSE_TICKLESS_IDLE */
    
    	/* Configure SysTick to interrupt at the requested rate. */
    	portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
    	portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
    }
    /*-----------------------------------------------------------*/
    
    #if( configASSERT_DEFINED == 1 )
    
    	void vPortValidateInterruptPriority( void )
    	{
    	extern uint32_t ulPortGetIPSR( void );
    	uint32_t ulCurrentInterrupt;
    	uint8_t ucCurrentPriority;
    
    		ulCurrentInterrupt = ulPortGetIPSR();
    
    		/* Is the interrupt number a user defined interrupt? */
    		if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
    		{
    			/* Look up the interrupt's priority. */
    			ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
    
    			/* The following assertion will fail if a service routine (ISR) for
    			an interrupt that has been assigned a priority above
    			configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
    			function.  ISR safe FreeRTOS API functions must *only* be called
    			from interrupts that have been assigned a priority at or below
    			configMAX_SYSCALL_INTERRUPT_PRIORITY.
    
    			Numerically low interrupt priority numbers represent logically high
    			interrupt priorities, therefore the priority of the interrupt must
    			be set to a value equal to or numerically *higher* than
    			configMAX_SYSCALL_INTERRUPT_PRIORITY.
    
    			Interrupts that	use the FreeRTOS API must not be left at their
    			default priority of	zero as that is the highest possible priority,
    			which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
    			and	therefore also guaranteed to be invalid.
    
    			FreeRTOS maintains separate thread and ISR API functions to ensure
    			interrupt entry is as fast and simple as possible.
    
    			The following links provide detailed information:
    			http://www.freertos.org/RTOS-Cortex-M3-M4.html
    			http://www.freertos.org/FAQHelp.html */
    			configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
    		}
    
    		/* Priority grouping:  The interrupt controller (NVIC) allows the bits
    		that define each interrupt's priority to be split between bits that
    		define the interrupt's pre-emption priority bits and bits that define
    		the interrupt's sub-priority.  For simplicity all bits must be defined
    		to be pre-emption priority bits.  The following assertion will fail if
    		this is not the case (if some bits represent a sub-priority).
    
    		If the application only uses CMSIS libraries for interrupt
    		configuration then the correct setting can be achieved on all Cortex-M
    		devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
    		scheduler.  Note however that some vendor specific peripheral libraries
    		assume a non-zero priority group setting, in which cases using a value
    		of zero will result in unpredicable behaviour. */
    		configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
    	}
    
    #endif /* configASSERT_DEFINED */
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    Thanks in advance.

  • Hi,

    At last, the compilation error is fixed with "--embedded_constants = off", but the application is not working due to some fault. I tried to fix this, but I could not.

    Glad that you made some progress without compilation error. Can you do single step debugging to find out which offending assembly instruction results in the fault?  Are you getting this fault with any flash memory protection turned on? Or you are nonetheless getting the fault without any flash memory protection? If you don't have memory protection enabled (e.g. setting some flash pages to execute-only or other protection modes) and still getting faults then I'm not sure what caused them. When the fault occurs, what is shown for the below registers? They should provide some clues if the faults are precise faults. 

    please do use this app note to diagnose the cause of the fault. https://www.ti.com/lit/pdf/spma043

  • Hi Charles,

    I'm glad too about the improvements with your and George's assistance.

    Now, I have the same project without any Flash protection. I made --embedded_constants = off. While executing, I am getting a FaultISR issue. So, I executed the code with the debugging option. I could come to this line as shown in the first image, and you can see the register details also.

    When I am jumping to the next line from the line

    /* Lazy save always. */
    *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;

    From FreeRTOS' port.c, I am getting into faultISR() and seeing the register (NVIC_DEBUG_STAT) details get changed.

    please do use this app note to diagnose the cause of the fault. https://www.ti.com/lit/pdf/spma043

    Please let me know if you have any solutions for this issue. In the meantime, I will also check the mentioned document.

     

    Thank you.

  • Hi,

      Your fault status register indicates an imprecise fault with a value of 0x00000400. This is most likely due to some type of write operation because faults due to read operations are usually precise. 

     Do you have the same issue if the application is non-FreeRTOS based and if the embedded-constants is set to OFF?

     I wonder if you put all sections of portasm.obj  in FLASH instead of CODE_FLASH, will it make a difference? 

  • Hi,

      I really think the reason that you are getting faultISR is answered in this post. 

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/927243/tm4c123gh6pz-flashprotectset-in-the-flash-protected-as-execute-only?tisearch=e2e-sitesearch&keymatch=FlashProtectSet#

    There are basically two issues:

     - The way you call  FlashProtectSet() with a address increment of 1 is wrong. You should not try to alter the protection scheme for the same block even though the protection scheme is the same. In another word, if a 2k flash block is protected for execute-only, you should not try to program the same block with execute-only again. The hardware doesn't like it. You should set the address increment to 2048. See the post for details. 

     - the drivelib.lib is not compiled to have Embedded Constants turned off and therefore the driverlib API calls are causing the FaultISR. You need to rebuild driverlib.lib to have  Embedded Constants turned off. But if you look at the suggestion, why don't you make it easier by allocating the entire driverlib.lib (.text and .const) to a non protected area. I will even suggest to not protect the entire FreeRTOS code or at least portasm.obj which is causing your compile issue. What you want to protect is your custom firmware, not driverlib and FreeRTOS as these are open-source code anyway. 

  • Hi,

    Yes, this gave me a solution. Now FreeRTOS and Memory protection are working.

    Thank you!

  • Glad your issue is resolved. Just to clarify for others who may run into the same problem. Below is what needs to be done. 

    - On top of changing LDR instructions mentioned by George to MOVW and MOVT, additional instructions are needed. For example, let's look at the below lines of code. The first commented line was the original line where it is doing an indirect addressing. When replaced with the MOVEW and MOVET, it becomes a direct addressing mode where it loads CPACRConst as an immediate value. Therefore, the code needs to be modified to insert a LDR R0, [R0] to first read the content of R0. 

    	;ldr.w r0, CPACRConst
    	movw r0, CPACRConst
    	movt r0, CPACRConst
    	
    	ldr	r0, [r0]
    	ldr r1, [r0]

    Here is the complete change of portasm.asm file. 

    7723.portasm.asm

    - Change the .cmd file as follows. Make sure the driverlib.lib is allocated to the non-protected region because driverlib.lib was built originally built with the embedded-constants turned ON. If driverlib.lib were to allocate to the protected region, it needs to be rebuilt with embedded-constants turned OFF. 

    /* The starting address of the application.  Normally the interrupt vectors  */
    /* must be located at the beginning of the application.                      */
    #define APP_BASE 0x00000000
    #define RAM_BASE 0x20000000
    
    /* System memory map */
    
    MEMORY
    {
        /* Application stored in and executes from internal flash */
        FLASH (RX) : origin = APP_BASE, length = 0xC000
        CODE_FLASH (X) : origin = 0xC000, length = 0x20000
        /* Application uses internal RAM for data */
        SRAM (RWX) : origin = 0x20000000, length = 0x00040000
    }
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        .intvecs:   > APP_BASE
        .libraries  :   > FLASH
        {
          --library=driverlib.lib (.text)
          --library=rtsv7M4_T_le_v4SPD16_eabi.lib(.text)
        }
    
        .text   :   > CODE_FLASH
    
        .const  :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
        .init_array : > FLASH
        .pc_const :> FLASH
    
        .vtable :   > RAM_BASE
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM
    }
    
    __STACK_TOP = __stack + 4096;

    - Add the link order as follows.