Embedded course assignment record - ARM review outline

Textbook: ARM 9 embedded system design, development and application (compiled by Xiong Maohua and Yang Zhenlun) (Tsinghua University Press)

Examination questions: 40 multiple-choice questions (20 questions), 10 blank filling questions (5 questions), 20 short answer questions (4 questions), 20 reading procedures (4 questions), and 10 writing procedures (1 question).

Keep a file for record, because the review outline is too long, so it is sent separately.

16. Initialization procedures of bus width and waiting register BWSCON and Bank control register BANKCONn, initialization of interrupt vector table and stack (see Notes)?

Used to set bus width and wait state. For example, the CPU clock frequency can be changed by configuring the value of the corresponding register.

Initialization procedure of bus width and wait control registers BWSCON and BANKCON control registers:

// config.h
/* Bus width control definition (0 for 8 bits, 1 for 16 bits, 2 for 32 bits) */
#define  	DW8			(0x0)
#define  	DW16		(0x1)
#define  	DW32		(0x2)
#define  	WAIT		(0x1<<2)
#define  	UBLB		(0x1<<3)

/* Bank Timing control (bit field) definition */
#define     MT 			 fifteen 			/*  Storage type selection, valid only for Bank6 and Bank7 (2bit)*/
#define     Trcd 		  two 			/*  RAS to CAS delay, valid only for SDRAM (2bit)*/
#define     SCAN 		  0 			/*  Column address bits, valid only for SDRAM (2bit)*/

#define     Tacs 		 thirteen 			/*  Establishment time of address signal before nGCSn is valid (2bit)*/
#define     Tcos 		 eleven 			/*  Set up time of film selection before nOE is valid (2bit)*/
#define     Tacc 		  eight 			/*  Access cycle (3bit)*/
#define     Tcoh 		  six 			/*  Hold time of chip selection signal after nOE (2bit)*/
#define     Tcah 		  four 			/*  After the end of nGCSn, the holding time of the address signal (2bit)*/
#define     Tacp 		  two 			/*  Access cycle of Page mode (2bit)*/
#define     PMC 			  0 			/*  Page mode configuration (2bit)*/

/**** The external bus configuration can be modified by the user according to actual needs****/
#define  	B7_BWCON	(DW16|WAIT|UBLB) 
#define   	 B6_BWCON 	 (DW32|UBLB)  	/*  Do not modify the Bank used by SDRAM*/ 
#define  	B5_BWCON	(DW16|WAIT|UBLB)  
#define  	B4_BWCON	(DW16|WAIT|UBLB)  
#define  	B3_BWCON	(DW16|WAIT|UBLB)  
#define  	B2_BWCON	(DW16|WAIT|UBLB)  
#define  	B1_BWCON	(DW16|WAIT|UBLB)

#define  	B7_BANKCON	((0<<MT)|(1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define   	 B6_BANKCON 	 ((3<<MT)|(1<<Trcd)|(1<<SCAN)) 		/*  Do not modify the Bank used by SDRAM*/
#define  	B5_BANKCON	((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define  	B4_BANKCON	((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define  	B3_BANKCON	((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define  	B2_BANKCON	((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define  	B1_BANKCON	((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))
#define  	B0_BANKCON	((1<<Tacs)|(1<<Tcos)|(7<<Tacc)|(1<<Tcoh)|(1<<Tcah)|(1<<Tacp)|(0<<PMC))



// s3c2410.h
// BWSCON register base address definition
#define  BWSCON_ADDR	0x48000000
// Memory control 
#define rBWSCON    (*(volatile unsigned *)0x48000000) //Bus width & wait status
#define rBANKCON0  (*(volatile unsigned *)0x48000004) //Boot ROM control
#define rBANKCON1  (*(volatile unsigned *)0x48000008) //BANK1 control
#define rBANKCON2  (*(volatile unsigned *)0x4800000c) //BANK2 cControl
#define rBANKCON3  (*(volatile unsigned *)0x48000010) //BANK3 control
#define rBANKCON4  (*(volatile unsigned *)0x48000014) //BANK4 control
#define rBANKCON5  (*(volatile unsigned *)0x48000018) //BANK5 control
#define rBANKCON6  (*(volatile unsigned *)0x4800001c) //BANK6 control
#define rBANKCON7  (*(volatile unsigned *)0x48000020) //BANK7 control
#define rREFRESH   (*(volatile unsigned *)0x48000024) //DRAM/SDRAM refresh
#define rBANKSIZE  (*(volatile unsigned *)0x48000028) //Flexible Bank Size
#define rMRSRB6    (*(volatile unsigned *)0x4800002c) //Mode register set for SDRAM
#define rMRSRB7    (*(volatile unsigned *)0x48000030) //Mode register set for SDRAM


