ジャンル不定の日記です。

C言語でGPIO触ってみた

C言語でHello World作ってOrange Piで実行できること確認した後pthread試してみて、あと必要なファイル書き込みやってみた。

#include <unistd.h>
#include <fcntl.h>

int main(void){
    char b;
    int fd=open("/sys/class/gpio/gpio12/value",O_WRONLY);
    b='1';
    write(fd,&b,1);
    sleep(5);
    b='0';
    write(fd,&b,1);
    sleep(5);
    b='1';
    write(fd,&b,1);
    return(0);
}
こんな感じで試してみた。
Orange Pi Zero準備するのめんどいんで、ヘッダーピンつけてないけどルーターとして常時起動してるOrange Pi R1で。GPIOはZeroとR1同じだしハード繋がない実験ならR1でやればいいね。

GPIO12を出力用にして実行してみた。
/sys/class/gpio/gpio12/value に'1'を書き込む。
5秒後に'0'を書き込む。
5秒後に'1'を書き込む。
って感じ。
最初は初回'1'を書き込んだところまでのコードで'1'に書き換わることを確認。
次に'0'を書き込んだとこまでのコードで確認したら'0'になってた。
最後のコードだと'1'だった。
ファイルは閉じずに1byteずつ書き込めば即時書き換わるぽい?
C言語のファイルアクセスはfopen使うのが普通みたいだが、バッファとか使われなそうと思ったんでシステムコール使ってみた。

ファイルはcloseするの忘れてたけどプロセス落ちれば勝手に閉じるよね?

Makefile自分で書いてみた

Orange Piを使ってGPIOを制御するプログラムを作る予定だが、C++はBuildroot標準でコンパイラがないようなので言語はCにする方向になった。
コンパイラを直接使ってOrange Piで動く"Hello World"はできたが、実際にはソースファイルが複数になってコンパイラの引数が多くなってわからなくなるのでmake使ってみることにした。

makeは同じディレクトリのMakefileに従ってコンパイルするマクロ的なもんだが、
ターゲット名:依存ファイル1 依存ファイル2
     コマンド
のような感じで、
:の左側にターゲット名、右側にスペース区切りで依存ファイルを書く。(依存ファイルは1つでもいいし多数でも。)
次の行に先頭からタブを空けてコマンドを書く。(コマンドは複数行書けると思う。)
参考にしたサイトだとどこも:の後にスペースがあったが必要ないみたい。
コマンド行のタブは必須。
単に
$ make
とした場合は最初に記載されたターゲットが処理されるらしい。

まあとりあえず、
CC=gcc

hello:main.o
    $(CC) -o $@ $^

.c.o:
    $(CC) -c $<

clean:
    $(RM) hello main.o
こんな感じで"Hello World"をmakeできるようにしてみた。

CCは変数みたいなものだがマクロと言うらしい。
gccを定義してあるが、ここ変えればクロスコンパイルできる。
定義の際はそのまま書いて使うときは$をつけるが、マクロ名が2文字以上の場合は$(CC)の様に()で囲む必要があるみたい。
$@ $^$<は内部マクロで、
$@=ターゲット名
$^=依存ファイルすべて
$<=依存ファイルの先頭1個
$(RM)は定義済みマクロで rm -f と同じ。

.c.oはサフィックスルールというもので、拡張子を2つ続けて書く感じでワイルドカード的に使える。

今回はソースファイルが main.c 1つなんで main.o は作る必要ないが今後のためにも main.o を作ってから hello コマンドを作る感じにした。
先頭のターゲットがhelloなんでmakeしたらhelloを作ろうとするが main.o がなければサフィックスルールに基づきmain.cからmain.oが作られ、main.oからhelloが作られる。
って感じかな。

Buildrootでクロスコンパイル

x86のArch Linux上でOrange pi用のアプリをコンパイルするのにarm-none-eabi-gcc使おうとしてたんだが、
arm-none-eabi-gccはstdio.hとかiostreamとかが無くてコンパイルできずかなり時間を費やしたが、結局別のクロスコンパイラを使う方法を発見した。
Buildrootのクロスコンパイラを使えばいいのね。

Buildrootってarm-none-eabi-gccを使ってシステムを作るものだと思ってたんだが、クロスコンパイラから作るのね。
いつもBuildrootのビルドするとき
$ make ARCH=arm CROSS_COMPILE=arm-none-eabi-
こんな感じでやってたが、これ、
$ make
だけでよかったのね。
Buildrootというものを勘違いしてた。

