ガレスタさんのDIY日記

電子回路、Web、組み込み、自作エフェクターを語るblog

Kinetis K64 ピン割り込み

今回は前回に引き続きなんですがGPIO関連ということでピン入力割り込みについてやって行きたいと思います。

Reference ManualのChapter11のPort Control and Interrupts (PORT)を参考資料としてつかうのでそれを用意してただいて作業をすると一段わかりやすくなっているかと思います。

ARM Cortex-M4|Kinetis K64 120 MHz 32-bit MCUs|NXP


ARMの割り込みの設定手順はだいたいこんな感じなので一個一個追って説明していく

  1. 割り込みを使いたいペリフェラル側で割り込みに関する部分を有効にする
  2. 対応する割り込みベクタ番号を調べてNVIC_SetPriorityというAPIで優先度を決定
  3. Enable_IRQというAPIで割り込みを有効
  4. 割り込みハンドラの記述

ペリフェラル側で割り込みに関する部分を有効にする

Pin Control RegisterのIRQCをセットしていく作業になる。
f:id:gsmcustomeffects:20170709010510p:plain

f:id:gsmcustomeffects:20170709011100p:plain

FRDMボードがこのようになっているのでフォーリング検出を選択する

f:id:gsmcustomeffects:20170709011523p:plain

ピン方向はInputに設定する。

f:id:gsmcustomeffects:20170709011837p:plain

PORT_SetPinInterruptConfigというAPIで割り込みの設定をします。

static inline void PORT_SetPinInterruptConfig(PORT_Type *base, uint32_t pin, port_interrupt_t config)

なので

PORT_SetPinInterruptConfig(GPIOA, 4U, kPORT_InterruptFallingEdge);

第三引数はマクロ化されているので便利である。

NVIC_SetPriorityというAPIで優先度を決定

void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)というAPIを使って設定している。

NVIC_SetPriority(PORTA_IRQn, 4);

Enable_IRQというAPIで割り込みを有効

EnableIRQ(PORTA_IRQn);

割り込み優先度はとりあえず4にしとく

割り込みハンドラの記述

PORTA_IRQHandlerという名前で定義されているのでmainの上のほうで適当に定義してあげます。
WEAK定義なので上書きして使ってあげるということですね。

void PORTA_IRQHandler(void)
{
    /* Clear external interrupt flag. */
    GPIO_ClearPinsInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
    /* Change state of button. */
    g_ButtonPress = true;
}

GPIO_ClearPinsInterruptFlagsは割り込みのフラグ解除をしている。
f:id:gsmcustomeffects:20170709020636p:plain

ISFに1を書き込むとフラグ解除される。

実行とデバッグ

割り込みハンドラ内でブレークポイントを設定しボード上のボタンを押すとブレークするのが確認できる。
f:id:gsmcustomeffects:20170709213351p:plain

対応する割り込みベクタ番号について

これについてはMK64F12.hに記述されている。コードのアブストにはCMSIS Peripheral Access Layer for MK64F12とあるので一応CMSIS関連のファイルだと思う。

f:id:gsmcustomeffects:20170708235114p:plain

このように今回はPORTAを使いたいので59という番号をNVICのAPIに投げてやる必要がある。
んで毎回調べるのも面倒な場合はPORTAまで打って補完に頼るのもいいかもしれない

f:id:gsmcustomeffects:20170708235414p:plain

ソースコード

最後に参考までにソースコードを貼っていく。

#include "fsl_debug_console.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "fsl_common.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define BOARD_LED_GPIO BOARD_LED_RED_GPIO
#define BOARD_LED_GPIO_PIN BOARD_LED_RED_GPIO_PIN

#define BOARD_SW_GPIO BOARD_SW3_GPIO
#define BOARD_SW_PORT BOARD_SW3_PORT
#define BOARD_SW_GPIO_PIN BOARD_SW3_GPIO_PIN
#define BOARD_SW_IRQ BOARD_SW3_IRQ
#define BOARD_SW_NAME BOARD_SW3_NAME

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/
/* Whether the SW button is pressed */
volatile bool g_ButtonPress = false;

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Interrupt service fuction of switch.
 *
 * This function toggles the LED
 */
void PORTA_IRQHandler(void)
{
    /* Clear external interrupt flag. */
    GPIO_ClearPinsInterruptFlags(BOARD_SW_GPIO, 1U << BOARD_SW_GPIO_PIN);
    /* Change state of button. */
    g_ButtonPress = true;
}

/*!
 * @brief Main function
 */
int main(void)
{
    /* Define the init structure for the input switch pin */
    gpio_pin_config_t sw_config = {
        kGPIO_DigitalInput, 0,
    };

    /* Define the init structure for the output LED pin */
    gpio_pin_config_t led_config = {
        kGPIO_DigitalOutput, 0,
    };

    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    /* Print a note to terminal. */
    //PRINTF("\r\n GPIO Driver example\r\n");
    //PRINTF("\r\n Press %s to turn on/off a LED \r\n", BOARD_SW_NAME);

    /* Init input switch GPIO. */
    PORT_SetPinInterruptConfig(BOARD_SW3_PORT, 4U, kPORT_InterruptFallingEdge);
    NVIC_SetPriority(PORTA_IRQn, 4);
    EnableIRQ(PORTA_IRQn);
    GPIO_PinInit(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, &sw_config);

    /* Init output LED GPIO. */
    GPIO_PinInit(BOARD_LED_GPIO, BOARD_LED_GPIO_PIN, &led_config);

    while (1)
    {
        if (g_ButtonPress)
        {
            //PRINTF(" %s is pressed \r\n", BOARD_SW_NAME);
            /* Toggle LED. */
            GPIO_TogglePinsOutput(BOARD_LED_GPIO, 1U << BOARD_LED_GPIO_PIN);
            /* Reset state of button. */
            g_ButtonPress = false;
        }
    }
}

余談だけどこんな記事読まなくてもMCUXpressoの機能からSampleインポートでこいつ読めば動くので何も考えず行ける
f:id:gsmcustomeffects:20170709022029p:plain

ちなみにサンプルはマクロ使いまくっててわかりにくかったのでこうやって色々書いただけ・・・・・あと割り込み優先度を設定してない公式サンプル・・・・・