Graduation Design path (9)-porting ucosi OS to stm32

Source: Internet
Author: User

This work is mainly based on the experience of netizens. In general, the following references are required.

Arm Cortex-m3 authoritative guide

Official transplant documents

User success stories

These three types of materials can be found in my resource uploads.

On the official website, I posted materials that have been transplanted from the official website to the stm32f103 evaluation board. Many of them have been implemented, so few changes need to be made, for details, refer to the third type of user transplant success experience documents. I am running ucosii2.86.

Next we will talk about the porting process:

Porting involves two source files: OS _cpu_c.c and OS _cpu_a.asm and OS _cpu.h. Other files are the ucoⅱ core files and do not need to be modified. There are also two configuration files: app_cfg.h and OS _cfg.h.

The entire file framework is shown in the following figure, using IAR.

This is the directory structure set against the above description.

The main transplantation part of the next interview. It is mainly concentrated in the OS _cpu_a.asm file. OS _cpu.h mainly involves macro configuration. The main function in OS _cpu_c.c must be written, that is, the stack initialization function.

Note the following points in OS _cpu.h.

The following is the macro of the switch interruption.

#define  OS_CRITICAL_METHOD   3#if OS_CRITICAL_METHOD == 3#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}#define  OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}#endif

The height of the cm3 stack is reduced to 1, and there is also a macro for task switching.

#define  OS_STK_GROWTH        1                   /* Stack grows from HIGH to LOW memory on ARM        */#define  OS_TASK_SW()         OSCtxSw()

There are also a few functions about javasick that need to be commented out. The OS _cpu_c.c below will explain the reason.

//                                                  /* See OS_CPU_C.C                                    *///void       OS_CPU_SysTickHandler(void);//void       OS_CPU_SysTickInit(void);////                                                  /* See BSP.C                                         *///INT32U     OS_CPU_SysTickClkFreq(void);

 

See OS _cpu_c.c.

Some functions are hook functions, which can be written as needed. You can leave it empty if you do not need it.

The following is the stack initialization function.

/***********************************************************************************************************                                        INITIALIZE A TASK'S STACK** Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the*              stack frame of the task being created.  This function is highly processor specific.** Arguments  : task          is a pointer to the task code**              p_arg         is a pointer to a user supplied data area that will be passed to the task*                            when the task first executes.**              ptos          is a pointer to the top of stack.  It is assumed that 'ptos' points to*                            a 'free' entry on the task stack.  If OS_STK_GROWTH is set to 1 then*                            'ptos' will contain the HIGHEST valid address of the stack.  Similarly, if*                            OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address*                            of the stack.**              opt           specifies options that can be used to alter the behavior of OSTaskStkInit().*                            (see uCOS_II.H for OS_TASK_OPT_xxx).** Returns    : Always returns the location of the new top-of-stack once the processor registers have*              been placed on the stack in the proper order.** Note(s)    : 1) Interrupts are enabled when your task starts executing.*              2) All tasks run in Thread mode, using process stack.**********************************************************************************************************/OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt){    OS_STK *stk;    (void)opt;                                   /* 'opt' is not used, prevent warning                 */    stk       = ptos;                            /* Load stack pointer                                 */                                                 /* Registers stacked as if auto-saved on exception    */    *(stk)    = (INT32U)0x01000000L;             /* xPSR                                               */    *(--stk)  = (INT32U)task;                    /* Entry Point                                        */    *(--stk)  = (INT32U)0xFFFFFFFEL;             /* R14 (LR) (init value will cause fault if ever used)*/    *(--stk)  = (INT32U)0x12121212L;             /* R12                                                */    *(--stk)  = (INT32U)0x03030303L;             /* R3                                                 */    *(--stk)  = (INT32U)0x02020202L;             /* R2                                                 */    *(--stk)  = (INT32U)0x01010101L;             /* R1                                                 */    *(--stk)  = (INT32U)p_arg;                   /* R0 : argument                                      */                                                 /* Remaining registers saved on process stack         */    *(--stk)  = (INT32U)0x11111111L;             /* R11                                                */    *(--stk)  = (INT32U)0x10101010L;             /* R10                                                */    *(--stk)  = (INT32U)0x09090909L;             /* R9                                                 */    *(--stk)  = (INT32U)0x08080808L;             /* R8                                                 */    *(--stk)  = (INT32U)0x07070707L;             /* R7                                                 */    *(--stk)  = (INT32U)0x06060606L;             /* R6                                                 */    *(--stk)  = (INT32U)0x05050505L;             /* R5                                                 */    *(--stk)  = (INT32U)0x04040404L;             /* R4                                                 */    return (stk);}

