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
-
$task;
-
LR (R14)
-
R12
-
R11
-
R10
-
R9
-
R8
-
R7
-
R6
-
R5
-
R4
-
R3
-
R2
-
R1
-
R0 : (argument)
-
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.
-
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
-
{
-
INT32U *stk;
-
-
opt = opt; /* 'opt' is not used, prevent warning */
-
stk = (INT32U *)ptos; /* Load stack pointer */
-
*(stk) = (OS_STK)task; /* Entry Point */
-
*(--stk) = (INT32U)0; /* LR (R14) */
-
*(--stk) = (INT32U)0; /* R12 */
-
*(--stk) = (INT32U)0; /* R11 */
-
*(--stk) = (INT32U)0; /* R10 */
-
*(--stk) = (INT32U)0; /* R9 */
-
*(--stk) = (INT32U)0; /* R8 */
-
*(--stk) = (INT32U)0; /* R7 */
-
*(--stk) = (INT32U)0; /* R6 */
-
*(--stk) = (INT32U)0; /* R5 */
-
*(--stk) = (INT32U)0; /* R4 */
-
*(--stk) = (INT32U)0; /* R3 */
-
*(--stk) = (INT32U)0; /* R2 */
-
*(--stk) = (INT32U)0; /* R1 */
-
*(--stk) = (INT32U)pdata; /* R0 : argument */
-
*(--stk) = (INT32U)0x00000013L; /* CPSR */
-
return ((OS_STK *)stk);
-
}
-
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
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
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- Europe's three largest chip giants re-examine their supply chains
- Breaking through the intelligent competition, Changan Automobile opens the "God's perspective"
- The world's first fully digital chassis, looking forward to the debut of the U7 PHEV and EV versions
- Design of automotive LIN communication simulator based on Renesas MCU
- When will solid-state batteries become popular?
- Adding solid-state batteries, CATL wants to continue to be the "King of Ning"
- The agency predicts that my country's public electric vehicle charging piles will reach 3.6 million this year, accounting for nearly 70% of the world
- U.S. senators urge NHTSA to issue new vehicle safety rules
- Giants step up investment, accelerating the application of solid-state batteries
- Guangzhou Auto Show: End-to-end competition accelerates, autonomous driving fully impacts luxury...
- How to change the PIN pin of the segment code LCD screen with zebra stripes?
- Automobile electronic instrument combination based on single chip microcomputer
- How to amplify uV signal?
- MC33078-9 Dual Quad Low Noise Operational Amplifier.rar
- A low-cost peak detector requiring only a few components WORD format
- NeoPixel Clock Using ESP8266
- Power Sequencer Based on GD32F350--Debugging Video
- Ask the moderator for advice (5)
- Please help me design a delay circuit
- EEWORLD University Hall----Live Replay: ST Wireless Connection Solution for Both Near and Far