西西软件园多重安全检测下载网站、值得信赖的软件下载站!
西西首页 常用软件 软件下载 安卓软件 游戏下载 安卓游戏 MAC应用 驱动下载 安卓电视
系统工具网络工具媒体工具图形图像聊天工具应用软件编程开发手机软件安卓应用电脑安全字体素材

FreeRTOS stm32 完整移植包

  • FreeRTOS stm32 完整移植包
  • 软件大小:8.5M
  • 更新时间:2013-07-22 16:09
  • 软件语言:中文
  • 软件厂商:
  • 软件类别:国产软件 / 免费软件 / 源码相关
  • 软件等级:4级
  • 应用平台:WinAll, WinXP
  • 官方网站:暂无
好评:50%
坏评:50%

本类精品

装机必备软件

软件介绍

介绍freertos在stm32上的移植说明,每一步都很详细,让你学会在stm32+freeRTOS的平台上开发应用程序

一、各文件关键部分的实现:

1、PORTMACRO.H 宏定义部分
1)定义编译器相关的各种数据类型
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE long

2)架构相关的定义
Cortex-M3的堆栈增长方向为高地址向低地址增长
#define portSTACK_GROWTH ( -1 )
每毫秒的心跳次数
#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
访问SRAM的字节对齐
#define portBYTE_ALIGNMENT 8

3)定义用户主动引起内核调度的2个函数
强制上下文切换,用在任务环境中调用
#define portYIELD() vPortYieldFromISR()
强制上下文切换,用在中断处理环境中调用
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()

4)定义临界区的管理函数
中断允许和关闭
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask()
临界区进入和退出
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
用于在中断环境的中断允许和关闭
#define portSET_INTERRUPT_MASK_FROM_ISR() 0;vPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x

2、PORT.C C接口部分
1)堆栈初始化
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
*pxTopOfStack = portINITIAL_XPSR; /* 程序状态寄存器 */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* 任务的入口点 */
pxTopOfStack--;
*pxTopOfStack = 0; /* LR */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* 任务的参数 */
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}

2)启动任务调度
portBASE_TYPE xPortStartScheduler( void )
{
让任务切换中断和心跳中断位于最低的优先级,使更高优先级可以抢占mcu
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;

设置并启动系统的心跳时钟
prvSetupTimerInterrupt();

初始化临界区的嵌套的个数
uxCriticalNesting = 0;

启动第一个任务
vPortStartFirstTask();

执行到vPortStartFirstTask函数,内核已经开始正常的调度
return 0;
}

3)主动释放mcu使用权
void vPortYieldFromISR( void )
{
触发PendSV系统服务中断,中断到来时由汇编函数xPortPendSVHandler()处理
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}
进入临界区时,首先关闭中断;当退出所以嵌套的临界区后再使能中断
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
}
void vPortExitCritical( void )
{
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
4)心跳时钟处理函数
void xPortSysTickHandler( void )
{
unsigned portLONG ulDummy;

如果是抢占式调度,首先看一下有没有需要调度的任务
#if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
#endif

ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
{ 通过task.c的心跳处理函数vTaskIncrementTick(),进行时钟计数和延时任务的处理
vTaskIncrementTick();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}

3、PORTASM.S 汇编处理部分
1)请求切换任务
xPortPendSVHandler:
保存当前任务的上下文到其任务控制块
mrs r0, psp
ldr r3, =pxCurrentTCB 获取当前任务的任务控制块指针
ldr r2, [r3]

stmdb r0!, {r4-r11} 保存R4-R11到该任务的堆栈
str r0, [r2] 将最后的堆栈指针保存到任务控制块的pxTopOfStack

stmdb sp!, {r3, r14}
关闭中断
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
切换任务的上下文,pxCurrentTCB已指向新的任务

bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r3, r14}
恢复新任务的上下文到各寄存器
ldr r1, [r3]
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0!, {r4-r11} /* Pop the registers. */
msr psp, r0
bx r14

2.)中断允许和关闭的实现,通过BASEPRI屏蔽相应优先级的中断源
vPortSetInterruptMask:
push { r0 }
mov R0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr BASEPRI, R0
pop { R0 }

bx r14

vPortClearInterruptMask:
PUSH { r0 }
MOV R0, #0
MSR BASEPRI, R0
POP { R0 }

bx r14

3)直接切换任务,用于vPortStartFirstTask第一次启动任务时初始化堆栈和各寄存器
vPortSVCHandler;
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
ldmia r0!, {r4-r11}
msr psp, r0
mov r0, #0
msr basepri, r0
orr r14, r14, #13
bx r14

4)启动第一个任务的汇编实现
vPortStartFirstTask
通过中断向量表的定位堆栈的地址
ldr r0, =0xE000ED08 向量表偏移量寄存器 (VTOR)
ldr r0, [r0]
ldr r0, [r0]
msr msp, r0 将堆栈地址保存到主堆栈指针msp中
触发SVC软中断,由vPortSVCHandler()完成第一个任务的具体切换工作
svc 0

FreeRTOS内核调度器启动的流程如下:

以上3个文件实现了FreeRTOS内核调度所需的底层接口,相关代码十分精简。

二、创建测试任务:

下面创建第一个测试任务,LED测试
int main( void )
{
设置系统时钟,中断向量表和LED使用的GPIO
使用stm32的固件包提供的初始化函数,具体说明见相关手册
prvSetupHardware();

通过xTaskCreate()创建4个LED任务vLEDFlashTask(),
每个任务根据各自的频率闪烁,分别对应开发板上的4个LED
vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );

? 创建一个IDLE任务后,通过xPortStartScheduler启动调度器
vTaskStartScheduler();

调度器工作不正常时返回
return 0;
}

portTASK_FUNCTION()是FreeRTOS定义的函数声明,没特殊作用
static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
{
……省略……,具体为计算各LED的闪烁频率
for(;;)
{
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED );

vTaskDelayUntil()的延时时间xFlashRate,是从上一次的延时时间xLastFlashTime算起的,
相对vTaskDelay()的直接延时更为精准。
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED );
}
}

FreeRTOS的任务创建与UC/OSII差异不大,主要参数为任务函数,堆栈大小和任务的优先级。如:
xTaskCreate( vLEDFlashTask, ( signed portCHAR * ) "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );

下面再创建一个LCD显示任务,以最低优先级运行:
xTaskCreate( vLCDTask, ( signed portCHAR * ) "LCD", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

void vLCDTask( void *pvParameters )
{
……省略……
for( ;; )
{
vTaskDelay(1000);
printf("%c ", usDisplayChar);
}
}
该任务很简单,每隔1000个ticks(就是1000ms),从LCD上刷新一个数字。

至此,FreeRTOS在STM32上的移植基本完成。与UC/OSII相比,FreeRTOS精简的实现更适合用来学习实时操作系统的工作原理,对其进行剖析也相对容易。

接下来,我们将会移植CAN,RS485,SD卡和USB等接口到FreeRTOS,使其在STM32平台上更加完善。

软件标签: FreeRTOS

软件截图

FreeRTOS stm32 完整移植包

    其他版本下载

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)

    下载帮助下载帮助西西破解版软件均来自互联网, 如有侵犯您的版权, 请与我们联系。

    TOP
    软件下载