// target.c
// Bus configuration data table (the user can configure the bus in the config.h file)	
const uint32  __BUS_INIT[] =
{	
	(B7_BWCON<<28)|(B6_BWCON<<24)|(B5_BWCON<<20)|(B4_BWCON<<16)|(B3_BWCON<<12)|(B2_BWCON<<8)|(B1_BWCON<<4),	// BWSCON register
	B0_BANKCON,			// BANKCON0 register
	B1_BANKCON,			// BANKCON1 register 	
	B2_BANKCON, 		// BANKCON2 register
	B3_BANKCON, 		// BANKCON3 register
	B4_BANKCON, 		// BANKCON4 register
	B5_BANKCON, 		// BANKCON5 register
	B6_BANKCON, 		// BANKCON6 register (SDRAM)
	B7_BANKCON, 		// BANKCON7 register (SRAM)
	(1<<23)|(0<<22)|(0<<20)|(3<<18)|(1113),		// REFRESH register (SDRAM), for example: period=15.6us, HCLK=60Mhz, (2048+1-15.6*60)
	(1<<7)|(1<<5)|(1<<4)|(2<<0),				// BANKSIZE register, 128MB
	(3<<4),										// MRSRB6 register
	(3<<4)										// MRSRB7 register	
};


// target.c
/*********************************************************************************************************
** Function name: TargetBusInit
** Descriptions: Bus system initialization for the target board, including Bank width, SDRAM controller, etc.
**               Do not add any user code to this function.
** Input: nothing
** Output: nothing
********************************************************************************************************/
void  TargetBusInit(void)
{   
#ifdef	__Release	
    int  i;
    volatile uint32  *cp1;
    							    		
	// Bus setting, initializing SDRAM controller
	cp1 = (void *)BWSCON_ADDR;
	for(i=0; i<13; i++)
	{
		*cp1++ = __BUS_INIT[i];		
	}
#endif    
}

Interrupt vector table initialization:

;Defines the size of the stack
USR_STACK_LEGTH     EQU         64
SVC_STACK_LEGTH     EQU         0
FIQ_STACK_LEGTH     EQU         16
IRQ_STACK_LEGTH     EQU         64
ABT_STACK_LEGTH     EQU         0
UND_STACK_LEGTH     EQU         0

			AREA	Example5,CODE,READONLY	; Declaration code snippet Example5
			ENTRY				; Identify program entry
			CODE32				; Declare 32 bits ARM instructions
START		MOV		R0,#0
			MOV		R1,#1
			MOV		R2,#2
			MOV		R3,#3
			MOV		R4,#4
			MOV		R5,#5
			MOV		R6,#6
			MOV		R7,#7
			MOV		R8,#8
			MOV		R9,#9
			MOV		R10,#10
			MOV		R11,#11
			MOV		R12,#12
			
			BL		InitStack	; Initialize stack pointer in each mode
			
			; open IRQ interrupt (take CPSR Register I Bit reset)
			MRS		R0,CPSR			; R0 <= CPSR
			BIC		R0,R0,#0x80 
			MSR		CPSR_cxsf,R0	; CPSR <= R0
						
			; Switch to user mode
        	MSR     CPSR_c, #0xd0
        	MRS		R0,CPSR
        	
        	; Switch to management mode
        	MSR     CPSR_c, #0xdf
        	MRS		R0,CPSR		

HALT		B		HALT

; name: InitStack
; Function: stack initialization, that is to initialize the stack pointer in each mode.
; Entry parameters: None
; Outlet parameters: None
; Note: call this subroutine in privileged mode, such as management mode after reset
InitStack    
        	MOV     R0, LR		; R0 <= LR,Because in various modes R0 It's the same

;Set management mode stack
        	MSR     CPSR_c, #0xd3
        	LDR     SP, StackSvc
;Set interrupt mode stack
        	MSR     CPSR_c, #0xd2
        	LDR     SP, StackIrq
