uCOS_II ported to mini2440

Publisher:EternalBlissLatest update time:2024-06-25 Source: elecfansKeywords:uCOS_II Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1. Prepare source code

Find the source code on the official website or elsewhere. The version I used is the previously downloaded version number V2.51. The source code has 16 files, including architecture-independent

OS_CORE.C OS_MBOX.C OS_FLAG..C

OS_SEM.C OS_Q.C OS_MUTEX.C
OS_TASK.C OS_TIME.C OS_MEM.C
uCOS_II.C (not used) OS_CONFIG.H uCOS_II.H
INCLUDE.H
There are three files related to the architecture:
OS_CPU.H OS_CPU_A.S OS_CPU_C.C
2. Select the development environment ADS 1.2. (The choice of compiler should consider whether it can generate reentrant code)
3. Modify the files related to the architecture. Mainly OS_CPU.H OS_CPU_A.S OS_CPU_C.C
1. Modify OS_CPU.H OS_CPU.H
mainly defines some constants related to the specific CPU and data types related to the precompiler. The following need to be modified:
OS_CRITICAL_METHOD = 3
This is the way to disable interrupts. Here, select OS_ENTER_CRITICAL(), and OS_ENTER_CRITICAL() is equivalent to (cpu_sr = OSCPUSaveSR()). This function is in OS_CPU_A.S and needs to be written by yourself.
#define OS_STK_GROWTH 1
This is the stack growth direction. The stack growth direction of the ADS1.2 development environment arm920t is decreasing, that is, it grows from high address to low address, and it is a full stack, that is, the stack pointer points to valid data.
2. Modify OS_CPU_C.C
OS_CPU_C.C mainly defines the OSTaskStkInit() function and some other hook extension functions. The hook extension function does not need to be modified and remains empty. OSTaskStkInit() is the stack initialization function, which is used in the task creation function OSTaskCreate() to initialize the task stack. The registers and data that need to be saved in the stack in arm920t are

  1. $task;

  2. LR (R14)

  3. R12

  4. R11

  5. R10

  6. R9

  7. R8

  8. R7

  9. R6

  10. R5

  11. R4

  12. R3

  13. R2

  14. R1

  15. R0 : (argument)

  16. CPSR (the stack pointer finally points here, this is the top of the stack, which is the smallest address)

So the stack initialization code is as follows. It can be seen that the task stack cannot be less than 16*4 bytes, otherwise the stack will overflow.

  1. OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)

  2. {

  3. INT32U *stk;

  4. opt = opt; /* 'opt' is not used, prevent warning */

  5. stk = (INT32U *)ptos; /* Load stack pointer */

  6. *(stk) = (OS_STK)task; /* Entry Point */

  7. *(--stk) = (INT32U)0; /* LR (R14) */

  8. *(--stk) = (INT32U)0; /* R12 */

  9. *(--stk) = (INT32U)0; /* R11 */

  10. *(--stk) = (INT32U)0; /* R10 */

  11. *(--stk) = (INT32U)0; /* R9 */

  12. *(--stk) = (INT32U)0; /* R8 */

  13. *(--stk) = (INT32U)0; /* R7 */

  14. *(--stk) = (INT32U)0; /* R6 */

  15. *(--stk) = (INT32U)0; /* R5 */

  16. *(--stk) = (INT32U)0; /* R4 */

  17. *(--stk) = (INT32U)0; /* R3 */

  18. *(--stk) = (INT32U)0; /* R2 */

  19. *(--stk) = (INT32U)0; /* R1 */

  20. *(--stk) = (INT32U)pdata; /* R0 : argument */

  21. *(--stk) = (INT32U)0x00000013L; /* CPSR */

  22. return ((OS_STK *)stk);

  23. }



3. Modify OS_CPU_A.S

OS_CPU_A.S is mainly the assembly code for operating CPU registers, which needs to be rewritten for the compiler. It mainly has the following functions

OSCtxSw() Normal task switching function