で、buildroot/output/host/bin/ 以下に arm-linux-gccとか arm-buildroot-linux-uclibcgnueabihf-gccがあるが、これがクロスコンパイラ。(どっちでも実体は同じらしい)
で、
$ PATH=$PATH:buildroot/output/host/bin
みたいな感じでPATHに追加して、
$ arm-linux-gcc -o hello hello.c
でコンパイルできた。
Orange Pi R1に転送して実行できた。
ターゲットのシステムに最適なコンパイラだから、Arch Linux標準のコンパイラ使うよりもいいね。

mSATA SSD 16GBとmSATA to SATA届いた

メルカリのポイント消化で、先日Aliで買ったmSATA SSD 32GBの認識が確認できなかったから、mSATA SSD 16GB(確認済み中古)をポチってたんだが届いた。
で、もう一個届いてた荷物確認したら、ちょうどmSATA to SATA(箱付き)の変換ボードだった。

というわけでBIOSで確認してみたが、今日届いたSSDも先日のSSDも認識した。
なので壊れてるのはmSATA to ZIFのボードだね。

あと、古いやつだが、
SATA to USBの変換ケーブルが認識しない。
てかこれはそもそもドライブレスでもケーブルだけでUSBデバイスになるよね?
ドライブつけてもつけなくても何も出てこない。
前は使ったことあるんだが・・・
これ系1個あると便利だが、電源の関係でUSB3の方がいいと思うからマザー変えてからUSB3の買うか・・・
と思ったが、今のマザーリアにUSB3あった。
今は到着待ちの商品多いから、全部届いたら買うか。

Orange Pi ZeroでGPIO使ってみた

XR819がうまく行かないOrange Pi Zeroだが、
とりあえずシリアルコンソールで制御してGPIO触ってみることにした。
ピンヘッダーはさっきくっつけた。

ピン配列だが、
https://gist.github.com/probonopd/97f6826cc5aa3c0c0950682b0bc266bc
画像検索したら上のページが出てきた。
画像無くなったときのために画像は転載しておく。

LANコネクタある側の外側がGNDで、対角に5Vが2本、外側が3.3V。
テスタで測ったらそんな感じだった。

Raspberry Piの情報だが、
https://www.jtp.co.jp/techport/2016-08-31-002/
↑にファイルアクセスでGPIO制御する方法載ってたんで参考にした。
ググるとPython使ったやり方が出てきたりするがファイルアクセスだけで制御できる。Pythonなんか入れてない。

# cd /sys/class/gpio
# ls -al
total 0
drwxr-xr-x    2 root     root             0 Jan  1 00:00 .
drwxr-xr-x   43 root     root             0 Jan  1 00:00 ..
--w-------    1 root     root          4096 Jan  1 00:00 export
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 gpiochip0 -> ../../devices/platform/soc/1c20800.pinctrl/gpio/gpiochip0
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 gpiochip352 -> ../../devices/platform/soc/1f02c00.pinctrl/gpio/gpiochip352
--w-------    1 root     root          4096 Jan  1 00:00 unexport
/sys/class/gpio/export にピン番号を書き込めば有効になってunexportに書き込むと無効になるらしい。
だが、ピン番号がわからない。

https://github.com/orangepi-xunlong/wiringOP
↑にあるWiringOPというコマンドを使うと番号が確認できるみたい。これはwiringPiというRaspberry Pi用のコマンドのOrange Pi用みたい。
BuildrootにもOrange Pi用に使えそうなコマンドがなかったんで上のをビルドしようと思ったが、これクロスコンパイルできない感じ?
なので、上のページに出力結果が載ってるんで信じることにした。
 +------+-----+----------+------+---+  OPi H2  +---+------+----------+-----+------+
 | GPIO | wPi |   Name   | Mode | V | Physical | V | Mode | Name     | wPi | GPIO |
 +------+-----+----------+------+---+----++----+---+------+----------+-----+------+
 |      |     |     3.3V |      |   |  1 || 2  |   |      | 5V       |     |      |
 |   12 |   0 |    SDA.0 | ALT2 | 0 |  3 || 4  |   |      | 5V       |     |      |
 |   11 |   1 |    SCL.0 | ALT2 | 0 |  5 || 6  |   |      | GND      |     |      |
 |    6 |   2 |    PWM.1 |  OFF | 0 |  7 || 8  | 0 | ALT2 | TXD.1    | 3   | 198  |
 |      |     |      GND |      |   |  9 || 10 | 0 | ALT2 | RXD.1    | 4   | 199  |
 |    1 |   5 |    RXD.2 | ALT2 | 0 | 11 || 12 | 0 | OFF  | PA07     | 6   | 7    |
 |    0 |   7 |    TXD.2 | ALT2 | 0 | 13 || 14 |   |      | GND      |     |      |
 |    3 |   8 |    CTS.2 |  OFF | 0 | 15 || 16 | 0 | ALT3 | SDA.1    | 9   | 19   |
 |      |     |     3.3V |      |   | 17 || 18 | 0 | ALT3 | SCK.1    | 10  | 18   |
 |   15 |  11 |   MOSI.1 | ALT2 | 1 | 19 || 20 |   |      | GND      |     |      |
 |   16 |  12 |   MISO.1 | ALT2 | 0 | 21 || 22 | 0 | OFF  | RTS.2    | 13  | 2    |
 |   14 |  14 |   SCLK.1 | ALT2 | 0 | 23 || 24 | 0 | ALT2 | CE.1     | 15  | 13   |
 |      |     |      GND |      |   | 25 || 26 | 0 | OFF  | PA10     | 16  | 10   |
 +------+-----+----------+------+---+----++----+---+------+----------+-----+------+
 | GPIO | wPi |   Name   | Mode | V | Physical | V | Mode | Name     | wPi | GPIO |
 +------+-----+----------+------+---+  OPi H2  +---+------+----------+-----+------+
