启动调度器接口,主要是创建空闲任务和定时器任务以及执行特定架构的启动调度器接口

// FreeRTOS\Source\tasks.c
void vTaskStartScheduler( void )
{
/* Add the idle task at the lowest priority. */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
/* The Idle task is being created using dynamically allocated RAM. */
xReturn = xTaskCreate( prvIdleTask,
configIDLE_TASK_NAME,
configMINIMAL_STACK_SIZE,
( void * ) NULL,
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
}
#endif /* configSUPPORT_STATIC_ALLOCATION */ #if ( configUSE_TIMERS == 1 )
{
if( xReturn == pdPASS )
{
xReturn = xTimerCreateTimerTask();
}
}
#endif /* configUSE_TIMERS */ /* Setting up the timer tick is hardware specific and thus in the portable interface. */
if( xPortStartScheduler() != pdFALSE )
{
/* Should not reach here as if the scheduler is running the
* function will not return. */
}
}
}

cortex-m4f架构上调度器启动接口,主要做os-tick初始化配置和运行第一个任务

// FreeRTOS\Source\portable\IAR\ARM_CM4F\port.c
BaseType_t xPortStartScheduler( void )
{
/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI; /* Start the timer that generates the tick ISR. Interrupts are disabled here already. */
vPortSetupTimerInterrupt(); /* Start the first task. */
vPortStartFirstTask();

配置os-tick

// FreeRTOS\Source\portable\IAR\ARM_CM4F\port.c
/*
* Setup the systick timer to generate the tick interrupts at the required
* frequency.
*/
__weak void vPortSetupTimerInterrupt( void )
{
/* Calculate the constants required to configure the tick interrupt. */
#if ( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
}
#endif /* configUSE_TICKLESS_IDLE */ /* Stop and clear the SysTick. */
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}

启动第一个任务

// FreeRTOS\Source\portable\IAR\ARM_CM4F\portasm.s
vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0] // 获取向量表起始地址
ldr r0, [r0] // 获取向量表
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Clear the bit that indicates the FPU is in use in case the FPU was used
before the scheduler was started - which would otherwise result in the
unnecessary leaving of space in the SVC stack for lazy saving of FPU
registers. */
mov r0, #0
msr control, r0
/* Call SVC to start the first task. */
cpsie i
cpsie f
dsb
isb
svc 0 // 产生SVC中断请求

SCB->VTOR

SVC机制

Cortex-M3 存储器布局

SVC服务程序

// FreeRTOS\Source\portable\IAR\ARM_CM4F\portasm.s
vPortSVCHandler:
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r1, [r3] // 获取当前任务控制块
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14} // 从当前任务栈顶开始弹栈
msr psp, r0 // 更新线程栈指针
isb // 清洗指令流,以保证之前的动作执行完毕
mov r0, #0
msr basepri, r0
bx r14

刚创建任务的栈初始化布局

(图片源自《FreeRTOS 内核实现与应用开发实战—基于STM32》)

任务控制块结构,第一个成员是栈顶指针

// FreeRTOS\Source\tasks.c
/*
* Task control block. A task control block (TCB) is allocated for each task,
* and stores task state information, including a pointer to the task's context
* (the task's run time environment, including register values)
*/
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
volatile StackType_t * pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */ #if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
#endif ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
StackType_t * pxStack; /*< Points to the start of the stack. */
char pcTaskName[ configMAX_TASK_NAME_LEN ]; /*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t * pxEndOfStack; /*< Points to the highest valid address for the stack. */
#endif #if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
#endif #if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
#endif #if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
UBaseType_t uxMutexesHeld;
#endif #if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t pxTaskTag;
#endif #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
#endif #if ( configGENERATE_RUN_TIME_STATS == 1 )
configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
#endif #if ( configUSE_NEWLIB_REENTRANT == 1 ) /* Allocate a Newlib reent structure that is specific to this task.
* Note Newlib support has been included by popular demand, but is not
* used by the FreeRTOS maintainers themselves. FreeRTOS is not
* responsible for resulting newlib operation. User must be familiar with
* newlib and must provide system-wide implementations of the necessary
* stubs. Be warned that (at the time of writing) the current newlib design
* implements a system-wide malloc() that must be provided with locks.
*
* See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
* for additional information. */
struct _reent xNewLib_reent;
#endif #if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
#endif /* See the comments in FreeRTOS.h with the definition of
* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
#endif #if ( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted;
#endif #if ( configUSE_POSIX_ERRNO == 1 )
int iTaskErrno;
#endif
} tskTCB; /* The old tskTCB name is maintained above then typedefed to the new TCB_t name
* below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t; /*lint -save -e956 A manual analysis and inspection has been used to determine
* which static variables must be declared volatile. */
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;