;Set fast interrupt mode stack
        	MSR     CPSR_c, #0xd1
        	LDR     SP, StackFiq
;Set abort mode stack
        	MSR     CPSR_c, #0xd7
      		LDR     SP, StackAbt
;Set undefined mode stack
        	MSR     CPSR_c, #0xdb
        	LDR     SP, StackUnd
;Set system mode stack
        	MSR     CPSR_c, #0xdf
        	LDR     SP, StackUsr

        	MOV     PC, R0

StackUsr   	DCD     UsrStackSpace + (USR_STACK_LEGTH - 1)*4
StackSvc    DCD     SvcStackSpace + (SVC_STACK_LEGTH - 1)*4
StackIrq    DCD     IrqStackSpace + (IRQ_STACK_LEGTH - 1)*4
StackFiq    DCD     FiqStackSpace + (FIQ_STACK_LEGTH - 1)*4
StackAbt    DCD     AbtStackSpace + (ABT_STACK_LEGTH - 1)*4
StackUnd    DCD     UndtStackSpace + (UND_STACK_LEGTH - 1)*4


; Allocate stack space 
        	AREA    MyStacks, DATA, NOINIT, ALIGN=2
UsrStackSpace     	SPACE  	USR_STACK_LEGTH * 4 	; User (system) mode stack space
SvcStackSpace      	SPACE  	SVC_STACK_LEGTH * 4  	; Manage mode stack space
IrqStackSpace      	SPACE  	IRQ_STACK_LEGTH * 4  	; Interrupt mode stack space
FiqStackSpace      	SPACE  	FIQ_STACK_LEGTH * 4  	; Fast interrupt mode stack space
AbtStackSpace      	SPACE  	ABT_STACK_LEGTH * 4  	; Abort mode stack space
UndtStackSpace     	SPACE  	UND_STACK_LEGTH * 4  	; Mode stack is not defined			
			
			
			END	

Stack initialization:

/*********************************************************************************************************
** Function name: OSTaskStkInit
** Function Description: task stack initialization code. Failure to call this function will crash the system
** Input: task: the address where the task starts to execute
**         pdata : Parameters passed to the task
**         ptos  : Start position of the task stack
**         opt   : Additional parameters. The current version is useless for this function. See the opt parameter of OSTaskCreateExt() for the specific meaning
** Output: stack top pointer position
** Global variables:
** Calling module: 
********************************************************************************************************/

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
    OS_STK *stk;

    opt    = opt;                           /* 'opt'  Not used. The purpose is to avoid compiler warnings    */
    stk    = ptos;                          /* Get stack pointer */

                                            /* Establish task environment, ads1 2 use full decrement stack       */
    *stk = (OS_STK) task;                   /*  pc  */
    *--stk = (OS_STK) task;                 /*  lr  */

    *--stk = 0;                             /*  r12  */
    *--stk = 0;                             /*  r11  */
    *--stk = 0;                             /*  r10  */
    *--stk = 0;                             /*  r9   */
    *--stk = 0;                             /*  r8   */
    *--stk = 0;                             /*  r7   */
    *--stk = 0;                             /*  r6   */
    *--stk = 0;                             /*  r5   */
    *--stk = 0;                             /*  r4   */
    *--stk = 0;                             /*  r3   */
    *--stk = 0;                             /*  r2   */
    *--stk = 0;                             /*  r1   */
    *--stk = (unsigned int) pdata;          /*  r0,The first parameter is passed using R0   */
    *--stk = (USER_USING_MODE|0x00);	    /*  spsr,Allow IRQ, FIQ interrupt   */
    *--stk = 0;                             /*  Turn off the interrupt counter OsEnterSum;    */

    return (stk);
}

17. The S3C2410 power control mode has four modes: normal, slow, idle and power off

  • [normal mode] the power management module provides clock for CPU and peripheral devices in S3C2410. In this mode, since all peripherals are turned on, the power consumption reaches the maximum.
  • [slow mode (no PLL mode)] does not use PLL, but uses the external clock (XTIPLL/EXTCLK) as the FCLK clock (CPU core clock). In this mode, the power consumption only depends on the external time frequency and is independent of PLL.
  • [idle mode] the power management module only disconnects the FCLK, but still provides clocks for all other peripherals. This mode reduces the power consumption of the CPU, and any interrupt request can wake up the CPU from the idle mode.
  • [power down mode] the power management module disconnects the internal power supply. Except for wake-up logic, neither CPU nor internal logic will generate power consumption. Two independent power supplies are required to activate the power down mode. One power supply supplies power to wake-up logic and the other power supply supplies power to other internal logic including CPU, which can be controlled by switch. In this mode, the second power supply will be turned off.

18. What are the common ways of mixed programming in assembly language and C?

There are three common ways:

  • Embedding assembly instructions in C code
void string_copy(char *dst,const char *str)
{
  char ch;
  __asm
  {
    loop
      LDRB  ch,[str],#1
      STRB  ch,[dst],#1
      CMP    ch,#0
      BNE loop 
  }
}

int main()
{
  char *a="hello world!"
  char b[64];
  string_copy(a,b);
  return 0;
}
  • C call assembly:

(1) Assembly export

(2) C language defines extern function

(3) C language call assembly

myArm.s
  AREA  myARM,CODE ,READONLY
  export my_strcopy
my_strcopy
      loop
        LDRB R4,[R0],#1
        CMP  R4,#0
        BEQ OVER
        STRB R4,[R1],#1
        B loop
      OVER
           end

myMain.c

extern void my_strcopy(char *dtr,char*str);
int main()
{
  char *a="hello world!"
  char b[64];
  my_strcopy(a,b);
  return 0;
}
  • Assembly calls C language:

(1) C language implementation function

(2) Assembly import function name

(3) BL function name

myArm.s
  AREA  myARM,CODE ,READONLY
  IMPORT c_fun
  ENTRY
start
  mov R0,#1
  mov R1,#2
  mov R2,#3
  BL  c_fun
  end

myMain.c
int c_fun(int a,int b,int c)//From the assembly to here, at this time a=1, b=2, c=3
{
  return a+b+c;//Return from here, R0=6;
}

19. The call between subroutines of mixed programming of arm assembly language and C language must follow certain call rules, which are collectively referred to as ATPCS

ATPCS is the abbreviation of arm thumb procedure call standard.
PCS specifies how application functions can be written separately, compiled separately, and finally connected together, so it actually defines a set of protocols between process (function) callers and callees.

PCS enforces the following conventions: how the calling function passes parameters (i.e. stack pressing method, how to store parameters), how the called function obtains parameters, and how to pass the return value of the function.

Some rules:

  • r0-r3 is generally used to transfer the parameters of the function, and r4-r7 is used to place local variables. r12-r15 can be used for special purposes.
  • Parameter values less than 32 bits are automatically extended to 32 bits.
  • A 64 bit parameter is treated as two 32 bits.
  • For floating point numbers If the chip hardware supports floating-point operation, the floating-point parameters will be passed in the floating-point register. If the hardware does not support floating-point operation, it will be converted to integer general-purpose register transfer.
  • Other types are passed as 32-bit integers.
  • For program calls with variable parameters, the first four parameters are passed in r0~r3. If there are more than four parameters, they are stored on the stack in the opposite order. The so-called opposite order refers to the stack after the first parameters.
  • For calls with fixed parameters, if there are hardware components that can perform floating-point operations, each floating-point parameter shall be processed in order; Allocate FP registers for each floating-point parameter; The allocation method is a set of consecutive FP registers with the smallest number to meet the needs of the floating-point parameter. The first integer parameter is passed through registers R0~R3, and other parameters are passed through the data stack.

20. ucos kernel scheduling features (P98)

uC/OS kernel scheduling mainly has the following characteristics:

  • Only priority based preemptive scheduling algorithm is supported, and time slice rotation training is not supported.
  • 64 priorities, only 64 tasks can be created, and the user can only create 56 tasks. There is an idle task with the lowest priority, which runs when there is no user task.
  • Each task has a different priority. 0 has the highest priority and 63 has the lowest priority.
  • Priority reversal is not supported.
  • READY queue realizes fast query through memory mapping table, which is very efficient.
  • Support clock beat.
  • Support semaphore, message queue, event control block, event flag group, message mailbox task communication mechanism.
  • Supports interrupt nesting, with up to 255 layers. Interrupts use the stack of the current task to save the context.
  • Each task has its own stack, and the stack size is determined by the user.
  • Support dynamic modification of task priority.
  • The task TCB is a static array. The creation task only obtains a TCB from it without dynamic allocation to free memory.
  • The task stack is created statically or dynamically by the user. It is completed outside the task creation. The task creation itself does not carry out dynamic memory allocation.
  • The total number of tasks (OS_MAX_TASKS) is determined by the user.

