ガレスタさんの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

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

Kinetis K64 GPIOメモ

GPIOいじるときにすぐ忘れるのでメモしておこうとおもった。

KSDK V2を使った場合で説明する

流れとしては

  1. PORTにクロック供給
  2. PINMUXの設定(GPIOへ設定)
  3. ピン方向の設定(構造体の定義)
  4. ピン方向の設定(InitAPIのコール)
  5. ピン操作APIのコール

こうなる。
さっそく見ていこうと思う

クロック供給

static inline void CLOCK_EnableClock(clock_ip_name_t name)っていうAPIがそれに値します。

引数としてnameが渡されますがそれはマクロで定義されています。

f:id:gsmcustomeffects:20170706002952p:plain

なので使う際は以下のように記述します。

CLOCK_EnableClock(kCLOCK_PortB);

PINMUXについて

最近のマイコンでは定番ですがピンの機能設定をします。
だいたいのマイコンでは初期がGPIOなので問題ないですがこいつの場合見ての通りデフォがADCとかDisableとかになってるんで設定してあげます。

f:id:gsmcustomeffects:20170706003658p:plain

K64の評価ボードではRGBLEDがついているんですがREDを使いたいのでPORTBの22番目を設定してあげることになります。
f:id:gsmcustomeffects:20170706003937p:plain


実際にはstatic inline void PORT_SetPinMux(PORT_Type *base, uint32_t pin, port_mux_t mux)というAPIでPINMUXを設定できます。

PORT_SetPinMux(PORTB, PIN22_IDX, kPORT_MuxAsGpio);

のように書くとピン機能の設定ができます。
第一引数と第二引数でPTB22を指定してます。

第三引数はALTファンクションなのでデータシート見て決めます

f:id:gsmcustomeffects:20170706004529p:plain

このようにALT1がそれにあたるのでマクロでもそのようになっています。

f:id:gsmcustomeffects:20170706004614p:plain

べたでやるならPin Control Resistorをセットしていく作業になります。

f:id:gsmcustomeffects:20170706005014p:plain

MUXフィールドに001をアサインする

f:id:gsmcustomeffects:20170706005133p:plain

ピン方向の設定(構造体の定義)

この作業についてはAPIリファレンスのGPIO項目にかかれています。
struct gpio_pin_config_tという構造体がそれにあたるんですがこれはリファレンスの説明が一番わかりやすくていいです

f:id:gsmcustomeffects:20170706005443p:plain

このようにOutputにしたい場合はkGpioDigitalOutputって定義してLogic部分は0でも1でもいいと思います。
尚構造体定義は以下のようになっています
f:id:gsmcustomeffects:20170706005739p:plain

ピン方向の設定(APIコール)

void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *config)っていうAPIをコールしてあげるだけです。

GPIO_PinInit(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, &led_config);

こう書けばいいんですがもっとわかりやすく書けば

GPIO_PinInit(GPIOB, 22U, &led_config);

GPIOBがポインタ型で渡されてなくない?って思った方のために
f:id:gsmcustomeffects:20170706010141p:plain

第三引数は先ほど作った構造体を投げるだけです。

ここでいじってるレジスタはPORT DATA Direction Resistorです

f:id:gsmcustomeffects:20170706010437p:plain

中身を見るとINかOUTかで判断してPDDRを操作してるだけ。
f:id:gsmcustomeffects:20170706011253p:plain

ピン操作APIのコール

ここまで来たらあとは以下のどれかを呼ぶだけです

f:id:gsmcustomeffects:20170706010701p:plain

反転専用レジスタがあるのでこれでもLチカは行けるw

GPIOB->PTOR = 1u << 22U;

f:id:gsmcustomeffects:20170706011010p:plain

ソース

int main(void)
{
    /* Define the init structure for the output LED pin*/
    gpio_pin_config_t led_config = {
        kGPIO_DigitalOutput, 0,
    };

   //GPIO_Type GPIOB;

    /* Board pin, clock, debug console init */
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    /* Print a note to terminal. */

    /* Init output LED GPIO. */
    GPIO_PinInit(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, &led_config);

    while (1)
    {
        delay();
       // GPIO_TogglePinsOutput(BOARD_LED_RED_GPIO, 1u << BOARD_LED_RED_GPIO_PIN);
        GPIOB->PTOR = 1u << 22U;

    }
}

まとめ

KinetisマイコンのGPIOについて紹介した。
一応かなり噛み砕いたけどわかりにくかったらコメントしてくれれば!

