打造自己的rtos(Build your own RTOS)_第1页
打造自己的rtos(Build your own RTOS)_第2页
打造自己的rtos(Build your own RTOS)_第3页
打造自己的rtos(Build your own RTOS)_第4页
打造自己的rtos(Build your own RTOS)_第5页
已阅读5页,还剩22页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、打造自己的rtos(Build your own RTOS)I was learning to write good in the top, I will continue to reissue back Chapter 1: function runningChapter 1: function runningIn general SCM system, it is the method of backstage (large cycle + interrupt) to process data and react.Examples are as follows:Makefile setti

2、ngs: run WinAvr in Mfile, set as followsMCU Type: MEGA8Optimization level: sDebug format: AVR-COFFC/C+ source file: selects the C file to be compiled#include Void fun1 (void)Unsigned char i=0;While (1)PORTB=i+;PORTC=0x01 (i%8);Int main (void)Fun1 ();First, ask a question: if you want to call a funct

3、ion, is it really going to be just the way it is?I believe learning C language you will answer, No! We have a way of using the function pointer variable function calls, if you are like me, the original textbook is Mr. Tan Haoqiangs C program design of the word, please find the books section 9.5.Exam

4、ple: call function with function pointer variable#include Void fun1 (void)Unsigned char i=0;While (1)PORTB=i+;PORTC=0x01 (i%8);Void (*pfun) (); / / pointer to functionInt main (void)Pfun=fun1; / /(*pfun); / / function pointerThe second is to refer to pointer variables pointing to functions as functi

5、on arguments#include Void fun1 (void)Unsigned char i=0;While (1)PORTB=i+;PORTC=0x01 (i%8);Void RunFun (void) (*pfun) (/ /) function is obtained to transfer address(*pfun); / / RunFun, function pointerInt main (void)RunFun (fun1); / / the function pointer passed as a variableLooking at the above two

