学习OSAL并移植到STM32F103开发板上
代码参考出处:https://github.com/mcuwty/osal.git
我在此此基础上做了整理,移植到了stm32f103上:demo链接: https://pan.baidu.com/s/1WoL8QCnicxO11hdeh4uh2Q 提取码: wsn3
参考资料: 学习笔记(二)——BLE协议栈OSAL - 知乎 (zhihu.com)
OSAL:即操作系统抽象层,它并不是一个传统意义上的操作系统,但是实现了部分类似操作系统的功能 ,包含消息通知,任务调度,时间控制等,不具有优先级抢占功能,由任务事件驱动。
可以创建任务,然后每个任务由一个16bit的事件标志来驱动,最高位用于驱动系统消息事件,其余15位可以我们自由设置:
任务结构体如下:
包含事件处理函数,任务ID,事件标志,任务优先级。
typedef struct OSALTaskREC
{
struct OSALTaskREC *next;
pTaskEventHandlerFn pfnEventProcessor; // Event Processor function
uint8_t task_id; // task id
uint8_t taskPriority; // task Priority
uint16_t events; // task event
} OsalTadkREC_t;
任务是一个链表,加入任务时,添加任务到链表尾部,同时比较优先级,优先级高的插入前级节点
osal_task_add();
uint8_t osal_task_add(uint8_t task_id,
pTaskEventHandlerFn pfnEventProcessor,
uint8_t taskPriority)
{
OsalTadkREC_t *task_new;
OsalTadkREC_t *task_search;
OsalTadkREC_t **task_ptr; task_new = osal_mem_alloc(sizeof(OsalTadkREC_t));
if (task_new)
{
task_new->pfnEventProcessor = pfnEventProcessor;
task_new->task_id = task_id;
task_new->events = 0; // default event is null
task_new->taskPriority = taskPriority;
task_new->next = (OsalTadkREC_t *)NULL; task_ptr = &g_pTaskHead;
task_search = g_pTaskHead;
g_tasks_count++; // task count + 1 while (task_search)
{
/* Poll the task list to select the correct position to insert */
if (task_new->taskPriority > task_search->taskPriority)
{
/* insert before the search node */
task_new->next = task_search;
*task_ptr = task_new;
return OSAL_RET_SUCCESS;
}
/* Find next node*/
task_ptr = &task_search->next;
task_search = task_search->next;
}
/* New nodes have the lowest priority ,Put it at the end of the task list.*/
*task_ptr = task_new;
return OSAL_RET_SUCCESS;
}
else
{
return OSAL_RET_ERROR;
}
}
任务的调度通过轮询来执行:
osal_system_start();
void osal_system_start(void)
{
uint16_t events;
uint16_t retEvents; while (1)
{
g_pTaskActive = osal_find_next_activeTask();//找有事件标志的任务
if (g_pTaskActive)
{
OSAL_ENTER_CRITICAL_SECTION();
events = g_pTaskActive->events;//清除标志位
// Clear the Events for this task
g_pTaskActive->events = 0;
OSAL_EXIT_CRITICAL_SECTION(); if (events != 0)
{
// Call the task to process the event(s)
if (g_pTaskActive->pfnEventProcessor)
{
retEvents = (g_pTaskActive->pfnEventProcessor)(g_pTaskActive->task_id, events);//运行任务
// Add back unprocessed events to the current task
OSAL_ENTER_CRITICAL_SECTION();
g_pTaskActive->events |= retEvents;
OSAL_EXIT_CRITICAL_SECTION();
}
}
}
}
}
事件标志用下面两个函数来配置:
osal_event_set();
osal_event_clear();
/**************************************************************************
\brief This function is called to set the event flags for a task.
The event passed in is OR'd into the task's event variable.
\param task_id receiving tasks ID
\param event_flag what event to set
\return uint8_t success or fail
**************************************************************************/
uint8_t osal_event_set(uint8_t task_id, uint16_t event_flag)
{
OsalTadkREC_t *task_search = NULL;
task_search = osal_find_task(task_id);
if (task_search)
{
OSAL_ENTER_CRITICAL_SECTION();
task_search->events |= event_flag; // Stuff the event bit(s)
OSAL_EXIT_CRITICAL_SECTION();
}
else
{
return (OSAL_RET_INVALID_TASK);
}
return (OSAL_RET_SUCCESS);
} /**************************************************************************
\brief This function is called to clear the event flags for a task.
The event passed in is masked out of the task's event variable.
\param task_id receiving tasks ID
\param event_flag what event to clear
\return uint8_t success or fail
**************************************************************************/
uint8_t osal_event_clear(uint8_t task_id, uint16_t event_flag)
{
OsalTadkREC_t *task_search;
task_search = osal_find_task(task_id);
if (task_search)
{
OSAL_ENTER_CRITICAL_SECTION();
task_search->events &= ~event_flag; // Mask the event bit(s)
OSAL_EXIT_CRITICAL_SECTION();
}
else
{
return (OSAL_RET_INVALID_TASK);
}
return (OSAL_RET_SUCCESS);
}
定时功能是通过设置事件标志位来实现的,本质也是轮询任务和事件标志位:
定时功能同样采用链表形式,通过单片机的定时器进行定时。在中断服务中,轮询这个定时链表,一旦达到设定时间,就设置相应的事件标志位。
osal_timer_start_once();
osal_timer_start_reload();
typedef struct
{
void *next;
uint16_t timeout; // 定时时间,每过一个系统时钟会自减
uint16_t event_flag; // 定时事件,定时时间减完产生任务事件
uint8_t task_id; // 响应的任务ID
uint16_t reloadTimeout; // 重装定时时间
} osalTimerRec_t; // 任务定时器,链表结构 /**************************************************************************
\brief This function is called to start a timer to expire in n mSecs.
When the timer expires, the calling task will get the specified event.
\param task_id
\param event_id
\param timeout_value
\return uint8_t
**************************************************************************/
static uint8_t osal_timer_start_once(uint8_t task_id, uint16_t event_id, uint16_t timeout_value)
{
osalTimerRec_t *newTimer; OSAL_ENTER_CRITICAL_SECTION();
/* Add timer */
newTimer = osal_timer_add_list(task_id, event_id, timeout_value);
OSAL_EXIT_CRITICAL_SECTION();
return ((newTimer != NULL) ? OSAL_SUCCESS : OSAL_RET_NO_TIMER_AVAIL);
} /**************************************************************************
\brief This function is called to start a timer to expire in n mSecs.
When the timer expires, the calling task will get the specified event
and the timer will be reloaded with the timeout value.
\param task_id
\param event_id
\param timeout_value
\return uint8_t
**************************************************************************/
static uint8_t osal_timer_start_reload(uint8_t task_id, uint16_t event_id, uint16_t timeout_value)
{
osalTimerRec_t *newTimer; OSAL_ENTER_CRITICAL_SECTION();
/* Add timer */
newTimer = osal_timer_add_list(task_id, event_id, timeout_value);
if (newTimer)
{
/* Load the reload timeout value */
newTimer->reloadTimeout = timeout_value;
} OSAL_EXIT_CRITICAL_SECTION();
return ((newTimer != NULL) ? OSAL_SUCCESS : OSAL_RET_NO_TIMER_AVAIL);
}
osal 定时中断函数:
void oasl_timer_update(uint16_t updateTime)
{
osalTimerRec_t *srchTimer;
osalTimerRec_t *prevTimer; OSAL_ENTER_CRITICAL_SECTION(); // Hold off interrupts.
// Update the system time
g_osal_systemClock += updateTime;
OSAL_EXIT_CRITICAL_SECTION(); // Re-enable interrupts. // Look for open timer slot
if (timerHead != NULL)
{
// Add it to the end of the timer list
srchTimer = timerHead;
prevTimer = (void *)NULL; // Look for open timer slot
while (srchTimer)
{
osalTimerRec_t *freeTimer = NULL; OSAL_ENTER_CRITICAL_SECTION(); // Hold off interrupts. if (srchTimer->timeout <= updateTime)
{
srchTimer->timeout = 0;
}
else
{
srchTimer->timeout = srchTimer->timeout - updateTime;
} // Check for reloading
if ((srchTimer->timeout == 0) && (srchTimer->reloadTimeout) && (srchTimer->event_flag))
{
// Notify the task of a timeout
osal_event_set(srchTimer->task_id, srchTimer->event_flag); // Reload the timer timeout value
srchTimer->timeout = srchTimer->reloadTimeout;
} // When timeout or delete (event_flag == 0)
if (srchTimer->timeout == 0 || srchTimer->event_flag == 0)
{
// Take out of list
if (prevTimer == NULL)
timerHead = srchTimer->next;
else
prevTimer->next = srchTimer->next; // Setup to free memory
freeTimer = srchTimer; // Next
srchTimer = srchTimer->next;
}
else
{
// Get next
prevTimer = srchTimer;
srchTimer = srchTimer->next;
} OSAL_EXIT_CRITICAL_SECTION(); // Re-enable interrupts. if (freeTimer)
{
if (freeTimer->timeout == 0)
{
osal_event_set(freeTimer->task_id, freeTimer->event_flag);
}
osal_mem_free(freeTimer);
}
}
}
}
消息通知也是一样,设置事件标志位传递消息,固定使用0x8000这一位。
内存管理:
参见:OSAL动态内存分配_osal_mem_free-CSDN博客
内存管理主要是划分一大块内存(一个大数组),通过给每一块内存划分一个头来判断该内存是否被使用,从而来分割内存和合并内存。减少内存的使用。
主要用于分配osal最基本的参数,包含定时器TCB,任务TCB;
这里的内存管理本质是管理定时器和消息的内存分配,重复利用该块内存,节约内存。 如果全部分配全局变量则会导致内存浪费:比如消息通知不使用时,内存造成浪费。也可以把系统使用的部分内存和app使用部分内存隔离开来,并提高CPU工作效率
void *osal_mem_alloc(uint16_t size){
osalMemHdr_t *prev = NULL;
osalMemHdr_t *hdr = NULL;
uint32_t tmp = 0;
bool is_have_idle_blk = false;
#if (OSALMEM_GUARD)
// Try to protect against premature use by HAL / OSAL.
if (ready != OSALMEM_READY)
{
osal_mem_init();
}
#endif
size += HDRSZ;
// Calculate required bytes to add to 'size' to align to halDataAlign_t.
if (sizeof(halDataAlign_t) == 2)
{
size += (size & 0x01); // judge size is odd or not,we need even
}
else if (sizeof(halDataAlign_t) != 1)
{
const uint8_t mod = size % sizeof(halDataAlign_t);
if (mod != 0)
{
size += (sizeof(halDataAlign_t) - mod); // Byte alignment
}
}
// Smaller allocations are first attempted in the small-block bucket.
OSAL_ENTER_CRITICAL_SECTION();
if (size <= OSALMEM_SMALL_BLKSZ)
{
hdr = g_p_ff1; // small-block bucket
}
else
{
hdr = g_p_ff2; // wilderness-block bucket
}
tmp = *hdr; // read current memory block head
do
{
if (tmp & OSALMEM_IN_USE)
{
tmp ^= OSALMEM_IN_USE; // This block memory has been used
is_have_idle_blk = false; // flag--> without air memory block
}
else // This block memory is not used
{
if (is_have_idle_blk) // have air Memory block but not enough
{
#if (OSAL_MEM_DEBUG)
blkCnt--; // Total memory block count -1
blkFree--; // freedown memory block count-1
#endif
*prev += *hdr; // Combine memory blocks
if (*prev >= size) // Find the enough memory size
{
hdr = prev;
tmp = *hdr;
break;
}
}
else // The memory block has idle blocks
{
if (tmp >= size) // Find the enough memory size
{
break;
}
is_have_idle_blk = true;
prev = hdr; // Continue to find
}
}
hdr = (osalMemHdr_t *)((uint8_t *)hdr + tmp); // memory block offset
tmp = *hdr;
if (tmp == 0)
{
hdr = ((void *)NULL); // Not enough memory blocks
break;
}
} while (1);
if (hdr != ((void *)NULL))
{
tmp -= size; // Calculate current block remaining size
if (tmp >= OSALMEM_MIN_BLKSZ) // If the remaining size is too big, it needs to be Split.
{
osalMemHdr_t *next = (osalMemHdr_t *)((uint8_t *)hdr + size); // Split the block before allocating it
*next = tmp;
*hdr = (size | OSALMEM_IN_USE); // Mark as used
#if (OSAL_MEM_DEBUG)
blkCnt++;
if (blkMax < blkCnt)
{
blkMax = blkCnt;
}
memAlo += size;
#endif
}
else
{
#if (OSAL_MEM_DEBUG)
memAlo += *hdr;
blkFree--;
#endif
*hdr |= OSALMEM_IN_USE;
}
#if (OSAL_MEM_DEBUG)
if (memMax < memAlo)
{
memMax = memAlo;
}
#endif
hdr++;
}
OSAL_EXIT_CRITICAL_SECTION();
return (void *)hdr;
}
主函数:三个任务
int main(void)
{
bsp_init(); __disable_irq();
osal_system_init(); app_task_led_init();
app_task_printf_init();
app_task_main_init(); task_add_end();
__enable_irq(); osal_system_start();
while (1)
{
}
}
主任务函数:
/**************************************************************************
\brief **************************************************************************/
#define TASK_PRIORITY_LED (uint8_t)3
#define TASK_PRIORITY_PRINTF (uint8_t)2
#define TASK_PRIORITY_MAIN (uint8_t)1 #define TASK_ID_LED (uint8_t)0
#define EVENT_LED_TOGGLE_1S (uint16_t)0x0001 #define TASK_ID_PRINTF (uint8_t)1
#define EVENT_PRINTF_1S (uint16_t)0x0001 #define TASK_ID_MAIN (uint8_t)2
/**************************************************************************
\brief task init
**************************************************************************/
void app_task_led_init(void)
{
osal_task_add(TASK_ID_LED, task_led_process, TASK_PRIORITY_LED);
osal_timer_add(TASK_ID_LED, EVENT_LED_TOGGLE_1S, 1000, TIMER_RELOAD);
} void app_task_printf_init(void)
{
osal_task_add(TASK_ID_PRINTF, task_printf_process, TASK_PRIORITY_PRINTF);
osal_timer_add(TASK_ID_PRINTF, EVENT_PRINTF_1S, 1000, TIMER_RELOAD);
} void app_task_main_init(void)
{
//main task drivers by message notice
osal_task_add(TASK_ID_MAIN, task_main_process, TASK_PRIORITY_MAIN);
}
/**************************************************************************
\brief task process
**************************************************************************/
uint16_t task_led_process(uint8_t task_id, uint16_t task_event)
{
if (task_event & EVENT_LED_TOGGLE_1S)
{
if(GPIO_ReadOutputDataBit(LED1_PORT,LED1_PIN)==1)
{
LED1_OFF;
}
else
{
LED1_ON;
}
return task_event ^ EVENT_LED_TOGGLE_1S;
}
return task_event;
} #define MSG_LED2_TOGGLE_1S (u8)1
uint16_t task_printf_process(uint8_t task_id, uint16_t task_event)
{
if (task_event & EVENT_PRINTF_1S)
{
printf("test success!\n\r");
app_send_msg(MSG_LED2_TOGGLE_1S,NULL,NULL);
return task_event ^ EVENT_PRINTF_1S;
}
return task_event;
} uint16_t task_main_process(uint8_t task_id, uint16_t task_event)
{
if (task_event & SYS_EVENT_MSG)
{
osal_sys_msg_t *p_msg;
p_msg = (osal_sys_msg_t *)osal_msg_receive(task_id);
while (p_msg)
{
app_msg_process(p_msg);
osal_msg_deallocate((u8 *)p_msg);
p_msg = (osal_sys_msg_t *)osal_msg_receive(task_id);
}
return (task_event ^ SYS_EVENT_MSG);
}
return task_event;
} /**************************************************************************
\brief msg sned
**************************************************************************/
uint8_t app_send_msg(uint8_t msg_event, uint8_t msg_status, uint8_t data)
{
osal_sys_msg_t* p_msg; p_msg = (osal_sys_msg_t*)osal_msg_allocate(sizeof(osal_sys_msg_t));
p_msg->hdr.event = msg_event;
p_msg->hdr.status = msg_status;
p_msg->data = data;
if(p_msg!=NULL)
{
osal_msg_send(TASK_ID_MAIN,(u8*)p_msg);
return 1;
}
return 0;
}
/**************************************************************************
\brief msg process
**************************************************************************/
void app_msg_process(osal_sys_msg_t *p_msg)
{
switch (p_msg->hdr.event)
{
case MSG_LED2_TOGGLE_1S:
if(GPIO_ReadOutputDataBit(LED2_PORT,LED2_PIN)==1)
{
LED2_OFF;
}
else
{
LED2_ON;
}
break;
default:
break;
}
}
实验现象:
LED1,LED2闪烁,串口1s打印1次