Because the stack addresses supported by cm3 are decreasing from high to low, they are all --. In addition, the automatic import sequence of cm3 interruptions is xpsr, PC, R14, R12, R3 ~ R0. For details, refer to the authoritative guide of cm3. So put it in front. Later R11 ~ R4 requires manual stack import. The top pointer of the stack is returned.

OS _cpu_c.c has something to comment out, because the official materials are written based on the evaluation board. If it is transplanted to a platform with the stm32 Firmware Library, you need to make some changes, this is based on the user transplant experience. These things that need to be commented out are mainly related to the timer of the specified IC.

The following is a comment.

//void  OS_CPU_SysTickInit (void)//{//    INT32U  cnts;//////    cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC;////    OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);//                                                 /* Enable timer.                                      *///    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;//                                                 /* Enable timer interrupt.                            *///    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;//}

 

//void  OS_CPU_SysTickHandler (void)//{//    OS_CPU_SR  cpu_sr;//////    OS_ENTER_CRITICAL();                         /* Tell uC/OS-II that we are starting an ISR          *///    OSIntNesting++;//    OS_EXIT_CRITICAL();////    OSTimeTick();                                /* Call uC/OS-II's OSTimeTick()                       */////    OSIntExit();                                 /* Tell uC/OS-II that we are leaving the ISR          *///}

 

//#define  OS_CPU_CM3_NVIC_ST_CTRL    (*((volatile INT32U *)0xE000E010))   /* SysTick Ctrl & Status Reg. *///#define  OS_CPU_CM3_NVIC_ST_RELOAD  (*((volatile INT32U *)0xE000E014))   /* SysTick Reload  Value Reg. *///#define  OS_CPU_CM3_NVIC_ST_CURRENT (*((volatile INT32U *)0xE000E018))   /* SysTick Current Value Reg. *///#define  OS_CPU_CM3_NVIC_ST_CAL     (*((volatile INT32U *)0xE000E01C))   /* SysTick Cal     Value Reg. */////#define  OS_CPU_CM3_NVIC_ST_CTRL_COUNT                    0x00010000     /* Count flag.                *///#define  OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC                  0x00000004     /* Clock Source.              *///#define  OS_CPU_CM3_NVIC_ST_CTRL_INTEN                    0x00000002     /* Interrupt enable.          *///#define  OS_CPU_CM3_NVIC_ST_CTRL_ENABLE                   0x00000001     /* Counter mode.              */

OS _cpu.c.c should be noted about this.

The following is OS _cpu_a.asm. The most things are provided here, which is also relatively difficult to understand. Therefore, you need to carefully read this document from the authoritative guide of cm3.

This is the assembly language implementation of the above switch interrupt macro.

OS_CPU_SR_Save    MRS     R0, PRIMASK                                         ; Set prio int mask to mask all (except faults)    CPSID   I    BX      LROS_CPU_SR_Restore    MSR     PRIMASK, R0    BX      LR

Start the highest priority function and call it only once. It is called in osstart.

;********************************************************************************************************;                                          START MULTITASKING;                                       void OSStartHighRdy(void);; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause;              the first task to start.;;           2) OSStartHighRdy() MUST:;              a) Setup PendSV exception priority to lowest;;              b) Set initial PSP to 0, to tell context switcher this is first run;;              c) Set OSRunning to TRUE;;              d) Trigger PendSV exception;;              e) Enable interrupts (tasks will run with interrupts enabled).;********************************************************************************************************OSStartHighRdy    LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority    LDR     R1, =NVIC_PENDSV_PRI    STRB    R1, [R0]    MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call    MSR     PSP, R0    LDR     R0, =OSRunning                                      ; OSRunning = TRUE    MOVS    R1, #1    STRB    R1, [R0]    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)    LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]    CPSIE   I                                                   ; Enable interrupts at processor levelOSStartHang    B       OSStartHang                                         ; Should never get here

It is mainly to manually suspend the pendsv interrupt, set osrunning to 1, and then enable the interrupt to enter the pendsv interrupt handler function to switch the task and start running ucoⅱ. Pendsv must be mastered to understand how cm3 manages the operating system.

