📄 arm_00_os_core.c
字号:
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。
ARM_00_OS_Core.c file
作者:Computer-lov
建立日期:2006-5-1
修改日期:2006-5-15
版本:V1.0
版权所有,盗版必究。
任何技术问题可到我的博客上留言: http://computer00.21ic.org
Copyright(C) Computer-lov 2006-2016
All rights reserved
**********************************************************************************************/
#include <ADuC7027.H>
#include "interrupt.h"
#include "LED.H"
#include "ARM_00_OS_TaskSwitch.H"
#include "my_type.h"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"
#include "Task.h"
OSpcb * OSReadyList; //就绪态任务表表头
OSpcb * OSSuspendList; //挂起态任务表表头
OSpcb * OSDelayList; //延时态任务表表头
OSpcb * OSCurrentPcb; //当前运行的任务
OSpcb OSSystemIdlePcb; //系统空闲任务
OSShortPcb OSSuspendListBottom; //挂起态列表表底
OSShortPcb OSDelayListBottom; //延时态列表表底
OSdevice OSDeviceBottom; //设备列表的底部
OSdevice * OSDeviceList; //设备列表
volatile uint32 CopyOfIRQEN; //用来备份IRQEN的状态
volatile uint32 CopyOfFIQEN; //用来备份FIQEN的状态
volatile uint32 OSEnCrCount; //用来统计进入临界代码段次数
volatile uint32 TaskAmount; //用来统计共有多少个任务
volatile uint32 TimeOfTaskStart; //用来保存一个任务刚被切换到运行态的时刻
#define OSMemoryLack 0x0000000100000000 /*错误号:内存资源不足*/
/**********************************************************************************************
功能:内存管理。
入口参数1:Operation。操作方式。可以设置为MEMORY_ALLOCATION(分配)、MEMORY_FREE(释放)、统计使用量(MEMORY_STATISTIC)
入口参数2:StartAddr。起始地址,释放内存时使用。
入口参数3:Length。申请内存或释放内存时的长度,单位为字节。但实际分配时,是按块分配的,所以分配时,
实际分配到的数量可能会比指定的多,所以分配时,最好按块的整数倍大小来指定分配长度。
返回:32无符号型整数。
当操作为分配内存时,返回32位的内存首地址,返回0表示无足够多的可以用内存。
当操作为释放内存时,返回1表示释放成功。返回0表示释放出错。
当操作为统计内存使用量时,返回的是内存被使用的字节数。
当操作为获取缓冲池大小时,返回的是内存缓冲池大小。
备注:缓冲池大小由OSSizeOfMemoryPool指定。每块的大小由OSSizePerBlock指定
**********************************************************************************************/
uint32 OSMemoryManage(uint32 Operation,uint32 StartAddr,uint32 Length)
{
//内存分配表
//内存分配表是32位整数的一维数组。用每一位来表示一块是否被使用。当某位设置为1时,表示那一块被使用。
//当某位为0时,表示那一块可用。
static uint32 OSMemoryTable[OSSizeOfMemoryPool/OSSizePerBlock/32];
static uint32 OSMemoryPool[OSSizeOfMemoryPool/4]; //内存缓冲池。内存缓冲池为一个大是数组
uint32 BlankCount; //统计空块的计数器
uint32 Mask; //分配内存时用的掩码
volatile uint32 i,j; //循环用的变量
OSEnterCritical(); //进入临界段
switch(Operation) //根据操作码,选择不同的操作
{
case MEMORY_INIT: //如果是内存初始化
{
for(i=0;i<OSSizeOfMemoryPool/OSSizePerBlock/32;i++)
{
OSMemoryTable[i]=0; //则将整张内存分配表清0
}
OSExitCritical(); //退出临界段
return 1; //返回1
}
case MEMORY_ALLOCATION: //如果是内存分配,则
{
BlankCount=0; //先将内存空块的数量清0
for(i=0;i<(OSSizeOfMemoryPool/OSSizePerBlock/32);i++) //扫描整个内存分配表
{
Mask=1; //掩码被设置为1,即最低位为1,其它位为0。
if(OSMemoryTable[i]==0xFFFFFFFF) //如果该字中的所以位都为1,表示该字节对应的所有块都被占用
{
BlankCount=0; //空块计数器置0
continue; //退出本次循环,查找下一个字
}
for(j=0;j<32;j++) //扫描一个字的32个bit是否有空闲的RAM
{
if((Mask & OSMemoryTable[i])==0) //如果该位为0,表示该块空闲
{
BlankCount++; //空块计数器加1。
}
else
{
BlankCount=0; //如果遇到非空块,则空块计数器置0。
}
if((BlankCount*OSSizePerBlock)>=Length) //如果空闲的RAM,大于或者等于需要的长度,那么分配成功
{
//计算被分配到的内存的起始地址,并将其保存在StartAddr中。
StartAddr=((uint32)OSMemoryPool)+(i*32+j+1)*OSSizePerBlock-OSSizePerBlock*BlankCount;
while(1) //设置被使用的块为1
{
OSMemoryTable[i] |=Mask; //将已经被分配的标志为1
Mask>>=1; //调整掩码的值
if(j==0) //如果已到最低位
{
Mask=0x80000000; //则掩码调整为第31位为1
j=32;
i--; //移到下一位
}
BlankCount--; //空块计数减1
j--; //移到下一个字
if(BlankCount==0) //如果空块计数器减到0,则标志完毕
{
OSExitCritical();
return StartAddr; //将启始地址StartAddr返回
}
}
}
Mask<<=1; //掩码调整,移动到下一个块
}
}
OSExitCritical();
return 0; //如果没有足够大的内存块可用,则返回0,分配失败
}
case MEMORY_FREE: //如果操作码是释放内存
{
if(Length==0) //如果要释放的内存长度为0
{
OSExitCritical(); //退出临界段
return 1; //返回1,释放成功
}
i=(StartAddr-(uint32)OSMemoryPool)/(32*OSSizePerBlock); //计算出指定地址内存在内存分配表中的位置
j=(StartAddr-(uint32)OSMemoryPool-i*32*OSSizePerBlock)/OSSizePerBlock;
Mask=1<<j; //将掩码调整到对应的值
while(Length) //直到全部被释放为止
{
if((OSMemoryTable[i])&(Mask)==0) //如果该内存并未被分配,则说明发生了错误,
{
OSExitCritical(); //推出临界段
return 0; //返回0,表示释放失败
}
OSMemoryTable[i] &=~Mask; //清除对应的位,即释放该块内存
j++; //调整到下一块
Mask<<=1; //掩码调整到下一块的位置
if(j==32) //如果已经到最高位
{
Mask=1; //掩码设置为1
j=0; //j回到最低位
i++; //调整下一个字
}
if(Length<=OSSizePerBlock) //如果释放完毕
{
Length=0; //则Length设置为0,退出循环
}
else //如果没释放完毕
{
Length-=OSSizePerBlock; //则长度减小一个块的量
}
}
OSExitCritical(); //退出临界段
return 1; //返回1,表示释放成功
}
case MEMORY_STATISTIC: //如果操作码是统计内存使用量
{
Length=0; //清Length
for(i=0;i<OSSizeOfMemoryPool/OSSizePerBlock/32;i++) //扫描整张内存分配表
{
if(OSMemoryTable[i]==0) //如果当前字是全0,则该字对应的内存都未被分配,
{
continue; //则跳过本次循环
}
if(OSMemoryTable[i]==0xFFFFFFFF) //如果当前字是全1,则该字对应的内存全部被分配
{
Length+=32*OSSizePerBlock; //Length累加上32块的长度
continue; //退出本次循环
}
Mask=1; //掩码设置为1
for(j=0;j<32;j++) //扫描当前字的32bit,看是否有内存被使用
{
if(OSMemoryTable[i]&Mask) //如果该块被使用
{
Length+=OSSizePerBlock; //则Length累加一块的长度
}
Mask<<=1; //调整掩码到下一位
}
}
OSExitCritical(); //退出临界段
return Length; //返回使用的内存数量
}
case GET_MEMORY_POOL_SIZE: //如果是获取缓冲池大小,
{
OSExitCritical(); //退出临界段
return OSSizeOfMemoryPool; //返回缓冲池的字节数
}
case MEMORY_TEST: //如果是内存检测
{
j=0xFF; //标志j为非0,即初始化成功
prints("Memory testing. ",1); //显示信息
for(i=0;i<OSSizeOfMemoryPool/4;i++) //检测整个内存缓冲池
{
OSMemoryPool[i]=0x55555555; //写入0x55555555
if(OSMemoryPool[i]!=0x55555555) //如果读回的不是0x55555555
{
j=0; //则测试失败
}
OSMemoryPool[i]=0xAAAAAAAA; //写入0xAAAAAAAA
if(OSMemoryPool[i]!=0xAAAAAAAA) //如果读回的不是0xAAAAAAAA
{
j=0; //则测试失败
}
OSMemoryPool[i]=0; //写入0
if(OSMemoryPool[i]!=0) //如果读回的不是0
{
j=0; //则测试失败
}
if(i%(OSSizeOfMemoryPool/4/80)==0) //显示测试进度。共显示80个>
{
prints(">",0);
}
}
prints("",1);
if(j) //如果测试成功
{
prints("Memory test passed.",1); //显示成功
}
else //否则,
{
prints("Memroy test failed.",1); //显示测试失败
}
OSExitCritical(); //退出临界段
return j; //返回是否成功
}
default: OSExitCritical();return 0;
}
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:进入临界段。
入口参数:无。
返回:无。
备注:该函数使用的是将中断分配寄存器清0的方法来关中断。比起用软中断,运行速度要快。
如果要开某个中断,则应该先调用一次该函数,然后再修改中断备份变量CopyOfIRQEN跟CopyOfFIQEN
的值,而不能直接修改IRQEN跟FIQEN的值。否则会出错。
**********************************************************************************************/
void OSEnterCritical(void)
{
if(OSEnCrCount==0) //如果前面未关中断
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -