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通信です。