ガレスタさんのDIY日記

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

MIMXRT1050-EVKでスイッチ入力を使う手順

今回は今後よく使うであろうスイッチ入力をやって行く。
まずボードにあるタクトスイッチは以下の四つである

SW2 ON/OFFスイッチ
SW3 リセット
SW4 デバッガチップリセット or bootloader mode
SW8 ユーザースイッチ

ここで SW2はON/OFFスイッチになっておりOFF状態で押すと電源がONになる面白い機能
一方ON状態で短く押すと割り込み生成ができるらしいw
あと長押し5秒でOFFできる。(何だこのゲーム機見たいな機能w

おっと脱線しました・・・・・・・

要はSW8(GPIO5-00)を使うってことですね。
場所はチップの左上にあるやつです。

f:id:gsmcustomeffects:20180119214134p:plain
早速やっていこう

使い方

プログラムの冒頭でコンフィグ構造体の設定をしてあげる。

typedef struct _gpio_pin_config
{
    gpio_pin_direction_t  direction;     /*!< Specifies the pin direction. */
    uint8_t outputLogic; /*!< Set a default output logic, which has no use in input */
    gpio_interrupt_mode_t interruptMode; /*!< Specifies the pin interrupt mode, a value of @ref gpio_interrupt_mode_t. */
} gpio_pin_config_t;

構造体が上記のようなメンバなのでこういう感じに設定してあげる。
ボタンはGNDに繋がっていてるのでこうやって設定する。(ピンのプルアップはこのあと説明

    gpio_pin_config_t sw_config = {
        kGPIO_DigitalInput, 0,
        kGPIO_IntFallingEdge,
    };

次にPINMUXの設定をする。
これは手打ちでやるべきでないのでMCUXpressoのピンコンフィグツールで行った方が無難
f:id:gsmcustomeffects:20180119231707p:plain

ピンのプルアップ抵抗値だったりヒステリシスだったり色々柔軟なことができる。(リファレンスマニュアル:Chapter 32
General Purpose Input/Output (GPIO)を参照)
f:id:gsmcustomeffects:20180119234248p:plain
それでコードを吐くとこうなる。

void BOARD_InitPins(void) {
  CLOCK_EnableClock(kCLOCK_Iomuxc);           /* iomuxc clock (iomuxc_clk_enable): 0x03u */
  CLOCK_EnableClock(kCLOCK_IomuxcSnvs);       /* iomuxc_snvs clock (iomuxc_snvs_clk_enable): 0x03u */

  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_12_LPUART1_TX,        /* GPIO_AD_B0_12 is configured as LPUART1_TX */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_GPIO_AD_B0_13_LPUART1_RX,        /* GPIO_AD_B0_13 is configured as LPUART1_RX */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinMux(
      IOMUXC_SNVS_WAKEUP_GPIO5_IO00,          /* WAKEUP is configured as GPIO5_IO00 */
      0U);                                    /* Software Input On Field: Input Path is determined by functionality */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_12_LPUART1_TX,        /* GPIO_AD_B0_12 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
  IOMUXC_SetPinConfig(
      IOMUXC_GPIO_AD_B0_13_LPUART1_RX,        /* GPIO_AD_B0_13 PAD functional properties : */
      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
                                                 Drive Strength Field: R0/6
                                                 Speed Field: medium(100MHz)
                                                 Open Drain Enable Field: Open Drain Disabled
                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
                                                 Pull / Keep Select Field: Keeper
                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
                                                 Hyst. Enable Field: Hysteresis Disabled */
}

あとはInit

GPIO_PinInit(GPIO5, 0, &sw_config);//GPIO5の0ピン

ここでやっとconfig構造体を渡す。
同じ設定使いたかったら構造体の使い回しできるし結構いい設計だと思う。
普通に使うならここで終了。GPIO_PinWrite,Readなりを呼んで使える。

割り込みを使う場合

割り込みの場合はIRQAPIで該当ポートを有効にする。

EnableIRQ(GPIO5_Combined_0_15_IRQn);

な感じで設定。
割り込み番号はデータシートかMIMXRT1052.hを参照

そのあとにGPIO_PinInitをコール(GPIO_SetPinInterruptConfigというAPIをInit内で呼んでいる為)

あとはMaskレジスタの設定をして終わり

GPIO_PortEnableInterrupts(GPIO5, 1U << 0U);

スイッチ押したときこのようにブレークが入ればOK
f:id:gsmcustomeffects:20180119233958p:plain

i.MX RT1050 SAI概略

一番最初に書くべきだったけど許してください

SAI(Synchronous Audio Interface)

マルチなプロトコルに対応したオーディオペリフェラルのこと。
最近のSTM32「Serial Audio Interfaceと呼ばれてる」とかにも載っている.

f:id:gsmcustomeffects:20180118231736p:plain

図を見てもらえればわかる通りに二つのブロックから構成されている。
2つのブロックをそれぞれ別に設定したり同期して使用することも可能

対応プロトコル

結構多くのプロトコルに対応している

  • I2S
  • Left justified,Right justified
  • 左寄せ
  • TDM
  • PCM
  • カスタマイズ
  • AC97

特徴

  • クロック柔軟性が高い(tx、rx独立も可能)
  • 広範囲サンプル周波数に対応(SDKでは8k~96kまで対応)
  • FIFOフレームが32Wordまで対応(32bit x 32)
  • データ詰めも柔軟に対応可能
  • FIFO関連の割り込みフラグが結構多い(DMAリクエストも同様)
  • 多くのデータラインを持つ(SAI1は4本のデータラインを持っている)

まとめ

STM32のSAIとの違いはFIFOの大きさ、割り込み生成フラグの種類、データラインの数ぐらいかな
i.MXRT1050はFreescale由来のペリフェラルが引き継がれてる。
大きな違いとしてはDMAがあげられる。オーディオのアプリケーションの場合ペリフェラルの組み合わせでパフォーマンスが決まるのでデータ処理に直結するDMA関連が柔軟当面ではアドバンテージがあると思う。
さらにRAM関連も見直されて柔軟になっているし期待できる。

一方STM32もH7になってからDMAの種類が変わってきているのでそちらも評価を行なって行く予定である。

i.MX RT1050 SAIメモ2

今回はレジスタのまとめ
TCR.....とかRCR......とかで実際に何してるかわからんので概略でも示せたらなと思ってまとめた。
一応Tx側だけ書いてみた。暇があればRx側もやろうかな

VERID(Version ID)

Verを示すレジスタ
この辺はMCUXpressoSDK使う分に勝手に取得すると思うしエラッタがあった場合おそらくSDK側で回避してくれるんだろう

PARAM(Parameter)

こちらもREADONLYなレジスタでハード情報の取得が可能っぽい
オーディオフレームワークを組む際にFIFOのサイズとか取得できるとありがたいしこれは良い

TCSR(Transmit Control Register)

各種Enable(Tx,Clock,interrupt,DMA),Error Flag,FIFO関連フラグの有効だったりができる。
おおもとの設定レジスタなのでここは把握する必要あり。

TCR(Transmit Configuration Register)

TCR1

TFW(FIFO watermark)「闘値」の設定だけしかない(他のビット無駄やんけw)

TCR2

Clock,Sync設定

TCR3

どのFIFOチャンネルを使うか指定するCFRビットだったりTxチャンネルの選択だったりができる。

TCR4

このレジスタはTCSR[TE]が有効でないと変更できない
protocolの指定レジスタであるがために一番重要だ。
クロック極性、フレームSyncだったり そう言った部分を設定してI2Sとして動かすことができる。

TCR5

このレジスタはTCSR[TE]が有効でないと変更できない
ワード幅だったりビットソフトの設定ができる

TDR(Transmit Data Register)

読んで字のごとしデータレジスタ
書き込むとFIFOに流れて行く

TFR(Transmit FIFO Register)

Write Combineの設定ビット、R/Wのポインタを示すビットがある。
TxFIFOってポインタ管理いるのかな?と思う単純に投げ続ければ一応はコーディックに流れて行くわけだしflagかなんかで割り込み動作させればなんとかなるんやない的な考えを持ってしまう。

TMR(Transmit Mask Register)

ここよくわかんない。
追記1/18
https://community.nxp.com/thread/441940
ここに乗ってた。

i.MX RT1050 SAIメモ1

自分用メモです。
割り込みに関して

FIFO Request Flag
FIFO Warning Flag
FIFO Error Flag
Sync Error Flag
Word Start Flag


がある。
ここでよく使うものについてだけ触れておこうと思う。

FIFO Request Flag

FIFO闘値の割り込みのこと。
あらかじめ設定しておいた闘値に達した時に割り込みフラグを発生することができる。
STM32のSAIではハーフとか1/4とかそんな感じで説明されている
(STのSAIは32[bit] x 8[word]だがi.MX RT1050は32 x 32もある)

FLAG SET         :闘値設定値より大きい場合にセットされる。
FLAG CLAER     : less than or equalとあるように値設定値小なりイコールでクリアされる。
設定するにはTCR1レジスタの4−0ビットをいじる

FlFO Warning Flag

Txの場合はFIFOemptyでSET、not emptyでCLEAR
Rxの場合はFIFOfullでSET、not fullでCLEAR

FIFO Error Flag

FIFO アンダーフロー時にSETされる一回セットされるとTCSRレジスタのFEFをクリアするまでTxからゼロデータが吐かれ続ける。

TCR4[FCONT]ビットがセットされている場合ソフトクリアなしで継続される。
オーバーフローが発生した場合RCSR[FEF](FIFOラーフラグ)がセットされる。
フラグクリアされるまではデータは捨てられてしまうので注意。
RCSR[FEF]クリア前にRxFIFOは空にすべき(マニュアルではshould〜みたいに書いてるのでどうなんでしょうね?)
RCR4[FCONT]は送信と同じ感じでエラーの際継続の有無

このフラグは割り込みのみ生成可能(DMAはなし)

ここでいうアンダーフローは送信コントローラがFIFO読みに言った際データがない状態、一方オーバーフローはRxFIFOがフルでその状態で次のデータがきてしまって溢れること。

MCUXpresso SDK attribute sectionマクロについて

自分用メモです。(皆さんの参考になれば幸いです。

ものとしてはcr_section_macros.hにて定義されている配置変更マクロについてです。
本来はgnu拡張機能

 __attribute__ ((section("セクションの名前”)))

と言う書き方をする。これを簡易化するためのマクロの話。
要は関数のメモリ配置の変更だったり変数配置メモリ変更だったりが行えます。

メモリ配置

使い方についてですがコメント部分に説明があるのでそれを参考にする。
まず以下のようなコードがある。

__SECTION(data,RAM1) char buffer[1024] ;

このように書くとbufferという配列がRAM1に配置されると言うことになる。
このSECTION自体はdefineマクロで構成されており

#define __SECTION(type, bank) __attribute__ ((section("." #type ".$" #bank)))

このような内容になる。
この#ってのが文字列型演算子で””つけたのと同じ意味になる。

複数引数になってるのはIBMの資料によると

複数の section 属性が変数宣言に適用された場合、最後の指定が用いられます。変数定義は上書きできないため、用いられる変数宣言で示されるセクションは、変数定義のセクションと一致している必要があります。定義済みの各変数は、1 つのセクションにのみ存在できます。

なのでこの場合RAM1だけ有効になるってこと。
なんでこうしてるのかは多分コードの可読性向上のためだと思われる。

実際にやってみるとこのような感じだ。
f:id:gsmcustomeffects:20180114231533p:plain
bufferと言う変数だけ異なる部分に配置されたことがわかる。
f:id:gsmcustomeffects:20180114231503p:plain

実際のメモリコンフィグはこのようになっており
f:id:gsmcustomeffects:20180114231741p:plain

直接セクション名を指定しなくてもエイリアスでRAM1とかそう言う感じで指定できる。

コード配置

次にコード配置になる
マクロとしては二つあって

 // Macros for causing functions to be relocated to RAM
#define __RAM_FUNC_EXT(name) __attribute__ ((section(".ramfunc.$" #name)))
#define __RAM_FUNC __attribute__ ((section(".ramfunc")))

// Macros to be used in preference to __RAM_FUNC to better match __DATA behaviour
#define __RAMFUNC_EXT(bank, name) __SECTION_EXT(ramfunc, bank, name)
#define __RAMFUNC(bank) __SECTION(ramfunc, bank)

上の方が単純にセクションの上から配置されるやつで(多分そう)下が明示的に好きなRAM領域に配置するやつ

使い方は

__RAMFUNC(RAM) void fooRAM(void) {...

な感じになる。

i.MX RT1050 : XIPで起動する

題名にある通り今回はXIP機能を使って外部のHyperFlashからプログラムを実行して行く

実習環境

  • MIMX RT1050-EVK(OpenSDA firmwareは最新のものでHyperFlash版にアップデートしたもの)
  • MCUXpresso IDE(10.1.0_589)
  • MacbookPro 2012 (MacOS HighSierra)

XIP(eXecute-In-Place)

Application eXecute-In-Place (XIP) with Linux and AXFS | Random Access Memory | Computer Data Storage
より

XIP, or eXecute-In-Place when written out, isa technique of directly accessing application code and data in non-volatile flash memory rather than transferring it to physical RAM first in order for an execution to proceed. It is frequently used in the contexts of embedded computing.

とあるようにRAMに転送することなく、不揮発性フラッシュメモリから直接アクセスする技術のことを指す。

利点としてはRAM展開しないことで手順を省ける。
欠点は安直にいうと速度の面で劣るという点である。
QSPI,HyperBusを使うと結構早いので最高速アクセスではないと補足しておくがコアクロックが600Mhzとかになってくると話は別になる。
クリティカルなリアルタイムコードとかになってくると密結合メモリへの配置が必須になってくる場合もある。

i.MXRT1050のブートについて

i.MX RT1050は以下に示すように様々なブートに対応している。

  • Serial NOR Flash via FlexSPI
  • Serial NAND Flash via FlexSPI
  • Parallel NOR Flash via Smart External Memory Controller (SEMC)
  • RAWNAND Flash via SEMC
  • SD/MMC
  • SPI NOR/EEPROM

各種アドレスは下に示す通りです。

Start add End add Size Description
0x80000000 0xDFFFFFFFF 1.5GB SEMC(外部RAMコントローラ)
0x60000000 0x7F7FFFFF 504MB FlexSPI
0x20200000 0x2027FFFF 512KB On Chip RAM
0x20000000 0x2007FFFF 512KB DTCM
0x00000000 0x0007FFFF 512KB ITCM

下から三つのOn chip RAM,ITCM.DTCMはFlexRAMであり自由に容量を割振れるRAMなので各種512KBづつあるわけではないので注意
FlexRAMについてはNXPのドキュメントAN12077を参照されたい

今回は青で示したFlexSPI経由で起動する流れを取る。

BOOT MODE

BOOTMODEはピンで設定をして行く流れとなる。

BOOT_MODE[1:0](評価ボードのSW7-3,SW7-4) BOOT Type
00 Fuseから起動
01 シリアルブート(USB,UART)
10 内部ブート(内部bootROM)
11 予約済み

ここでFuse起動は内部ブートと似ているがGPIOでのboot設定は無視されてeFUSEを参考に起動する流れ(結構特殊なので基本は10でいいんじゃないかなと思います。
最終的なDIPスイッチ設定はこのようになる。

SW7-1 SW7-2 SW7-3 SW7-4 BOOT Device
0 1 1 0 HyperFlash
0 1 1 0 QSPI Flash
0 1 1 0 SD Card

HyperFlashで起動したいので0110に評価ボードのDIPスイッチ(SW7)を設定してください
これでブートの説明は以上になるがブータブルイメージの構成やIVT(image vector table)データ構造体やBOOTDATAだったりの話があるのでかなり端折っている。

プロジェクトを用意する。

前項まででブートの軽い説明とボード状のDIPスイッチをいじったので次はプロジェクトを作って行きます。
一からnewprojectしてもいいですがコードにはできるだけ触れたくない(GPIOの説明とかで脱線したくないため)のでSDKサンプルをXIP向けに変えて行きます。
import sdk sample からledチカのプログラムを選択する。
f:id:gsmcustomeffects:20180107013827p:plain
あとは流れに沿ってFinish そのあと一旦コンパイルしてビルドが通ることを確認する。

メモリコンフィグの編集

案の定RAMリンクなプロジェクトなのでEXT Flashの宣言がない・・・・・
f:id:gsmcustomeffects:20180107015927p:plain

そこでFlashを追加する。
location:0x60000000,Size:0x400000,DriverはMIMX
f:id:gsmcustomeffects:20180107020049p:plain

XIPファイルの追加

プロジェクトエクスプローラーの上の方の十字みたいなのをクリックします。
f:id:gsmcustomeffects:20180107020756p:plain

XIPを選択して追加する。
f:id:gsmcustomeffects:20180107020934p:plain

XIP_EXTERNAL_FLASHシンボルを追加する

Properties/C/C++ Build/Setting/PreprocessorからXIP_EXTERNAL_FLASHマクロを追加
f:id:gsmcustomeffects:20180107021626p:plain

restore linkage to flash(RAM向けからFlashへ)

Properties/C/C++ Build/Setting/Managed Linker Script
Link application to RAMのチェックを外す
f:id:gsmcustomeffects:20180107021942p:plain

あとはリビルドしてデバッグする。

XIP起動

このようにプログラムカウンタが0x60000000番台に来てればOKです。
f:id:gsmcustomeffects:20180107022354p:plain

できなければ下部にあるトラブルシューティングを参照してください。

まとめ

  • XIPで起動できた
  • ブートの知見を深めたので今後はRAM移動への知見を深めて行きたい。

Troubleshooting

デバッガが繋がらないときはOpenSDAのファームウエアの更新をしてください
OpenSDA Serial and Debug Adapter|NXP

それでも繋がらない場合はフラッシュの消去を行う

LinkserverGUI Flash Programmerを開く(上のアイコンメニューのチップみたいなやつをクリック)
f:id:gsmcustomeffects:20180107022804p:plain

Mass eraseをかけて再度debugする。