6、ways, many people might say, its really good, but what does it have to do with the RTOS we want? Ladies and gentlemen, please look down carefully.Here is how GCC compiled the above code:The compilation of RunFun (fun1) in main () is as followsLDI, R24, lo8 (PM (fun1)LDI, R25, Hi8 (PM (fun1)Rcall Run

7、FunThe compilation of void RunFun (void (*pfun) is as follows/*void RunFun (void) (*pfun) (*)(*pfun); / * * /.LM6:Movw, R30, R24IcallRetWhen you call void RunFun (void (*pfun), you can really pass the address of fun1 through R24 and R25 to RunFun (). But how can RTOS effectively use the address of t

8、he function?- second: artificial stackOn the MCU, a class instruction is specially with the stack and the PC pointer of the road, they areRcall relative Call Subroutine instructionIcall indirect Call Subroutine instructionsRET subroutine return instructionReti interrupt return instructionFor RET and

9、 reti, they can be used to eject two bytes from the top of the stack top into the program counter PC, which are generally used to exit from subroutines or interrupts. Among them, reti can also restart the global interrupt enable when the interruption is interrupted.With this foundation, we can build

10、 our artificial stack.Cases:#include Void fun1 (void)Unsigned char i=0;While (1)PORTB=i+;PORTC=0x018); / / function high stack address,*pStack-= (unsigned int pfun); / / function low stack address,SP=pStack; / / the stack pointer to the artificial stack_asm_ _volatile_ (RET nt); / / return and break

11、s, running fun1 ()Int main (void)RunFunInNewStack (fun1, &Stack99);RunFunInNewStack () saves the value of the pointer to the function to an array of unsigned char Stack as the artificial stack. And pass the top value of the stack to the stack pointer SP, so when the RET is returned, the value return

12、ed from SP to the PC is changed to point to the address of fun1 (), and the fun1 () is startedIn the example above, the assembler code RET is embedded in the last sentence of RunFunInNewStack (), which can actually be removed. Because when RunFunInNewStack () returns, the compiler already adds RET.

13、I wrote it specifically to show you the process of running fun1 () with RET as a return.Third: the allocation and use of registers in GCCIn many RTOS applications for AVR, when you have task scheduling, insert the following statement:Stack entry:_asm_ _volatile_ (PUSH R0 nt);_asm_ _volatile_ (PUSH R

14、1 nt);._asm_ _volatile_ (PUSH R31 nt);The stack_asm_ _volatile_ (POP R31 nt);._asm_ _volatile_ (POP R1 nt);_asm_ _volatile_ (POP R0 nt);It is generally assumed that at the start of task scheduling, of course, all general-purpose registers are stored, and the program status register SREG should be sa

15、ved. Then, in the reverse order, the contents of the register of the new task are restored.But is that really the case? If you have read the small rots51 written by Mr. Chen Mingji, you will find that the general-purpose register it holds is only the 1 set of 4 sets of general-purpose registers.In t

16、he Win AVR in avr-libc Manual Related help file in the Pages Frequently Asked Questions, in fact, there is a problem is What registers are used by the C Compiler? answered the registers are used by the compiler. In general, the compiler uses the following registers1, Call-used, registers (r18-r27, r

17、30-r31): the function is passed as a parameter, that is, the most used register.2, Call-saved, registers (r2-r17, r28-r29): when calling a function, passing as a result,The R28 and R29 in it may be used as pointers to variables on the stack.3, Fixed, registers (R0, R1): fixed action. R0 is used to s

18、tore temporary data, and R1 is used to store 0.Another problem is the How to permanently bind variable to a register a, which is the method of binding variables to a general register. And I found that if a register is defined as a variable, the compiler does not assign the register to other uses. Th

19、ats important for RTOS.In the Inline Asm, C Names Used in Assembler Code explicitly states that if too many general-purpose registers are defined as variables, the variables that are defined in the compilation process are still likely to be taken by the compiler.You can compare the following two exa

20、mples to see the compiler generated code: (in the *.lst file)First example: no general register is defined as a variable#include Unsigned, char, add (unsigned, char, B, unsigned, char, C, unsigned, char, d)Return b+c*d;Int main (void)Unsigned char a=0;While (1)A+;PORTB=add (a, a, a);In this case, ad

21、d (a, a, a) is compiled as follows:MOV, R20, R28MOV, R22, R28MOV, R24, R28Rcall addThe second example: defining a universal register as a variable#include Unsigned, char, add (unsigned, char, B, unsigned, char, C, unsigned, char, d)Return b+c*d;Register unsigned char a ASM (R20); / / define R20 as a

22、 variablesInt main (void)While (1)A+;PORTB=add (a, a, a);In this case, add (a, a, a) is compiled as follows:MOV, R22, R20MOV, R24, R20Rcall addOf course, in the two examples above, some of the code is optimized by the compiler.Through repeated tests, it is found that the compiler generally uses the

23、following registers:First types of registers, second classes of registers, R28, R29, and third classes of registersIf there is a call base in the interrupt function, the function will just insert the first class registers and third kinds of registers into the stack after entering the interrupt, and

24、then they will be out of the stack when they are out of the interrupt.Fourth: the collaborative kernel Cooperative Multitasking, which has only a delayed serviceBefore and after system, collaborative kernel system, and preemptive kernel system, what is different?Remember this parable in * * *, you (

25、small) in the toilet, the manager ranked first on the outside, the boss in the outside row second. If the front and back, no matter who it is, must be according to the queuing order to use the toilet; if it is cooperative, so you can use the toilet, the boss will first enter the manager than preempt

26、ive; if it is, as long as there are more senior people waiting outside the toilet, so no matter who will be the first time let it out, let the person with the highest level.#include #include #include Unsigned char Stack200;Register unsigned char OSRdyTbl ASM (R2); / / task ready listRegister unsigne

27、d char OSTaskRunningPrio ASM (R3); / / running tasks#define OS_TASKS 3 / set number of running tasks结构taskctrblock /任务控制块unsigned int ostaskstacktop;/ /保存任务的堆栈顶unsigned int oswaittick;/ /任务延时时钟 TCB os_tasks + 1 ;/ /防止被编译器占用登记unsigned char tempr4 ASM(“R4”);登记unsigned char tempr5 ASM(“R5”);登记unsigned

28、char tempr6 ASM(“R6”);登记unsigned char tempr7 ASM(“R7”);登记unsigned char tempr8 ASM(“R8”);登记unsigned char tempr9 ASM(“R9”);登记unsigned char tempr10 ASM(“R10”);登记unsigned char tempr11 ASM(“工”);登记unsigned char tempr12 ASM(“R12”);登记unsigned char tempr13 ASM(“R13”);登记unsigned char tempr14 ASM(“R14”);登记unsi

29、gned char tempr15 ASM(“R15”);登记unsigned char tempr16 ASM(“R16”);登记unsigned char tempr17 ASM(“R17”);/ /建立任务无效ostaskcreate(void(*任务)(void),unsigned char *堆栈,unsigned char taskId)未签名字符;*栈- =(unsigned int)任务 8;/ /将任务的地址高位压入堆栈*栈- =(unsigned int)/将任务的地址低位压入堆栈任务;*栈- = 0x00;/ / R1 _zero_reg_*栈- = 0x00;/ / R

30、0 _tmp_reg_*栈- = 0x80;/ SREG在任务中,开启全局中断为(i = 0;i 14;i+)/在AVR libc中的FAQ中的哪些寄存器是由C编译器使用?*栈- =我;/ /描述了寄存器的作用TCB taskId 。ostaskstacktop =(unsigned int)栈;/ /将人工堆栈的栈顶,保存到堆栈的数组中osrdytbl | = 0x01 taskId;/ /任务就绪表已经准备好/ /开始任务调度,从最低优先级的任务的开始无效osstarttask()ostaskrunningprio = os_tasks;SP = TCB os_tasks 。ostasks

31、tacktop + 17;_asm_ _volatile_(“RETI”n“T”);/ /进行任务调度ossched虚空(void) /根据中断时保存寄存器的次序入栈,模拟一次中断后,入栈的情况_asm_ _volatile_(“推_zero_reg_ nn T”);/ / R1_asm_ _volatile_(“推_tmp_reg_ nn T”);/ / R0_asm_ _volatile_(“_tmp_reg_,_sreg_ nn T”);/ /保存状态寄存器SREG_asm_ _volatile_(“推_tmp_reg_ nn T”);_asm_ _volatile_(“CLR _zer

32、o_reg_ nn T”);/ / R0重新清零_asm_ _volatile_(“推R18 nn T”);_asm_ _volatile_(“推R19 nn T”);_asm_ _volatile_(“推R20 nn T”);_ _ asm _ _ _ _ volatile _ _ (push r21 n t);_ _ asm _ _ _ _ volatile _ _ (push r22 n t);_ _ asm _ _ _ _ volatile _ _ (push r23 n t);_ _ asm _ _ _ _ volatile _ _ (push r24 n t);_ _ asm _

33、_ _ _ volatile _ _ (push r25 n t);_ _ asm _ _ _ _ volatile _ _ (push r26 n t);_ _ asm _ _ _ _ volatile _ _ (push r27 n t);_ _ asm _ _ _ _ volatile _ _ (push r30 n t);_ _ asm _ _ _ _ volatile _ _ (push r31 n t);_ _ asm _ _ _ _ volatile _ _ (push r28 n t); / / r28与r29用于建立在堆栈上的指针_ _ asm _ _ _ _ volatil

34、e _ _ (push r29 n t); / / 入栈完成tcb (ostaskrunningprio.ostaskstacktop = sp; / / 将正在运行的任务的堆栈底保存unsigned char osnexttaskid; / / 在现有堆栈上开设新的空间for (osnexttaskid = 0; / / 进行任务调度osnexttaskid - os _ tasks & &! (osrdytbl & (0x01 osnexttaskid);osnexttaskid + +);ostaskrunningprio = osnexttaskid;cli (); / / 保护堆栈转

35、换sp = tcb (ostaskrunningprio.ostaskstacktop;you are ()./ / 根据中断时的出栈次序_ _ asm _ _ _ _ volatile _ _ (pop r29 n t);_ _ asm _ _ _ _ volatile _ _ (pop r28 n t);_ _ asm _ _ _ _ volatile _ _ (pop r31 n t);_ _ asm _ _ _ _ volatile _ _ (pop r30 n t);_ _ asm _ _ _ _ volatile _ _ (pop r27 n t);_ _ asm _ _ _ _

36、volatile _ _ (pop r26 n t);_ _ asm _ _ _ _ volatile _ _ (pop r25 n t);_ _ asm _ _ _ _ volatile _ _ (pop r24 n t);_ _ asm _ _ _ _ volatile _ _ (pop r23 n t);_ _ asm _ _ _ _ volatile _ _ (pop r22 n t);_ _ asm _ _ _ _ volatile _ _ (pop r21 n t);_ _ asm _ _ _ _ volatile _ _ (pop r20 n t);_ _ asm _ _ _ _

37、 volatile _ _ (pop o n t);_ _ asm _ _ _ _ volatile _ _ (pop r18 n t);_ _ asm _ _ _ _ volatile _ _ (pop _ _ tmp _ reg _ _ n t); / / sergeant 出栈并恢复_ _ asm _ _ _ _ volatile _ _ (out _ _ sreg _ _, _ _ tmp _ reg _ _ n t);_ _ asm _ _ _ _ volatile _ _ (pop _ _ tmp _ reg _ _ n t); / / r0 出栈_ _ asm _ _ _ _ volatile _ _ (pop _ _ zero _ re

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论