Tiva C EK-TM4C123GXLを使ってみるの8回目です。前回は、ボード上のスイッチを使いましたが、今回はタイマと割り込みです。
以下のメーカのサイトを見ながらプログラムを作っていきます。
Getting Started with the TIVA™ C Series TM4C123G LaunchPad
更に、このサイトで下の方の、Workshop MaterialのThe workbookを見ながら作ります。
直接のPDFファイルへのリンクは、The workbook PDF です。
このPDFファイルのLab4のプログラムそのままです。詳細は、このPDFファイルのLab4のあたりを参照して下さい。
プロジェクト一式はここからダウンロード出来ます。
プログラムの処理としては、汎用のTimer0を使って周期的に連続した処理を行います。その連続した処理は、またLEDの点滅です。(暗いところではあまり実行しない方がいいような点滅です。念のためです。)
ソース全体は以下です。コメントは私が適当に付けました。参考程度にして下さい。
一応、毎回書こうと思いますが、TivaWare付属のサンプルプログラム等を見ていると、ROM_ で始まっている関数をよく見かけますが、ROM_ の方は、ROM内蔵版です。こちらを使うとプログラム全体の大きさが小さくなりますが、ここでは特にサイズを気にする程でもないので、普通にリンクして使う、ROM_ が付いていない通常版の関数を使います。
#include <stdint.h> #include <stdbool.h> #include "inc/tm4c123gh6pm.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" int main(void) { uint32_t ui32Period; //システムクロックの設定(これで結果的に40MHz) SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN); //ポートとタイマーへのクロック供給(必須) SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); //出力への方向設定 GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3); //タイマーの構成(Timer0を32bitの継続で利用) TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC); //10Hz で 50% duty サイクル ui32Period = (SysCtlClockGet() / 10) / 2; TimerLoadSet(TIMER0_BASE, TIMER_A, ui32Period -1); //割り込み可の設定 IntEnable(INT_TIMER0A); TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); IntMasterEnable(); //タイマー開始 TimerEnable(TIMER0_BASE, TIMER_A); while(1) { } } // // タイマー関数 // この関数は、startup_ewarm.c に登録する // void Timer0IntHandler(void) { // タイマ割り込みクリア TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // 点滅するようにRead、Write if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2)) { GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0); } else { GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 4); } }
次にこの割り込みハンドラの登録についてです。この割り込みハンドラをベクタテーブルに登録する必要があります。そのベクタテーブルはスタートアップにあります。
ここでは開発環境はEWARMなので、スタートアップはstartup_ewarm.cになっています。ここにまずは以下のように関数プロトタイプを宣言します。場所はコンパイルエラーにならない場所でいいと思います。ここでは、以下の場所です。
//***************************************************************************** // // Enable the IAR extensions for this source file. // //***************************************************************************** #pragma language=extended extern void Timer0IntHandler(void);
次に、ベクタテーブルに登録します。
//***************************************************************************** // // The vector table. Note that the proper constructs must be placed on this to // ensure that it ends up at physical address 0x0000.0000. // //***************************************************************************** __root const uVectorEntry __vector_table[] @ ".intvec" = { { .ui32Ptr = (uint32_t)pui32Stack + sizeof(pui32Stack) }, // The initial stack pointer ResetISR, // The reset handler //途中省略 Timer0IntHandler, // Timer 0 subtimer A //← ここです。 IntDefaultHandler, // Timer 0 subtimer B IntDefaultHandler, // Timer 1 subtimer A //以下省略
これで、Timer0IntHandler()が周期的に実行されます。ここではEWARMを使っています。元の文書では、Code Composer Studioでの登録がありますので必要な場合はそちらを参照して下さい。
今回はここまでです。次回は、UART通信です。