freertos(第十课,基于standalone移植freertos)

我们来看看SDK中已经移植好的freertos,具体做了哪些事情。

在BSP文件夹下,除了常规的standaloneOS所提供的模块,还多了一个freertos901_xilinx_v1_1文件夹。
打开system.mss,可以看到freertos901的相关配置。
这些配置会对应生成freerotscnfig.h。一般情况下,我们不需要手工修改freertosconfig.h,而只需要在system.mss里配置各种选项即可。

这里注意几个重要的选项:

  1. stdin,stdout,设置为ps7_uart_1.
  2. hook_function->use_malloc_failed_hook,设置为true。
    3)kernel behavior,
    idle_yield,设置为true,
    max_api_call_interrupt_priority设置为18,
    max_priority设置为8,
    tick_rate,设置为100,也就是10ms,
    use_preemption,设置为true,
    use_timeslicing,设置为true,
    4)kernel feature,
    全部选true。
    5)soft timer
    timer_command_queue_length,设置为10,
    timer_task_priority,设置为(configMAX_PRIORITIES - 1)
    timer_task_stack_depth,设置为(configMINIMAL_STACK_SIZE)
    6)tick_setup,设置为true。
    psu_ttc0_select,设置为true。

configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY,这两个宏是等价的,后者是前者的新名字,在中断服务例程中仅可以调用以“FromISR”结尾的API函数。
configMAX_SYSCALL_INTERRUPT_PRIORITY用来设置可以在中断服务程序中安全调用FreeRTOS API函数的最高中断优先级。优先级小于等于这个宏所代表的优先级时,程序可以在中断服务程序中安全的调用FreeRTOS API函数;如果优先级大于这个宏所代表的优先级,表示FreeRTOS无法禁止这个中断,在这个中断服务程序中绝不可以调用任何API函数。不调用API的中断可以运行在比configMAX_SYSCALL_INTERRUPT_PRIORITY高的优先级,这些级别的中断不会被FreeRTOS禁止,因此不会因为执行RTOS内核而被延时。

SDK移植的文件是portZynq7000.c
这个文件中,只实现了两个函数,TICK和IRQ。
先来看看IRQ。

.section .vectors
_vector_table:
_freertos_vector_table:
	B	  _boot
	B	  FreeRTOS_Undefined
	ldr   pc, _swi
	B	  FreeRTOS_PrefetchAbortHandler
	B	  FreeRTOS_DataAbortHandler
	NOP	  /* Placeholder for address exception vector*/
	LDR   PC, _irq
	B	  FreeRTOS_FIQHandler

_irq:   .word FreeRTOS_IRQ_Handler
_swi:   .word FreeRTOS_SWI_Handler

.align 4
.type FreeRTOS_IRQ_Handler, %function
FreeRTOS_IRQ_Handler:
	LDR		r1, FreeRTOS_ApplicationIRQHandlerConst

FreeRTOS_ApplicationIRQHandlerConst: .word FreeRTOS_ApplicationIRQHandler

void FreeRTOS_ApplicationIRQHandler( uint32_t ulICCIAR )
{
	extern const XScuGic_Config XScuGic_ConfigTable[];
	static const XScuGic_VectorTableEntry *pxVectorTable = XScuGic_ConfigTable[ XPAR_SCUGIC_SINGLE_DEVICE_ID ].HandlerTable;
	uint32_t ulInterruptID;
	const XScuGic_VectorTableEntry *pxVectorEntry;
	
		/* The ID of the interrupt is obtained by bitwise anding the ICCIAR value
		with 0x3FF. */
		ulInterruptID = ulICCIAR & 0x3FFUL;
		if( ulInterruptID < XSCUGIC_MAX_NUM_INTR_INPUTS )
		{
			/* Call the function installed in the array of installed handler functions. */
			pxVectorEntry = &( pxVectorTable[ ulInterruptID ] );
			pxVectorEntry->Handler( pxVectorEntry->CallBackRef );
		}
}

从中可以看出,IRQ的处理过程,和standaloneOS是一致的,最终都是调用的注册到GIC中的Callback来处理的。

TICK也是使用了GIC的TIMER中断,来看看具体实现。
当程序启动调度器时,xPortStartScheduler会调用setuptickinterrupt函数。

void FreeRTOS_SetupTickInterrupt( void )
{
	BaseType_t xStatus;
	extern void FreeRTOS_Tick_Handler( void );
	XScuTimer_Config *pxTimerConfig;
	XScuGic_Config *pxGICConfig;
	const uint8_t ucRisingEdge = 3;
	
		/* Ensure XScuGic_CfgInitialize() has been called.  In this demo it has
		already been called from prvSetupHardware() in main(). */
		pxGICConfig = XScuGic_LookupConfig( XPAR_SCUGIC_SINGLE_DEVICE_ID );
		xStatus = XScuGic_CfgInitialize( &xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress );
		configASSERT( xStatus == XST_SUCCESS );
		( void ) xStatus; /* Remove compiler warning if configASSERT() is not defined. */
	
		/* The priority must be the lowest possible. */
		XScuGic_SetPriorityTriggerType( &xInterruptController, XPAR_SCUTIMER_INTR, portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, ucRisingEdge );
	
		/* Install the FreeRTOS tick handler. */
		xStatus = XScuGic_Connect( &xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, ( void * ) &xTimer );
		configASSERT( xStatus == XST_SUCCESS );
		( void ) xStatus; /* Remove compiler warning if configASSERT() is not defined. */
	
		/* Initialise the timer. */
		pxTimerConfig = XScuTimer_LookupConfig( XPAR_SCUTIMER_DEVICE_ID );
		xStatus = XScuTimer_CfgInitialize( &xTimer, pxTimerConfig, pxTimerConfig->BaseAddr );
		configASSERT( xStatus == XST_SUCCESS );
		( void ) xStatus; /* Remove compiler warning if configASSERT() is not defined. */
	
		/* Enable Auto reload mode. */
		XScuTimer_EnableAutoReload( &xTimer );
	
		/* Ensure there is no prescale. */
		XScuTimer_SetPrescaler( &xTimer, 0 );
	
		/* Load the timer counter register. */
		XScuTimer_LoadTimer( &xTimer, XSCUTIMER_CLOCK_HZ / configTICK_RATE_HZ );
	
		/* Start the timer counter and then wait for it to timeout a number of
		times. */
		XScuTimer_Start( &xTimer );
	
		/* Enable the interrupt for the xTimer in the interrupt controller. */
		XScuGic_Enable( &xInterruptController, XPAR_SCUTIMER_INTR );
	
		/* Enable the interrupt in the xTimer itself. */
		FreeRTOS_ClearTickInterrupt();
		XScuTimer_EnableInterrupt( &xTimer );
}

从中可以看出,利用standalone提供的GIC和TIMER的API,我们配置了GIC,并配置了TIMER。这样,SYSTICKTIMER就能够开始工作,并周期性的发出IRQ。
我们挂接的IRQHandler,是FreeRTOS_Tick_Handler。这是port.c中的函数。
它是ARM体系的通用函数,与zynq无关了。

如果我们需要挂接中断服务函数Callback,仍然需要standaloneOS中提供的API,将IRQ的Callback连接到GIC的HandlerTable中。
如果希望能够在ISR中使用API,那么GIC连接时,setpriorityandtype,就要设置成RTOS能够屏蔽的优先级。
例如,这里设置的是18,而SYSTICK使用的是30,30是最低的可用优先级,所以,连接到GIC的IRQ,如果希望使用FromISR的API,就必须设置为大于30小于18的优先级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值