SysTick驱动对TinyCLR来说非常重要,.Net Micro Framework系统的多线程和多任务(对托管代码来说是单任务多线程,但是还存在和托管代码同时运行的任务,如我们用MFDeploy程序Ping TinyCLR或擦写Flash 的时候,就是另外的任务在执行)就是靠它来实现的。
SysTick驱动有三个功用,一是我们上面所说的多任务和多线程支持;二是获得系统当前Tick,以此实现延时等待,比如我们常见的Events_WaitForEvents函数就靠它来实现延时功能的;三是为Native代码提供两个版本的Sleep函数。
和ARM7或ARM9相比,Cortex-M3系列的CPU提供了SysTick这个feature,所以我们就不需要用Timer来模拟Tick的功能了,直接用系统提供的SysTick就可以了。Cortex-M3的SysTick其定时器计数是递减的,递减到0就会触发中断(当然要使TICKINT使能),然后自动会加载LOAD寄存器的值,启动下一次计数循环。
LOAD寄存器可填入的最大值为0x00FFFFFF,对72M主频的CPU来说,大概会有250毫秒左右的延时。由于VAL寄存器的值是递减的,所以在移植相关代码的时候要特别注意,我们概念中的Tick的值应该是(LOAD-VAL)。
在CortexM3.h文件中添加如下代码,以便于配置SysTick寄存器。
struct CortexM3_SysTick
{
static const UINT32 c_Base = 0xE000E010;
/****/ volatile UINT32 CTRL; //0xE000E010
static const UINT32 CTRL_COUNTFLAG= ((UINT32)0x00010000);
static const UINT32 CTRL_CLKSOURCE= ((UINT32)0x00000004);
static const UINT32 CTRL_TICKINT= ((UINT32)0x00000002);
static const UINT32 CTRL_ENABLE= ((UINT32)0x00000001);
/****/ volatile UINT32 LOAD; //0xE000E014
static const UINT32 LOAD_RELOAD= ((UINT32)0x00FFFFFF);
/****/ volatile UINT32 VAL; //0xE000E018
static const UINT32 VAL_CURRENT= ((UINT32)0x00FFFFFF);
/****/ volatile UINT32 CALIB; //0xE000E01C
static const UINT32 CALIB_NOREF= ((UINT32)0x80000000);
static const UINT32 CALIB_SKEW= ((UINT32)0x40000000);
static const UINT32 CALIB_TENMS= ((UINT32)0x00FFFFFF);
};
然后在/DeviceCode/Targets/Native/CortexM3/DeviceCode/SysTick新建四个文件SysTick.h、SysTick.cpp、SysTick_Functions.cpp、dotNetMF.proj。
在SysTick.h中创建SYSTICK_Driver结构体,SysTick.cpp存放该结构体的具体实现代码。
struct SYSTICK_Driver
{
static const UINT32 c_MaxTimerValue = 0xFFFFFF; //16777215 最大 250ms左右的定时
volatile UINT64 m_Tick;
volatile UINT64 m_nextCompare;
static BOOL Initialize ();
static BOOL Uninitialize();
static UINT64 CounterValue();
static void SetCompareValue( UINT64 CompareValue );
static INT64 TicksToTime( UINT64 Ticks );
static INT64 CurrentTime();
static void Sleep_uSec( UINT32 uSec );
static void Sleep_uSec_Loop( UINT32 uSec );
static void ISR( void* Param );
};
Cortex-M3内核下的UINT64 CounterValue()函数的具体实现不同于.Net Micro Framework自带的各平台上的源码,所以有必要介绍一下它的实现:
UINT64 SYSTICK_Driver::CounterValue()
{
GLOBAL_LOCK(irq);
CortexM3_SysTick &SysTick= CortexM3::SysTick();
UINT32 value = (SysTick.LOAD - SysTick.VAL);
if(SysTick.CTRL & CortexM3_SysTick::CTRL_COUNTFLAG)
{
g_SYSTICK_Driver.m_Tick+=SysTick.LOAD;
}
return g_SYSTICK_Driver.m_Tick + value;
}
Value的值为(SysTick.LOAD - SysTick.VAL),这是和其它平台的驱动一个区别。此外m_Tick也是我新添加的,它是不断累加计数的,但是它不能真实反映系统开机以来的Tick数,因为SysTick有可能会被禁止中断,也就是说ISR函数不能保证整个系统运行期内都被正常触发。
ISR是一个重点,它是系统实现多任务和多线程的“动力源”。
void SYSTICK_Driver::ISR( void* Param )
{
if(CounterValue() >= g_SYSTICK_Driver.m_nextCompare)
{
HAL_COMPLETION::DequeueAndExec();
}
else
{
SetCompareValue( g_SYSTICK_Driver.m_nextCompare );
}
}
HAL_COMPLETION::DequeueAndExec()代码是关键,每间隔一个指定的时间就会执行一次任务,常见间隔时间为20ms。
Sleep_uSec函数是通过Tick计数计算延时间隔的。
void __section(SectionForFlashOperations) SYSTICK_Driver::Sleep_uSec( UINT32 uSec )
{
GLOBAL_LOCK(irq);
CortexM3_SysTick &SysTick= CortexM3::SysTick();
UINT32 maxDiff = CPU_MicrosecondsToTicks( uSec ); //每微秒的滴答数
SysTick.LOAD = maxDiff & 0xFFFFFF;
while(!(SysTick.CTRL & CortexM3_SysTick::CTRL_COUNTFLAG));
}
__section(SectionForFlashOperations)标识该函数会被拷贝到RAM中去运行(保证执行时间)。
而Sleep_uSec_Loop函数则是通过汇编代码的循环实现的,延时相对比较精确。
void __section(SectionForFlashOperations) SYSTICK_Driver::Sleep_uSec_Loop( UINT32 uSec )
{
// iterations must be signed so that negative iterations will result in the minimum delay
uSec *= (SYSTEM_CYCLE_CLOCK_HZ / CLOCK_COMMON_FACTOR);
uSec /= (ONE_MHZ / CLOCK_COMMON_FACTOR);
// iterations is equal to the number of CPU instruction cycles in the required time minus
// overhead cycles required to call this subroutine.
int iterations = (int)uSec - 14; // Subtract off call & calculation overhead
CYCLE_DELAY_LOOP2(iterations);
}
CYCLE_DELAY_LOOP2的实现代码是汇编,我把它放在FirstEntry.s文件里了,具体代码如下:
IDelayLoop2
EXPORT IDelayLoop2
subs r0,r0, #2 ;; 1 cycle
bgt IDelayLoop2 ;; 1 cycle
mov pc, lr ;; 5 cycles
Sleep_uSec_Loop函数实现代码中的uSec – 14是从其它CPU代码中拷贝来的,针对Cortex-M3应该是多少,我还没有细算过,以后有时间再补上这一课。
在NativeSample.proj中添加如下条目,就可以测试SysTick驱动了:
<ItemGroup>
<RequiredProjects Include="$(SPOCLIENT)/DeviceCode/Targets/Native/CortexM3/DeviceCode/SysTick/dotNetMF.proj" />
<DriverLibs Include="SysTick.$(LIB_EXT)" />
</ItemGroup>
在NativeSample.cpp中我们只能通过Events_WaitForEvents( 0, 1000 )代码测试SysTick驱动的一部分功能,全部的功能要在TinyCLR项目去测试了。
小插曲:在实现LCD驱动的时候,初始化LCD寄存器需要延时,在采用CYCLE_DELAY_LOOP2时,debug版本和release版本有很大的区别,debug可正常运行,但是release会有问题,在Sleep_uSec_Loop函数开始添加GLOBAL_LOCK(irq)代码就可以了,但是这样一改在TinyCLR代码中能正常运行的debug版本就会出问题了。可见嵌入式开发的难点不在于代码的编写,而在于调试。
分享到:
相关推荐
LM3S8962是一款基于ARM Cortex-M3...总的来说,理解和掌握LM3S8962中的SYSTICK驱动库对于开发高效、可靠的嵌入式系统至关重要。通过实践和调试相关例程,开发者可以更好地理解这个强大的工具,并将其优势发挥到极致。
Lab 3 – GPIO, SysTick and Interrupt C Programming for a real time operating system RTOS) scheduler using Keil simulator For this lab exercise you will Keil simulator (based on Nucleo-F103RB board). ...
本篇将详细讲解SysTick的工作原理、配置方法以及如何在STM32F10x系列单片机上编写驱动代码。 首先,SysTick是一个24位向下计数的定时器,每当计数值减到零时,会产生一个中断。其主要功能包括: 1. **系统延时**:...
本文将详细解析针对该系列单片机的SysTick定时器驱动程序,帮助开发者更好地理解和利用SWM32SRET6的硬件资源。 首先,SysTick定时器是ARM Cortex-M内核的一个内置定时器,适用于实现操作系统内核的时钟节拍、任务...
在这款芯片中,SysTick定时器是一个非常重要的系统级定时器,它是Cortex-M系列处理器内核自带的硬件定时器。SysTick主要用于实现周期性的任务,如软件定时器、实时操作系统(RTOS)的时钟滴答等。 SysTick定时器主要...
在本实验报告中,我们将深入探讨STM32单片机中的SysTick滴答时钟,这是一个重要的系统定时器,广泛应用于实时操作系统(RTOS)和其他时间关键型应用。SysTick是ARM Cortex-M系列处理器内置的一个核心组件,对于理解...
SysTick定时器具有周期性中断功能,可以被配置为以固定的时间间隔触发中断,这在嵌入式开发中非常有用,例如实现周期性的任务执行或硬件定时。 首先,我们来详细了解一下SysTick定时器的基本概念。SysTick定时器的...
在嵌入式系统开发中,Systick定时器是一个非常关键的组件,特别是在微控制器(MCU)如S32K144的应用中。S32K144是NXP半导体公司生产的一款高性能32位微控制器,广泛应用于汽车电子、工业控制和其他对实时性能有高...
在给定的项目中,由于已声明"项目可直接编译、运行",意味着所有必要的配置和代码已经准备就绪,用户可以直接在STM32CubeIDE中打开工程,进行编译和下载到目标硬件,体验STM32MP157的SysTick定时器驱动功能。...
SysTick定时器是一个24位递减计数器,由系统时钟源(通常为HCLK)驱动。它有一个固定的周期,并在每个周期结束时产生中断。不过在这个案例中,我们关注的是非中断方式的延时实现,这意味着我们将不依赖于SysTick的...
- **任务调度**:在RTOS中,Systick定时器驱动的任务调度器可以确保各个任务按预定的时间片公平执行。 - **周期性任务**:如数据采集、通信协议的定时发送等。 总的来说,STM32F407上的Systick程序是一个关键的工具...
SysTick是一个24位递减计数器,由系统时钟(SYSCLK)驱动,可以用于实现周期性任务、延迟函数以及作为RTOS(实时操作系统)的基础。下面我们将详细探讨STM32中SysTick的配置、使用方法以及相关知识点。 1. **...
- 在LM3S中,配置SYSTICK涉及以下几个寄存器:SYSTICK_CTRL、SYSTICK_LOAD和SYSTICK_RVR。 - SYSTICK_CTRL寄存器控制SYSTICK的启动、停止、中断使能以及是否允许系统计数器在等待模式下继续运行。 - SYSTICK_LOAD...
STM32中的Systick是系统定时器,是嵌入式微控制器中的一种硬件定时资源,常用于实现...通过这个实例,开发者可以深入理解Systick定时器的使用方法以及中断驱动编程,同时也熟悉了MDK-ARM和Proteus这两款工具的运用。
SysTick定时器 C Lib STM32F10xR LIB STM32F10x s SysTick Opt SysTick Uv2 SysTick plg SysTick HC6800 EM3 dep SysTick Opt Bak SysTick Target 1 dep SysTick Uv2 Bak list STM32F10x lst SysTick ...
**SysTick定时器详解** SysTick定时器是嵌入式微控制器中常见的一种系统定时器,尤其在基于ARM Cortex-M系列处理器的芯片中,如STM32,它...在实际开发中,熟练运用SysTick定时器能够极大地提高程序的效率和可靠性。
在"STM32关于GPIO、中断、SysTick以及串口通信的综合实验"中,我们将探讨这些关键模块的功能和实际应用。 1. GPIO(General-Purpose Input/Output):GPIO是STM32芯片上用于与外部设备进行数字信号交互的接口。STM...
在本项目中,开发者已经编写了针对STM32的1602 LCD驱动,并结合了调试功能以及SYSTICK定时器的精确延时实现。以下是关于这些知识点的详细说明: 1. **STM32微控制器**:STM32是由意法半导体(STMicroelectronics)...
SysTick定时器是一种24位递减计数器,由系统时钟源(SYSCLK)驱动。它可以被配置为周期性中断源,每隔固定时间间隔触发一次中断。这使得开发者能够创建精确的延时函数,或者实现周期性的后台任务。 在这个STM32F10x...
STM32奋斗板-SysTick.zip是一个针对STM32初学者的编程实例资源包,它包含了一个基于Keil开发环境的工程。STM32是一款基于ARM Cortex-M内核的微控制器,广泛应用于嵌入式系统设计。SysTick是Cortex-M系列处理器内置的...