21. ucos TCB content (P100)

(what a mess)

The functions of main parameters are as follows:

  • *OSTCBStkPtr is a pointer to the top of the current task stack.
  • *OSTCBExtPtr is used by the task extension module.
  • *OSTCBStkBottom is a pointer to the bottom of the task stack.
  • OSTCBStkSize is the number of pointer elements that can be held in the storage stack.
  • OSTCBOpt passes the "selection" to the function OSTashCreateExt(). Only when the user sets the OS_ CFG. OS in H file_ TASK_ CREATE_ This variable is valid only when ext is set to 1.
  • OSTCBId is used to store the identification code (ID) of the task.
  • Ostcbtext and OSTCBPrev are used for task control OS_ Before and after the bidirectional linked list of TCBS, which is connected in the clock beat function OSTimerTick().
  • OSTCBEventPtr is a pointer to the event control block.
  • OSTCBMsg is a pointer to the message passed to the task.
  • OSTCBDly this variable is used when the task needs to be delayed by several clock beats, or the task needs to be suspended for a period of time to wait for an event to occur.
  • OSTCBStat is the status word of the task.
  • OSTCBPrio is the task priority, and the OSTCBPrio value of high priority tasks is the smallest.
  • OSTCBDelReq is a Boolean quantity used to indicate whether the task needs to be deleted.
  • OSTCBX OSTCBY OSTCBBitX OSTCBBitY is used to accelerate the process of a task entering the ready state or the process of waiting for an event to sound. These values are calculated when the task is established or when the task priority is changed.

22. ucos ready table, write table (Registration), delete table algorithm (P100) query highest priority algorithm (P101) (fill in the blank)

(1) Ready table

The task readiness table records all the tasks in the ready state in the system. From the code point of view, it is an array OSRdyTbl [] of type INT8U.. When there are 32 tasks in the system, OSRdyTbl [] has 4 members. Each member occupies 8 bits, so each data element of OSRdyTbl [] corresponds to 8 tasks, which are called a task group. In the ready table, the binary bit of task priority is used. When this bit is 1, it indicates that the corresponding task is in ready state, and vice versa.

Considering the search efficiency, uCOS-II defines an INT8U variable OSRdyGrp, and each bit of the variable corresponds to a task group (i.e. a member of the data) of OSRdyTbl []. If the position corresponding to a task is set to 1, otherwise it is 0.

For example: OSRdyGrp=00001011, it means that there are ready tasks in OSRdyTbl[0], OSRdyTbl[1] and OSRdyTbl[3]. As can be seen from the figure, uCOS-II can manage up to 8 * 8 = 64 tasks.

The task ready table is sorted from low to high according to the priority of the task, so it is easy to find the position of the task in the ready table according to the priority of the task:

Since the system supports 64 tasks at most, the priority is 63 at most, that is, binary 00111111, which only occupies the lower 6 bits, and each OSRdyTbl [] element only occupies 8. Therefore, only 3 binary bits are needed to indicate which of the 8 bits is 1. Similarly, the upper 3 bits are used to indicate which of the 8 OSRdyTbl [] elements. That is, the upper 3 bits (D5, D4, D3) of the priority indicate, that is, the upper 3 bits (D5, D4, D3) of the priority indicate the array subscript n of OSRdyTbl [], and the lower 3 bits (D2, D1, D0) indicate which data bit of OSRdyTbl[n]. In addition, determine the subscript n of OSRdyTbl [] and also indicate the position bit of OSRdyGrp.

For example, if the priority of a task is prio=24, which position in the ready table does the task fall in?

The binary bits of 24 are 00011000, D5, D4 and D3 are 011, that is, the subscript of OSRdyTbl [] is 3, and D2, D1 and D0 are 0, that is, the task with priority prio=24 is in bit 0 of OSRdyTbl[3]. Bit 3 of OSRdyGrp.

The ready status flag of each task is put into the ready table, which has two variables OSRdyGrp and OSRdyTbl [].

In OSRdyGrp, tasks are grouped by priority, and 8 tasks are a group. Each bit in OSRdyGrp indicates whether each of the eight groups of tasks has a task in the ready state.

