UCOS_II的移植到S3C2440 ADS 1.2

本文详细介绍了如何在S3C2440平台下进行uC/OS-II的移植,并配置了关键文件如OS_CPU.H、Os_cpu_a.s、Os_cpu_c.c等,包括工程设置、文件修改和移植文件的调整,旨在提供一套完整的移植解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、新建工程
1.新建一个ARM Executable Image
2.创建uCOS_II文件夹,创建两个子文件夹,分别为ARM、SOURCE
ARM存放和平台相关的文件("OS_CPU.H" "Os_cpu_a.s" "Os_cpu_c.c" )
SOURCE下存入和平台无关的文件("ucos_ii.h" "os_cfg.h" "os_core.c" "os_flag.c" "os_mbox.c" "os_mem.c" "os_mutex.c" "os_q.c" "os_sem.c" "os_task.c" "os_time.c" "os_tmr.c" )
3.创建一个S3C2440文件夹,创建两个子文件夹,分别为INC、SRC
INC存放S3C2440相关头文件("2440addr.h" "2440lib.h" "2440slib.h" "config.h" "Def1.h" "lcd.h" "mmu.h" "Option.h" "Target.h" "Timer.h" )
SRC存放S3C2440相关源文件("Timer.c" "2440init.s" "2440lib.c" "2440slib.s" "Font_Libs.c" "iphone.c" "lcd.c" "mmu.c" "nand.c" "Target.c" )
4.创建一个app文件夹(app_cfg.h、main.c、Printf.c、Printf.h)
二、工程设置Edit->DebugRel Settings下
1.Target->Target Settings,Post-linker:ARM fromELF
2.Target->Access Paths选中Always Search User Paths(ucos_ii部分文件采用#include <>包涵,不修改这里找不到文件)
3.Language Settings下ARM Assembler、ARM C Compliler、ARM C++ Complier处理器设置成ARM920T
4.Language Settings下ARM C Compliler下Errors下去掉Implicit pointer c,ARM C Compliler下Warnings下去掉Unused declaration(-O1 -g+ -cpu ARM920T -Wx -Ec)
5.ARM Linker下,Output下RO Base设置成0x30000000,Options下Image entry point设置成0x30000000,Layout下Place at beginning of image下的Object/Symbol设置成2440init.o,Section设置成Init,Listings下选勾Image map、List file设置list.txt,勾上Sizes、Totals、Unused、Veneers

6.ARM fromELF下Output file name下填写输出的二进制

三、移植文件的修改

对OS_CPU.H的修改:

  1. /*
  2. *********************************************************************************************************
  3. *ARM
  4. *
  5. *Method#1:NOTIMPLEMENTED
  6. *Disable/Enableinterruptsusingsimpleinstructions.Aftercriticalsection,interrupts
  7. *willbeenabledeveniftheyweredisabledbeforeenteringthecriticalsection.
  8. *
  9. *Method#2:NOTIMPLEMENTED
  10. *Disable/Enableinterruptsbypreservingthestateofinterrupts.Inotherwords,if
  11. *interruptsweredisabledbeforeenteringthecriticalsection,theywillbedisabledwhen
  12. *leavingthecriticalsection.
  13. *NOTIMPLEMENTED
  14. *
  15. *Method#3:Disable/Enableinterruptsbypreservingthestateofinterrupts.Generallyspeakingyou
  16. *wouldstorethestateoftheinterruptdisableflaginthelocalvariable'cpu_sr'andthen
  17. *disableinterrupts.'cpu_sr'isallocatedinallofuC/OS-II'sfunctionsthatneedto
  18. *disableinterrupts.Youwouldrestoretheinterruptdisablestatebycopyingback'cpu_sr'
  19. *intotheCPU'sstatusregister.Thisisthepreferedmethodtodisableinterrupts.
  20. *********************************************************************************************************
  21. */
  22. #defineOS_CRITICAL_METHOD3
  23. #ifOS_CRITICAL_METHOD==3
  24. #defineOS_ENTER_CRITICAL()(cpu_sr=OSCPUSaveSR())/*Disableinterrupts*/
  25. #defineOS_EXIT_CRITICAL()(OSCPURestoreSR(cpu_sr))/*Restoreinterrupts*/
  26. #endif
  27. /*
  28. *********************************************************************************************************
  29. *ARMMiscellaneous
  30. *********************************************************************************************************
  31. */
  32. #defineOS_STK_GROWTH1/*StackgrowsfromHIGHtoLOWmemoryonARM*/
  33. #defineOS_TASK_SW()OSCtxSw()
/* ********************************************************************************************************* * ARM * * Method #1: NOT IMPLEMENTED * Disable/Enable interrupts using simple instructions. After critical section, interrupts * will be enabled even if they were disabled before entering the critical section. * * Method #2: NOT IMPLEMENTED * Disable/Enable interrupts by preserving the state of interrupts. In other words, if * interrupts were disabled before entering the critical section, they will be disabled when * leaving the critical section. * NOT IMPLEMENTED * * Method #3: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you * would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then * disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to * disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr' * into the CPU's status register. This is the prefered method to disable interrupts. ********************************************************************************************************* */ #define OS_CRITICAL_METHOD 3 #if OS_CRITICAL_METHOD == 3 #define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR()) /* Disable interrupts */ #define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr)) /* Restore interrupts */ #endif /* ********************************************************************************************************* * ARM Miscellaneous ********************************************************************************************************* */ #define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on ARM */ #define OS_TASK_SW() OSCtxSw()
对Os_cpu_c.c的修改:

  1. /*
  2. *********************************************************************************************************
  3. *uC/OS-II
  4. *TheReal-TimeKernel
  5. *
  6. *(c)Copyright1992-2003,Micrium,Inc.,Weston,FL
  7. *AllRightsReserved
  8. *
  9. *ARM9Port
  10. *
  11. *File:OS_CPU_C.C
  12. *********************************************************************************************************
  13. */
  14. //#defineOS_CPU_GLOBALS
  15. #include"ucos_ii.h"
  16. /*
  17. *********************************************************************************************************
  18. *INITIALIZEATASK'SSTACK
  19. *
  20. *Description:ThisfunctioniscalledbyeitherOSTaskCreate()orOSTaskCreateExt()toinitializethe
  21. *stackframeofthetaskbeingcreated.Thisfunctionishighlyprocessorspecific.
  22. *
  23. *Arguments:taskisapointertothetaskcode
  24. *
  25. *p_argisapointertoausersupplieddataareathatwillbepassedtothetask
  26. *whenthetaskfirstexecutes.
  27. *
  28. *ptosisapointertothetopofstack.Itisassumedthat'ptos'pointsto
  29. *a'free'entryonthetaskstack.IfOS_STK_GROWTHissetto1then
  30. *'ptos'willcontaintheHIGHESTvalidaddressofthestack.Similarly,if
  31. *OS_STK_GROWTHissetto0,the'ptos'willcontainstheLOWESTvalidaddress
  32. *ofthestack.
  33. *
  34. *optspecifiesoptionsthatcanbeusedtoalterthebehaviorofOSTaskStkInit().
  35. *(seeuCOS_II.HforOS_TASK_OPT_???).
  36. *
  37. *Returns:Alwaysreturnsthelocationofthenewtop-of-stack'oncetheprocessorregistershave
  38. *beenplacedonthestackintheproperorder.
  39. *
  40. *Note(s):1)Interruptsareenabledwhenyourtaskstartsexecuting.
  41. *2)AlltasksruninSVCmode.
  42. *********************************************************************************************************
  43. */
  44. OS_STK*OSTaskStkInit(void(*task)(void*pd),void*p_arg,OS_STK*ptos,INT16Uopt)
  45. {
  46. OS_STK*stk;
  47. optopt=opt;/*'opt'isnotused,preventwarning*/
  48. stk=ptos;/*Loadstackpointer*/
  49. *(stk)=(OS_STK)task;/*EntryPoint*/
  50. *(--stk)=(INT32U)0;/*LR*/
  51. *(--stk)=(INT32U)0;/*R12*/
  52. *(--stk)=(INT32U)0;/*R11*/
  53. *(--stk)=(INT32U)0;/*R10*/
  54. *(--stk)=(INT32U)0;/*R9*/
  55. *(--stk)=(INT32U)0;/*R8*/
  56. *(--stk)=(INT32U)0;/*R7*/
  57. *(--stk)=(INT32U)0;/*R6*/
  58. *(--stk)=(INT32U)0;/*R5*/
  59. *(--stk)=(INT32U)0;/*R4*/
  60. *(--stk)=(INT32U)0;/*R3*/
  61. *(--stk)=(INT32U)0;/*R2*/
  62. *(--stk)=(INT32U)0;/*R1*/
  63. *(--stk)=(INT32U)p_arg;/*R0:argument*/
  64. *(--stk)=(INT32U)0x00000013L;/*CPSR(SVCmode,EnablebothIRQandFIQinterrupts)*/
  65. return(stk);
  66. }
  67. #ifOS_CPU_HOOKS_EN
  68. /*
  69. *********************************************************************************************************
  70. *OSINITIALIZATIONHOOK
  71. *(BEGINNING)
  72. *
  73. *Description:ThisfunctioniscalledbyOSInit()atthebeginningofOSInit().
  74. *
  75. *Arguments:none
  76. *
  77. *Note(s):1)Interruptsshouldbedisabledduringthiscall.
  78. *********************************************************************************************************
  79. */
  80. #ifOS_VERSION>203
  81. voidOSInitHookBegin(void)
  82. {
  83. }
  84. #endif
  85. /*
  86. *********************************************************************************************************
  87. *OSINITIALIZATIONHOOK
  88. *(END)
  89. *
  90. *Description:ThisfunctioniscalledbyOSInit()attheendofOSInit().
  91. *
  92. *Arguments:none
  93. *
  94. *Note(s):1)Interruptsshouldbedisabledduringthiscall.
  95. *********************************************************************************************************
  96. */
  97. #ifOS_VERSION>203
  98. voidOSInitHookEnd(void)
  99. {
  100. }
  101. #endif
  102. /*
  103. *********************************************************************************************************
  104. *TASKCREATIONHOOK
  105. *
  106. *Description:Thisfunctioniscalledwhenataskiscreated.
  107. *
  108. *Arguments:ptcbisapointertothetaskcontrolblockofthetaskbeingcreated.
  109. *
  110. *Note(s):1)Interruptsaredisabledduringthiscall.
  111. *********************************************************************************************************
  112. */
  113. voidOSTaskCreateHook(OS_TCB*ptcb)
  114. {
  115. ptcbptcb=ptcb;/*Preventcompilerwarning*/
  116. }
  117. /*
  118. *********************************************************************************************************
  119. *TASKDELETIONHOOK
  120. *
  121. *Description:Thisfunctioniscalledwhenataskisdeleted.
  122. *
  123. *Arguments:ptcbisapointertothetaskcontrolblockofthetaskbeingdeleted.
  124. *
  125. *Note(s):1)Interruptsaredisabledduringthiscall.
  126. *********************************************************************************************************
  127. */
  128. voidOSTaskDelHook(OS_TCB*ptcb)
  129. {
  130. ptcbptcb=ptcb;/*Preventcompilerwarning*/
  131. }
  132. /*
  133. *********************************************************************************************************
  134. *TASKSWITCHHOOK
  135. *
  136. *Description:Thisfunctioniscalledwhenataskswitchisperformed.Thisallowsyoutoperformother
  137. *operationsduringacontextswitch.
  138. *
  139. *Arguments:none
  140. *
  141. *Note(s):1)Interruptsaredisabledduringthiscall.
  142. *2)Itisassumedthattheglobalpointer'OSTCBHighRdy'pointstotheTCBofthetaskthat
  143. *willbe'switchedin'(i.e.thehighestprioritytask)and,'OSTCBCur'pointstothe
  144. *taskbeingswitchedout(i.e.thepreemptedtask).
  145. *********************************************************************************************************
  146. */
  147. voidOSTaskSwHook(void)
  148. {
  149. }
  150. /*
  151. *********************************************************************************************************
  152. *STATISTICTASKHOOK
  153. *
  154. *Description:ThisfunctioniscalledeverysecondbyuC/OS-II'sstatisticstask.Thisallowsyour
  155. *applicationtoaddfunctionalitytothestatisticstask.
  156. *
  157. *Arguments:none
  158. *********************************************************************************************************
  159. */
  160. voidOSTaskStatHook(void)
  161. {
  162. }
  163. /*
  164. *********************************************************************************************************
  165. *OSTCBInit()HOOK
  166. *
  167. *Description:ThisfunctioniscalledbyOSTCBInit()aftersettingupmostoftheTCB.
  168. *
  169. *Arguments:ptcbisapointertotheTCBofthetaskbeingcreated.
  170. *
  171. *Note(s):1)InterruptsmayormaynotbeENABLEDduringthiscall.
  172. *********************************************************************************************************
  173. */
  174. #ifOS_VERSION>203
  175. voidOSTCBInitHook(OS_TCB*ptcb)
  176. {
  177. ptcbptcb=ptcb;/*PreventCompilerwarning*/
  178. }
  179. #endif
  180. /*
  181. *********************************************************************************************************
  182. *TICKHOOK
  183. *
  184. *Description:Thisfunctioniscalledeverytick.
  185. *
  186. *Arguments:none
  187. *
  188. *Note(s):1)InterruptsmayormaynotbeENABLEDduringthiscall.
  189. *********************************************************************************************************
  190. */
  191. voidOSTimeTickHook(void)
  192. {
  193. }
  194. /*
  195. *********************************************************************************************************
  196. *IDLETASKHOOK
  197. *
  198. *Description:Thisfunctioniscalledbytheidletask.Thishookhasbeenaddedtoallowyoutodo
  199. *suchthingsasSTOPtheCPUtoconservepower.
  200. *
  201. *Arguments:none
  202. *
  203. *Note(s):1)Interruptsareenabledduringthiscall.
  204. *********************************************************************************************************
  205. */
  206. #ifOS_VERSION>=251
  207. voidOSTaskIdleHook(void)
  208. {
  209. }
  210. #endif
  211. #endif
/* ********************************************************************************************************* * uC/OS-II * The Real-Time Kernel * * (c) Copyright 1992-2003, Micrium, Inc., Weston, FL * All Rights Reserved * * ARM9 Port * * File : OS_CPU_C.C ********************************************************************************************************* */ //#define OS_CPU_GLOBALS #include "ucos_ii.h" /* ********************************************************************************************************* * 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_???). * * 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 SVC mode. ********************************************************************************************************* */ OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt) { OS_STK *stk; opt = opt; /* 'opt' is not used, prevent warning */ stk = ptos; /* Load stack pointer */ *(stk) = (OS_STK)task; /* Entry Point */ *(--stk) = (INT32U)0; /* LR */ *(--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)p_arg; /* R0 : argument */ *(--stk) = (INT32U)0x00000013L; /* CPSR (SVC mode, Enable both IRQ and FIQ interrupts) */ return (stk); } #if OS_CPU_HOOKS_EN /* ********************************************************************************************************* * OS INITIALIZATION HOOK * (BEGINNING) * * Description: This function is called by OSInit() at the beginning of OSInit(). * * Arguments : none * * Note(s) : 1) Interrupts should be disabled during this call. ********************************************************************************************************* */ #if OS_VERSION > 203 void OSInitHookBegin (void) { } #endif /* ********************************************************************************************************* * OS INITIALIZATION HOOK * (END) * * Description: This function is called by OSInit() at the end of OSInit(). * * Arguments : none * * Note(s) : 1) Interrupts should be disabled during this call. ********************************************************************************************************* */ #if OS_VERSION > 203 void OSInitHookEnd (void) { } #endif /* ********************************************************************************************************* * TASK CREATION HOOK * * Description: This function is called when a task is created. * * Arguments : ptcb is a pointer to the task control block of the task being created. * * Note(s) : 1) Interrupts are disabled during this call. ********************************************************************************************************* */ void OSTaskCreateHook (OS_TCB *ptcb) { ptcb = ptcb; /* Prevent compiler warning */ } /* ********************************************************************************************************* * TASK DELETION HOOK * * Description: This function is called when a task is deleted. * * Arguments : ptcb is a pointer to the task control block of the task being deleted. * * Note(s) : 1) Interrupts are disabled during this call. ********************************************************************************************************* */ void OSTaskDelHook (OS_TCB *ptcb) { ptcb = ptcb; /* Prevent compiler warning */ } /* ********************************************************************************************************* * TASK SWITCH HOOK * * Description: This function is called when a task switch is performed. This allows you to perform other * operations during a context switch. * * Arguments : none * * Note(s) : 1) Interrupts are disabled during this call. * 2) It is assumed that the global pointer 'OSTCBHighRdy' points to the TCB of the task that * will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCur' points to the * task being switched out (i.e. the preempted task). ********************************************************************************************************* */ void OSTaskSwHook (void) { } /* ********************************************************************************************************* * STATISTIC TASK HOOK * * Description: This function is called every second by uC/OS-II's statistics task. This allows your * application to add functionality to the statistics task. * * Arguments : none ********************************************************************************************************* */ void OSTaskStatHook (void) { } /* ********************************************************************************************************* * OSTCBInit() HOOK * * Description: This function is called by OSTCBInit() after setting up most of the TCB. * * Arguments : ptcb is a pointer to the TCB of the task being created. * * Note(s) : 1) Interrupts may or may not be ENABLED during this call. ********************************************************************************************************* */ #if OS_VERSION > 203 void OSTCBInitHook (OS_TCB *ptcb) { ptcb = ptcb; /* Prevent Compiler warning */ } #endif /* ********************************************************************************************************* * TICK HOOK * * Description: This function is called every tick. * * Arguments : none * * Note(s) : 1) Interrupts may or may not be ENABLED during this call. ********************************************************************************************************* */ void OSTimeTickHook (void) { } /* ********************************************************************************************************* * IDLE TASK HOOK * * Description: This function is called by the idle task. This hook has been added to allow you to do * such things as STOP the CPU to conserve power. * * Arguments : none * * Note(s) : 1) Interrupts are enabled during this call. ********************************************************************************************************* */ #if OS_VERSION >= 251 void OSTaskIdleHook (void) { } #endif #endif
对Os_cpu_a.s的修改:

  1. ;*********************************************************************************************************
  2. ;uC/OS-II
  3. ;TheReal-TimeKernel
  4. ;
  5. ;(c)Copyright1992-2003,JeanJ.Labrosse,Weston,FL
  6. ;AllRightsReserved
  7. ;
  8. ;ARM920TPort
  9. ;ADSv1.2Compiler
  10. ;SamsungS3C2440A
  11. ;
  12. ;File:os_cpu_a.srefrencetoucosapplicationnoteforarmAN-1014
  13. ;Des:S3C2440uC/OS-IIPort
  14. ;by:tangxiaofengxidian503
  15. ;History:
  16. ;OSCtxSw(),OSIntCtxSw()OSStartHighRdy()OS_CPU_IRQ_ISR()OSTickISR()
  17. ;*********************************************************************************************************/
  18. SRCPNDEQU0x4a000000;Sourcepending
  19. INTPNDEQU0x4a000010;Interruptrequeststatus
  20. rEINTPENDEQU0x560000a8
  21. INTOFFSETEQU0x4a000014
  22. USERMODEEQU0x10
  23. FIQMODEEQU0x11
  24. IRQMODEEQU0x12
  25. SVCMODEEQU0x13
  26. ABORTMODEEQU0x17
  27. UNDEFMODEEQU0x1b
  28. MODEMASKEQU0x1f
  29. NOINTEQU0xc0
  30. ;*********************************************************************************************************
  31. ;EXPORTandEXTERNALREFERENCES
  32. ;*********************************************************************************************************/
  33. IMPORTOSRunning
  34. IMPORTOSTCBCur
  35. IMPORTOSTCBHighRdy
  36. IMPORTOSPrioCur
  37. IMPORTOSPrioHighRdy
  38. IMPORTOSIntNesting
  39. IMPORTOSIntEnter
  40. IMPORTOSIntExit
  41. IMPORTOSTaskSwHook
  42. IMPORTOSTimeTick
  43. IMPORTHandleEINT0
  44. EXPORTOSStartHighRdy
  45. EXPORTOSCtxSw
  46. EXPORTOSTickISR
  47. EXPORTOSIntCtxSw
  48. EXPORTOSCPUSaveSR
  49. EXPORTOSCPURestoreSR
  50. EXPORTOS_CPU_IRQ_ISR
  51. AREAUCOS_ARM,CODE,READONLY
  52. ;*********************************************************************************************************
  53. ;STARTMULTITASKING
  54. ;voidOSStartHighRdy(void)
  55. ;
  56. ;Thestackframeisassumedtolookasfollows:
  57. ;
  58. ;EntryPoint(TaskName)(Highmemory)
  59. ;LR(R14)
  60. ;R12
  61. ;R11
  62. ;R10
  63. ;R9
  64. ;R8
  65. ;R7
  66. ;R6
  67. ;R5
  68. ;R4
  69. ;R3
  70. ;R2
  71. ;R1
  72. ;R0:argument
  73. ;OSTCBHighRdy->OSTCBStkPtr-->CPSR(Lowmemory)
  74. ;
  75. ;Note:OSStartHighRdy()MUST:
  76. ;a)CallOSTaskSwHook()then,
  77. ;b)SetOSRunningtoTRUE,
  78. ;c)Switchtothehighestprioritytask.
  79. ;***********************************************************************************************************/
  80. OSStartHighRdy
  81. ;----------------------------------------------------------------------------------
  82. ;OSRunning=TRUE;
  83. ;----------------------------------------------------------------------------------
  84. MSRCPSR_cxsf,#SVCMODE|NOINT;SwitchtoSVCmodewithIRQ&FIQdisable
  85. BLOSTaskSwHook;CalluserdefineTaskswitchhook
  86. LDRR0,=OSRunning;OSRunning=TRUE
  87. MOVR1,#1
  88. STRBR1,[R0]
  89. ;----------------------------------------------------------------------------------
  90. ;SP=OSTCBHighRdy->OSTCBStkPtr;
  91. ;----------------------------------------------------------------------------------
  92. LDRR0,=OSTCBHighRdy
  93. LDRR0,[R0]
  94. LDRSP,[R0]
  95. ;----------------------------------------------------------------------------------
  96. ;Preparetoreturntopropermode
  97. ;----------------------------------------------------------------------------------
  98. LDMFDSP!,{R0}
  99. MSRSPSR_cxsf,R0
  100. LDMFDSP!,{R0-R12,LR,PC}^
  101. ;**********************************************************************************************************
  102. ;PERFORMACONTEXTSWITCH(Fromtasklevel)
  103. ;voidOSCtxSw(void)
  104. ;
  105. ;Note(s):1)Uponentry:
  106. ;OSTCBCurpointstotheOS_TCBofthetasktosuspend
  107. ;OSTCBHighRdypointstotheOS_TCBofthetasktoresume
  108. ;
  109. ;2)Thestackframeofthetasktosuspendlooksasfollows:
  110. ;
  111. ;PC(Highmemory)
  112. ;LR(R14)
  113. ;R12
  114. ;R11
  115. ;R10
  116. ;R9
  117. ;R8
  118. ;R7
  119. ;R6
  120. ;R5
  121. ;R4
  122. ;R3
  123. ;R2
  124. ;R1
  125. ;R0
  126. ;OSTCBCur->OSTCBStkPtr---->CPSR(Lowmemory)
  127. ;
  128. ;
  129. ;3)Thestackframeofthetasktoresumelooksasfollows:
  130. ;
  131. ;PC(Highmemory)
  132. ;LR(R14)
  133. ;R12
  134. ;R11
  135. ;R10
  136. ;R9
  137. ;R8
  138. ;R7
  139. ;R6
  140. ;R5
  141. ;R4
  142. ;R3
  143. ;R2
  144. ;R1
  145. ;R0
  146. ;OSTCBHighRdy->OSTCBStkPtr---->CPSR(Lowmemory)
  147. ;*********************************************************************************************************/
  148. OSCtxSw
  149. STMFDSP!,{LR};PC
  150. STMFDSP!,{R0-R12,LR};R0-R12LR
  151. MRSR0,CPSR;PushCPSR
  152. STMFDSP!,{R0}
  153. ;----------------------------------------------------------------------------------
  154. ;OSTCBCur->OSTCBStkPtr=SP
  155. ;----------------------------------------------------------------------------------
  156. LDRR0,=OSTCBCur
  157. LDRR0,[R0]
  158. STRSP,[R0]
  159. ;----------------------------------------------------------------------------------
  160. ;OSTaskSwHook();
  161. ;---------------------------------------------------------------------------------
  162. BLOSTaskSwHook
  163. ;----------------------------------------------------------------------------------
  164. ;OSTCBCur=OSTCBHighRdy;
  165. ;----------------------------------------------------------------------------------
  166. LDRR0,=OSTCBHighRdy
  167. LDRR1,=OSTCBCur
  168. LDRR0,[R0]
  169. STRR0,[R1]
  170. ;----------------------------------------------------------------------------------
  171. ;OSPrioCur=OSPrioHighRdy;
  172. ;----------------------------------------------------------------------------------
  173. LDRR0,=OSPrioHighRdy
  174. LDRR1,=OSPrioCur
  175. LDRBR0,[R0]
  176. STRBR0,[R1]
  177. ;----------------------------------------------------------------------------------
  178. ;OSTCBHighRdy->OSTCBStkPtr;
  179. ;----------------------------------------------------------------------------------
  180. LDRR0,=OSTCBHighRdy
  181. LDRR0,[R0]
  182. LDRSP,[R0]
  183. ;----------------------------------------------------------------------------------
  184. ;RestoreNewtaskcontext
  185. ;----------------------------------------------------------------------------------
  186. LDMFDSP!,{R0};POPCPSR
  187. MSRSPSR_cxsf,R0
  188. LDMFDSP!,{R0-R12,LR,PC}^
  189. ;*********************************************************************************************************
  190. ;TICKHANDLER
  191. ;
  192. ;Description:
  193. ;ThishandlesalltheTimer0(INT_TIMER0)interruptwhichisusedtogeneratetheuC/OS-IItick.
  194. ;*********************************************************************************************************/
  195. OSTickISR
  196. MOVR5,LR
  197. MOVR1,#1
  198. MOVR1,R1,LSL#10;Timer0SourcePendingReg.
  199. LDRR0,=SRCPND
  200. LDRR2,[R0]
  201. ORRR1,R1,R2
  202. STRR1,[R0]
  203. LDRR0,=INTPND
  204. LDRR1,[R0]
  205. STRR1,[R0]
  206. ;----------------------------------------------------------------------------------
  207. ;OSTimeTick();
  208. ;----------------------------------------------------------------------------------
  209. BLOSTimeTick
  210. MOVPC,R5;Return
  211. ;*********************************************************************************************************
  212. ;PERFORMACONTEXTSWITCH(FromanISR)
  213. ;voidOSIntCtxSw(void)
  214. ;
  215. ;Description:1)Thiscodeperformsacontextswitchifahigherprioritytaskhasbeenmadeready-to-run
  216. ;duringanISR.
  217. ;
  218. ;2)Thestackframeofthetasktosuspendlooksasfollows:
  219. ;
  220. ;PC(Highmemory)
  221. ;LR(R14)
  222. ;R12
  223. ;R11
  224. ;R10
  225. ;R9
  226. ;R8
  227. ;R7
  228. ;R6
  229. ;R5
  230. ;R4
  231. ;R3
  232. ;R2
  233. ;R1
  234. ;R0
  235. ;
  236. ;OSTCBCur->OSTCBStkPtr---->CPSR(Lowmemory)
  237. ;
  238. ;
  239. ;3)Thestackframeofthetasktoresumelooksasfollows:
  240. ;
  241. ;PC(Highmemory)
  242. ;LR(R14)
  243. ;R12
  244. ;R11
  245. ;R10
  246. ;R9
  247. ;R8
  248. ;R7
  249. ;R6
  250. ;R5
  251. ;R4
  252. ;R3
  253. ;R2
  254. ;R1
  255. ;R0
  256. ;OSTCBHighRdy->OSTCBStkPtr---->CPSR(Lowmemory)
  257. ;*********************************************************************************************************/
  258. OSIntCtxSw
  259. ;----------------------------------------------------------------------------------
  260. ;CallOSTaskSwHook();
  261. ;----------------------------------------------------------------------------------
  262. BLOSTaskSwHook
  263. ;----------------------------------------------------------------------------------
  264. ;OSTCBCur=OSTCBHighRdy;
  265. ;----------------------------------------------------------------------------------
  266. LDRR0,=OSTCBHighRdy
  267. LDRR1,=OSTCBCur
  268. LDRR0,[R0]
  269. STRR0,[R1]
  270. ;----------------------------------------------------------------------------------
  271. ;OSPrioCur=OSPrioHighRdy;
  272. ;----------------------------------------------------------------------------------
  273. LDRR0,=OSPrioHighRdy
  274. LDRR1,=OSPrioCur
  275. LDRBR0,[R0]
  276. STRBR0,[R1]
  277. ;----------------------------------------------------------------------------------
  278. ;SP=OSTCBHighRdy->OSTCBStkPtr;
  279. ;----------------------------------------------------------------------------------
  280. LDRR0,=OSTCBHighRdy
  281. LDRR0,[R0]
  282. LDRSP,[R0]
  283. ;----------------------------------------------------------------------------------
  284. ;RestoreNewTaskcontext
  285. ;----------------------------------------------------------------------------------
  286. LDMFDSP!,{R0};POPCPSR
  287. MSRSPSR_cxsf,R0
  288. LDMFDSP!,{R0-R12,LR,PC}^
  289. OS_CPU_IRQ_ISR
  290. STMFDSP!,{R1-R3};WewilluseR1-R3astemporaryregisters
  291. ;----------------------------------------------------------------------------
  292. ;R1--SP
  293. ;R2--PC
  294. ;R3--SPSR
  295. ;------------------------------------------------------------------------
  296. MOVR1,SP
  297. ADDSP,SP,#12;AdjustIRQstackpointer
  298. SUBR2,LR,#4;AdjustPCforreturnaddresstotask
  299. MRSR3,SPSR;CopySPSR(TaskCPSR)
  300. MSRCPSR_cxsf,#SVCMODE|NOINT;ChangetoSVCmode
  301. ;SAVETASK''SCONTEXTONTOOLDTASK''SSTACK
  302. STMFDSP!,{R2};Pushtask''sPC
  303. STMFDSP!,{R4-R12,LR};Pushtask''sLR,R12-R4
  304. LDMFDR1!,{R4-R6};LoadTask''sR1-R3fromIRQstack
  305. STMFDSP!,{R4-R6};PushTask''sR1-R3toSVCstack
  306. STMFDSP!,{R0};PushTask''sR0toSVCstack
  307. STMFDSP!,{R3};Pushtask''sCPSR
  308. LDRR0,=OSIntNesting;OSIntNesting++
  309. LDRBR1,[R0]
  310. ADDR1,R1,#1
  311. STRBR1,[R0]
  312. CMPR1,#1;if(OSIntNesting==1){
  313. BNE%F1
  314. LDRR4,=OSTCBCur;OSTCBHighRdy->OSTCBStkPtr=SP;
  315. LDRR5,[R4]
  316. STRSP,[R5];}
  317. 1
  318. MSRCPSR_c,#IRQMODE|NOINT;ChangetoIRQmodetouseIRQstacktohandleinterrupt
  319. LDRR0,=INTOFFSET
  320. LDRR0,[R0]
  321. LDRR1,IRQIsrVect
  322. MOVLR,PC;SaveLRbeforjumptotheCfunctionweneedreturnback
  323. LDRPC,[R1,R0,LSL#2];CallOS_CPU_IRQ_ISR_handler();
  324. MSRCPSR_c,#SVCMODE|NOINT;ChangetoSVCmode
  325. BLOSIntExit;CallOSIntExit
  326. LDMFDSP!,{R4};POPthetask''sCPSR
  327. MSRSPSR_cxsf,R4
  328. LDMFDSP!,{R0-R12,LR,PC}^;POPnewTask''scontext
  329. IRQIsrVectDCDHandleEINT0
  330. ;*********************************************************************************************************
  331. ;CRITICALSECTIONMETHOD3FUNCTIONS
  332. ;
  333. ;Description:Disable/Enableinterruptsbypreservingthestateofinterrupts.Generallyspeakingyou
  334. ;wouldstorethestateoftheinterruptdisableflaginthelocalvariable'cpu_sr'andthen
  335. ;disableinterrupts.'cpu_sr'isallocatedinallofuC/OS-II''sfunctionsthatneedto
  336. ;disableinterrupts.Youwouldrestoretheinterruptdisablestatebycopyingback'cpu_sr'
  337. ;intotheCPU''sstatusregister.
  338. ;
  339. ;Prototypes:OS_CPU_SROSCPUSaveSR(void);
  340. ;voidOSCPURestoreSR(OS_CPU_SRcpu_sr);
  341. ;
  342. ;
  343. ;Note(s):1)Thesefunctionsareusedingenerallikethis:
  344. ;
  345. ;voidTask(void*p_arg)
  346. ;{
  347. ;#ifOS_CRITICAL_METHOD==3/*AllocatestorageforCPUstatusregister*/
  348. ;OS_CPU_SRcpu_sr;
  349. ;#endif
  350. ;
  351. ;:
  352. ;:
  353. ;OS_ENTER_CRITICAL();/*cpu_sr=OSCPUSaveSR();*/
  354. ;:
  355. ;:
  356. ;OS_EXIT_CRITICAL();/*OSCPURestoreSR(cpu_sr);*/
  357. ;:
  358. ;:
  359. ;}
  360. ;
  361. ;2)OSCPUSaveSR()isimplementedasrecommendedbyAtmel''sapplicationnote:
  362. ;
  363. ;"DisablingInterruptsatProcessorLevel"
  364. ;*********************************************************************************************************
  365. OSCPUSaveSR
  366. MRSR0,CPSR;SetIRQandFIQbitsinCPSRtodisableallinterrupts
  367. ORRR1,R0,#0xC0
  368. MSRCPSR_c,R1
  369. MRSR1,CPSR;ConfirmthatCPSRcontainstheproperinterruptdisableflags
  370. ANDR1,R1,#0xC0
  371. CMPR1,#0xC0
  372. BNEOSCPUSaveSR;Notproperlydisabled(tryagain)
  373. MOVPC,LR;Disabled,returntheoriginalCPSRcontentsinR0
  374. OSCPURestoreSR
  375. MSRCPSR_c,R0
  376. MOVPC,LR
  377. END