こんな感じで出力されるらしい。
なお、ピン配列の画像のページにもこのコマンドの結果が載ってるが番号が違う。よく見るとh3用をビルドしてるんで違うpiの結果を出力しちゃってるぽい。
H2(ZeroとR1)の配列は上の通りと思われる。
ピンヘッダーの配置と同じ感じの出力になってるわけね。
これのGPIOの欄に書かれている数字が /sys/class/gpio へのアクセスで使う数字ぽい。

# echo "12">export
# ls -al
total 0
drwxr-xr-x    2 root     root             0 Jan  1 00:00 .
drwxr-xr-x   43 root     root             0 Jan  1 00:00 ..
--w-------    1 root     root          4096 Jan  1 01:18 export
lrwxrwxrwx    1 root     root             0 Jan  1 01:18 gpio12 -> ../../devices/platform/soc/1c20800.pinctrl/gpiochip0/gpio/gpio12
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 gpiochip0 -> ../../devices/platform/soc/1c20800.pinctrl/gpio/gpiochip0
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 gpiochip352 -> ../../devices/platform/soc/1f02c00.pinctrl/gpio/gpiochip352
--w-------    1 root     root          4096 Jan  1 00:00 unexport
3.3Vの隣りにある12番ピンを使うことにした。
exportにechoで"12"を書き込めば /sys/class/gpio/gpio12 が出てくる。
なお、echoのダブルクォート要らないんじゃね?思ったが要るみたい。(改行が入っちゃうとかか?)

# ls -alL gpio12
total 0
drwxr-xr-x    3 root     root             0 Jan  1 01:18 .
drwxr-xr-x    3 root     root             0 Jan  1 01:18 ..
-rw-r--r--    1 root     root          4096 Jan  1 01:19 active_low
drwxr-xr-x    4 root     root             0 Jan  1 00:00 device
-rw-r--r--    1 root     root          4096 Jan  1 01:19 direction
-rw-r--r--    1 root     root          4096 Jan  1 01:19 edge
drwxr-xr-x    2 root     root             0 Jan  1 01:19 power
drwxr-xr-x    2 root     root             0 Jan  1 00:00 subsystem
-rw-r--r--    1 root     root          4096 Jan  1 01:18 uevent
-rw-r--r--    1 root     root          4096 Jan  1 01:19 value
/sys/class/gpio/gpio12 には上記のファイルがある。
directionがin outの向きの確認と変更ができるみたい。
valueで値が確認できる。

# cat gpio12/direction
in
最初はinになってる。

# echo "out">gpio12/direction
# cat gpio12/direction
out
"out"を書き込むとoutになる。

# cat gpio12/value
0
valueの値は0。
この状況でテスタで電圧を測ってみたら0V強だった。
なお、inの状態でのテスタは3V強だった。active_lowだから?

# echo "1">gpio12/value
# cat gpio12/value
1
valueに"1"を書き込んだら1になった。
この状況でテスタで電圧を測ってみたら3V強だった。

テスタ当てるだけで制御できてることが確認できてるわけだが、一応LEDもくっつけてみた。
手元にVf2前後の緑LEDがあったんで20mA程度流せば光るだろうと計算したところ3.3Vに65Ωの抵抗で20mAになることがわかった。
100Ωの抵抗で光るだろうと判断して100Ω抵抗とLEDを直列でGPIO12とGNDの間につないでみた。
で、
# echo "0">gpio12/value
# echo "1">gpio12/value
# echo "0">gpio12/value
と交互に"0"と"1"をvalueに書き込んだら点滅した。