The following are two task switching functions: one is task-level switching, and the other is interruption and task switching. Although the Code is the same, it has different meanings, this is mainly related to the pendsv interrupt mentioned above. Because of this interruption, the main task we implement in task switching is to trigger the pendsv interruption and let the interruption process the task switching details.

;********************************************************************************************************;                               PERFORM A CONTEXT SWITCH (From task level);                                           void OSCtxSw(void);; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch.  This function;              triggers the PendSV exception which is where the real work is done.;********************************************************************************************************OSCtxSw    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)    LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]    BX      LR;********************************************************************************************************;                             PERFORM A CONTEXT SWITCH (From interrupt level);                                         void OSIntCtxSw(void);; Notes:    1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as;              the result of an interrupt.  This function simply triggers a PendSV exception which will;              be handled when there are no more interrupts active and interrupts are enabled.;********************************************************************************************************OSIntCtxSw    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)    LDR     R1, =NVIC_PENDSVSET    STR     R1, [R0]    BX      LR

Below is a very important pendsv interrupt processing function.

;********************************************************************************************************;                                         HANDLE PendSV EXCEPTION;                                     void OS_CPU_PendSVHandler(void);; Note(s) : 1) PendSV is used to cause a context switch.  This is a recommended method for performing;              context switches with Cortex-M3.  This is because the Cortex-M3 auto-saves half of the;              processor context on any exception, and restores same on return from exception.  So only;              saving of R4-R11 is required and fixing up the stack pointers.  Using the PendSV exception;              this way means that context saving and restoring is identical whether it is initiated from;              a thread or occurs due to an interrupt or exception.;;           2) Pseudo-code is:;              a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);;              b) Save remaining regs r4-r11 on process stack;;              c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;;              d) Call OSTaskSwHook();;              e) Get current high priority, OSPrioCur = OSPrioHighRdy;;              f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;;              g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;;              h) Restore R4-R11 from new process stack;;              i) Perform exception return which will restore remaining context.;;           3) On entry into PendSV handler:;              a) The following have been saved on the process stack (by processor):;                 xPSR, PC, LR, R12, R0-R3;              b) Processor mode is switched to Handler mode (from Thread mode);              c) Stack is Main stack (switched from Process stack);              d) OSTCBCur      points to the OS_TCB of the task to suspend;                 OSTCBHighRdy  points to the OS_TCB of the task to resume;;           4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we;              know that it will only be run when no other exception or interrupt is active, and;              therefore safe to assume that context being switched out was using the process stack (PSP).;********************************************************************************************************OS_CPU_PendSVHandler    CPSID   I                                                   ; Prevent interruption during context switch    MRS     R0, PSP                                             ; PSP is process stack pointer    CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack    STM     R0, {R4-R11}    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;    LDR     R1, [R1]    STR     R0, [R1]                                            ; R0 is SP of process being switched out                                                                ; At this point, entire context of process has been savedOS_CPU_PendSVHandler_nosave    PUSH    {R14}                                               ; Save LR exc_return value    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();    BLX     R0    POP     {R14}    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;    LDR     R1, =OSPrioHighRdy    LDRB    R2, [R1]    STRB    R2, [R0]    LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;    LDR     R1, =OSTCBHighRdy    LDR     R2, [R1]    STR     R2, [R0]    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack    ADDS    R0, R0, #0x20    MSR     PSP, R0                                             ; Load PSP with new process SP    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack    CPSIE   I    BX      LR                                                  ; Exception return will restore remaining context    END

 

What we will talk about here is the part of the unmentioned javasick. as the heart of the operating system, we need to organize this interruption on our own.

There is a javasick_handler () function in the terminal processing file stm32f10x_it.c in the stm32 library, and processing is added in it.

 

/**  * @brief  This function handles SysTick Handler.  * @param  None  * @retval None  */void SysTick_Handler(void){OSIntEnter();OSTimeTick();OSIntExit();}

Add the javasick initialization function to main. C.

static void Systick_init(void){RCC_ClocksTypeDef rcc_clocks;RCC_GetClocksFreq(&rcc_clocks);SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC);}

Another change is to replace all the pendsv_handler in the stm32 Startup File with OS _cpu _ pendsvhandler, because the UCOS default port file uses OS _cpu _ pendsvhandler.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.