stm32plusを使う - STM32

GPIO

解説

stm32plusでは,各ペリフェラルに対してFeature(特徴)をオプションとして渡して初期化することで,コード量の省略と実行時処理の削減を実現している.

GpioPortクラス

GpioPort<uint32_t TPortAddress,class... Features> : public GpioPortBase,public Features...
引数デフォルト値説明
uint32_t TPortAddress
-GPIOxのベースアドレス
GPIOA_BASE,GPIOB_BASE,GPIOC_BASE,...
class... Features
-使用するFeature(複数可)
DigitalInputFeature,DigitalOutputFeature,AnalogInputFeature,AlternateFunctionFeatureとそのDefault

GpioX

GpioC<DefaultDigitalOutputFeature<8> > pc;

このコードでは,GpioCのテンプレートにDefaultDigitalOutputFeature<8>というFeatureを渡してGpioCの実体pcを生成している.

GpioPorts.hによると,

template<class... Features> using GpioC=GpioPort<GPIOC_BASE,Features...>;

とあり,GpioCはGpioPortを特殊化したものであるということがわかる.

Feature

Default*Featureは,それぞれのFeatureのデフォルト値を入れたテンプレートになっている.

AlternateFunctionFeature

  • F1
    AlternateFunctionFeature<GPIOSpeed_TypeDef TSpeed,GpioOutputType TOutputType,uint8_t... TPins> : public Gpio
    引数デフォルト値説明
    GPIOSpeed_TypeDef TSpeed
    GPIO_Speed_50MHz
    GPIOのスピード
    GPIO_Speed_50MHz,GPIO_Speed_100MHz
    Gpio::GpioOutputType TOutputType
    Gpio::PUSH_PULL
    GPIOのアウトプットタイプ
    Gpio::PUSH_PULL,Gpio::OPEN_DRAIN
    uint8_t... TPins
    -設定するピンの番号(複数可)
    数値 0〜15
    複数のAFIOが割り当たっているピンの機能の選択は,StdPeriphLib同様にリマップ関数を使うはず(要検証).
  • F4
    AlternateFunctionFeature<uint8_t TAfSelection,GPIOSpeed_TypeDef TSpeed,GpioOutputType TOutputType,GpioPullUpDownType TPullUpDownType,uint8_t... TPins> : public Gpio
    引数デフォルト値説明
    uint8_t... TAfSelection
    -設定するAFIOの種類
    GPIO_AF_TIM1〜5,GPIO_AF_TIM8〜14,GPIO_AF_I2C1〜3,GPIO_AF_SPI1〜3,GPIO_AF_USART1〜3,GPIO_AF_UART4〜5,GPIO_AF_USART6,GPIO_AF_FSMC,GPIO_AF_SDIO
    GPIOSpeed_TypeDef TSpeed
    GPIO_Speed_50MHz
    GPIOのスピード
    GPIO_Speed_50MHz,GPIO_Speed_100MHz
    Gpio::GpioOutputType TOutputType
    Gpio::PUSH_PULL
    GPIOのアウトプットタイプ
    Gpio::PUSH_PULL,Gpio::OPEN_DRAIN
    Gpio::GpioPullUpDownType TPullUpDownType
    Gpio::PUPD_NONE
    プルアップ/ダウンの設定
    Gpio::PUPD_NONE,Gpio::PUPD_UP,Gpio::PUPD_DOWN
    uint8_t... TPins
    -設定するピンの番号(複数可)
    数値 0〜15

AnalogInputFeature

AnalogInputFeature<uint8_t... TPins> : public Gpio
引数デフォルト値説明
uint8_t... TPins
-設定するピンの番号(複数可)
数値 0〜15

DigitalInputFeature

DigitalInputFeature<GPIOSpeed_TypeDef TSpeed,GpioPullUpDownType TPullUpDownType,uint8_t... TPins> : public Gpio
引数デフォルト値説明
GPIOSpeed_TypeDef TSpeed
GPIO_Speed_50MHz
GPIOのスピード
GPIO_Speed_50MHz,GPIO_Speed_100MHz
Gpio::GpioPullUpDownType TPullUpDownType
Gpio::PUPD_NONE
プルアップ/ダウンの設定
Gpio::PUPD_NONE,Gpio::PUPD_UP,Gpio::PUPD_DOWN
uint8_t... TPins
-設定するピンの番号(複数可)
数値 0〜15

DigitalOutputFeature

DigitalOutputFeature<GPIOSpeed_TypeDef TSpeed,GpioOutputType TOutputType,GpioPullUpDownType TPullUpDownType,uint8_t... TPins> : public Gpio
引数デフォルト値説明
GPIOSpeed_TypeDef TSpeed
GPIO_Speed_50MHz
GPIOのスピード
GPIO_Speed_50MHz,GPIO_Speed_100MHz
Gpio::GpioOutputType TOutputType
Gpio::PUSH_PULL
GPIOのアウトプットタイプ
Gpio::PUSH_PULL,Gpio::OPEN_DRAIN
Gpio::GpioPullUpDownType TPullUpDownType
Gpio::PUPD_NONE
プルアップ/ダウンの設定
Gpio::PUPD_NONE,Gpio::PUPD_UP,Gpio::PUPD_DOWN
uint8_t... TPins
-設定するピンの番号(複数可)
数値 0〜15

細かいお話

Featureの全てに共通する

uint8_t... TPins

だが,stm32plusを使う - STM32#ld75c0c1でも述べたように,複数のピンをカンマ区切りで指定して,例えば

GpioC<DefaultDigitalOutputFeature<0,2,3> > pc;

のように扱うことができる.
これは,可変長の引数をコンパイル時に再帰的に処理するというテンプレートメタプログラミング(TMP)の,稀に見る実用例である.

例えば,最も単純なAnalogInputFeatureを例にとってコンストラクタを見ると,

AnalogInputFeature(GpioPortBase& port) : Gpio(port) {
  uint32_t pins;
  // recurse to get the pin mask
  pins=0;
  GpioPinMerge<TPins...>(pins);
  // do the initialisation
  initialise(pins);
}

となっており,更に親クラスであるGpioのコードをたどるためにGpio.hを読むと,

namespace  {
  template<uint8_t TPin>
  void GpioPinMerge(uint32_t& pins) {
    pins|=1 << TPin;
  }
  template<uint8_t First,uint8_t Next,uint8_t... Rest>
  void GpioPinMerge(uint32_t& pins) {
    pins|=1 << First;
    GpioPinMerge<Next,Rest...>(pins);
  }
}

というコードが見つかる.

この,GpioPinMergeなるテンプレート関数がコンパイル時に再帰的に処理され,ピン番号の列を16bitのバイナリ列に変換しているのである.

例えば,TPinsとして0,2,3が渡されたとすると,まず最初に

void GpioPinMerge<0,2,3>(uint32_t &pins)

が呼ばれるため,実際の処理内容としては,後の方のテンプレート関数が呼ばれ

となる.次には

void GpioPinMerge<2,3>(pins)

が呼ばれ,同様に

最終的に

void GpioPinMerge<3>(pins)

すなわち前の方のテンプレート関数が呼ばれ,

となる.

ただし,この旨みは指定するピン番号等がコンパイル時に定数であることが必要なので,このへんを動的にいじるヘンタイさんには別途用意されているGpioPinInitialiser::initialise関数を呼ぶ必要がある.


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-01-13 (月) 23:45:35 (1539d)