FreeRTOS 任务、中断解读--zynq

FreeRTOS 任务、中断解读–zynq

1. 中断中如何进行任务切换

FreeRTOS在中断返回时判断ulPortYieldRequired变量的值,如果该值为true则执行进程切换,否则不执行。所以在中断中只看到了ulPortYieldRequired变量的赋值,没有看到任务的切换,实际切换是在中断返回后的汇编代码中实现的。

FreeRTOS_IRQ_Handler:
  /* Return to the interrupted instruction. */
  SUB		lr, lr, #4

  /* Push the return address and SPSR. */
  PUSH	{lr}
  MRS		lr, SPSR
  PUSH	{lr}

  /* Change to supervisor mode to allow reentry. */
  CPS		#SVC_MODE

  /* Push used registers. */
  PUSH	{r0-r4, r12}

  /* Increment nesting count.  r3 holds the address of ulPortInterruptNesting
  for future use.  r1 holds the original ulPortInterruptNesting value for
  future use. */
  LDR		r3, ulPortInterruptNestingConst
  LDR		r1, [r3]
  ADD		r4, r1, #1
  STR		r4, [r3]
	LDR		r1, =ulPortYieldRequired ; /*判断该变量是否为True*/
  LDR		r0, [r1]
  CMP		r0, #0
  BNE		switch_before_exit

exit_without_switch:
  /* No context switch.  Restore used registers, LR_irq and SPSR before
  returning. */
  POP		{r0-r4, r12}

2. 代码中如何进行任务切换

代码中直接调用portYIELD(),实现任务切换,该函数实际为软中断指令,软中断中实现任务切换,portYIELD()定义如下:

#define  portYIELD()  __asm volatile ( "SWI 0" ::: "memory" );
 //软中断中实现了任务切换
 FreeRTOS_SWI_Handler:
	/* Save the context of the current task and select a new task to run. */
	portSAVE_CONTEXT
	LDR R0, vTaskSwitchContextConst
	BLX	R0
	portRESTORE_CONTEXT

3 外设中断向量初始化

外设中断向量初始化必须启动一个Task,在Task中初始化。 原因:FreeRTOS的任务调度是由cpu 32bit private Timer的硬件定时器中断实现,在调用xPortStartScheduler()函数启动任务的时候会对中断寄存器进行重新配置,将Tick中断使能,映射中断处理函数,这个过程会将原来的中断寄存器值覆盖掉,因此只能在Task中初始化外设中断向量,同时注意保证中断寄存器其他位的数据不变,否则可能导致Tick不工作,整个系统无法执行。

经验分享 程序员 微信小程序 职场和发展