任务切换接口

/**
* task. h
*
* Macro for forcing a context switch.
*
* \defgroup taskYIELD taskYIELD
* \ingroup SchedulerControl
*/
#define taskYIELD() portYIELD()

cortex-m4f架构上的实现

// FreeRTOS\Source\portable\IAR\ARM_CM4F\portmacro.h
#define portYIELD() \
{ \
/* Set a PendSV to request a context switch. */ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
__DSB(); \
__ISB(); \
} #define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )

查看cortex-m权威指南,上述代码本质是触发了PendSVC中断

PendSVC服务程序

// FreeRTOS\Source\portable\IAR\ARM_CM3\portasm.s
xPortPendSVHandler:
mrs r0, psp // 将线程栈指针传给r0,为后续压栈准备
isb
ldr r3, =pxCurrentTCB // 获取当前线程控制块变量地址到r3
ldr r2, [r3] // 将栈顶地址给r2 stmdb r0!, {r4-r11} // 手动压栈
str r0, [r2] // 更新栈顶指针 stmdb sp!, {r3, r14} // 因在中断上下文环境,故使用sp指针进行压栈,压入上文线程栈控制块和LR,存LR是因为接下来要调用函数vTaskSwitchContext
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0 // 进入临界区,关闭受控的中断
dsb
isb
bl vTaskSwitchContext // 该函数中会更新变量pxCurrentTCB
mov r0, #0
msr basepri, r0 // 退出临界区,打开受控的中断
ldmia sp!, {r3, r14} // 函数调用结束弹栈 ldr r1, [r3] // 获取当前线程控制块变量地址
ldr r0, [r1] // 获取切换下文的任务栈顶指针
ldmia r0!, {r4-r11} // 从下文任务栈中弹栈
msr psp, r0
isb
bx r14 // 返回后,自动弹栈寄存器 R0-R3, R12, LR, PSR 和 PC,执行新任务

cortex-m4f架构会额外处理浮点寄存器的压栈弹栈

// FreeRTOS\Source\portable\IAR\ARM_CM4F\portasm.s
xPortPendSVHandler:
mrs r0, psp // 将线程栈指针传给r0,为后续压栈准备
isb
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r2, [r3] /* Is the task using the FPU context? If so, push high vfp registers. */
tst r14, #0x10
it eq
vstmdbeq r0!, {s16-s31} /* Save the core registers. */
stmdb r0!, {r4-r11, r14} // 手动压栈 /* Save the new top of stack into the first member of the TCB. */
str r0, [r2] stmdb sp!, {r0, r3}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r0, r3} /* The first item in pxCurrentTCB is the task top of stack. */
ldr r1, [r3]
ldr r0, [r1] /* Pop the core registers. */
ldmia r0!, {r4-r11, r14} /* Is the task using the FPU context? If so, pop the high vfp registers
too. */
tst r14, #0x10
it eq
vldmiaeq r0!, {s16-s31} msr psp, r0
isb
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
#if WORKAROUND_PMU_CM001 == 1
push { r14 }
pop { pc }
#endif
#endif bx r14

开始运行的任务栈布局,发生上下文切换时自动压栈寄存器 R0-R3, R12, LR, PSR 和 PC,psp指向R0,后续进行手动压栈

(图片源自《FreeRTOS 内核实现与应用开发实战—基于STM32》)

上下文切换,主要是找出就绪任务表中最高优先级的任务,栈溢出检查也在此执行

