日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【.Net Micro Framework PortingKit – 12】SysTick驱动开发

發布時間:2024/1/17 asp.net 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【.Net Micro Framework PortingKit – 12】SysTick驱动开发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

SysTick驅動對TinyCLR來說非常重要,.Net Micro Framework系統的多線程和多任務(對托管代碼來說是單任務多線程,但是還存在和托管代碼同時運行的任務,如我們用MFDeploy程序Ping TinyCLR或擦寫Flash 的時候,就是另外的任務在執行)就是靠它來實現的。

SysTick驅動有三個功用,一是我們上面所說的多任務和多線程支持;二是獲得系統當前Tick,以此實現延時等待,比如我們常見的Events_WaitForEvents函數就靠它來實現延時功能的;三是為Native代碼提供兩個版本的Sleep函數。

ARM7ARM9相比,Cortex-M3系列的CPU提供了SysTick這個feature,所以我們就不需要用Timer來模擬Tick的功能了,直接用系統提供的SysTick就可以了。Cortex-M3SysTick其定時器計數是遞減的,遞減到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.hSysTick.cppSysTick_Functions.cppdotNetMF.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版本就會出問題了。可見嵌入式開發的難點不在于代碼的編寫,而在于調試。

總結

以上是生活随笔為你收集整理的【.Net Micro Framework PortingKit – 12】SysTick驱动开发的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。