When the task enters the ready state, the corresponding bit of the corresponding element in the ready table OSRdyTbl [] is also set to 1. The size of the ready table OSRdyTbl [] array depends on the OS_LOWEST_PRIO.

In order to determine which priority task to run next time, the kernel scheduler always places the task with the lowest priority in the corresponding position 1 of the corresponding byte in the ready table, that is, OS_LOWEST_PRIO = 1.

(2) Write and delete tables

Enter the task into the ready table (Set 1 in the corresponding row and column of the ready table through OSMapTbl []):

OSRdyGrp           |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];

The lower three bits of the task priority are used to determine the position of the task in the general readiness table OSRdyTbl [], and the next three bits are used to determine the number of elements in the OSRdyTbl [] array. OSMapTbl [] is used to limit the subscripts of OSRdyTbl [] array elements to 0-7.

Delete a task from the ready table (set 0 in the corresponding row and column of the ready table through OSMapTbl []):

if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)
   OSRdyGrp &= ~OSMapTbl[prio >> 3];

Clear the corresponding bit of the corresponding element in the ready task table array OSRdyTbl [] to 0. For OSRdyGrp, the corresponding bit is cleared to 0 only when none of the tasks in the task group where the deleted task is located has entered the ready state, that is, when all the bits of OSRdyTbl [prio > > 3] are 0, the corresponding bit of OSRdyGrp is cleared to zero.

(3) Find the task with the highest priority from the ready table

The hash algorithm is used.

So to find the task with the highest priority, there are two steps:

The first step is to determine the task group (subscript of OSRdyTbl []) Y: find the lowest bit Y of 1 in OSRedyGrp;

Step 2: determine the bit X in the task group: find the lowest bit X of 1 in OSRdyTbl[x] in the task group.

To sum up, the core algorithm for finding the target task is to determine the lowest bit of a value of 1. The specific implementation of uCOS-II is to use the OSUnMapTbl [] array:

For example, 0x06(00000110), the lowest bit of 1 is Bit[1], then OSUnMapTbl[0x06]=1; 0x20(00100000), the lowest bit of 1 is Bit[5], that is, OSUnMapTbl[0x20]=5.

INT8U   y;
y             = OSUnMapTbl[OSRdyGrp]; //Task group with the highest priority     
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); //Bit of the task group in which the highest priority task is located

INT8U  const  OSUnMapTbl[256] = {
    0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x00 to 0x0F  */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x10 to 0x1F */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x20 to 0x2F */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x30 to 0x3F */
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x40 to 0x4F */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x50 to 0x5F */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x60 to 0x6F */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x70 to 0x7F */
    7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x80 to 0x8F */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x90 to 0x9F */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xA0 to 0xAF */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xB0 to 0xBF */
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xC0 to 0xCF */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xD0 to 0xDF */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xE0 to 0xEF */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0        /* 0xF0 to 0xFF */
};

Priority of task prio = (Task group Y) << 3 | Who's on the task force X

y   = OSUnMapTbl[OSRdyGrp];
x   = OSUnMapTbl[OSRdyTbl[y]];

prio = (y << 3) + x;

23. Task management class create (P104), Sem synchronization class create, pend, post (P105), Mbox communication class create, pend, post usage (read program questions, write program questions) (P105)

There are two communication modes between processes. One is to use shared memory. This mode basically does not rely on OS and has no corresponding system overhead. The other requires OS support to realize the communication between tasks by establishing a linker.

In UCOSii, multiple tasks using the same memory area need to provide a mutually exclusive access method. Otherwise, the shared data is likely to be reset by other tasks before being accessed.

Where OS_ENTER_CRITICAL() is the shutdown function, and OS_EXIT_CRITICAL() is the interrupt function.
Using Shutdown macro OS_ENTER_CRITICAL(),OS_EXIT_CRITICAL() and opening scheduling lock use the functions OSSchedLock() and OSSchekUnlock() to realize the temporary exclusive enjoyment of a resource by a single task.

There are great limitations in using this method to realize data sharing. For a simple example, when a shared resource is allowed to be occupied by multiple tasks at the same time, this method is very inefficient.

RTOS will provide semaphores, mailboxes and message queues to support communication and synchronization between tasks. Even non real-time operating systems also have such interfaces, which is similar to a specification.

The concept of semaphore was originally proposed by Edsger Dijkstra.