自分用メモ Kinetisやる際によむとこ

SDK内のフォルダのDocの中のこれ

f:id:gsmcustomeffects:20170705025103p:plain

DriverExampleのReadme

リファレンスマニュアル

f:id:gsmcustomeffects:20170705025354p:plain

SDKのGettingStartおよびファイル構造解説

f:id:gsmcustomeffects:20170705025514p:plain

基本ここ読めばだいたいのコツはつかめる。
あとはInit系のAPIはマクロ化でウザったいので注意

GettingStartKinetisVer2

以前こんなの書いたんですけど
gsmcustomeffects.hatenablog.com


いつの間にかNXPになりそしてMCUXpressoSDKなるものが出てIDEも変わったので初心者のためにかきます。
あくまで初心者のためです。強い人はかえってどうぞ

必要なもの

  • FRDMボード
  • MCUXpressoIDE

の二つが必要です。

評価ボードについては定番であるFRDM-K64Fを使っていきたいと思いますので同じようにやりたい方は購入してください。
IDEに関しては此方からダウンロードできます。

MCUXpresso IDE|NXP

SDKのビルド

Kinetisの場合STM32のCubeHALとは違いオンラインで色々選択してSDKをダウンロードして使う仕組みなので先ずはそれをやって行く

mcuxpresso.nxp.com

上記のサイトでNXPアカウントでログインする。

FRDM-K64Fを選択するとこのような画面になる

f:id:gsmcustomeffects:20170705015403p:plain