学习OSAL并移植到STM32F103开发板上的更多相关文章
- 物联网操作系统HelloX已成功移植到MinnowBoard MAX开发板上
在HelloX开发团队的努力下,以及Winzent Tech公司(总部在瑞典斯德哥尔摩)的支持下,HelloX最新版本V1.78已成功移植到MinnowBoard MAX开发板上.相关源代码已经发布到 ...
- 【原创】车载实时路况信息接收终端移植于Smart210开发板 --- 综合教程
[原创]车载实时路况信息接收终端移植于Smart210开发板 --- 综合教程 所用工具: windows电脑 Ubuntu12.04 Smart210开发板 4g以上SD卡 U盘 步骤: 1. ...
- 使用Xilinx SDSoc在Xilinx zcu102开发板上编程HelloWorld
关于Xilinx SDSoc的介绍我就不再复述了,我理解的也不一定准确,可以阅读官方文档了解SDSoc,你可以把它理解为一个集成开发环境 (IDE),通过SDSoc我们能够简单快速的对Xilinx的开 ...
- zedboard开发板上移植opencv代码(立体匹配)
前言 公司要做立体匹配相关的项目,已有matlab和c++版本,可是不能做到实时显示立体信息,想要硬件实现实时,无奈本渣也是个硬件的新手,先按照实验室lyq同学的思路在zedboard开发板的纯ARM ...
- 【开发实录】在鸿蒙开发板上使用websocket(移植自librws库)
librws: Tiny, cross platform websocket client C library 相关代码可在下面下载,也可进入librws: 将librws移植到鸿蒙Hi_3861开发 ...
- FS210开发板上Qt4.7.0移植过程
作者:冯老师,华清远见嵌入式学院讲师. 1. 搭建Qt开发环境平台 1.开发环境:ubuntu 12.04 2.交叉编译链:arm-cortex_a8-linux-gnueabi 3.开发板:FS21 ...
- linux 3.4.103 内核移植到 S3C6410 开发板 移植失败 (问题总结,日本再战!)
linux 3.4.103 内核移植到 S3C6410 开发板 这个星期差点儿就搭在这里面了,一開始感觉非常不值得,移植这样的浪费时间的事情.想立刻搞定,然后安安静静看书 & coding. ...
- Opencv2.2 移植到am335x-y开发板
1.虚拟机上运行cmake-gui,报找不到文件,指示安装. 2.下载opencv2.2.0 http://opencv.org/downloads.html 3.cmake-gui,配置参考< ...
- Madplay移植到mini2440开发板【转】
本文转载自:https://blog.csdn.net/simanstar/article/details/24035379 madplay交叉编译 交叉编译器:arm-linux-gcc 3.4.1 ...
- emWin 移植 - 基于红牛开发板
一直想利用所学的东西自己设计一个精致一些的作品,手头正好有一块红牛开发板,就先用它来写一些软件,熟悉一下过程和一些想法的可行性.首先当然是选择一个操作系统了,对比了几种之后选择了emWin.那就移植一 ...
随机推荐
- 突破Excel百万数据导出瓶颈:全链路优化实战指南
在日常工作中,Excel数据导出是一个常见的需求. 然而,当数据量较大时,性能和内存问题往往会成为限制导出效率的瓶颈. 当用户点击"导出"按钮时,后台系统往往会陷入三重困境: 内 ...
- 操作系统综合题之“短进程优先调度算法(Shortest-Process-First,SPF)和非抢占式优先权调度算法(Priority-Scheduling Lgorithm)的进程执行顺序并计算周转时间以及平均周转时间【分开计算题】”
一.问题: 1.当系统采用短进程优先调度算法时,试写出进程的执行顺序,并计算各个进程的周转时间以及平均周转时间 2.当系统采用优先权调度算法时,试写出进程的执行顺序,并计算各个进程的周转时间以及平均周 ...
- vue中 <el-table-column>回显转成百分比【数字转为百分比】
一.方案1[不保留小数] 这里直接乘以100然后加入百分号既可 <el-table-column prop="refundRate15" label="15天退款率 ...
- HarmonyOS NEXT实战教程:菜谱App
随着鸿蒙系统5.0的发布,兼容的机型越来越多,对于开发者来说机会也越来越多,大家不要气馁,学习鸿蒙肯定会有用武之地,我们要做的就是做好准备. 今天跟大家分享实战教程是一个菜谱App. ListO& ...
- ceph存储介绍
一.ceph简介 ceph是一个开源的.统一的分布式存储系统,设计初衷是提供较好的性能.可靠性和可扩展性.其中"统一"是说ceph可以一套存储系统同时提供块存储设备.文件系统存储和 ...
- net core mvc6使用jwt实现简单的登录
创建一个新的.NET Core Web应用程序项目.在创建项目时,选择MVC模板. 在项目中添加Microsoft.AspNetCore.Authentication.JwtBearer包: 在Vis ...
- Special Binary String——LeetCode进阶路
原题链接https://leetcode.com/problems/special-binary-string/ 题目描述 Special binary strings are binary stri ...
- MYSQL优化学习总结
mysql学习小结---索引的使用及优化 1. 索引那些事 1.1 复合索引 复合索引是指:包含一个或者多个列的索引.但复合索引的触发是有条件的. 假设我们现在有一个复合索引a,a中包含了三个列(id ...
- Tcode:PFAL说明
Short text HR: ALE Distribution of HR Master Data Description. Scenario 1: Distribution of HR Master ...
- 快来玩玩便捷、高效的Demo练习场
Demo练习场 Vonajs 提供了一个 Demo 练习场的功能,允许我们非常方便.快捷的对代码做测试,对想法做验证 步骤 简而言之,Demo练习场的使用只需两步:第一步写代码,第二步执行终端命令.具 ...