Petalinux2018.3でキャラクタLCD制御(ST7032i) のバックアップの現在との差分(No.3)
更新- バックアップ一覧
- 差分 を表示
- ソース を表示
- バックアップ を表示
- 電気回路/zynq/Petalinux2018.3でキャラクタLCD制御(ST7032i) へ行く。
- 追加された行はこの色です。
- 削除された行はこの色です。
[[電気回路/zynq/Petalinux2018.3環境を整える]] [[電気回路/zynq]] * I2C 経由で繋いだキャラクタ型の液晶ディスプレイ(LCD)を制御する [#b227347f] 繋いだのはこれ [[digikey:NHD-C0216CIZ-FSW-FBW-3V3-ND]] 16 文字 x 2 行 で白色バックライト付きの LCD 付属の PDF だけだといろいろ情報が足りなくて困るのだけれど、 どうやらこの LCD には ST7032i という有名なコントローラが載っているらしいので、 このキーワードで検索すればいろいろと情報が得られる。 どうやらこの LCD には [[Strawberry Linux の ST7032i>https://strawberry-linux.com/pub/ST7032i.pdf]] という有名なコントローラが載っているらしいので、このキーワードで検索すればいろいろと情報が得られる。 ST7032i のマニュアル:~ https://strawberry-linux.com/pub/ST7032i.pdf ** 目次 [#v08453ec] #contents * 環境 [#h9cf1202] [[作業履歴>電気回路/zynq/Petalinux2018.3環境を整える#wa39ab55]] のように Petalinux 2018.3 を基本として作業しています。 [[作業履歴>電気回路/zynq#kc37dfd8]] のように Petalinux 2018.3 を基本として作業してます。 LCD は i2c-1 に繋がっているはず。 LCD は i2c-1 に繋いだ。Petalinux は i2c-1 を認識して dtb に反映してくれていた。 Petalinux は i2c-1 を認識して dtb に反映してくれています。 Zynq 機器で動作する Ubuntu 18.04LTC のコンソールで、 LANG:console $ less /boot/system.dts ... i2c1: i2c@e0005000 { compatible = "cdns,i2c-r1p10"; status = "disabled"; clocks = <&clkc 39>; interrupt-parent = <&intc>; interrupts = <0 48 4>; reg = <0xe0005000 0x1000>; #address-cells = <1>; #size-cells = <0>; }; ... $ sudo grep i2c /var/log/syslog Jan 28 15:58:20 zturn2018_3 kernel: i2c /dev entries driver Jan 28 15:58:20 zturn2018_3 kernel: cdns-i2c e0004000.i2c: 400 kHz mmio e0004000 irq 24 Jan 28 15:58:20 zturn2018_3 kernel: cdns-i2c e0005000.i2c: 400 kHz mmio e0005000 irq 25 $ ls -l /dev | grep i2c crw------- 1 root root 89, 0 1月 28 15:58 i2c-0 crw------- 1 root root 89, 1 1月 28 15:58 i2c-1 $ cat /proc/device-tree/amba/i2c@e0005000/status okay ちゃんと 400kHz クロックになっている。 ちゃんと 400kHz クロックになっており、status = "okay" なのでそのまま使える。 * まずはリセットピンを制御可能にする [#e9ee91d6] * リセットピンを制御可能にする [#e9ee91d6] ** axi_gpio の追加 [#cf1a998e] [[電気回路/zynq/Petalinux2018.3でaxi_gpio]] により、 /sys/class/gpio/gpio905/value 経由でリセットピンの上げ下げができるようになった。 CPU から axi_gpio 経由で制御する。 リセットは Active Low なので、使用時には上げておく必要がある。 vivado の Block Diagram に axi_gpio を置き、ダブルクリック。 GPIO Width に適当な値を入れる。 (ここでは LCD_RST ピン以外も制御したかったため5を入れた) LANG:console $ echo 905 > /sys/class/gpio/export $ echo out > /sys/class/gpio/gpio905/direction $ echo 0 > /sys/class/gpio/gpio905/value # reset $ echo 1 > /sys/class/gpio/gpio905/value # release reset &ref(axi_gpio-width.png,,33%); * LCD との通信 [#cdba4dc7] GPIO ポートの上で右クリック後 [Make External] する。 LCD のアドレスは 0x7c だそうだ(後で間違いであったことが発覚)。 &ref(axi_gpio-make_external.png,,50%); - int i2c = open("/dev/i2c-1", O_RDWR); - ioctl(i2c, I2C_SLAVE, 0x7c); - write(i2c, &bytes, length_of_bytes); - read(i2c, &buffer, length_to_receive); 追加された GPIO_1 ポートをクリックして、プロパティエディタで適当な名前に変更。 の組み合わせでやりとりすればいい・・・のかと思ったのだけれど、 &ref(axi_gpio-port-rename.png,,50%); https://www.kernel.org/doc/Documentation/i2c/dev-interface Diagram の右クリックから [Run Connection Automation] すると、 を見ると、 &ref(axi_gpio-connection.png,,33%); > Note that only a subset of the I2C and SMBus protocols can be achieved by the means of read() and write() calls. In particular, so-called combined transactions (mixing read and write messages in the same transaction) aren't supported. For this reason, this interface is almost never used by user-space programs. Processor System Reset および AXI Interconnect が追加され、接続が完了する。 などと書かれてた orz ** design_1_wrapper の編集 [#td6a4ab7] LCD の制御だけが目的の場合にはデータの読み出しを必要としないので、 まあそこそこ行ける・・・かな? design_1 は Dialog から生成されるのだけれど、 design_1_wrapper は手動で変更しなければならないらしい? 試してみる。 LANG:verilog module design_1_wrapper( ... //user define io, DATAPINS, ... ); inout [4:0] DATAPINS; .... // user wire define code wire [4:0] DATAPINS_i, DATAPINS_o, DATAPINS_t; ... //user logic example IOBUF DATAPINS_0_iobuf(.I(DATAPINS_o[0]),.IO(DATAPINS[0]),.O(DATAPINS_i[0]),.T(DATAPINS_t[0])); IOBUF DATAPINS_1_iobuf(.I(DATAPINS_o[1]),.IO(DATAPINS[1]),.O(DATAPINS_i[1]),.T(DATAPINS_t[1])); IOBUF DATAPINS_2_iobuf(.I(DATAPINS_o[2]),.IO(DATAPINS[2]),.O(DATAPINS_i[2]),.T(DATAPINS_t[2])); IOBUF DATAPINS_3_iobuf(.I(DATAPINS_o[3]),.IO(DATAPINS[3]),.O(DATAPINS_i[3]),.T(DATAPINS_t[3])); IOBUF DATAPINS_4_iobuf(.I(DATAPINS_o[4]),.IO(DATAPINS[4]),.O(DATAPINS_i[4]),.T(DATAPINS_t[4])); design_1 design_1_i( ... .DATAPINS_tri_i(DATAPINS_i), .DATAPINS_tri_o(DATAPINS_o), .DATAPINS_tri_t(DATAPINS_i), ... ); * ちょっとうまく行かないので調べ中 [#f00a2f54] ** ピン配置の指定 [#ie814751] まずはこれだけ。 xdc ファイルの中で PACKAGE_PIN を指定する。 LANG:c int i2c = open("/dev/i2c-1",O_RDWR); ioctl(i2c, I2C_SLAVE, 0x7c); write(i2c, "\x00\x38", 2); close(i2c); LANG:xdc set_property PACKAGE_PIN A20 [get_ports {DATAPINS[4]}] ;# IO_B35_LN[2] set_property IOSTANDARD LVCMOS33 [get_ports {DATAPINS[4]}] ;# IO_B35_LN[2] オシロスコープで見た信号は、 - コメントは # の前に ; を付けておかないとエラーになるらしい &tchart( @w_hold 5 @w_transient 1 SCL ~~~___|~~__|~~__|~~__|~~__|~~__|~~__|~~__|~~__|~~__|~~~~~ SDA ~~|___~~~~~~~~~~~~~~~~~~~~____________~~~~____|~~ DATA -=S=--=1=--=1=--=1=--=1=--=1=--=0=--=0=--=0=--=1=--=0=-=P=- HEX -----==========7=X==============C=XW===XNA===------- ); https://japan.xilinx.com/support/answers/51613.html のようになっていた。 ** vivado 上でビルド [#u89f9a56] 例えば http://www.picfun.com/c15.html を参考に波形を読み解くと、 vivado 上で Generate Block Design 後、Generate Bitstream する。 - SCL = 1 における SDA negedge がスタートコンディション (S) - 以降、SCL = 0 でのみ SDA の遷移が許される - SCL posedge にてデータの読み取り - 1バイト目は 7bit のスレーブアドレスに R/W フラグを付けたもの - 今の場合は (0x7C << 1) + (write ? 0 : 1) の write モードになる - スレーブが自分のアドレスを受け取ると、上のチャートで NA となっているところで SDA を 0 にする(Acknowledge)のだが、実測ではここが1になっているのでスレーブが反応していない状況だ - SCL = 1 における SDA posedge がストップコンディション (P) - ストップを送るためには SDA を一旦 0 にしなければならないので、直前にマスターが 0 を出している あれ? 思った通りの信号が出ているにもかかわらずスレーブが応答しない理由は・・・まさかアドレスが間違ってる?! [Synth 8-439] module 'design_1_processing_system7_0_0' not found ["(snip).srcs/sources_1/bd/design_1/synth/design_1.v":239] もう一度 LCD のマニュアルを見直すと、 のエラーが出た。 #ref(lcd-address.png,,50%,around); [Design Sources]-[design_1_wrapper]-[design_1_i] の上で右クリックから、 [Reset Output Products] してからビルドしたところうまくいった。 でかでかと Slave Address = 0x7C と書いておきながら、 サンプルコード等で実際に送っているアドレスは 0b0111110 = 0x3e だった orz &ref(design-reset-output.png,,50%); ** PL をプログラムする [#i092c854] すっかり騙されたよ。 (project).runs\impl_1\design_1_wrapper.bin を ~/lcd-control/design_1_wrapper.bin にコピー ioctl(i2c, I2C_SLAVE, 0x3e); にしたところ、うまく行き始めた。 * 操作プログラム [#k04ab626] こういうプログラムを作った。 lcd-control : https://github.com/osamutake/zynq-utils/tree/master/src/lcd-control マニュアルによれば、これを使って、 LANG:console $ cd ~/lcd-control $ sudo fpga-load design_1_wrapper.bin $ sudo lcd-control -c 0x38 $ sudo lcd-control -c 0x39 $ sudo lcd-control -c 0x14 0x78 0x5e 0x6d 0x0c 0x06 0x01 $ sudo lcd-control "Hello, world!" ** Device Tree の更新 [#tab2c783] で良いはずなのだけれど、実際には 上のようにして追加した axi_gpio は petalinux の作る system.dtb に現れるんだろうか? - コントラスト、というか、黒が強すぎる - 1行目の上半分が表示されない 試してみたいところだが、system.dtb のみをビルドする方法が分からない の不具合があった。 普通にやるなら hdf を petalinux へ持って行って、 もう一度 petalinux-configure してから petalinux-build だけど、 これをやると小一時間かかるのでいくらなんでも・・・ コントラストについては、0x5e となっていたところを 0x5d にすれば良くなった。 そこで、 https://okchan08.hateblo.jp/entry/2019/02/01/190000 を見ながら手動で設定してしまう。 1行目の上半分が表示されないのは、たまたま当たってしまった LCD の初期不良な可能性が高い。~ → LCD を指で押すと表示されない領域が増えたり減ったりする orz ということで、以下のようにして使えるようになった。 LANG:console $ cat << EOT > gpio1.dtso > // Device Tree File for gpio1 > /dts-v1/; > /plugin/; > / { > fragment@0 { > target-path = "/amba"; > __overlay__ { > #address-cells = <1>; > #size-cells = <1>; > axi_gpio_0: axi_gpio@41200000 { > #gpio-cells = <3>; > clock-names = "s_axi_aclk"; > clocks = <&clkc 15>; > compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a"; > gpio-controller ; > reg = <0x41200000 0x10000>; > xlnx,all-inputs = <0x0>; > xlnx,all-inputs-2 = <0x0>; > xlnx,all-outputs = <0x0>; > xlnx,all-outputs-2 = <0x0>; > xlnx,dout-default = <0x00000000>; > xlnx,dout-default-2 = <0x00000000>; > xlnx,gpio-width = <0x5>; > xlnx,gpio2-width = <0x0>; > xlnx,interrupt-present = <0x0>; > xlnx,is-dual = <0x0>; > xlnx,tri-default = <0xFFFFFFFF>; > xlnx,tri-default-2 = <0xFFFFFFFF>; > }; > }; > }; > }; > EOT $ ls /sys/kernel/config/device-tree/overlays/ $ sudo mkdir -p /sys/kernel/config/device-tree/overlays/gpio1 $ ls /sys/kernel/config/device-tree/overlays/gpio1 dtbo path status $ sudo dtc -o dtb gpio1.dtso -o /sys/kernel/config/device-tree/overlays/gpio1/dtbo $ ls /proc/device-tree/amba/axi_gpio@41200000/ '#gpio-cells' gpio-controller xlnx,all-inputs-2 xlnx,dout-default-2 xlnx,is-dual clock-names name xlnx,all-outputs xlnx,gpio-width xlnx,tri-default clocks reg xlnx,all-outputs-2 xlnx,gpio2-width xlnx,tri-default-2 compatible xlnx,all-inputs xlnx,dout-default xlnx,interrupt-present $ ls /dev/gpiochip1 /dev/gpiochip1 $ # 初期化 $ sudo lcd-control -c 0x38 $ sudo lcd-control -c 0x39 $ sudo lcd-control -c 0x14 0x78 0x5d 0x6d 0x0c 0x06 $ # 通常の使い方 $ sudo lcd-control -c 0x01 # 画面消去&ホームポジション $ sudo lcd-control -c 0xc0 # 2行目先頭へ移動 $ sudo lcd-control "Hello, world!" $ # IP アドレスを表示 $ sudo lcd-control -c 0x01 # 画面消去&ホームポジション $ sudo lcd-control -c 0xc0 # 2行目先頭へ移動 $ sudo lcd-control `ip a s eth0 | grep "inet " | sed -e "s/.*inet //" | sed -e "s/\/.*//"` /dev/gpiochip1 というデバイスができた。 元々この LCD は Ethernet 経由でデバイスを制御する目的で IP アドレスを表示するためのものだったので、さしあたりは 1行しか表示できなくてもまあなんとかなりそう。 https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841846/AXI+GPIO * LAN ケーブルの抜き差しに応じて表示を変更する [#x7edb681] に使い方がある。 eth0 が有効・無効になった直後に LCD 表示を更新する。 * LCD との通信 [#cdba4dc7] /usr/local/bin/lcd-show-ip LANG:sh #!/bin/sh test -e /sys/class/gpio/gpio905 || exit 1 # Deassert active-low reset echo out > /sys/class/gpio/gpio905/direction echo 0 > /sys/class/gpio/gpio905/value # reset echo 1 > /sys/class/gpio/gpio905/value # release reset lcd-control -c 0x38 lcd-control -c 0x39 lcd-control -c 0x14 0x7c 0x5d 0x6d 0x0c 0x06 0x01 lcd-control -c 0x01 # clear screen lcd-control -c 0xc0 # move to second line # show ip address ADDR=`ip a s eth0 | grep "inet " | sed -e "s/.*inet //" | sed -e "s/\/.*//"` if [ -z $ADDR ]; then lcd-control "NO ADDRESS" else lcd-control $ADDR fi LCD のアドレスは 0x7c だそうで、 を用意して、 $ mkdir lcd-control $ cd lcd-control $ git init $ jed lcd-control.c LANG:console $ sudo chown root:root /usr/local/bin/lcd-show-ip $ sudo ln -s /usr/local/bin/lcd-show-ip /usr/lib/networkd-dispatcher/routable.d/lcd-show-ip $ sudo ln -s /usr/local/bin/lcd-show-ip /usr/lib/networkd-dispatcher/no-carrier.d/lcd-show-ip としたところ、 - LAN ケーブルを抜くと NO ADDRESS を表示 - LAN ケーブルを挿すと dhcp で自動取得した IP アドレスを表示 を実現できた。 作業履歴へ戻る → [[電気回路/zynq]] * コメント・質問 [#d67302dc] #article_kcaptcha
Counter: 3311 (from 2010/06/03),
today: 3,
yesterday: 3