// FreeRTOS\Source\tasks.c
void vTaskSwitchContext( void )
{
if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
{
/* The scheduler is currently suspended - do not allow a context
* switch. */
xYieldPending = pdTRUE;
}
else
{
xYieldPending = pdFALSE;
traceTASK_SWITCHED_OUT(); #if ( configGENERATE_RUN_TIME_STATS == 1 )
{
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
#else
ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif /* Add the amount of time the task has been running to the
* accumulated time so far. The time the task started running was
* stored in ulTaskSwitchedInTime. Note that there is no overflow
* protection here so count values are only valid until the timer
* overflows. The guard against negative values is to protect
* against suspect run time stat counter implementations - which
* are provided by the application, not the kernel. */
if( ulTotalRunTime > ulTaskSwitchedInTime )
{
pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
}
else
{
mtCOVERAGE_TEST_MARKER();
} ulTaskSwitchedInTime = ulTotalRunTime;
}
#endif /* configGENERATE_RUN_TIME_STATS */ /* Check for stack overflow, if configured. */
taskCHECK_FOR_STACK_OVERFLOW(); /* Before the currently running task is switched out, save its errno. */
#if ( configUSE_POSIX_ERRNO == 1 )
{
pxCurrentTCB->iTaskErrno = FreeRTOS_errno;
}
#endif /* Select a new task to run using either the generic C or port
* optimised asm code. */
taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
traceTASK_SWITCHED_IN(); /* After the new task is switched in, update the global errno. */
#if ( configUSE_POSIX_ERRNO == 1 )
{
FreeRTOS_errno = pxCurrentTCB->iTaskErrno;
}
#endif #if ( configUSE_NEWLIB_REENTRANT == 1 )
{
/* Switch Newlib's _impure_ptr variable to point to the _reent
* structure specific to this task.
* See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
* for additional information. */
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
}
#endif /* configUSE_NEWLIB_REENTRANT */
}
}

系统调度,主要做os-tick++和触发PendSVC中断

// FreeRTOS\Source\portable\IAR\ARM_CM3\port.c
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
* executes all interrupts must be unmasked. There is therefore no need to
* save and then restore the interrupt mask value as its value is already
* known. */
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
* the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portENABLE_INTERRUPTS();
}

OS-Tick 心跳