Assuming that there are multiple tasks that need to read and write the flash chip on a board, if they do not negotiate, but read and write the flash separately, the flash read and write operation will be in an unpredictable state. At this time, you can create a semaphore. When there is a task to read and write, you can apply for the semaphore and release it after the operation is completed. If a task has occupied the semaphore, the request semaphore will fail. The task can wait for the semaphore to be released before relevant operations. A shared resource may also be occupied by several tasks at most. In this case, the semaphore can be a counter. When a task occupies a shared resource, the semaphore will be reduced by one.

Obviously, semaphores only solve the problem of occupation of shared resources. It can not transmit information. If a lower computer has a task specially used to explain the control command of the upper computer, when the upper computer has no data transmission, the task is suspended. However, when the communication interruption occurs, the task not only needs to know that a control word has been transmitted, but also needs to know what the control word is. Therefore, semaphores are not applicable here. The solution is to establish a mailbox. Since the information to be passed is likely to exceed the size of a regular variable, the content of the mailbox is a pointer. Set the priority of the command interpreter higher than other tasks, and it always waits for a mailbox. Point the value of the pointer in the mailbox to the receive buffer, and the task starts processing the control word.

A message queue is a set of pointers, which can be regarded as a collection of mailboxes.

Suppose there is an assembly line sorting system, and the sensor will detect some physical parameters of the goods. For each product, the system establishes a structure about the product to describe the attributes of the product. If a mailbox is used, the processing of new products must be delayed before a product is processed by the sorting task. Using message queuing, you can push a set of pointers into the queue, and each pointer describes a product. In this way, the sorting task can sort each product in turn according to the sequence of entering the queue.

The event control block Ecb is used to maintain all the information of an event control block. The structure not only contains the values of semaphore / mailbox / message queue, but also contains the task list waiting for it.

Ecb reflects a simple idea of simplifying program logic structure. Use a unified data structure to describe the attributes of objects, and then deal with them uniformly in the handler. The creation and maintenance of semaphores / mailboxes / message queues only read and write the Ecb. In the scheduler, the Ecb is processed uniformly.

typedef struct {
void *OSEventPtr; /* Pointer to a message or message queue */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Waiting task list */
INT16U OSEventCnt; /* Counter (when the event is a semaphore) */
INT8U OSEventType; /* Event type */
INT8U OSEventGrp; /* Wait for the group in which the task is located */
} OS_EVENT;

(1) Task class

  • OSTaskCreate(): creates a task. There are four parameters (the entry address of the task, the parameters of the task, the first address of the stack of the task, and the priority of the task). After calling this function, the system will first apply for an empty TCB pointer from the TCB free list, then initialize the task stack according to the parameters given by the user, and mark the task as ready in the internal task ready table. After returning, you can successfully create a task. This function should be called at least once in the main function and after the OSInit function is called.

  • Ostask suspend(): suspend the specified task. If the current task is suspended, it will cause the system to execute the task pilot function oshed to perform a task switching. Only one parameter (specifies the priority of the task). Note that the ID of a task is its priority, so ucos does not allow the same priority.

  • Ostaskaresume(): used to restore a pending task to a ready state. If the priority of the recovery task is higher than the current task, a task switch will be triggered. Note that this function does not have to be used in pairs with the above functions.

(2) Message class

  • OSMBoxCreate(): used to create message mailboxes. Message mailbox is a way of communication between tasks of the operating system. A task can wait for the mailbox message sent by another task to its mailbox with or without blocking, and act according to the message content. (is this human talk???)

  • OSMBoxPost(): used to send mailbox messages from one task to the mailbox of another task. The content of the message is specified in the parameter.

  • OSMBoxPend(): used for a task to obtain messages in the task mailbox. If there are no messages in the mailbox, wait and the task is blocked.

