admin 管理员组文章数量: 887021
STM32第二十九课(Freertos, HAL, cubemx,CMSIS)
来看看CMSIS_V1对Freertos的API的封装。
主要是cmsis_os.h文件。
+++++++++++++++++++++++++++++++++++++++++++++++++++++
typedef enum {osPriorityIdle = -3, ///< priority: idle (lowest)osPriorityLow = -2, ///< priority: lowosPriorityBelowNormal = -1, ///< priority: below normalosPriorityNormal = 0, ///< priority: normal (default)osPriorityAboveNormal = +1, ///< priority: above normalosPriorityHigh = +2, ///< priority: highosPriorityRealtime = +3, ///< priority: realtime (highest)osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal priority
} osPriority;
定义了任务优先级。我们通常设置的7级。
#define osWaitForever 0xFFFFFFFF
定义了MAX_TIMEOUT。
typedef enum {osOK = 0, ///< function completed; no error or event occurred.osEventSignal = 0x08, ///< function completed; signal event occurred.osEventMessage = 0x10, ///< function completed; message event occurred.osEventMail = 0x20, ///< function completed; mail event occurred.osEventTimeout = 0x40, ///< function completed; timeout occurred.osErrorParameter = 0x80, ///< parameter error: a mandatory parameter was missing or specified an incorrect object.osErrorResource = 0x81, ///< resource not available: a specified resource was not available.osErrorTimeoutResource = 0xC1, ///< resource not available within given time: a specified resource was not available within the timeout period.osErrorISR = 0x82, ///< not allowed in ISR context: the function cannot be called from interrupt service routines.osErrorISRRecursive = 0x83, ///< function called multiple times from ISR with same object.osErrorPriority = 0x84, ///< system cannot determine priority or thread has illegal priority.osErrorNoMemory = 0x85, ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.osErrorValue = 0x86, ///< value of a parameter is out of range.osErrorOS = 0xFF, ///< unspecified RTOS error: run-time error but no other error message fits.os_status_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
} osStatus;
定义了状态码。
typedef enum {osTimerOnce = 0, ///< one-shot timerosTimerPeriodic = 1 ///< repeating timer
} os_timer_type;
定义了soft timer的类型码。
typedef TaskHandle_t osThreadId;
定义了TCB的句柄的类型。
typedef void (*os_pthread) (void const *argument);
定义了taskfunc的函数指针的类型。
typedef TimerHandle_t osTimerId;
定义了soft timer的句柄的类型。
typedef void (*os_ptimer) (void const *argument);
定义了soft timer的callback的函数指针的类型。
+++++++++++++++++++++++++++++++++++++++++++++++++++
#define osThreadDef(name, thread, priority, instances, stacksz) \
const osThreadDef_t os_thread_def_##name = \
{ #name, (thread), (priority), (instances), (stacksz), NULL, NULL }
宏拟函数,作用是填充一个TCB。包括taskfunc,优先级,taskname,stacksize,taskfuncref等。
#define osThread(name) \
&os_thread_def_##name
宏拟函数,作用是获取一个TCB的句柄。
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
宏拟函数。作用是控制访问临界区。
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument);
创建task,返回值是一个TCB的句柄。
osStatus osKernelStart (void);
调度器的启动函数。返回值是状态码。
uint32_t osKernelSysTick (void);
查询SYSTICK的函数。返回值是当前SYSTICK值。
osStatus osThreadTerminate (osThreadId thread_id);
删除一个task。返回值是状态码。
来看看函数实现。
osStatus osThreadTerminate (osThreadId thread_id)
{vTaskDelete(thread_id);return osOK;
}
其实就是对vTaskDelete的调用的二次封装。
osStatus osDelay (uint32_t millisec);
阻塞任务,并在延时到期后,解除阻塞。
来看看函数实现。
osStatus osDelay (uint32_t millisec)
{TickType_t ticks = millisec / portTICK_PERIOD_MS;vTaskDelay(ticks ? ticks : 1); /* Minimum delay = 1 tick */return osOK;
}
其实就是对vTaskDelay的二次封装。
osStatus osThreadYield (void);
主动发起一次任务调度。
来看看函数实现。
osStatus osThreadYield (void)
{taskYIELD();return osOK;
}
其实就是对taskYIELD的二次封装。
osStatus osThreadSuspend (osThreadId thread_id);
挂起一个task。在管理者任务里调用。
来看看函数实现。
osStatus osThreadSuspend (osThreadId thread_id)
{vTaskSuspend(thread_id); return osOK;}
其实就是对vTaskSuspend的二次封装。
osStatus osThreadResume (osThreadId thread_id);
恢复一个task。在管理者任务里调用。
来看看函数实现。
osStatus osThreadResume (osThreadId thread_id)
{if(inHandlerMode()){if (xTaskResumeFromISR(thread_id) == pdTRUE){portYIELD_FROM_ISR(pdTRUE);}}else{vTaskResume(thread_id);}return osOK;
}
其实就是对vTaskResume的二次封装。
通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portYIELD_FROM_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
++++++++++++++++++++++++++++++++++++++++++++++++++++
#define osTimerDef(name, function) \
const osTimerDef_t os_timer_def_##name = \
{ (function), NULL }
宏拟函数,作用是填充一个STDB,包括callback,callbackref等。
#define osTimer(name) \
&os_timer_def_##name
宏拟函数,作用是获取一个STDB的句柄。
osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument);
创建一个softtimer。返回值是一个soft timer的句柄。
osStatus osTimerDelete (osTimerId timer_id);
删除一个soft timer。返回值是状态码。
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
启动一个soft timer。返回值是状态码。
osStatus osTimerStop (osTimerId timer_id);
停止一个soft timer,返回值是状态码。
+++++++++++++++++++++++++++++++++++++++++++++++++++++
static int inHandlerMode (void)
{return __get_IPSR() != 0;
}#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
在很多CMSIS封装的API中,都会出现这几个函数。
它们就是进行上下文判断,如果是ISR中,就调用fromisr版本的API,
如果不是ISR中,就调用常规版本的API。
+++++++++++++++++++++++++++++++++++++++++++++++++++
typedef QueueHandle_t osMessageQId;
定义了queue的句柄的类型。
typedef struct QueueDefinition * QueueHandle_t;
typedef struct QueueDefinition xQUEUE;
typedef xQUEUE Queue_t;
所以,在CMSIS下,osMessageQId,是一个指针,是一个Queue的句柄。
const osMessageQDef_t os_messageQ_def_##name = \
{ (queue_sz), sizeof (type), NULL, NULL }
宏拟函数,用来填充一个MsgQDB。
#define osMessageQ(name) \
&os_messageQ_def_##name
宏拟函数,用来获取一个MsgQDB的句柄。
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
创建一个MsgQDB,并返回MsgQDB的句柄。
osStatus osMessageDelete (osMessageQId queue_id);
删除一个MsgQDB,返回值是状态码。
来看看函数实现。
osStatus osMessageDelete (osMessageQId queue_id)
{if (inHandlerMode()) {return osErrorISR;}vQueueDelete(queue_id);return osOK;
}
其实就是对vQueueDelete的二次封装。
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
向一个MsgQ中,填充一个Msg。返回值是状态码。
来看看函数实现。
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)
{portBASE_TYPE taskWoken = pdFALSE;TickType_t ticks;...if (inHandlerMode()) {if (xQueueSendFromISR(queue_id, &info, &taskWoken) != pdTRUE) {return osErrorOS;}portEND_SWITCHING_ISR(taskWoken);}else {if (xQueueSend(queue_id, &info, ticks) != pdTRUE) {return osErrorOS;}}return osOK;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
注意,如果要使用osMessagePut ,传递的info,那么就必须是uint32_t类型。MsgQ会根据ItemSize,从info中取出需要的Byte。如果Msg的长度大于4个byte,那么就需要使用传址方式了。将sendbuffer的基地址,作为info传递。
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
从一个MsgQ中,获取一个Msg。返回
来看看函数实现。
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)
{portBASE_TYPE taskWoken;TickType_t ticks;osEvent event;event.def.message_id = queue_id;event.value.v = 0;taskWoken = pdFALSE;...if (inHandlerMode()) {if (xQueueReceiveFromISR(queue_id, &event.value.v, &taskWoken) == pdTRUE) {/* We have mail */event.status = osEventMessage;}else {event.status = osOK;}portEND_SWITCHING_ISR(taskWoken);}else {if (xQueueReceive(queue_id, &event.value.v, ticks) == pdTRUE) {/* We have mail */event.status = osEventMessage;}else {event.status = (ticks == 0) ? osOK : osEventTimeout;}}return event;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
返回值是一个osEvent类型的变量。返回值中,event.status携带了状态码,event.value.v则携带了Msg的内容。
注意,如果要使用osMessagePut ,传递的info,那么就必须是uint32_t类型。MsgQ会根据ItemSize,从info中取出需要的Byte。如果Msg的长度大于4个byte,那么就需要使用传址方式了。将sendbuffer的基地址,作为info传递。
来看看event的定义。
typedef struct {osStatus status; ///< status code: event or error informationunion {uint32_t v; ///< message as 32-bit valuevoid *p; ///< message or mail as void pointerint32_t signals; ///< signal flags} value; ///< event valueunion {osMailQId mail_id; ///< mail id obtained by \ref osMailCreateosMessageQId message_id; ///< message id obtained by \ref osMessageCreate} def; ///< event definition
} osEvent;
这是一个结构体对象,并且使用了struct-union技巧。
成员变量value和成员变量def,都是Union。
当我们用成员索引运算符".“或者”->"选择union的member时,本质上,是选取了对union的类型的解析方式,
换句话说,当我们对union使用了成员索引运算符时,实际上是执行了强制类型转换操作。
所以,在表达式event.value.v中,value.v这个子表达式,就将value强制转换成uint32_t类型。
osEvent osMessagePeek (osMessageQId queue_id, uint32_t millisec);
探取但是并不取走Msg。
注意,如果要使用osMessagePut ,传递的info,那么就必须是uint32_t类型。MsgQ会根据ItemSize,从info中取出需要的Byte。如果Msg的长度大于4个byte,那么就需要使用传址方式了。将sendbuffer的基地址,作为info传递。
来看看函数实现。
osEvent osMessagePeek (osMessageQId queue_id, uint32_t millisec)
{TickType_t ticks;osEvent event;event.def.message_id = queue_id;...if (xQueuePeek(queue_id, &event.value.v, ticks) == pdTRUE) {/* We have mail */event.status = osEventMessage;}else {event.status = (ticks == 0) ? osOK : osEventTimeout;}return event;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
++++++++++++++++++++++++++++++++++++++++++++++++++++
uint32_t osMessageWaiting(osMessageQId queue_id);
判断MsgQ中,有多少Msg等待被取走。返回值是有效的msg的数量。
来看看函数实现。
uint32_t osMessageWaiting(osMessageQId queue_id)
{if (inHandlerMode()) {return uxQueueMessagesWaitingFromISR(queue_id);}else{return uxQueueMessagesWaiting(queue_id);}
}
函数中会判断上下文是否是ISR,并调用对应的fromisr版本的API。
来看看uxQueueMessagesWaiting函数实现。
UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue )
{
UBaseType_t uxReturn;configASSERT( xQueue );taskENTER_CRITICAL();{uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting;}taskEXIT_CRITICAL();return uxReturn;
}typedef struct QueueDefinition /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{...volatile UBaseType_t uxMessagesWaiting;/*< The number of items currently in the queue. */...
} xQUEUE;
可见,该函数返回值是有效Msg的数量。
uint32_t osMessageAvailableSpace(osMessageQId queue_id);
判断MsgQ中,有多少MsgSpace可以用来填充。返回值是有效的MsgSpace的数量。
来看看函数实现。
uint32_t osMessageAvailableSpace(osMessageQId queue_id)
{return uxQueueSpacesAvailable(queue_id);
}
就是对uxQueueSpacesAvailable的二次封装。
来看看uxQueueSpacesAvailable的函数实现。
UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue )
{
UBaseType_t uxReturn;
Queue_t * const pxQueue = xQueue;configASSERT( pxQueue );taskENTER_CRITICAL();{uxReturn = pxQueue->uxLength - pxQueue->uxMessagesWaiting;}taskEXIT_CRITICAL();return uxReturn;
}
可见,该函数返回值是有效MsgSpace的数量。
++++++++++++++++++++++++++++++++++++++++++++++++
typedef SemaphoreHandle_t osSemaphoreId;
定义了semaph的句柄的类型。
#define osSemaphoreDef(name) \
const osSemaphoreDef_t os_semaphore_def_##name = { 0, NULL }
宏拟函数,作用是填充一个SemDB。
#define osSemaphore(name) \
&os_semaphore_def_##name
宏拟函数,作用是获取SemDB的句柄。
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count);
创建一个semaph,返回值是状态码。
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
删除一个semaph,返回值是状态码。
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
在一个semaph上阻塞,然后等待,直到get semaph或者timeout,就解除阻塞,并返回,返回值是有效的token的数量。
来看看函数实现。
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec)
{TickType_t ticks;portBASE_TYPE taskWoken = pdFALSE; ...if (inHandlerMode()) {if (xSemaphoreTakeFromISR(semaphore_id, &taskWoken) != pdTRUE) {return osErrorOS;}portEND_SWITCHING_ISR(taskWoken);} else if (xSemaphoreTake(semaphore_id, ticks) != pdTRUE) {return osErrorOS;}return osOK;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
释放掉一个semaph,并将阻塞在这个semaph上的task解除阻塞。返回值是状态码。
来看看函数实现。
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id)
{osStatus result = osOK;portBASE_TYPE taskWoken = pdFALSE;if (inHandlerMode()) {if (xSemaphoreGiveFromISR(semaphore_id, &taskWoken) != pdTRUE) {return osErrorOS;}portEND_SWITCHING_ISR(taskWoken);}else {if (xSemaphoreGive(semaphore_id) != pdTRUE) {result = osErrorOS;}}return result;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
+++++++++++++++++++++++++++++++++++++++++++++++
typedef SemaphoreHandle_t osMutexId;
定义了mutex的句柄的类型。
#define osMutexDef(name) \
const osMutexDef_t os_mutex_def_##name = { 0, NULL }
宏拟函数,作用是填充一个MutDB。
#define osMutex(name) \
&os_mutex_def_##name
宏拟函数,作用是获取一个MutDB的句柄。
osMutexId osMutexCreate (const osMutexDef_t *mutex_def);
创建一个mutex,返回值是状态码。
osStatus osMutexDelete (osMutexId mutex_id);
删除一个mutex。返回值是状态码。
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
在一个mutex上阻塞,然后等待,直到get mutex或者timeout,就解除阻塞,并返回,返回值是状态码。
来看看函数实现。
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec)
{TickType_t ticks;portBASE_TYPE taskWoken = pdFALSE; ...if (inHandlerMode()) {if (xSemaphoreTakeFromISR(mutex_id, &taskWoken) != pdTRUE) {return osErrorOS;}portEND_SWITCHING_ISR(taskWoken);} else if (xSemaphoreTake(mutex_id, ticks) != pdTRUE) {return osErrorOS;}return osOK;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
osStatus osMutexRelease (osMutexId mutex_id);
释放掉一个mutex,并将阻塞在这个mutex上的task解除阻塞。返回值是状态码。
来看看函数实现。
osStatus osMutexRelease (osMutexId mutex_id)
{osStatus result = osOK;portBASE_TYPE taskWoken = pdFALSE;if (inHandlerMode()) {if (xSemaphoreGiveFromISR(mutex_id, &taskWoken) != pdTRUE) {return osErrorOS;}portEND_SWITCHING_ISR(taskWoken);}else if (xSemaphoreGive(mutex_id) != pdTRUE) {result = osErrorOS;}return result;
}
其实内部就是通过检查是否处于ISR中,判断是否调用fromisr版本的API。
如果是fromisr版本的API,还配套执行一次portEND_SWITCHING_ISR,
如果不是处于ISR中,那么就执行常规版本的API。
++++++++++++++++++++++++++++++++++++++++++
如果使用递归互斥量,那么有对应的API。
osMutexId osRecursiveMutexCreate (const osMutexDef_t *mutex_def);
创建一个递归互斥量。返回一个RMutDB的句柄。
osStatus osRecursiveMutexWait (osMutexId mutex_id, uint32_t millisec);
在一个mutex上阻塞,然后等待,直到get mutex或者timeout,就解除阻塞,并返回,返回值是状态码。
osStatus osMutexDelete (osMutexId mutex_id);
删除一个mutex。返回值是状态码。
osStatus osRecursiveMutexWait (osMutexId mutex_id, uint32_t millisec);
在一个mutex上阻塞,然后等待,直到get mutex或者timeout,就解除阻塞,并返回,返回值是状态码。
如果递归申请,则对RecurMutex进行计数加一。
osStatus osRecursiveMutexRelease (osMutexId mutex_id);
释放掉一个mutex,并将阻塞在这个mutex上的task解除阻塞。返回值是状态码。
如果递归释放,则对RecurMutex进行计数减一。
uint32_t osSemaphoreGetCount(osSemaphoreId semaphore_id);
获取semaph的当前计数值。
来看看函数实现。
uint32_t osSemaphoreGetCount(osSemaphoreId semaphore_id)
{return uxSemaphoreGetCount(semaphore_id);
}#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
其实就是对uxSemaphoreGetCount的二次封装。底层,就是查询MsgQ中有效的Msg的数量。
本文标签: STM32第二十九课(Freertos HAL cubemx,CMSIS)
版权声明:本文标题:STM32第二十九课(Freertos, HAL, cubemx,CMSIS) 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1699123664h330834.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论