次にSDK Builderに進んでDownloadをすればSDK関連は終わりです。(ミドルウエアは適宜選んでください

f:id:gsmcustomeffects:20170705015615p:plain

MCUXpressoにSDKを入れていくぞ

まず起動してワークスペースを開くと基本画面が出てくるので下部のSDK部分からさっき落としてきたZipファイルをインポートしてあげます。(右クリックでアーカイブZip)

f:id:gsmcustomeffects:20170705020216p:plain

するとこうなります。

新規プロジェクトを作っていく

New projectをクリックすると先ほど入れたSDKが出てくると思います。(なんかかっこいいw

f:id:gsmcustomeffects:20170705020400p:plain

今回はK64をつかうのでこれ

f:id:gsmcustomeffects:20170705020431p:plain

するとこうなるので適宜選んで進む
f:id:gsmcustomeffects:20170705020530p:plain

ここではUtilityについては割愛

あとはC言語のlib関連とFloating Pointの設定とかしてく

f:id:gsmcustomeffects:20170705020743p:plain

んで終了

ソースコード

書くところは二つあります。
まずはpin_mux.cです。

#include "fsl_common.h"
#include "fsl_port.h"
#include "pin_mux.h"


#define PIN16_IDX                       16u   /*!< Pin number for pin 16 in a port */

#define PIN17_IDX                       17u   /*!< Pin number for pin 17 in a port */

#define PIN22_IDX                       22u   /*!< Pin number for pin 22 in a port */
#define SOPT5_UART0TXSRC_UART_TX      0x00u   /*!< UART 0 transmit data source select: UART0_TX pin */

/*
 * TEXT BELOW IS USED AS SETTING FOR THE PINS TOOL *****************************
BOARD_InitPins:
- options: {coreID: singlecore, enableClock: 'true'}
- pin_list:
  - {pin_num: '62', peripheral: UART0, signal: RX, pin_signal: PTB16/SPI1_SOUT/UART0_RX/FTM_CLKIN0/FB_AD17/EWM_IN}
  - {pin_num: '63', peripheral: UART0, signal: TX, pin_signal: PTB17/SPI1_SIN/UART0_TX/FTM_CLKIN1/FB_AD16/EWM_OUT_b}
 * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE PINS TOOL ***
*/

/*FUNCTION**********************************************************************
 * 
 * Function Name : BOARD_InitBootPins
 * Description   : Calls initialization functions.
 * 
 *END**************************************************************************/
void BOARD_InitBootPins(void) {
  BOARD_InitPins();
}


/*FUNCTION**********************************************************************
 *
 * Function Name : BOARD_InitPins
 * Description   : Configures pin routing and optionally pin electrical features.
 *
 *END**************************************************************************/
void BOARD_InitPins(void) {
  CLOCK_EnableClock(kCLOCK_PortB);                           /* Port B Clock Gate Control: Clock enabled */

  PORT_SetPinMux(PORTB, PIN16_IDX, kPORT_MuxAlt3);           /* PORTB16 (pin 62) is configured as UART0_RX */
  PORT_SetPinMux(PORTB, PIN17_IDX, kPORT_MuxAlt3);           /* PORTB17 (pin 63) is configured as UART0_TX */
  PORT_SetPinMux(PORTB, PIN22_IDX, kPORT_MuxAsGpio);
  SIM->SOPT5 = ((SIM->SOPT5 &
    (~(SIM_SOPT5_UART0TXSRC_MASK)))                          /* Mask bits to zero which are setting */
      | SIM_SOPT5_UART0TXSRC(SOPT5_UART0TXSRC_UART_TX)       /* UART 0 transmit data source select: UART0_TX pin */
    );
}

PORTへのクロック供給と22ピンをGPIOにアサインする記述を追加しています。

次にMain.c

#include <stdio.h>
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "fsl_gpio.h"
#include "MK64F12.h"

/* TODO: insert other include files here. */

/* TODO: insert other definitions and declarations here. */

/*
 * @brief   Application entry point.
 */
void delay(void)
{
    volatile uint32_t i = 0;
    for (i = 0; i < 800000; ++i)
    {
        __asm("NOP"); /* delay */
    }
}

/*!
 * @brief Main function
 */
int main(void)
{
    /* Define the init structure for the output LED pin*/
    gpio_pin_config_t led_config = {
        kGPIO_DigitalOutput, 0,
    };

    /* Board pin, clock, debug console init */
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    /* Print a note to terminal. */

    /* Init output LED GPIO. */
    GPIO_PinInit(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, &led_config);

    while (1)
    {
        delay();
        GPIO_TogglePinsOutput(BOARD_LED_RED_GPIO, 1u << BOARD_LED_RED_GPIO_PIN);
    }
}

こんな感じです。

デバッグ

デバッガの設定はCMSIS-DAPファームが入ってるならNXPがプラグインでやってくれてるので楽になった

f:id:gsmcustomeffects:20170705021513p:plain

JLINK GDBやOpenOCDでつなぐなら各自設定してほしい。

あとはブレイクしてステップ実行なりでデバッグ機能の確認ができる

f:id:gsmcustomeffects:20170705024340p:plain

その他機能

こういった使い方のほかにサンプルをそのままインポート補助する機能もあるのでそれを使うともっと楽だ(むしろKinetisは豊富なサンプル使ってなんぼですよねw

f:id:gsmcustomeffects:20170705024547p:plain

こんな感じで80個ぐらいサンプルあるので強すぎるとw

まとめ

Kinetisの新しい開発環境を紹介した。

いろいろサンプル増えててあせったw
CMSISの管轄の境界線はどこなんやという感想を持ちましたw
共通化はレジスタ定義のヘッダーとかぐらいにしてくれればわかりやすくていいと思います。

記事のまとめ

当てつけでもありませんが真面目に書いてるやつが日記的なのに埋もれてきたのでWikiっぽいの作った。

https://gsmcustomeffects.github.io/stm32


f:id:gsmcustomeffects:20170701230319p:plain
でもWikiほど固くなくて記事の重要な部分だけ抜き出しただけ
ちなみにJekyllっていうの使って作りました

Jekyll • シンプルで、ブログのような、静的サイト


でもこれで文句言われることが少なくなりそうで・・・・・・・

ESP-WROOM-32

f:id:gsmcustomeffects:20170628022904p:plain

f:id:gsmcustomeffects:20170628033924p:plain

ESP-WROOM-32はケイデンス(元てんしりか)のIPであるXtensa LX6内蔵のESP32というSoCがのってる。

ちなみにIPコア自体のデータシート読むとデバッグはARMのCoresight内蔵なのでJTAGでつながるみたい

f:id:gsmcustomeffects:20170628022540p:plain

開発はGNUベースであるらしい

f:id:gsmcustomeffects:20170628023431p:plain

SDKもESP IDFってのがあるのでARMマイコン的な楽ちん開発が可能?

f:id:gsmcustomeffects:20170628023515p:plain

いうてラインナップが少ないのでアブストラクションレイヤーなんてなくても専用コード書けば問題ない(そういうことじゃないw

高クロックなので強い

f:id:gsmcustomeffects:20170628024403p:plain

ペリフェラルもいい感じ

f:id:gsmcustomeffects:20170628024515p:plain

興味があるのがFIFO付きI2S

こいつ使ってエフェクタ作れそうじゃねとか思ってるw

というわけで今後はこのおもちゃで記事書いていこうと思う