(3) Synchronization class

  • OSSemCreate(): used to create semaphores. Semaphore is a way of synchronization between tasks of the operating system. Two or more tasks can obtain the state of semaphore and act according to it to achieve synchronization. (it's a bit awkward, and the language is unqualified!)

  • OSSemPost(): used to set a semaphore for a task. The content of the setting is specified in the parameter.

  • OSSemPend(): used for a task to obtain the status of this semaphore. If the semaphore is not zero, the semaphore is successfully obtained and subtracted by 1; If the semaphore is zero, wait and the task is blocked.

(4) Time class (supplementary)

  • OSTimeDly(): it is used to hang the current task first, and then switch tasks. After the specified time comes, the current task will be restored to ready status, but not necessarily run. If the ready task with the highest priority is restored, it will be run.

(5) Memory operation class (supplementary)

  • OSMemCreate(): creates a memory partition.
  • OSMemGet(): allocates a memory block from a specified memory area.
  • OSMemPut(): releases a memory block.

24. Requirements of UCOS porting for processor, 4 steps of porting (P107)

The processor must meet the following requirements:

  • The C compiler of the processor can produce reentrant code.
  • Interrupts can be turned on or off in the program.
  • The processor supports interrupts and can generate timed interrupts.
  • The processor supports a hardware stack that can hold a certain amount of data.
  • The processor has instructions stored in stack pointers and other CPU registers and instructions read out to the stack (or memory).

4 steps of migration:

  • Set os_cpu.h processor and compiler related code.
  • Six operating system related functions are written in C language. (stack initialization function, task creation hook function, task deletion hook function, task switching hook function, task status hook function, clock beat hook function)
  • Four processor related functions are written in assembly language. (ready task function with the highest priority, task switching function at task level, task switching function at interrupt level and clock beat interrupt function)
  • Write a simple multitasking program to test whether the migration is successful.

25. Be able to work out some C language multiple-choice questions, such as the operation of arrays, pointers and structures

Go back and review the basics of C language for me! No more details!

26. Program reading (20 points)

  • 1 assembly and C call each other (supplementary statement)
  • 1 ucos (explain the operation results)
  • 1 bare metal (note)
  • 1 assembly (describing functions and operation results)

27. Program writing: MBOX and SEM (communication and synchronization mechanism) of ucos (for example, after tasks A, B and c run once, B runs, and finally C runs after both A and B run) (10 points)

Suppose task1 priority is 3, task2 priority is 7, and task3 priority is 9. Running sequence: task1, task2, task1, task2, task3. (ha ha, I can't do it, so I recite the following framework directly, so I can earn points. I'm going to study ucos again in winter vacation.)

#define 	 Task1StkLengh 	 64 / / define the stack length of user task 1
#define 	 Task2StkLengh 	 64 / / define the stack length of user task 2
#define 	 Task3StkLengh 	 64 / / define the stack length of user task 3

OS_STK	Task1Stk [Task1StkLengh];       // Define the stack for user task 1
OS_STK	Task2Stk [Task2StkLengh];       // Define the stack for user task 2
OS_STK	Task3Stk [Task3StkLengh];       // Define the stack for user task 3

OS_EVENT *Sem1;         // Semaphore 1
OS_EVENT *Sem2;         // Semaphore 2
OS_EVENT *Sem3;         // Semaphore 3

//OS_EVENT *RandomMBox;

void Task1	(void *pdata);
void Task2	(void *pdata);
void Task3	(void *pdata);

int main (void)
{
	OSInit ();			
	
	OSTaskCreate (Task1, (void *)0, &Task1Stk[Task1StkLengh - 1], 3);		
	OSTaskCreate (Task2, (void *)0, &Task2Stk[Task2StkLengh - 1], 7);
	OSTaskCreate (Task3, (void *)0, &Task3Stk[Task3StkLengh - 1], 9);
	
	Sem1 = OSSemCreate (0);
	Sem2 = OSSemCreate (1);
	Sem3 = OSSemCreate (0);
	
	//RandomMBox = OSMBoxCreate((void *)0);
	
	OSStart ();
	return 0;															
}

void Task1	(void *pdata)
{
    INT8U Reply;

	pdata = pdata;
	for (;;)
	{
	    OSSemPend (Sem1, 0, &Reply);
	    OSSemPost (Sem2);
	    
	    //OSMboxPost (RandomMBox, s);
	    
	    OSTimeDlyHMSM (0, 0, 0, 350);
	}
}

void Task2	(void *pdata)
{
    INT8U err;

    pdata = pdata;
    for (;;)
    {
        //msg = OSMBoxPend (RandomMBox, 0, &err);
        OSTimeDlyHMSM (0, 0, 0, 350);
    }
}

void Task3	(void *pdata)
{
	pdata = pdata;
	for (;;)
	{
	    OSTimeDlyHMSM (0, 0, 0, 350);
	}
}

Keywords: Single-Chip Microcomputer ARM

Added by phdatabase on Mon, 03 Jan 2022 22:36:27 +0200