LoginSignup
5
4

More than 5 years have passed since last update.

Orange Pi 2G-IOTのGPIOをフル活用する

Last updated at Posted at 2018-01-08

はじめに

Orange Piの中でも2G-IOTはちょっと特殊な扱いで、まずCPUからして他のシリーズとは全然毛色の異なるRDA8810。H3などとは違いCPUについての情報がほとんどありません。唯一の手掛かりはカーネルのソースのみ。しかも1コアなので貧弱。とは言え、安価なラインながらもNANDフラッシュを内蔵していて数秒でLinuxが起動するのは魅力的です。まぁ、これも非公式対応(参考ページ、ただしスペイン語)で、オフィシャルにはNANDからはAndroidしか起動しないのですが。そして、もう1つの弱点がGPIO。WiringPiなどの対応も不完全で、使えるピン数も少ない。ところが、これも頑張れば28個くらいまで使えることがわかったので、それについてのメモになります。

ピンアウト

標準設定

GPIO# Function # # Function GPIO#
2.8V 1 2 5V
/dev/i2c.0 - SDA 3 4 5V
/dev/i2c.0 - SCL 5 6 GND
56 GPIO B24 7 8 /dev/ttyS2 - TxD
GND 9 10 /dev/ttyS2 - RxD
/dev/ttyS1 - RxD 11 12 GPIO B5 37
/dev/ttyS1 - TxD 13 14 GND
/dev/ttyS1 - CTS 15 16 GPIO C5 101
2.8V 17 18 GPIO C25 121
4 SPI2 - MOSI/DI 19 20 GND
3 SPI2 - MISO/DIO 21 22 /dev/ttyS1 - RTS
2 SPI2 - SCLK/CLK 23 24 SPI2 - CS0 5
GND 25 26 SPI2 - CS1 6
1 I2C2 - SDA 27 28 I2C2 - SCL 0
122 GPIO C26 29 30 GND
123 GPIO C27 31 32 /dev/ttyS2 - RTS
124 GPIO C28 33 34 /dev/ttyS2 - CTS
125 GPIO C29 35 36 GND
126 GPIO C30 37 38 /dev/i2c-2 - SCL
GND 39 40 /dev/i2c-2 - SDA

たったこれだけ。ここに書かれたGPIOは、おおよそ/sys/class/gpioのインタフェースを使って制御できるようです。あと、GPIOはA/B/C系列ありますが、C系列はCPUから見えるI/Oには直接ぶらさがっておらず、速度を要する用途には不向きかもしれません。あと自前で制御しようとすると面倒。そう考えると実質9ピンしかない。

GPIOに強制的に切り替えた設定

GPIO# Function # # Function GPIO#
2.8V 1 2 5V
62 /dev/i2c.0 - SDA 3 4 5V
63 /dev/i2c.0 - SCL 5 6 GND
56 GPIO B24 7 8 /dev/ttyS2 - TxD 72
GND 9 10 /dev/ttyS2 - RxD 71
70 /dev/ttyS1 - RxD 11 12 GPIO B5 37
14 /dev/ttyS1 - TxD 13 14 GND
15 /dev/ttyS1 - CTS 15 16 GPIO C5 101
2.8V 17 18 GPIO C25 121
4 SPI2 - MOSI/DI 19 20 GND
3 SPI2 - MISO/DIO 21 22 /dev/ttyS1 - RTS 16
2 SPI2 - SCLK/CLK 23 24 SPI2 - CS0 5
GND 25 26 SPI2 - CS1 6
1 I2C2 - SDA 27 28 I2C2 - SCL 0
122 GPIO C26 29 30 GND
123 GPIO C27 31 32 /dev/ttyS2 - RTS 41
124 GPIO C28 33 34 /dev/ttyS2 - CTS 40
125 GPIO C29 35 36 GND
126 GPIO C30 37 38 /dev/i2c-2 - SCL 38
GND 39 40 /dev/i2c-2 - SDA 39

こんな感じで、実は電源以外は強制的にGPIOに切り替え可能。ただし、デバイスファイル名が書いてあるところなんかはドライバが見てたりするので取り扱い注意。うっかり競合すると最悪panicする事もあるかもしれません。