またXR819やってみたが・・・

昨日は https://github.com/karabek/xradio の方のドライバでOrange Pi ZeroのXR819を使おうとしてうまくいかず、
今日は https://github.com/fifteenhex/xradio の方でやってみた。
前者のほうがArmbianのやつ?だけど後者の方も数ヶ月以内に更新されてて放置されてはいない感じ。
なんだが、dtsが古いやつをベースにしてるんだと思うがそのままだと使えない感じ。

でコンパイルして機能してるようには見えるんだが、結局昨日のと同じくudhcpcでIPの取得ができない。
デバイスは使えるようになってもTKIPだと通信できてない感じ。

TKIPを指定せずにやると昨日は一時的に通信できてルーター側がのwifiがフリーズする感じだったが、
これはルーター側のRTL8189FTVに問題がありそう。
RTL8189FTVもなんか良くないんだよな・・・

XR819でハマった・・・

Orange Pi Zero LTSをSPIフラッシュとXR819対応でlinux,u-boot,Buildrootの作り直ししたがXR819を使うのにかなり苦戦した。

XR819のビルドは前回の記事のやつ。

5時間以上試行錯誤したと思うが、
結果的には、ルーター(R1)側の /etc/wpa_supplicant.conf が、
network={
  mode=2
  ssid="SSID"
  key_mgmt=WPA-PSK
  psk="パスフレーズ"
}
で、proto,pairwise,groupとか設定しちゃうとダメぽい。(というか、設定がXR819対応したものならいいんだろうがちょっとわかんない)
元々pairwiseがCCMPだと不安定な感じだったのでTKIPを設定してた。
XR819のgitにWPA2のみ対応でWPA1がだめとか書いてあるのでCCMPとか試したがダメで、何も書かないといけた。

udhcpcでIPアドレスの取得ができず、staticも無理でルーター側にもログでないのでつながってない感じだったんだが、
クライアント側にはエラーが出ずですごいハマった。
# ip link set wlan0 up
しないとリンクが確認できなかったりもしたんだが、そのへんは関係ないぽい。

クライアント(Zero)側の /etc/wpa_supplicant.conf は、
network={
  ssid="SSID"
  psk="パスフレーズ"
}
で普通に。

ダメなときは、
# dmesg
[   35.739500] wlan0: authenticate with 7c:a7:b0:81:a5:6f
[   35.744945] wlan0: send auth to 7c:a7:b0:81:a5:6f (try 1/3)
[   35.765618] wlan0: authenticated
[   35.769316] xradio_wlan mmc1:0001:1 wlan0: disabling HT/VHT/HE due to WEP/TKIP use
[   35.780730] wlan0: associate with 7c:a7:b0:81:a5:6f (try 1/3)
[   35.789081] wlan0: RX AssocResp from 7c:a7:b0:81:a5:6f (capab=0x411 status=0 aid=7)
[   35.799978] wlan0: associated
[  302.868029] wlan0: deauthenticated from 7c:a7:b0:81:a5:6f (Reason: 2=PREV_AUTH_NOT_VALID)
[  303.843281] wlan0: authenticate with 7c:a7:b0:81:a5:6f
[  303.848662] wlan0: send auth to 7c:a7:b0:81:a5:6f (try 1/3)
[  303.864728] wlan0: authenticated
[  303.868478] xradio_wlan mmc1:0001:1 wlan0: disabling HT/VHT/HE due to WEP/TKIP use
[  303.880733] wlan0: associate with 7c:a7:b0:81:a5:6f (try 1/3)
[  303.889239] wlan0: RX AssocResp from 7c:a7:b0:81:a5:6f (capab=0x411 status=0 aid=7)
[  303.899847] wlan0: associated
こんな感じで、認証に成功してるように見えるが、「disabling HT/VHT/HE due to WEP/TKIP use」とか出てて数分おきに再認証が発生してる。

成功してるときは
# dmesg
[   16.979911] wlan0: authenticate with 7c:a7:b0:81:a5:6f
[   16.985361] wlan0: send auth to 7c:a7:b0:81:a5:6f (try 1/3)
[   17.057485] wlan0: authenticated
[   17.070765] wlan0: associate with 7c:a7:b0:81:a5:6f (try 1/3)
[   17.080267] wlan0: RX AssocResp from 7c:a7:b0:81:a5:6f (capab=0x411 status=0 aid=5)
[   17.090588] wlan0: associated
こんな感じで、「disabling HT/VHT/HE due to WEP/TKIP use」とか出ない。