OSIntCtxSw() interrupt returns task switching function
OSStartHighRdy() OSStart() function starts the first high priority task
OS_CPU_IRQ_ISR() interrupt handler
OSTickISR() timer tick interrupt service routine
OSCPUSaveSR() interrupt shutdown function
OSCPURestoreSR() interrupt enable function
(1) OSStartHighRdy()
sets the CPU to SVC mode and disables interrupts
Execute OSTaskSwHook
OSRunning = TRUE
SP = OSTCBHighRdy->OSTCBStkPtr
pops the stack to restore the CPU mode (actually still SVC)
pops the stack, saves the data from the top to the bottom of the stack to R0-R12, LR, PC respectively
, then the program jumps to the address pointed to by PC to execute
(2) OSCtxSw():
(First, it is clear that in the task code, C language may use SP so that SP does not point to the lower stack of the current task stack when switching tasks. Because it is OSCtxSw called by the task, the program return address is saved in LR, which is the address to be returned to next time you switch back.)
Push PC LR R12-R0 CPSR into the task stack
OSTCBCur->OSTCBStkPtr = SP (Previously, it was believed that this was not necessary because OSTCBCur->OSTCBStkPtr had not changed. However, SP may not point to the lower stack after the task is executed, which means that the originally allocated stack has an internal offset and the top of the stack must be located again.)
Execute OSTaskSwHook
to change OSTCBCur OSTCBCur = OSTCBHighRdy
to change OSPrioCur OSPrioCur = OSPrioHighRdy
to make SP point to the new task stack SP=OSTCBHighRdy->OSTCBStkPtr
(Note that as long as you get the pointer to the TCB, you will find the task stack because the pointer to the task stack is saved in the first element of the TCB)
LDR R0, =OSTCBHighRdy
OSTCBHighRdy is a pointer variable. This just gets the address of OSTCBHighRdy and saves it in R0.
LDR R0, [R0]
gets the address of TCB .
LDR SP, [R0]
gets the first element of TCB, which is the pointer of the task stack
. All the data are popped from the stack. From the top to the bottom of the stack, the data is saved to R0-R12, LR, PC respectively.
Then the program jumps to the address pointed by PC to execute
(3) OSIntCtxSw()
This function is mainly used in the interrupt handler. The interrupt return calls the task switching function in OSIntExit(). Because the scene has been saved in the interrupt handler, there is no need to do useless work here. Just point SP to the task stack of the next task to be run and restore the scene.
Execute OSTaskSwHook
to change OSTCBCur OSTCBCur = OSTCBHighRdy
and change OSPrioCur OSPrioCur = OSPrioHighRdy
to make SP point to the new task stack SP = OSTCBHighRdy->OSTCBStkPtr.
Pop all the stacks and save the data from the top to the bottom of the stack to R0-R12, LR, PC respectively.
Then the program jumps to the address pointed by PC to execute
(4) OSCPUSaveSR():
Save CPSR to the formal parameter (ATPCS standard stipulates that the formal parameter is saved in R0)
Set the corresponding bit of CPSR to turn off the interrupt
(5) OSCPURestoreSR()
extracts the value of CPSR from R0 and restores the previous interrupt status
(6) OSTickISR()
is the clock beat interrupt service function, which mainly clears the interrupt flag bit. There are mainly two registers SRCPND and INTPND. Jump to OSTimeTick() to execute.
(7) OS_CPU_IRQ_ISR()
This function is mainly an interrupt processing function. All IRQ interrupts need to be processed by this function. First, we need to understand the interrupt process of ARM920T. The interrupt process can be divided into the following steps:
ⅰ The interrupt line of the external device generates an interrupt signal and transmits it to the interrupt controller. The interrupt controller identifies the type of interrupt and gives the CPU an IRQ or FIQ interrupt line signal. At the same time, INTOFFSET generates the interrupt offset.
ⅱ After the CPU receives the interrupt signal, it first automatically saves the PC to the LR, saves the CPSR to the SPSR in the corresponding mode, sets the CPSR to the corresponding mode, and the program jumps to the exception vector at the logical address 0X00. (Because the program is running at 0X30000000, when an interrupt occurs, the interrupt vector cannot be found at 0X00, so the help of the MMU is needed to map 0X30000000 to 0X00. This can ensure the normal response of the interrupt).
ⅲ At the interrupt vector, we saved the address of HandlerIRQ, so the program executes at HandlerIRQ.
ⅳ At HandlerIRQ, macro expansion is used to make the program jump to the HandleIRQ label to execute
ⅴ HandleIRQ is a memory buffer pool that stores the address of our interrupt handler, which is OS_CPU_IRQ_ISR, the interrupt handler we want to write.
ⅵ The above is implemented in 2440init.s. Next, the OS_CPU_IRQ_ISR function is what we want to write. Note that it is now in IRQ mode, and the SP physical address is already in IRQ mode (this has been initialized in 2440init.s).
There are three mode switches here.
The first time, the purpose of switching from IRQ MODE to SVC MODE is to save the interrupt scene. If it is a first-level interrupt, the return address of the task and the status of each register when the interrupt is in SVC mode are saved. If it is not a first-level interrupt, the return address in the interrupt service program and the status of each register in IRQ mode are saved. Then OSIntNesting is added by 1 to determine whether it is 1. If it is 1, it means it is a first-level interrupt, which is related to a specific task. OSTCBCur->OSTCBStkPtr=SP. If SP is not saved, then if it is preempted when the interrupt returns, it will not be able to switch back. Note that whether it is a first-level interrupt or a multi-level interrupt, the interrupt scene is saved in the current task stack, so if interrupt nesting is allowed, ensure that the task stack is large enough.
The second time, the purpose of switching from SVC MODE to IRQ MODE is to load the entry address of the interrupt service program and execute the interrupt service program.
The third time, the purpose of switching from IRQ MODE to SVC MODE is to execute OSIntExit to determine whether the first-level interrupt returns and whether task switching is required. Interrupt return, it may return to the previous interrupt or return to the task.
(Note: interrupts are prohibited when interrupt services are executed, so if you want to nest interrupts, just reopen the interrupts)
4. Modify the configuration file
Mainly modify OS_CFG.H. This file mainly configures and cuts the functions provided by the system. It is appropriately cut according to the size of the system RAM and the requirements of the project to ensure that the system can run efficiently and normally. No modification is required here, because mini2440 is enough to bear all functions.
5. Create ADS project files, compile and debug
Create corresponding Groups as needed: uCOS_II (kernel) BdInit (board-level initialization) OsDir (driver) API Then add the corresponding files, compile, and download. Test. Compilation is mainly for troubleshooting. If you encounter many problems, you need to analyze them carefully and don't just go to extremes. For example, if such an error occurs

Add in uCOS_II.H

[1] [2]
Keywords:uCOS_II Reference address:uCOS_II ported to mini2440

Previous article:Use QEMU to create a mini2440 simulation environment
Next article:Compile 2.6.39.4 kernel for mini2440

Recommended ReadingLatest update time:2024-11-22 03:49

STM32 uCOS_II practice of external interrupt events and system operation process
Before proceeding with the uCOSII program, let's review the operation of external interrupts of stm32 on the bare metal platform. It can be roughly divided into 4 steps: 1-Configure the corresponding pin as a floating input; 2-Configure the corresponding pin as an external interrupt port and set its interrupt properti
[Microcontroller]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号