This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ARM: Porting an application from IAR to Keil (Porteil QK QP)

Hello all,

I've just port the QK Os and the QP framework (state machine framework) from the LM3S6965 to the LM3S9B96.

I've done this using IAR and now I'm trying to use Keil as my company own some licenses for Keil.

I have a problem with an IAR specific directive. It's concerning the vector table, to make it ends up at physical address 0x0000.0000 they use this method in IAR:

__root const uVectorEntry __vector_table[] @ ".intvec" =
{
    { .ulPtr = (unsigned long)pulStack + sizeof(pulStack) },
                                            // The initial stack pointer
    __iar_program_start,                    // The reset handler
....
    Ethernet_IRQHandler,                    // Ethernet
    Hibernate_IRQHandler                    // Hibernate
};

How to convert the @ ".intvec" or what the equivalent of this part of code in Keil?

Maybe some information here but for Cx51 compiler...:
http://www.keil.com/support/man/docs/c51/c51_intvector.htm

I also have some issues finding an equivalent to ".noinit" in this part of code: (used to reserve space for the system stack)

static unsigned long pulStack[STACK_SIZE/sizeof(unsigned long)] @ ".noinit";

Thanks in advance for any help or suggestion about this two issues.

  • Have you looked at all the Keil examples?

    They place the interrupt vector table at the start, which they basically have to.

    There are a number of threads on this forum discussing zero-init variables.

    But in this case you don't need any zero-init stack unless you are very pressed for startup time. It's better to have the stack zero-initialized just to make sure that all runs of the program have the same data on the stack - easier to get same malfunction on multiple runs if you have some uninitialized auto variables.

  • Thanks westermark for your reply, thanks to your advice I finally got it working!

    Now I'm blocked on some library generation! I want to create the library used by QP for Keil.
    I get a cpu and fpu attributes not compatible error.

    I use armcc like this:

    armcc -J \IncludeFolder -O3 -g --cpu cortex-m3 --debug -c SourceFolder\source.c -o Output\lib.obj

    And then armar to create the library:
    armar -r Library\Library1.lib Output\lib.obj

    When Keil try to link my program I get this two error:

    QP.axf: Error: L6366E: qmp_get.obj attributes are not compatible with the provided cpu and fpu attributes .
    QP.axf: Error: L6242E: Cannot link object qmp_get.obj as its attributes are incompatible with the image attributes.

    Do someone have an idea about this issue? I check cpu should be cortex-m3 and fpu the value by default. If I choose fpu=none I got some error because of some float type variable used in my program.

    Thanks in advance for any advise and help

  • I've sold the previous issue but now I have some problem with an assembler file...

    I have one version for GNU and another one for IAR but for both I don't understand how it is working...

    I got some error like Unknown opcode CODE:CODE:ROOT or unknown opcode PUBLIC, I know I should translate the asm file for KEIL but it's hard to find information about what my code should do!

    Here is the first part of the file for IAR:

        RSEG CODE:CODE:NOROOT(2)
    
        PUBLIC  PendSV_Handler    ; CMSIS-compliant PendSV exception name
        PUBLIC  QK_init
        PUBLIC  SVC_Handler       ; CMSIS-compliant SVC exception name
    
        EXTERN  QK_schedPrio_     ; external reference
        EXTERN  QK_sched_         ; external reference
    

    And this should be the same, but for GNU:

        .syntax unified
        .thumb
        .section .text.QK_init
        .global QK_init
        .type   QK_init, %function
    

    Then the code should set some priorities and disable and restore interrupt, this part should not be a problem.
    My problem is about the code attached above, QK_init is called from the C program, how to declare it for Keil armasm?

  • Finally I change the ASM code as I can, now it's linking but I don't have interrupt on my board...

    Here is the first line of the ASM code:

            GLOBAL  PendSV_Handler    ; CMSIS-compliant PendSV exception name GLOBAL=EXPORT
        GLOBAL  QK_init
        GLOBAL  SVC_Handler       ; CMSIS-compliant SVC exception name
    
        IMPORT  QK_schedPrio_     ; external reference
        IMPORT  QK_sched_         ; external reference
    
    
            AREA |.text.QK_init|, CODE, READONLY, ALIGN=2
            THUMB
            REQUIRE8
            PRESERVE8
    

    For the AREA statement should I keep |text.Qk_init| or simply |text| ?

    This is the code folowing:

    QK_init
        MRS     r0,PRIMASK        ; store the state of the PRIMASK in r0
        CPSID   i                 ; disable interrupts (set PRIMASK)
    
        LDR     r1,=0xE000ED18    ; System Handler Priority Register
        LDR     r2,[r1,#8]        ; load the System 12-15 Priority Register
        MOVS    r3,#0xFF
        LSLS    r3,r3,#16
        ORRS    r2,r3             ; set PRI_14 (PendSV) to 0xFF
        STR     r2,[r1,#8]        ; write the System 12-15 Priority Register
        LDR     r2,[r1,#4]        ; load the System 8-11 Priority Register
        LSLS    r3,r3,#8
        BICS    r2,r3             ; set PRI_11 (SVCall) to 0x00
        STR     r2,[r1,#4]        ; write the System 8-11 Priority Register
    
        MSR     PRIMASK,r0        ; restore the original PRIMASK
        BX      lr                ; return to the caller
    
    PendSV_Handler
        CPSID   i                 ; disable interrupts at processor level
        BL      QK_schedPrio_     ; check if we have preemption
        CMP     r0,#0             ; is prio == 0 ?
        BNE.N   scheduler         ; if prio == 0, branch to scheduler
    
    ...
    

    I someone can help me with that because it's really hard for me to find any course about the assembler file for armasm... Tanks

  • In case someone need it one day, here is the qk_port.s now working to make QP library in Keil for the LM3S9B96 board (should be the same for any Cortex M3):

            AREA CODE,CODE
            THUMB
            REQUIRE8
            PRESERVE8
            ;ENTRY
    
        GLOBAL  QK_init
            GLOBAL  PendSV_Handler    ; CMSIS-compliant PendSV exception name GLOBAL=EXPORT
        GLOBAL  SVC_Handler       ; CMSIS-compliant SVC exception name
    
        IMPORT  QK_schedPrio_     ; external reference
        IMPORT  QK_sched_         ; external reference
    
    
    ;*****************************************************************************
    ;
    ; The QK_init function sets the priorities of PendSV and SVCall exceptions
    ; to 0xFF and 0x00, respectively. The function internally disables
    ; interrupts, but restores the original interrupt lock before exit.
    ;
    ;*****************************************************************************
    QK_init
        MRS     r0,PRIMASK        ; store the state of the PRIMASK in r0
        CPSID   i                 ; disable interrupts (set PRIMASK)
    
        LDR     r1,=&E000ED18     ; System Handler Priority Register
        LDR     r2,[r1,#8]        ; load the System 12-15 Priority Register
        MOVS    r3,#0xFF
        LSLS    r3,r3,#16
        ORRS    r2,r3             ; set PRI_14 (PendSV) to 0xFF
        STR     r2,[r1,#8]        ; write the System 12-15 Priority Register
        LDR     r2,[r1,#4]        ; load the System 8-11 Priority Register
        LSLS    r3,r3,#8
        BICS    r2,r3             ; set PRI_11 (SVCall) to 0x00
        STR     r2,[r1,#4]        ; write the System 8-11 Priority Register
    
        MSR     PRIMASK,r0        ; restore the original PRIMASK
        BX      lr                ; return to the caller
    
    
    ;*****************************************************************************
    ;
    ; The PendSV_Handler exception hanlder is used for handling asynchronous
    ; preemptions in QK. The use of the PendSV exception is the recommended
    ; and most efficient method for performing context switches with ARM Cortex.
    ;
    ; The PendSV exception should have the lowest priority in the whole system
    ; (0xFF, see QK_init). All other exeptions and interrupts should have higher
    ; priority. For example, for NVIC with 2 priority bits all interrupts and
    ; exceptions must have numerical value of priority lower than 0xC0. In this
    ; case the interrupt priority levels available to your applications are (in
    ; the order from the lowest urgency to the highest urgency): 0x80, 0x40, 0x00.
    ;
    ; Also, *all* ISRs in the QK application must trigger the PendSV exception
    ; by calling the QK_ISR_EXIT() macro.
    ;
    ; Due to tail-chaining and its lowest priority, the PendSV exception will be
    ; entered immediately after the exit from the *last* nested interrupt (or
    ; exception). In QK, this is exactly the time when the QK scheduler needs to
    ; check for the asynchronous preemptions.
    ;
    ;*****************************************************************************
    PendSV_Handler
        CPSID   i                 ; disable interrupts at processor level
        BL      QK_schedPrio_     ; check if we have preemption
        CMP     r0,#0             ; is prio == 0 ?
        BNE.N   scheduler         ; if prio == 0, branch to scheduler
    
        CPSIE   i                 ; enable interrupts at processor level
        MOVS    r0,#0x6
        MVNS    r0,r0             ; r0:=~0x6=0xFFFFFFF9
        BX      r0                ; exception-return to the task
    
    scheduler
        MOVS    r3,#1
        LSLS    r3,r3,#24         ; r3:=(1 << 24), set the T bit  (new xpsr)
        LDR     r2,=QK_sched_     ; address of the QK scheduler   (new pc)
        LDR     r1,=svc_ret       ; return address after the call (new lr)
        PUSH    {r1-r3}           ; push xpsr,pc,lr
        SUB     sp,sp,#(4*4)      ; don't care for r12,r3,r2,r1
        PUSH    {r0}              ; push the prio argument        (new r0)
        MOVS    r0,#0x6
        MVNS    r0,r0             ; r0:=~0x6=0xFFFFFFF9
        BX      r0                ; exception-return to the scheduler
    
    svc_ret
        CPSIE   i                 ; enable interrupts to allow SVCall exception
        SVC     0                 ; SV exception returns to the preempted task
    
    
    
    ;*****************************************************************************
    ;
    ; The SVC_Handler exception handler is used for returning back to the
    ; interrupted context (task or interrupt). The SVC exception should have
    ; the lowest priority in the whole system (see QK_init). The SVCall
    ; exception simply removes its own interrupt stack frame from the stack and
    ; returns to the preempted task using the interrupt stack frame that must be
    ; at the top of the stack.
    ;
    ;*****************************************************************************
    SVC_Handler
        ADD     sp,sp,#(8*4)      ; remove one interrupt frame from the stack
        BX      lr                ; return to the preempted task
            ALIGN 2,0,0xFF                                    ; make sure the END is properly aligned
        END
    
    

    Now my QP is working on the LM3S9B96 with Keil uVision 4