;********************************************************************************************************* ; uC/OS-II ; The Real-Time Kernel ; ; (c) Copyright 1992-2003, Jean J. Labrosse, Weston, FL ; All Rights Reserved ; ; ARM920T Port ; ADS v1.2 Compiler ; Samsung S3C2440A ; ; File : os_cpu_a.s refrence to ucos application note for arm AN-1014 ; Des : S3C2440 uC/OS-II Port ; by : tangxiaofeng xidian 503 ; History : ; OSCtxSw(), OSIntCtxSw() OSStartHighRdy() OS_CPU_IRQ_ISR() OSTickISR() ;******************************************************************************************************** */ SRCPND EQU 0x4a000000 ; Source pending INTPND EQU 0x4a000010 ; Interrupt request status rEINTPEND EQU 0x560000a8 INTOFFSET EQU 0x4a000014 USERMODE EQU 0x10 FIQMODE EQU 0x11 IRQMODE EQU 0x12 SVCMODE EQU 0x13 ABORTMODE EQU 0x17 UNDEFMODE EQU 0x1b MODEMASK EQU 0x1f NOINT EQU 0xc0 ;********************************************************************************************************* ; EXPORT and EXTERNAL REFERENCES ;*********************************************************************************************************/ IMPORT OSRunning IMPORT OSTCBCur IMPORT OSTCBHighRdy IMPORT OSPrioCur IMPORT OSPrioHighRdy IMPORT OSIntNesting IMPORT OSIntEnter IMPORT OSIntExit IMPORT OSTaskSwHook IMPORT OSTimeTick IMPORT HandleEINT0 EXPORT OSStartHighRdy EXPORT OSCtxSw EXPORT OSTickISR EXPORT OSIntCtxSw EXPORT OSCPUSaveSR EXPORT OSCPURestoreSR EXPORT OS_CPU_IRQ_ISR AREA UCOS_ARM, CODE, READONLY ;********************************************************************************************************* ; START MULTITASKING ; void OSStartHighRdy(void) ; ; The stack frame is assumed to look as follows: ; ; Entry Point(Task Name) (High memory) ; LR(R14) ; R12 ; R11 ; R10 ; R9 ; R8 ; R7 ; R6 ; R5 ; R4 ; R3 ; R2 ; R1 ; R0 : argument ; OSTCBHighRdy->OSTCBStkPtr --> CPSR (Low memory) ; ; Note : OSStartHighRdy() MUST: ; a) Call OSTaskSwHook() then, ; b) Set OSRunning to TRUE, ; c) Switch to the highest priority task. ;********************************************************************************************************** */ OSStartHighRdy ;---------------------------------------------------------------------------------- ; OSRunning = TRUE; ;---------------------------------------------------------------------------------- MSR CPSR_cxsf,#SVCMODE|NOINT ;Switch to SVC mode with IRQ&FIQ disable BL OSTaskSwHook ;Call user define Task switch hook LDR R0, =OSRunning ; OSRunning =TRUE MOV R1, #1 STRB R1, [R0] ;---------------------------------------------------------------------------------- ; SP = OSTCBHighRdy->OSTCBStkPtr; ;---------------------------------------------------------------------------------- LDR R0, =OSTCBHighRdy LDR R0, [R0] LDR SP, [R0] ;---------------------------------------------------------------------------------- ; Prepare to return to proper mode ;---------------------------------------------------------------------------------- LDMFD SP!, {R0} MSR SPSR_cxsf, R0 LDMFD SP!, {R0-R12, LR, PC}^ ;********************************************************************************************************** ; PERFORM A CONTEXT SWITCH (From task level) ; void OSCtxSw(void) ; ; Note(s): 1) Upon entry: ; OSTCBCur points to the OS_TCB of the task to suspend ; OSTCBHighRdy points to the OS_TCB of the task to resume ; ; 2) The stack frame of the task to suspend looks as follows: ; ; PC (High memory) ; LR(R14) ; R12 ; R11 ; R10 ; R9 ; R8 ; R7 ; R6 ; R5 ; R4 ; R3 ; R2 ; R1 ; R0 ; OSTCBCur->OSTCBStkPtr ----> CPSR (Low memory) ; ; ; 3) The stack frame of the task to resume looks as follows: ; ; PC (High memory) ; LR(R14) ; R12 ; R11 ; R10 ; R9 ; R8 ; R7 ; R6 ; R5 ; R4 ; R3 ; R2 ; R1 ; R0 ; OSTCBHighRdy->OSTCBStkPtr ----> CPSR (Low memory) ;*********************************************************************************************************/ OSCtxSw STMFD SP!, {LR} ;PC STMFD SP!, {R0-R12, LR} ;R0-R12 LR MRS R0, CPSR ;Push CPSR STMFD SP!, {R0} ;---------------------------------------------------------------------------------- ; OSTCBCur->OSTCBStkPtr = SP ;---------------------------------------------------------------------------------- LDR R0, =OSTCBCur LDR R0, [R0] STR SP, [R0] ;---------------------------------------------------------------------------------- ; OSTaskSwHook(); ;--------------------------------------------------------------------------------- BL OSTaskSwHook ;---------------------------------------------------------------------------------- ; OSTCBCur = OSTCBHighRdy; ;---------------------------------------------------------------------------------- LDR R0, =OSTCBHighRdy LDR R1, =OSTCBCur LDR R0, [R0] STR R0, [R1] ;---------------------------------------------------------------------------------- ; OSPrioCur = OSPrioHighRdy; ;---------------------------------------------------------------------------------- LDR R0, =OSPrioHighRdy LDR R1, =OSPrioCur LDRB R0, [R0] STRB R0, [R1] ;---------------------------------------------------------------------------------- ; OSTCBHighRdy->OSTCBStkPtr; ;---------------------------------------------------------------------------------- LDR R0, =OSTCBHighRdy LDR R0, [R0] LDR SP, [R0] ;---------------------------------------------------------------------------------- ;Restore New task context ;---------------------------------------------------------------------------------- LDMFD SP!, {R0} ;POP CPSR MSR SPSR_cxsf, R0 LDMFD SP!, {R0-R12, LR, PC}^ ;********************************************************************************************************* ; TICK HANDLER ; ; Description: ; This handles all the Timer0(INT_TIMER0) interrupt which is used to generate the uC/OS-II tick. ;*********************************************************************************************************/ OSTickISR MOV R5,LR MOV R1, #1 MOV R1, R1, LSL #10 ; Timer0 Source Pending Reg. LDR R0, =SRCPND LDR R2, [R0] ORR R1, R1,R2 STR R1, [R0] LDR R0, =INTPND LDR R1, [R0] STR R1, [R0] ;---------------------------------------------------------------------------------- ; OSTimeTick(); ;---------------------------------------------------------------------------------- BL OSTimeTick MOV PC, R5 ; Return ;********************************************************************************************************* ; PERFORM A CONTEXT SWITCH (From an ISR) ; void OSIntCtxSw(void) ; ; Description: 1) This code performs a context switch if a higher priority task has been made ready-to-run ; during an ISR. ; ; 2) The stack frame of the task to suspend looks as follows: ; ; PC (High memory) ; LR(R14) ; R12 ; R11 ; R10 ; R9 ; R8 ; R7 ; R6 ; R5 ; R4 ; R3 ; R2 ; R1 ; R0 ; ; OSTCBCur->OSTCBStkPtr ----> CPSR (Low memory) ; ; ; 3) The stack frame of the task to resume looks as follows: ; ; PC (High memory) ; LR(R14) ; R12 ; R11 ; R10 ; R9 ; R8 ; R7 ; R6 ; R5 ; R4 ; R3 ; R2 ; R1 ; R0 ; OSTCBHighRdy->OSTCBStkPtr ----> CPSR (Low memory) ;*********************************************************************************************************/ OSIntCtxSw ;---------------------------------------------------------------------------------- ; Call OSTaskSwHook(); ;---------------------------------------------------------------------------------- BL OSTaskSwHook ;---------------------------------------------------------------------------------- ; OSTCBCur = OSTCBHighRdy; ;---------------------------------------------------------------------------------- LDR R0, =OSTCBHighRdy LDR R1, =OSTCBCur LDR R0, [R0] STR R0, [R1] ;---------------------------------------------------------------------------------- ; OSPrioCur = OSPrioHighRdy; ;---------------------------------------------------------------------------------- LDR R0, =OSPrioHighRdy LDR R1, =OSPrioCur LDRB R0, [R0] STRB R0, [R1] ;---------------------------------------------------------------------------------- ; SP = OSTCBHighRdy->OSTCBStkPtr; ;---------------------------------------------------------------------------------- LDR R0, =OSTCBHighRdy LDR R0, [R0] LDR SP, [R0] ;---------------------------------------------------------------------------------- ; Restore New Task context ;---------------------------------------------------------------------------------- LDMFD SP!, {R0} ;POP CPSR MSR SPSR_cxsf, R0 LDMFD SP!, {R0-R12, LR, PC}^ OS_CPU_IRQ_ISR STMFD SP!, {R1-R3} ; We will use R1-R3 as temporary registers ;---------------------------------------------------------------------------- ; R1--SP ; R2--PC ; R3--SPSR ;------------------------------------------------------------------------ MOV R1, SP ADD SP, SP, #12 ;Adjust IRQ stack pointer SUB R2, LR, #4 ;Adjust PC for return address to task MRS R3, SPSR ; Copy SPSR (Task CPSR) MSR CPSR_cxsf, #SVCMODE|NOINT ;Change to SVC mode ; SAVE TASK''S CONTEXT ONTO OLD TASK''S STACK STMFD SP!, {R2} ; Push task''s PC STMFD SP!, {R4-R12, LR} ; Push task''s LR,R12-R4 LDMFD R1!, {R4-R6} ; Load Task''s R1-R3 from IRQ stack STMFD SP!, {R4-R6} ; Push Task''s R1-R3 to SVC stack STMFD SP!, {R0} ; Push Task''s R0 to SVC stack STMFD SP!, {R3} ; Push task''s CPSR LDR R0,=OSIntNesting ;OSIntNesting++ LDRB R1,[R0] ADD R1,R1,#1 STRB R1,[R0] CMP R1,#1 ;if(OSIntNesting==1){ BNE %F1 LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP; LDR R5,[R4] STR SP,[R5] ;} 1 MSR CPSR_c,#IRQMODE|NOINT ;Change to IRQ mode to use IRQ stack to handle interrupt LDR R0, =INTOFFSET LDR R0, [R0] LDR R1, IRQIsrVect MOV LR, PC ; Save LR befor jump to the C function we need return back LDR PC, [R1, R0, LSL #2] ; Call OS_CPU_IRQ_ISR_handler(); MSR CPSR_c,#SVCMODE|NOINT ;Change to SVC mode BL OSIntExit ;Call OSIntExit LDMFD SP!,{R4} ;POP the task''s CPSR MSR SPSR_cxsf,R4 LDMFD SP!,{R0-R12,LR,PC}^ ;POP new Task''s context IRQIsrVect DCD HandleEINT0 ;********************************************************************************************************* ; CRITICAL SECTION METHOD 3 FUNCTIONS ; ; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you ; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then ; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II''s functions that need to ; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr' ; into the CPU''s status register. ; ; Prototypes : OS_CPU_SR OSCPUSaveSR(void); ; void OSCPURestoreSR(OS_CPU_SR cpu_sr); ; ; ; Note(s) : 1) These functions are used in general like this: ; ; void Task (void *p_arg) ; { ; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ ; OS_CPU_SR cpu_sr; ; #endif ; ; : ; : ; OS_ENTER_CRITICAL(); /* cpu_sr = OSCPUSaveSR(); */ ; : ; : ; OS_EXIT_CRITICAL(); /* OSCPURestoreSR(cpu_sr); */ ; : ; : ; } ; ; 2) OSCPUSaveSR() is implemented as recommended by Atmel''s application note: ; ; "Disabling Interrupts at Processor Level" ;********************************************************************************************************* OSCPUSaveSR MRS R0, CPSR ; Set IRQ and FIQ bits in CPSR to disable all interrupts ORR R1, R0, #0xC0 MSR CPSR_c, R1 MRS R1, CPSR ; Confirm that CPSR contains the proper interrupt disable flags AND R1, R1, #0xC0 CMP R1, #0xC0 BNE OSCPUSaveSR ; Not properly disabled (try again) MOV PC, LR ; Disabled, return the original CPSR contents in R0 OSCPURestoreSR MSR CPSR_c, R0 MOV PC, LR END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值