Orange Pi Zero とりあえず起動した

先日届いたOrange Pi Zero LTSだが、標準の2MBフラッシュじゃLinux入らんので、R1のときのカーネルとかをSDカードに入れてXR819のモジュールだけ作って起動しようと思った。

XR819のモジュールは、AURだと https://github.com/fifteenhex/xradio になってるが、
コメント欄に https://github.com/karabek/xradio じゃないと起動しないとか書いてあった。
後者のほうが開発続いてる感じなんで後者にした。

$ git clone https://github.com/karabek/xradio.git
$ cd xradio
のあとに、Makefileの4,5行目
CONFIG_WLAN_VENDOR_XRADIO := m
ccflags-y += -DCONFIG_XRADIO_USE_EXTENSIONS
の部分をコメントアウトする必要がある。
で、
$ make ARCH=arm CROSS_COMPILE=arm-none-eabi- -C ../linux/linux-5.4.16 M=$PWD modules
とR1の時に作ったカーネルのモジュールを作ろうとしたら、
cc1: error: incompatible gcc/plugin versions
cc1: error: failed to initialize plugin ./scripts/gcc-plugins/arm_ssp_per_task_plugin.so
こんなエラー出てコンパイルできなかった。
どうも、カーネル作ったときとGCCのバージョンが変わって互換性が無くなってるみたい。
gcc-pluginsだけのリビルドはやり方わからなかったので、5.8.3でカーネルを作り直すことにした。
どうせだし、Buildrootとu-bootも作り直した。
XR819のモジュールはカーネルのリビルドしたら問題なく実行できた。

Orange Pi R1のときにまとめた情報を見ながら作ったが、
今回はカーネルのビルドはBuildroot上でやらなかったら/lib/modulesがなかったんでモジュール置くのに手動で作る必要があった。
ファームウェアは/lib/firmware/xr819以下にBuildrootが置いててくれた。
R1と共通化するためにルーター関連のアプリなんかも入れたんだが、カーネルのpppサポートを入れ忘れた。

u-bootは一応作り直したがsfコマンドが使えなかった。
menuconfigでSPIフラッシュ関連の項目があったんで設定しないとダメになったのかも。
前は include/configs/sunxi-common.h を改造してboot.scrをロードするようにしてたが、インストール後にsetenvでdistro_bootcmdを書き換えちゃえばいい気がした。

そして、buildrootでdepmod入れ忘れてたようでdepmodコマンドが使えるようになってなかった。
というわけで、再度Buildrootの必要がある感じ。
flashcpなんかはBuildrootの標準で有効になってたんでBusyboxでは入れる必要なさそうな感じ。

あと、rootパスワードも設定忘れてたんだが、パスワード設定しないとオートログインになるんだね。

Orange Pi Zero LTS届いた

GPIOの実験に使おうとしてるOrange Pi Zero LTS届いた。

SPIフラッシュは印字の上にインクか何か付着してるようでよく見えないんだが、MX25L1606Eぽい。
2MBフラッシュじゃLinux入らないので交換を考えて16MBフラッシュも買ってあるが、周辺回路近すぎて厳しいw

Orange Pi R1との差異は、
wifi(SDIO)のチップが違う。
R1はUSBイーサネットがある。
SPIフラッシュが違う。
の3点かな。

Linuxのドライバは、
SPIフラッシュは特定チップ用のドライバは不要。
USBイーサネットのドライバはあってもZeroで問題ない。
wifiのドライバは両機種ともモジュール。
なので、カーネル自体は同じでXR819のモジュールを用意すれば良さそう。
あとはdtbsがちょっと違う。

工人舎SXにAtheros AR9285つけてみた

工人舎SXのwifiは、裏蓋から取り外せる位置にVIA VNT6656ってカードがついてるが不安定で頻繁に切断する。
ググるとこのデバイスかなりひどいらしい。(SXはUSBデバイス内蔵しすぎだし電圧不安定だったりするのかもしれんが)
形状はmini PCIeだがUSBデバイスなんでPCIeデバイスが利用可能なスロットかわからんかったが、ハーフサイズだがAcer aspire oneについてたカードをくっつけてみた。
ハーフサイズをフルサイズにするブラケットとか持ってないんで固定せずそのままw

そしたら認識した。
Atheros AR9285ってpcieのデバイスだった。
なので、SXの裏蓋から着脱できるmini PCIeスロットはUSBでもpcieでもOKだね。

とりあえず、セロテープで固定しといた。
しばらくAR9285使ってみる。