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.

porting uCOSIII on Cortex M4 LM4F120XL



I want to port uCOSIII on an ARM Cortex M4 (LM4F120XL board)

I am using Eclipse with GCC compiler and OpenOCD to flash and debug the board.

I have build the project but when I flash and debug the SW I get stuck in the hard fault interrupt handler.

By debugging I found out that the problem may be the PendSV interrupt handler.

The interrupt handler is defined in assembler file as_cpu_a.asm like follows:

also the handler is defined as global in the assembler file:  .globl  OS_CPU_PendSVHandler

In the startup code the handler is declared as:

extern void OS_CPU_PendSVHandler(void);

and then added in the vector table defined like this:

The PendSV interrupt is set in the following assembler routine that is executed, but then the execution reaches the hard fault interrupt:

with the defines:

I tried several things:

1. I replaced the PendSV handler with a wrapper of the same OS_CPU_PendSVHandler, basically called the assembler function, and this works first => the interrupt is executed, but then the returning from the function reaches a special routine where the execution should not reach:

By doing some research,  I found that could be a stack problem, and I am not sure I am doing the right thing with my linker configuration file that looks like this:

  • Hi,

    First, if you have an hard fault, you must use it and get info to help you figure out what is the problem. The work procedure in this case is described by the application note spma043.pdf - Diagnosing Software, which you can find on TM4C page.

    Second, looking to your stack - yes, it is small, try to increase it - start with at least 1K, then you will see.

    Third, it is wise to look at the Tiva examples -  the startup_gcc.c file has all interrupt vectors - try to modify your nvic section to have it all - otherwise you will update it when using peripheral interrupts.

    For linker sections now - the .data section content is not OK - first you should have *(vtable) then *(data) - this is because the vtable should be located only at the beginning of the ram, and the software should find it there, address 0x20000000.

    After section bss, my linker file looks like this:

    /* .stack_dummy section doesn't contains any symbols. It is only
     * used for linker to calculate size of stack sections, and assign
     * values to stack symbols later */
    .stack_dummy (COPY):
    {
    *(.stack*)
    } > RAM
    /* Set stack top to end of RAM, and stack limit move down by
     * size of stack_dummy section */
    __StackTop = ORIGIN(RAM) + LENGTH(RAM);
    __StackLimit = __StackTop - SIZEOF(.stack_dummy);
    PROVIDE(__stack = __StackTop);
    /* Check if data + heap + stack exceeds RAM limit */
    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
    This will locate the stack at top of the ram - (while it is also possible to locate it after .bss).
    In case you have problems, you can use a .cmd file from TI (by renaming it with .ld), should work OK also that file.
     
    Petrei

  • Hello Petrei, thanks for your quick answer!

    Now, I'm not experienced with linker files but i'm not sure that I set the "ORIGIN" ok.

    The linker file I use is from an example that is not using the stack, and it worked with no stack size.

    Now I want to use the stack and I write in the linker file:  

    MEMORY
    {
        FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
        RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
        STACK (rwx) : ORIGIN = 0x20007FFF , LENGTH = 0x00000400
    }

    so I set the STACK to start from 0x20007FFF (and here I'm not sure how the stack grows)

    -> if when the data is pushed in the stack the address deaceases => than it is ok

    -> if the address increases than the ORIGIN is wrong.

  • Hi,

    The stack is decreasing, so apparently what you write is good. 

    But I am not sure you have or not some compiler warnings/errors - some problems could arise from not configuring well the IDE - for instance, you must have these settings declared in Project | Properties | C/C++ Build | Compiler | Preprocessor:

    DEBUG
    PART_LM4F120H5QD              /* write here the exact type of your micro */
    TARGET_IS_BLIZZARD_RA1
    gcc

    Not declaring some of these (gcc) could generate hard fault.

    I have attached here my complete linker file (for another processor) - just modify memory sizes. remove .txt extension and rename it with .ld extension

    /******************************************************************************
    * Linker file for LM4F232H5QD 
    ******************************************************************************
    */
    OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    SEARCH_DIR(.)
    ENTRY(ResetISR)
    
    MEMORY
    {
        FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
        SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
    }
    
    GROUP(libgcc.a libc.a libm.a libnosys.a)
    
    STACK_SIZE = 4096;
    HEAP_SIZE = 8192;
    
    SECTIONS
    {
        .isr_vector : {
    	KEEP(*(.isr_vector))
    	. = ALIGN(4);
        } > FLASH
    
        .text : {
            . = ALIGN(4);
            *(.text*)
    	
    	KEEP(*(.init))
    	KEEP(*(.fini))
    	
    	/* .ctors */
    	*crtbegin.o(.ctors)
    	*crtbegin?.o(.ctors)
    	*(EXCLUDE_FILE(*.crtend?.o *crtend.o) .ctors)
    	*(SORT(.ctors.*))
    	*(.ctors)
    
    	/* .dtors */
    	*crtbegin.o(.dtors)
    	*crtbegin?.o.(dtors)
    	*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
    	*(SORT(.dtors.*))
    
    	*(.rodata*)
    	KEEP(*(.eh_frame*))
    
    	. = ALIGN(4);
        } > FLASH
    
        .ARM.extab : {
            *(.ARM.extab* .gnu.linkonce.armextab.*)
        } > FLASH
    
        __exidx_start = .;
        .ARM.exidx : {
            *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        } > FLASH
        . = ALIGN(4);
    
        __exidx_end = .;
        
        _etext = .;
        
        .data : AT(_etext)
        {
            _data = .;
    	__data_start__ = .;
            *(vtable)
            *(.data*)
    	. = ALIGN(4);
    	/* preinit data */
    	PROVIDE_HIDDEN (__preinit_array_start = .);
    	KEEP(*(.preinit_array))
    	PROVIDE_HIDDEN (__preinit_array_end = .);
    
    	. = ALIGN(4);
    	/* init data */
    	PROVIDE_HIDDEN (__init_array_start = .);
    	KEEP(*(SORT(.init_array.*)))
    	KEEP(*(.init_array))
    	PROVIDE_HIDDEN (__init_array_end = .);
            
    	. = ALIGN(4);
    	/* finit data */
    	PROVIDE_HIDDEN (__fini_array_start = .);
    	KEEP(*(SORT(.fini_array.*)))
    	KEEP(*(.fini_array))
    	PROVIDE_HIDDEN (__fini_array_end = .);
    
    	. = ALIGN(4);
    	/* All data end */
    	__data_end__ = .;
            
        } > SRAM
    
        .bss : 
        {
            . = ALIGN(4);
    	_bss = .;
    	__bss_start__ = .;
            *(.bss*)
            *(COMMON)
    	. = ALIGN(4);
    	__bss_end__ = .;
    	_ebss = .;
        } > SRAM
    
        .heap : {
    	. = ALIGN(4);
    	__end__ = .;
    	end = __end__;
    	*(.heap*)
    	. = ALIGN(4);    
    	__HeapLimit = .;
        } > SRAM
    
        .stack_dummy : 
        {
    	*(.stack)
        } > SRAM
    
        __StackTop = ORIGIN(SRAM) + LENGTH(SRAM);
        __StackLimit = __StackTop - SIZEOF(.stack_dummy);
        PROVIDE(__stack = __StackTop);
    
        ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
        _edata = .;	
    }
    /* EOF */
    
    

  • Hello Petrei,


    I have the configured symbols, that are added to the command line at compilation:

    PART_LM4F120H5QR
    ARM_MATH_CM4
    TARGET_IS_BLIZZARD_RA1

    But if I didn't have them then even the template project wouldn't work. But before starting porting the OS I tested the environment.

    Now I will try to integrate my sources in the IAR IDE and build&debug the project, and see if it works and then i'll try to go to eclipse and figure out what is missing.

    I can not do assembler debug in Eclipse and that's the major problem.

    Now from what I saw by debugging until now, the problem is somehow related to PendSV interrupt, but I don't know where.

    Petru Tabac

  • Hi,

    Please do not mix the things - as far as I know, uCosIII is not built on CMSIS basis, so ARM_MATH_CM4 define is useless here. TI uses its driverlib implementation and you must conform with that. Also, various compilers uses to define some primitive operations in their own way - what you probably encounter in PendSV is some definition, so you need to define the compiler type (for IAR the word is"ewarm" - use IAR if you have a paid version otherwise is a time waist). Why you do not use CCS? it is free with the development board.

    The name defined (gcc) is used to insert/define the vector table for ram, so take care.

    Also, how do you use Eclipse? only for writing? the debugger works for me (I use OpenOCD 0.7.0).

    Do not neglect the application note about diagnosing software - you will met this situation many times and you must know how to debug, so first learn that. 

    Petrei

  • Hi,

    I'm using openOCD 0.6.1 and I can not do assembler debugging with it (maybe I do not have the asm symbols loaded or something).

    Also I didn't receive any CCS with the development board.

    About the compiler configuration: I use the GNU Tools ARM Embedded 4.7 installed on my PC.

    gcc with prefix arm-none-eabi- so arm-none-eabi-gcc

    with the additional options:

    -DPART_LM4F120H5QR -DARM_MATH_CM4 -DTARGET_IS_BLIZZARD_RA1 -I "(here are the includes)" -O0 -g3 -Wall -c -fmessage-length=0 -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -ffunction-sections -fdata-sections

  • Hi,

    OpenOCD 0.6.1 is still buggy for ICDI, seems all bugs have been corrected in version 0.7.0, so it is wise to update from freddy chopin site.

    As for compiler options, you have a mixed (bad) options in use:

    - ARM_MATH_CM4 is for users of CMSIS software, so remove it, since uCosIII do not use that;

    - DEBUG is not defined, so that's why you cannot debug;

    - fpv4-sp-d16 is the library for hardware floating point module inside LM4F, while you later call -mfloat-abi=softfp, which is a huge software floating point library, execution time and flash space consuming.

    My settings for compiler are:

    -DDEBUG -DPART_LM4F120H5QD -DTARGET_IS_BLIZZARD_RA1 -Dgcc -I/usr/local/gcc-arm-none-eabi-4_7-2012q4/arm-none-eabi/include -I/usr/local/gcc-arm-none-eabi-4_7-2012q4/lib/gcc/arm-none-eabi/4.7.3/include-fixed -I/usr/local/gcc-arm-none-eabi-4_7-2012q4/lib/gcc/arm-none-eabi/4.7.3/include -I"/Users/A/Proj/Sine-dem" -Os -ffunction-sections -fdata-sections -Wall -Wextra -Wa,-adhlns="$@.lst" -c -fmessage-length=0 -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -g3 -gdwarf-2

    Also, CCS is free - if you do not have it, it is free to download/install.

    Did you correctly modified bps.c files for porting to TI?

    Petrei

  • Hello Petrei,


    I used your linker file and updated the compiler options, but if I use the -mfloat-abi=hard instead of -mfloat-abi=softfp, I get the errors:

    c:/program files (x86)/gnu tools arm embedded/4.7 2012q4/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/bin/ld.exe: error: ./Micrium/Software/EvalBoards/LAUNCHPAD/BSP/a_file.o uses VFP register arguments, LM4F120.elf does not

    for all C modules.

    If I change to -mfloat-abi=softfp, the compilation works.

     

    Also related to bsp.c: I updated the preinit and postinit functions with functions from StellarisWare

    At preinit I just set the clock using the function SysCtlClockSet and disable the interrupts

    Thanks

    Petru Tabac

  • Hi,

    To wipe out all these errors, you need to make clean first (use this command: make clean) or manually remove all .o generated files. Then compile with provided switches.

    You need also the linker switches, as below:

    -T"/Users/A/Proj/Sine-dem/lm4f120h5qr.ld" -nostartfiles -Xlinker --gc-sections -L/usr/local/gcc-arm-none-eabi-4_7-2012q4/arm-none-eabi/lib/armv7e-m/fpu/ -Wl,-Map,Sine-dem.map -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -g3 -gdwarf-2

    Please observe the paths provided.

    Petrei

  • Hi Petri,


    I need to use for linking the library from stellarisware: driverlib-cm4f.a
    , because I use in the library fumctions.

    I see that you use the libraries from GNU Tool ARM.

    If I compile the code with the linker switches you provided and with this library, I get the same VFP error but for the driverlib-cm4f.a library.

    Also...I managed to install openOCD 0.7.0 => the assembler debugging works (i think because i added -g to the assembler flags)

    I do not know how libraries are added to the linking but I see that in the linker file that you gave me there is the line:

    GROUP(libgcc.a libc.a libm.a libnosys.a)

    Can I use all libraries(also driverlib-cm4f.a ) for linking and how I configure that?

    Thank you!
    Petru Tabac

  • Hello Petrei,

    Using the IAR setup, I got pass the PendSV interrupt issue, but still the software doesn't work.

    What hapens is that after like 6 context switches there is a brach to a invalid memory and the execution ends up in the hard fault handler.

    I saw that in the PendSV handler where the context switching happens the context is saved in the "process stack" by using the MRS instruction.

    On the ARM Information center site I found that note: "Your initialization or context switching code must initialize the process stack pointer."

    Where this initialization should be?

    Thanks!

    Petru Tabac

  • Hi,

    Some responses:

    1) Linking the cm4f-driverlib: you should specify this at the linker options, providing the path and the name of this library. Take care to be before "l" and "m". A second option is to avoid this by prefixing with ROM_ each function calls  since these are already embedded on-chip.

    2) As for PendSV - could be caused by not enough or not complete initializations. There is a uCosIII user manual detailing all these aspects. Did you read it? This micro may use two stacks, one for privileged mode, another for user mode, but it is not mandatory. Correspondingly there should be some initializations - user manual again. But since you already passed through that function several times, it is unlikely to be that the cause of hard fault. 

    Petrei

  • Hi Petrei,

    So I managed to enter the PendSV interrupt using the Eclipse tool set, and I know the primary cause of that by I don't know why it is like this....let me describe...

    So after a lot of debugging, also read a lot about the fault handling, I didn't manage to understand what is the problem. Now I looked in the memory at address 0x00000000 where the vector table begins and I checked that the addresses of the handlers in the memory is ok. So what I observed is that in the vector table the addresses of the handlers are odd numbers and they are eqal to dissembly address + 1, but only the PendSV handler (that is defined in assembler) has a even address. Now just to test, I set the handler for PendSV in the vector table: OS_CPU_PendSVHandler +1 (because it is a pointer) and set a breakpoint in the PendSV interrupt handler and the execution reached the breakpoint.

    So I have several questions:

    1. Why the addresses of the vector table handlers are uneven?

    2. I all the other addresses of the other handlers are uneven, why the PendSV handler address is even?

    Now related to the linker symbols that we talked:

    I used  "-mfloat-abi=hard " at compilation and it works, but when the linking starts I get the error that the library libdriver-cm4f does not use VFP register arguments

    Thank you,

    Petru Tabac

  • Hi,

    1. The addresses of interrupt vectors must be odd to signal the core the thumb mode for the interrupt. ARM rules.

    2. To make the PendSV odd, you need to make this declaration before the definition of the interrupt:

    void PendSV(void) __attribute__((__interrupt__));

    if you are in a C file but for your case try to use it in startup_gcc or whatever is the file with interrupt vectors. These are GCC rules, you must obey that. 

    About the linking with floating point libs: A second option is to avoid this by prefixing with ROM_ each function calls  since these are already embedded on-chip. as suggested in a previous post - i.e. omit linking with cm4f-driverlib since this library is already present on-chip in a ROM area. (user manual..). Otherwise you must re-build this library with compiler options hardfp..

    About hard fault: seems you did not read yet the suggested application note. What to say - run it again and when you reach hard fault please inspect the following registers and post the result:

    "CFSR" at address 0xE000ED28

    "HFSR" at address 0xE000ED2C

    "DFSR" at address 0xE000ED30

    "AFSR" at address 0xE000ED3C

    To make your life easier you may install this plugin for Eclipse: 

     http://embsysregview.sourceforge.net/update

    for viewing registers by name. Otherwise you may found them in memory area.

    Petrei

  • Hi Petrei,

    I did read the application note, and took a look in this registers, but this didn't help because it was from the interrupt handler definition.

    Like you said the addresses of the interrupt vectors in thumb mode should be odd, and if the interrupt is defined in a C file you can use

    void __attribute__((__interrupt__))  PendSV(void);

    but it is not mandatory; you just can use -mthumb in the command line for the gcc compiler.

    Now the PendSV handler was defined in assembler, and even if I use the -mthumb in the assembler command line the handler still has even address in memory.

    So I found out that I need to specify .thumb_func before the interrupt handler in order "to allow the assembler and linker to generate correct code for interworking between Arm and Thumb instructions"

    This solved the problem.

    Thank you for your support and help to get to this point.