制御方法

GPIOの有効化

以下のレジスタを使って制御できます。

物理アドレス 名前 機能
0x11A09008 BB_GPIO_MODE C系列のGPIO設定
0x11A0900C AP_GPIO_A_MODE A系列のGPIO設定
0x11A09010 AP_GPIO_B_MODE B系列のGPIO設定

A系列はGPIO#0-31、B系列はGPIO#32-63、C系列はGPIO#96-127に対応します。各GPIO設定はbit Nが各系列のN番目のGPIOの設定となり、1を入れた時にGPIOが有効となります。例えば

*AP_GPIO_A_MODE |= (1 << 14);
*AP_GPIO_B_MODE |= (1 << 6);

などとすれば、GPIO A14がpin 15で、GPIO B6がpin 38で有効になります。

GPIOの制御

上記のレジスタから強制的に有効化してあげたGPIOは、それだけで/sys/class/gpioから使えるようです。また以下のレジスタを使い直接制御する事も可能です。

GPIO系列 ベースアドレス
GPIO A 0x20930000
GPIO B 0x20931000
オフセット 名前 機能
+0x00 OEN_VAL 未調査
+0x04 OEN_SET_OUT 対応するGPIOをアウトプットモードに設定
+0x08 OEN_SET_IN 対応するGPIOをインプットモードに設定
+0x0C VAL GPIOの入力値読み取り
+0x10 SET 対応するGPIOをHIGHに設定
+0x14 CLR 対応するGPIOをLOWに設定
+0x18 INT_CTRL_SET 未調査
+0x1C INT_CTRL_CLR 未調査
+0x20 INT_CLR 未調査
+0x24 INT_STATUS 未調査
+0x28 CHG_CTRL 未調査
+0x2C CHG_CMD 未調査

OEN_SET_OUT/OEN_SET_INは書き込んだ際に立っていたbitに対応するGPIOがそれぞれアウトプットモード、インプットモードに切り替わります。SET/CLRも同様に立っていたbitに対応するGPIOの出力がそれぞれHIGH/LOWに切り替わります。

物理レジスタへのアクセス

Orange Pi Zero Armbian導入後の設定とmmapなLチカで紹介した/dev/memをmmapする方法が使えます。

#define RDA_CONFIG_REGS 0x11a09000

volatile struct config_regs {
  uint32_t chip_id;
  uint32_t build_version;
  uint32_t bb_gpio_mode;
  uint32_t ap_gpio_a_mode;
  uint32_t ap_gpio_b_mode;
  uint32_t ap_gpio_d_mode;
  // ...
}* cfg;

#define GPIOA_BASE 0x20930000

volatile struct pio_cfg {
  uint32_t oen_val;
  uint32_t oen_set_out;
  uint32_t oen_set_in;
  uint32_t val;
  uint32_t set;
  uint32_t clr;
  // ...
}* pa;

int main(int argc, char** argv) {
  int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
  if (mem_fd < 0) {
    perror("can not open /dev/mem");
    exit(EXIT_FAILURE);
  }

  int prot = PROT_READ | PROT_WRITE;
  size_t size = sysconf(_SC_PAGE_SIZE);
  cfg = mmap(NULL, size, prot, MAP_SHARED, mem_fd, RDA_CONFIG_REGS);

  cfg->ap_gpio_a_mode |= (1 << 14) | (1 << 15);  // Enable GPIO 14, 15

  pa = mmap(NULL, size, prot, MAP_SHARED, mem_fd, GPIOA_BASE);

  pa->oen_set_out = 1 << 15;  // Setup GPIO 15 as output pin
  pa->clr = 1 << 15;  // Drive GPIO 15 as LOW
  sleep(1);
  pa->set = 1 << 15;  // Drive GPIO 15 as HIGH
  return 0;
}

まとめ

という事で、少々乱暴ですがI/O空間をマップしてあげて内部レジスタを叩いてあげる事で、ほぼ全てのピンがGPIOとして利用できるようになります。ただし利用に際しては、くれぐれもドライバなどと競合しないよう注意が必要です。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4