// FreeRTOS\Source\tasks.c
BaseType_t xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE; /* Called by the portable layer each time a tick interrupt occurs.
* Increments the tick then checks to see if the new tick value will cause any
* tasks to be unblocked. */
traceTASK_INCREMENT_TICK( xTickCount ); if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
/* Minor optimisation. The tick count cannot change in this
* block. */
const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1; /* Increment the RTOS tick, switching the delayed and overflowed
* delayed lists if it wraps to 0. */
xTickCount = xConstTickCount; if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
{
taskSWITCH_DELAYED_LISTS();
}
else
{
mtCOVERAGE_TEST_MARKER();
} /* See if this tick has made a timeout expire. Tasks are stored in
* the queue in the order of their wake time - meaning once one task
* has been found whose block time has not expired there is no need to
* look any further down the list. */
if( xConstTickCount >= xNextTaskUnblockTime )
{
for( ; ; )
{
if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
{
/* The delayed list is empty. Set xNextTaskUnblockTime
* to the maximum possible value so it is extremely
* unlikely that the
* if( xTickCount >= xNextTaskUnblockTime ) test will pass
* next time through. */
xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
break;
}
else
{
/* The delayed list is not empty, get the value of the
* item at the head of the delayed list. This is the time
* at which the task at the head of the delayed list must
* be removed from the Blocked state. */
pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) ); if( xConstTickCount < xItemValue )
{
/* It is not time to unblock this item yet, but the
* item value is the time at which the task at the head
* of the blocked list must be removed from the Blocked
* state - so record the item value in
* xNextTaskUnblockTime. */
xNextTaskUnblockTime = xItemValue;
break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */
}
else
{
mtCOVERAGE_TEST_MARKER();
} /* It is time to remove the item from the Blocked state. */
listREMOVE_ITEM( &( pxTCB->xStateListItem ) ); /* Is the task waiting on an event also? If so remove
* it from the event list. */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
{
listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
} /* Place the unblocked task into the appropriate ready
* list. */
prvAddTaskToReadyList( pxTCB ); /* A task being unblocked cannot cause an immediate
* context switch if preemption is turned off. */
#if ( configUSE_PREEMPTION == 1 )
{
/* Preemption is on, but a context switch should
* only be performed if the unblocked task has a
* priority that is equal to or higher than the
* currently executing task. */
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_PREEMPTION */
}
}
} /* Tasks of equal priority to the currently running task will share
* processing time (time slice) if preemption is on, and the application
* writer has not explicitly turned time slicing off. */
#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
{
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ #if ( configUSE_TICK_HOOK == 1 )
{
/* Guard against the tick hook being called when the pended tick
* count is being unwound (when the scheduler is being unlocked). */
if( xPendedTicks == ( TickType_t ) 0 )
{
vApplicationTickHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_TICK_HOOK */ #if ( configUSE_PREEMPTION == 1 )
{
if( xYieldPending != pdFALSE )
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_PREEMPTION */
}
else
{
++xPendedTicks; /* The tick hook gets called at regular intervals, even if the
* scheduler is locked. */
#if ( configUSE_TICK_HOOK == 1 )
{
vApplicationTickHook();
}
#endif
} return xSwitchRequired;
}

心跳接口做了如下几件事

1、os-tick计数溢出检查,溢出后交换延时链表pxDelayedTaskList与溢出延时链表pxOverflowDelayedTaskList,以使逻辑正确执行

Delay函数会将阻塞任务根据os-tick计数是否溢出,分别将唤醒状态链表挂载到链表DelayedTaskList或OverflowDelayedTaskList

// FreeRTOS\Source\tasks.c
void vTaskDelay( const TickType_t xTicksToDelay )
{
/* A delay time of zero just forces a reschedule. */
if( xTicksToDelay > ( TickType_t ) 0U )
{
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
} static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
/* Calculate the time at which the task should be woken if the event does not occur. This may overflow but this
* doesn't matter, thekernel will manage it correctly. */
xTimeToWake = xConstTickCount + xTicksToWait; /* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); if( xTimeToWake < xConstTickCount )
{
/* Wake time has overflowed. Place this item in the overflow list. */
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
/* The wake time has not overflowed, so the current block list is used. */
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) ); /* If the task entering the blocked state was placed at the head of the list of blocked tasks then xNextTaskUnblockTime
* needs to be updated too. */
if( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake;
}

上述代码实现逻辑如下

2、检查阻塞任务的计时结束,遍历Delay任务链表获取激活任务

2.1、将激活任务从阻塞状态和事件链表删除

2.2、将激活任务加入就绪链表

2.3、若使能抢占式调度,则标记切换请求

3、若使能抢占式调度和时间片调度,则标记切换请求以切换同优先级任务进行时间片共享

4、计数调度器挂起os-tick数

5、进行os-tick钩子函数调用

详细分析可见:https://infiniteyuan.blog.csdn.net/article/details/83027976

【FreeRTOS】任务调度的更多相关文章

  1. FreeRTOS——任务调度—抢占式,时间片和合作式

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章教程为大家将介绍 FreeRTOS 操作系统支持的任务调度方式:抢占式,时间片和合作式,这部分算是 Fr ...

  2. FreeRTOS基础篇教程目录汇总

    以下教程(大部分章节)(尤其理论介绍部分)转载自安富莱电子,官网链接: http://forum.armfly.com/forum.php 然后根据安富莱的教程自己做了分析和测试,希望大家共同进步. ...

  3. 双非本科进大疆(SP)!

    哈喽,大家好,我是仲一.今天和大家分享的是一位优秀双非本科生上岸大疆的经历(羡慕哭了...). 今年4月底的时候,这位学弟和我分享了他拿下oppo,京东,联发科实习offer的经历,当时我还发了朋友圈 ...

  4. freertos 启动任务调度器后卡在svc 0,汇编停在了0x0800014A E7FE B 0x0800014A

    分别引导加载程序和应用程序(带有或不带有FreeRTOS)都可以正常工作. 引导加载程序和应用程序(无需FreeRTOS)可以完美运行. 但是,如果我在应用程序中使用freeRTOS并完成两项任务(显 ...

  5. FreeRTOS学习及移植笔记之二:在IAR和STM32F103VET上移植FreeRTOS

    上一次,我们简单的测试了FreeRTOS的基于IAR EWARM v6.4和STM32F103VET6平台的Demo,对其有了一个基本认识.接下来我们开始自己移植FreeRTOS的过程. 1.创建一个 ...

  6. STM32与FreeRTOS实现低功耗

    在工作过程中,遇到这样一个产品,它基于 Cortex-M7 内核的 STM32F769 芯片,同时使用了 FreeRTOS 实时操作系统. 由于该产品使用电池供电,因此有着低功耗的需求. 接下来,我将 ...

  7. FreeRTOS初步认识

    源:FreeRTOS初步认识 用了半天时间对FreeRTOS有了一个初步的认识,大概总结一下,其中混杂了系统实现和实际应用方面的问题. 现只是以应用为目的,实现方面待以后进一步研究. 1.FreeRT ...

  8. FreeRTOS——任务管理

    1. FreeRTOS 任务不允许以任何方式从实现函数中返回——他们绝不能有一条“return”语句,也不可能执行到函数的末尾.如果一个函数不需要,可以将其删除,如在任务中使用函数vTaskDelet ...

  9. 2、FreeRTOS任务相关API函数

    1.任务相关的API函数 函数存在于task.c中,主要的函数有: xTaskCreate():使用动态的方法创建一个任务: xTaskCreatStatic():使用静态的方法创建一个任务(用的非常 ...

  10. FREERTOS学习笔记

    2012-02-25 21:43:40 为提升自己对实时操作系统(RTOS)的认识,我学习了freeRTOS. 理解了OS任务的状态.优先级的概念.信号量的概念.互斥的概念.队列.内存管理.这都是和R ...

随机推荐

  1. 这些 git 高级命令你知道几个

    大家好,我是 dom 哥.今天给大家分享几个 git 的高级应用. git 是目前最流行的版本控制工具.git 玩的 6 不 6,轻则影响自己的开发幸福指数 ,重则影响下班时间 .本文介绍一些日常开发 ...

  2. Java使用HttpUtil.request方法可以发送请求即【Java访问url得到响应数据】

    Java使用HttpUtil.request方法可以发送请求即[Java访问url得到响应数据] 注:这个工具类可以在网上找,也可以自己手写 ,手写的话需要用到以下依赖: <dependency ...

  3. iMessage群发系统常见代码分享!

    随着iMessage的普及,越来越多的开发者开始关注如何利用iMessage进行消息群发,今天,我们就来分享一些常见的iMessage群发系统的代码示例,帮助大家更好地实现这一功能. 一.使用Swif ...

  4. 【C# 技术】C# 常用排序方式

     前言  在最近的项目中经常会对C#中的数据进行排序,对于基本数据类型,其排序方式比较简单,只需要调用内置算法即可实现,但对于自定义数据类型以及自定义排序规则的情况实现起来就比较麻烦,所以在本文章中将 ...

  5. 直击云栖|践行数据化运维,云掣重新解读MSP

    2020年云栖大会百城汇·杭州站,云掣MSP专场圆满落幕! 本次云栖大会·云掣MSP专场以"数据智能,智能运维"为主题,主要聚焦企业云化转型演进趋势,云上运维全景监控以及云原生云环 ...

  6. JNA入门(一)

    JNA入门,代码在github写得明明白白:https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md 一. ...

  7. 如何强制SQL走性能更优的hash join

    本文分享自华为云社区<[SQL优化]为什么有时候无法走执行性能更优的hashjoin>,作者: leapdb. 1. hash join通常优于nestloop join 通常nestlo ...

  8. 问鼎CodeXGLUE榜单,华为云UniXcoder-VESO-v1算法取得突破

    摘要:华为云PaaS技术创新团队基于UniXcoder模型,在公开测试数据集(CodeXGLUE)上的代码搜索任务评测结果上取得突破,在CodeXGLUE榜单上排名中第一. 本文分享自华为云社区< ...

  9. 解读顶会ICDE’21论文:利用DAEMON算法解决多维时序异常检测问题

    摘要:该论文针对多维时序数据的异常检测问题,提出了基于GAN和AutoEncoder的深度神经网络算法,并取得了当前State of the Art (SOTA)的检测效果.论文是云数据库创新LAB在 ...

  10. 带你掌握二进制SCA检测工具的短板及应对措施

    摘要:本文针对二进制SCA检测技术短板所面临的一些特殊场景.检测影响及应对措施进行详细分析和说明,希望对使用二进制SCA检测工具的测试和研发人员有所帮助. 本文分享自华为云社区<二进制SCA检测 ...