2021年10月19日火曜日

WSL : 端末 に GNOME-TERMINAL を 使用する

 目的:

WSL (Windows Subsystem for Linux) の端末として gnome-terninal を使用する。

概要:

X-Window 環境で gnomi-terminal を使用する。
gnomi-terminal を使用する事により、簡単に端末の色分け 等ができるようになる。
X-Window は  VcXsrv を使用する。
 ( Xサーバーをインストールする 参照 )

インストール手順:

  1. gnome-terminal のインストール
    • インストール
      sudo apt install gnome-terminal
      sudo apt install dbus-x11

    • 起動
      gnome-terminal
  2. ターミナルのカラースキームを gogh で設定
    • Goghの実行に必要なパッケージを以下でインストール
      sudo apt-get install dconf-cli uuid-runtime
       
    • Goghの実行
      gnome-terminal 上で、以下を実行
      bash -c  "$(wget -qO- https://git.io/vQgMr)"

      実行すると、カラースキームのリストが表示され、使用する カラースキームの番号 の入力待ちになる為、リストの左側の番号を入力する。
      (見本)
      gnome-terminal 上で 右クリックし、Profiles にカーソルを合わせると、入力したカラースキームが追加されている為、これを選択し、適用する。
      必要に応じ、メニューバーから 「Edit」-「Profile Preferences」で各種設定を行う。

      2021.11.09 追記
      新しいPC に WSL2 をインストールしたら、Gogh が動作しなかった。
      ( カラースキーム のリストが表示されずに終了 )
      git をインストールしたら、表示されるようになった。
      sudo apt-get install git-all

  3. 日本語入力をできるようにする。
    • 日本語化
      以下をインストール/実行
      sudo apt install locales locales-all
      sudo update-locale LANG=ja_JP.UTF-8

    • fcitx-mozcのインストール
      以下をインストール
      sudo apt install fcitx-mozc x11-xserver-utils

    • machine-idファイルの作成
      以下を実行
      sudo sh -c "dbus-uuidgen > /var/lib/dbus/machine-id"

    • 環境変数などを.profileファイルに設定
      .profile に以下を追記

      # set for fcitx ------------------
      export GTK_IM_MODULE=fcitx
      export QT_IM_MODULE=fcitx
      export XMODIFIERS=@im=fcitx
      export DefaultIMModule=fcitx
      if [ $SHLVL = 1 ] ; then
        (fcitx-autostart > /dev/null 2>&1 &)
        xset -r 49  > /dev/null 2>&1
      fi

    • 再起動
      WSL を再起動する。
      PowerShell を立ち上げ、 ディストリビューション名を確認。
      wsl -l
      WSL を再起動。(Debian の場合)
      wsl -t Debian

      再度端末を立ち上げ、gnome-terminal を立ち上げる。
      gnome-terminal実行時に、以下の様なワーニングが発生する場合、

      ** (gnome-terminal:54): WARNING **: Couldn't connect to accessibility bus: Failed to connect to socket /tmp/dbus-3BGGQVhj0i: 接続を拒否されました

      .bashrc に 以下を追記
      # disable to display dbind-WARNING
      export NO_AT_BRIDGE=1

    • 日本語入力設定
      以下を実行し、設定を確認/修正する。
      fcitx-config-gtk3
       ( 日本語入力切り替えのキー等を好みにより設定。)

    以上で、日本語入力が可能になる。
    また、gnome-terminal 等のメニュー等も日本語になっているはず。

  4. フォント追加
    Windows の フォントを gnome-terminal 等で 使用できる様にする。
    /etc/fonts に 以下の様な "local.conf" を作成する。
    sudo vim /etc/fonts/local.conf

    <local.conf>
    <?xml version="1.0"?>
    <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
    <fontconfig>
        <dir>/mnt/c/Windows/Fonts</dir>
    </fontconfig>

    作成後、
    fc-cache -fv
    を実行する。

    実行終了したら、
    fc-list | head
    で、Windows の フォントがあることを確認する。

    但し、この状態で gnome-terminal の プロファイルの設定 から、Windows の フォントを選択することができなかった。(ドロップダウンリストに入っていない)
    ... 色々試行錯誤しているうちに、選択できるようになっていた。
      WSL の再起動が必用 ?


2021年10月13日水曜日

verilog : Vivado GUI でのシミュレーション手順

目的:

 Vivado (GUI) での シミュレーション手順を記す。

手順:

  1. vivado 起動
  2. プロジェクトの作成
    1. Create Project  又は  File → Project → New を押下
    2. 「Create a New Vivado Project」 ウィンドウが開いたら Next 押下
    3. 「Project Name」 ウィンドウで Project 名 と 保存先 を入力して Next 押下
    4. 「Project Type」 ウィンドウで "RTL Project" を選択 して Next 押下
    5. 「AddSources」 ウィンドウでは そのまま Next 押下。
        (ソースは後で追加/作成)
    6. 「Add Constraints(optional) 」 ウィンドウでは そのまま Next 押下。
        (制約は後で作成)
    7. 「Default Part」 ウィンドウで 使用する FPGA を選択し、Next を押下。
    8. 「New Project Summary 」 ウィンドウで 内容を確認し、Finish を押下する。
  3. ソースコードの作成/追加
    1. Flow Navigator (左側) の  "PROJECT MANAGER" 内の Add Sources  をクリック
    2. 「Add Sources」ウィンドウで Add or create design sources を選択して Next を押下
      既にシミュレーション用のソースがある場合
      1. "Add Files" を押下
      2. 「Add Source File」 ウィンドウで RTL を選択し、OK を押下する。
      3. "Copy sources into project" 等、必要に応じてチェックし、Finish を押下する。
      新規にソースを作成する場合
      1. "Create Files" を押下
      2. 「Create Source File」ウィンドウで File name を 入力し、OK を押下
      3. Finish を押下
      4. 「Define Module」ウィンドウ で Module name, I/O ポートを入力し、OKを押下。(I/O ポートは、最低限(clk,rstのみ)で可。無しでも可。後でソース修正。)
  4. テストベンチの作成/追加
    1. Flow Navigator (左側) の  "PROJECT MANAGER" 内の Add Sources  をクリック
    2. Add Sources」ウィンドウで Add or create simulation sources を選択して Next を押下
      既にシミュレーション用のソースがある場合
      1. Add Files を押下
      2. 「Add Source File」 ウィンドウで RTL を選択し、OK を押下する。
      3. "Copy sources into project" 等、必要に応じてチェックし、Finish を押下する
      新規にソースを作成する場合
      1. "Create Files" を押下
      2. 「Create Source File」ウィンドウで File name を 入力し、OK を押下
      3. Finish を押下
      4. 「Define Module」ウィンドウ で Module name, I/O ポートを入力し、OKを押下。(I/O ポートは、最低限(clk,rstのみ)で可。無しでも可。後でソース修正。)
  5. 論理シミュレーション
    シミュレーションの実行
    1. シミュレーション実行
      Flow Navigator (左側) の  "SIMULATION" 内の Run Simulation  をクリックし、
      "Run Behavioral Simulaion" を選択
      • シミュレーションが規定時間分 実行される。( default 1000 nS )
        規定時間は、"Tools"-"Settings…" の 左側 "Simulation" を選択し、右側 "simulation"タブの
        "xsim.simulate.runtime" で 設定する。
      • コンパイル等でエラーが発生した場合、画面下方の 「Tcl Consoke 」を選択してエラー内容の確認/修正を行い、保存後、再度  "Run Behavioral Simulation" を実行する。
      • シミュレーションが実行されると、画面右側に波形が表示される。
        ( $finish()等で停止した場合は ソースコードが表示される。
        この場合、Untitled タブを選択すると 波形が表示される )
    2. 最後まで実行
      "Run All" (メニュバー "Run"  又は アイコン) で 最後まで シミュレーションを実行する。
    その他、シミュレーションについて
    • 表示波形の追加
      Scope ウィンドウで 表示したいモジュールを選択し、Objects ウィンドウで 信号を選択して ドラッグアンドドロップ で 波形ウィンドウに追加する。
      追加した信号の波形表示をする為には再度シミュレーションを実行する必要がある。
    • シミュレーション再実行
      "Restart " (メニュバー "Run"  又は アイコン) で シミュレーション結果をクリアし、
      "Run All" (メニュバー "Run"  又は アイコン) で 最後まで シミュレーションを実行する。
    • 波形表示信号の保存
      "Save Waveform Configuration" (アイコン) で 波形表示設定ファイルを保存する。
    • 再コンパイル
      ソースコードやテストベンチ修正して、再度コンパイルを実行する場合
      "Relaunch simulation " (メニュバー "Run"  又は アイコン) で コンパイルから再実行する。
    • シミュレーション結果がおかしい場合
      ソースコードを修正したり、ソースファイルを削除した後等に 削除したはずの信号が残っている等、結果がおかしい場合、
      "Settings" の 左側 "Simulation" を選択し、右側 "Advanded"タブの
      "Enable incremental compilation" のチェックを外し、再コンパイルしてみる。

2021年10月8日金曜日

verilog : Vivado ML (2021.1) で source が 開けない

現象:

Vivado ML (2021.1) で ソースコードを開こうとすると 動作が異常に遅くなる。

状況等:

ソースコードを開こうとすると、
"Initializing Language Server and Opening ……"
のウィンドウのまま 処理が進まない (以上に遅くなる)。
ソースコードが開いても、動作が異常の遅い。(ほとんど動かない)

原因:

Vivado 2021.1 の 問題らしい。
Xilinxのフォーラムに回避策が書いてあるとのこと。

回避策:

回避策1 : 下記のファイルを削除して Vivadoを起動する。

C:\ユーザー\<ユーザ名>\AppData\Roaming\Xilinx\Vivado\tclapp\mainfest.tcl
  → 試してみたが、Vivado 起動時に ファイルが生成され、改善できなかった

回避策2 : Vivado の 設定 変更。

以下の設定を変更する。
メニューバー の Tools から  "Settings" 選択。
開いたウィンドウの 左側 にある Tool Settings の Text Editor  を展開し、
"Syntax Checking"  を 選択。
右側の Syntax checking の ドロップダウンリストで Sigasi から Vivado に変更。
"OK" で 終了後、vivado を 終了し、再度立ち上げる。


上述の 回避策2 で 普通に動作するようになった。



2021年9月25日土曜日

raspberry pi : apt upgrade で エラー発生 ( Fatal Python error )

現象:

apt upgrade 実行時、Fatal Python error が発生し、upgrade できない。

原因:

不明。

対処 (暫定) :

OS 再インストール

経緯:

久しぶりに apt update, apt upgrade を行ったところ、apt upgrade で以下の様なエラーが発生。

 :
 :
取得:408 http://archive.raspberrypi.org/debian buster/main armhf vlc-plugin-visualization armhf 3.0.12-0+deb10u1+rpt2 [142 kB]
取得:409 http://archive.raspberrypi.org/debian buster/main armhf cups-pk-helper armhf 0.2.6-1+rpi1 [69.0 kB]
513 MB を 3分 18秒 で取得しました (2,593 kB/s)
Fatal Python error: initimport: can't import _frozen_importlib
ValueError: bad marshal data (unknown type code)

Current thread 0xb6faaad0 (most recent call first):
Aborted
E: 子プロセス /usr/bin/apt-listchanges --apt || test $? -lt 10 がエラーコード (1) を返しました
E: Failure running script /usr/bin/apt-listchanges --apt || test $? -lt 10
$

対処として、以下を行ったが、効果なし。

  1. .pycファイルを削除 --- 効果なし
    sudo find /usr -name '*.pyc' -delete
    で *.pyc を削除して apt upgrade を実施したが、効果なし
  2. python, python3 の再インストール --- 効果なし
    ソースコード を wget して、コンパイル/インストール したが、効果なし

 また、ufw status 等でも 同様のエラーが発生。
 1カ月程古い バックアップイメージ で 復元したが、現象変わらず。
 何かのファイルが壊れているのかもしれないが、原因不明で  upgrade, install ができず、このままにしておくわけにはいかない。
修復を諦め、最新の OS バージョンで再度インストールを実施した。

raspberry pi : FTPサーバーのインストール

 目的:

FTPサーバーをインストールして Windows等 からのファイルアクセスができるようにする。

手順:

以下の手順で vsftpd をインストールする。
  1. パッケージリストの更新、パッケージのアップデートを行う。
    sudo apt update
    sudo apt upgrade

  2. vsftpd のインストールを行う。
    sudo apt install vsftpd
     
  3. raspberry pi 起動時に vsftpd も立ち上げる様にする。
    sudo systemctl enable vsftpd

  4. /etc/vsftpd.conf を修正して ファイルの書き込みを許可する。
    sudo vi /etc/vsftpd.conf

    #write_enable=YES

    write_enable がコメントアウトされているので、#を消して有効にする。

ファイル転送:

 Windows PC 等 から、FTPクライアントソフト ( WinSCP 等 ) からアクセスし、ファイル転送できる事を確認する。


 

2021年9月11日土曜日

Windows : WSL (Debian) にVivado ML をインストールする。

目的:

WSL (Debian) に Vivado ML (スタンダード) を インストールする。

以前、Vivado  (2020.1) をインストールしたが、最新版(Vivado ML スタンダード) のインストールを行い、動作を確認する。

インストール手順:

今回は、GUI にて インストールできた。手順を以下に記す。
  1. インストーラをダウンロードする ( Windows )
    Xilinx のサイトから、「ザイリンクス統合インストーラー 2021.1: Linux 用自己解凍型ウェブ インストーラー (BIN - 301.28 MB) 」を 任意のディレクトリにダウンロードする。 (アカウントが必用。なければ、作成する)
  2. Xサーバーを起動 するWindows 上で Xサーバーを起動する。
  3. インストーラ を実行する
    必要に応じ、sudo apt update, sudo apt upgrade を実行しておく。
    WSL (Debian) の 端末から、インストーラを実行する。
     ダウンロードしたディレクトリ : D:\download\xilinx
     ダウンロードしたファイル名  : Xilinx_Unified_2021.1_0610_2318_Lin64.bin
    の場合、
     cd /mnt/d/download/xilinx
     ./Xilinx_Unified_2021.1_0610_2318_Lin64.bin
    を実行すると、インストーラのウィンドウが立ち上がる。
    1. Welcom の 画面 :
      next を押下
    2. Select Install Typw の画面 :
      E-mail Address, password を入力し、
      "Download and Install Now" が選択されていることを確認し、
      next を押下
    3. Select Product to Install の画面:
      vivad を選択し、next を押下
    4. Select Edition to Install の画面:
      Viado ML Standard を選択し、 next を押下
    5. Vivado ML Standard の画面:
      インストール内容を確認し、next を押下
    6.  Accept License Agreements
      全て(3か所) の "I Agree" にチェックを付け、next を押下
    7. Select Destination Directory の画面
      インストール先のディレクトリを指定する。
      各インストール先、ディスク容量等を確認し、next を押下
    8. Installation Summary の画面
      インストールの内容を確認し、Install を押下
    インストール終了まで待つ

Vivado の実行:

以下の様に、インストールディレクトリの settings64.sh を ソースし、vivado を実行する。( インストール先 : /tools/Xilinx, Ver 2021.1 の場合 )
 source /tools/Xilinx/Vivado/2020.1/settings64.sh
 vivado
vivado の実行で GUI の画面が立ち上がる。

コマンドラインで使用する場合も、2021.1 の settings64.sh を source した後に使用する。
以前のバージョン (2020.1) を使用する場合は、2020.1 の settings64.sh を source することで、以前のバージョンが使用できる。

普段使用するバージョンの settings64.sh を .bashrc に 記載しておくのが良いと思う。


 

2021年7月5日月曜日

Windows : LINE で ビデオ通話ができない

現象:

以前はできていた LINE の ビデオ通話 ができなくなった。

状況等:

ビデオ通話を行おうとしても開始されない。
設定を確認すると、カメラが 「接続されていません」となる。
( 左下の 「…」から 「設定」-「通話」を 確認 )
Windows の「カメラ」アプリからは カメラは動作する。
使用しているカメラは、ELECOM  UCAM-C310FBBK

2021.08.08 追記
バージョン v7.1.0 に上がったところ、カメラは認識するようになった。
が、ビデオ通話を開始しようとすると、1回(?)コールしたところで呼び出し中の画面が消え、通話できない。この為、依然、バージョンダウンして使用。

2021.09.12 追記

バージョン v7.2.0 に上がり、ビデオ通話 可能となった。

原因:

LINE バージョン v7.0.3 の問題と推定。
原因は不明であるが、最新バージョン (v7.0.3) では カメラを認識しない。

v.7.2.0 で 解消。

対処方法:

LINE を旧バージョンにダウングレードする。
 所在 :  https://line.jp.uptodown.com/windows/versions
 ダウンロードバージョン : 6.7.2.2497  ( line-6-7-2-2497.exe )
             6.7.1 Build 2490 ( line-6-7-1-build-2490.exe )

インストール後、自動で起動し、今すぐアップデートするか聞かれるが、今はしないにする。

尚、再起動等で LINE を立ち上げ直すと自動で アップデートしてしまう。
アップデートをしないようにする設定は無い模様。

この為、使用するたびに 旧バージョンの 再インストールが必用。


2021年5月5日水曜日

windows : Windows10 ネットワークドライブで接続できない_2

現象:

Windows10 から ネットワークドライブ (IOデータ "LAN DISK") にアクセスできないことがある。
SMB1.0 有効化, ゲストログオン の有効化は 実施済み。

PC の電源 ON や 再起動時で "LAN DISK" への接続ができなくなるが、いつの間にか 接続できるようになったり、再起動で接続できるようになったりする。
一度接続できるようになった後は、電源OFF や 再起動するまで接続できる。

以前は、再起動で接続できることが多かったが、最近、再起動でも接続できないことが多くなった。

原因:

不明。

対処方法:

"LAN DISK" は、Windows のドライブに割り当てて使用しているが、電源 ON で接続できないと色々不都合な為、取り敢えず、以下で対処した。

"LAN DISK" へは raspberry pi (LINUX) からは 安定して接続(マウント) できている。
この為、

  1. "LAN DISK" の 各フォルダを raspberry pi にマウント。
  2. マウントしたフォルダを raspberry pi の samba で共有設定。
  3. windows10 からは、raspberry pi にマウントしたフォルダをドライブに割り当てる。

2021.11.07 追記
Windows のアカウントを マイクロソフトアカウントにすると、安定してアクセスできるっぽい。
ローカルアカウントだと、Windows 立ち上げ後等、アクセスできないことが多いが、マイクロソフトアカウントに切り替えたら、今のところ、アクセスできないことがない。
(まだ、切り替えてから数日の為、またアクセスできなくなることがあるかもしれないが、、、)

2021年4月27日火曜日

Excel で OneDrive の サインイン ができない

 

 現象:

Excel (2019) で OneDrive のファイルを開いたところ、

「サインイン()してください。キャッシュされた資格情報の期限が切れているため、変更内容をアップロードまたはダウンロードできません。」

の表示が出て、表示右側の 「サインイン」ボタンを押下しても 再び同じメッセージが発生する。


対処方法:

今回は、以下の方法で対処を行った。

  1. Excel の 「ファイル」メニューを押下。
  2. 左下にある 「アカウント」 を押下。
  3. ユーザ名の下にある 「サインアウト」を押下。
    「このアカウントを削除すると...」 のダイアログボックスが表示される。
    「はい」を押下。
  4. Excel を終了し、PC を再起動。
  5. 再起動後に、Excel で One Drive のファイルを開く。
  6. サインインのダイアログボックスが表示されるため、サインインを行う。

以上の手順で、 以降、上述のメッセージは発生しなくなり、ファイルの保存もできるようになった。

 

尚、
タスクバーの OneDrive の雲のマーク ( 画面右下 ) を右クリックして 右下にある「ヘルプと設定」から 「設定」を開き、[Office]タブの「Office アプリケーションを使用して、開いている Office ファイルを同期する」のチェックを外す。

でも、 上述のメッセージは発生しなくなるとのこと。
( 同期 を 止めたら どのような影響があるかは 理解できてませんが、、 )


2021年1月28日木曜日

verilog : 擬似乱数生成

 目的: 

疑似乱数の生成方法、RTLについて記す。

仕様:

本疑似乱数生成は、
  1. 9bit LFSR (線形帰還シフトレジスタ) をベースに生成する。
  2. 出力は 9bit 疑似乱数で 0x001~0x1ff を出力。
  3. 開始パルスで初期値を設定し、イネーブル信号で疑似乱数を更新する。

疑似乱数生成方法:

9bit LFSR

9bit LFSRのブロック図を以下に示す。
これは、多項式 X^9+X^5+1 の ガロアLFSR(線形帰還シフトレジスタ) で、
2^9=512 通り の内、0 を除いた 511通りの値を周期的に変化する。
512番目の値が最初の値と同じになる。
これを書き換えると以下の様に書ける。

出力 Q[9:1] は、初期値を 0x1FF とすると、
 0x1FF, 0x1EF, 0x1E7, 0x1E3, 0x1E1, 0x1E0, 0x0F0, 0x078, 0x03C, 0x01E, ……
 (511) (495) (487) (483) (481) (480) (240) (120) (60)  (30)  

の様に変化し、512番目で 0x1FF に戻る。
このままでも 疑似乱数ではあるが、隣り合う値の多くのビットは 1bit シフトした値の為、似た様なビットパターンとなる。

疑似乱数の生成

上述の為、下図の様に ビットシフトとEOR 部分(LSF) を 9段重ね、ビットシフトが1周したデータ(9個置きの値)を取得する様にする。

出力 Q[9:1] は、初期値を 0x1FF とすると、
 0x1FF, 0x01E, 0x1C3, 0x1B9, 0x090, 0x099, 0x1A2, 0x1FC, 0x07B, ……
 (511) ( 30) (451) (441) (144) (153) (418) (508) (123)
の様に変化し、512番目で 0x1FF に戻る。
尚、この疑似乱数には 0 は含まれない。FF の出力が 0 となると、以降、FF出力は 0のまま変化しなくなる。

0を含んだ疑似乱数が必要な場合、1bit 削ることで0を含む疑似乱数を得ることができる。
例えば、8bit の 疑似乱数を取得する場合、上の出力 Q の 下位 8bit (Q[8:1]) を取り出す。
但し、この場合、511  データ中に 0 が 1回、1~255 が 2回づつ発生となり、0の発生回数が他よりも少ない。
或いは、外部回路で 適用な位置に '0' を挿入する必要がある。


ブロック図:

疑似乱数生成回路のブロック図を以下に示す。
本回路は、上述の疑似乱数生成回路に以下を追加したものとなる。
  1. 初期値(SEED値) を設定できるようにする。
  2. イネーブルを追加し、イネーブルが 'H' の期間のみ出力を更新する。

RTL:

上述のブロック図 2 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Pseudo-Random Number
//
//   Module Name : prn
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module prn (                            // Module name : prn
  CLR,                                  // port list
  CLK,
  seed,
  load,
  enable,
  prn
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [ 8:0] seed     ;
input              load     ;
input              enable   ;
output      [ 8:0] prn      ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire [9:1]  lsf0        ;
wire [9:1]  lsf1        ;
wire [9:1]  lsf2        ;
wire [9:1]  lsf3        ;
wire [9:1]  lsf4        ;
wire [9:1]  lsf5        ;
wire [9:1]  lsf6        ;
wire [9:1]  lsf7        ;
wire [9:1]  lsf8        ;

reg  [9:1]  Q           ;

// logical description -------------

assign lsf0 = {Q[1],Q[9:7],(Q[1]^Q[6]),Q[5:2]} ;
assign lsf1 = {lsf0[1],lsf0[9:7],(lsf0[1]^lsf0[6]),lsf0[5:2]} ;
assign lsf2 = {lsf1[1],lsf1[9:7],(lsf1[1]^lsf1[6]),lsf1[5:2]} ;
assign lsf3 = {lsf2[1],lsf2[9:7],(lsf2[1]^lsf2[6]),lsf2[5:2]} ;
assign lsf4 = {lsf3[1],lsf3[9:7],(lsf3[1]^lsf3[6]),lsf3[5:2]} ;
assign lsf5 = {lsf4[1],lsf4[9:7],(lsf4[1]^lsf4[6]),lsf4[5:2]} ;
assign lsf6 = {lsf5[1],lsf5[9:7],(lsf5[1]^lsf5[6]),lsf5[5:2]} ;
assign lsf7 = {lsf6[1],lsf6[9:7],(lsf6[1]^lsf6[6]),lsf6[5:2]} ;
assign lsf8 = {lsf7[1],lsf7[9:7],(lsf7[1]^lsf7[6]),lsf7[5:2]} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    Q <= #P_DLY 9'h1ff  ;
  else if (load)
    Q <= #P_DLY seed ;
  else if (enable)
    Q <= #P_DLY lsf8 ;

assign prn = Q[9:1] ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。


2021年1月10日日曜日

verilog : 除算器2( 商を 固定小数点化 )

目的: 

商を固定小数点とした除算器の構成、RTLについて記す。

仕様:

本除算器は、
  1. 演算は 16bit ÷ 16bit の符号なし整数の除算で、出力は 32bit 固定小数点(u16.16) の商
  2. 複数クロックを使用して演算を行う。
  3. 開始パルスで演算を開始し、演算終了で終了信号を出力する。

除算方法:

除算器 と同様。
違いは、
  1. 商の bit幅を 32bit に拡張 (整数部 16bit, 小数部 16bit の 固定小数点 )
  2. 繰り返し回数を 32回に増加 (商が 32bit の為)
  3. 剰余は削除
のみ。

ブロック図:

除算器のブロック図を以下に示す。

RTL:

上述のブロック図 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Divider 
//
//   Module Name : divid
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module divid (                          // Module name : divid
  CLR,                                  // port list
  CLK,
  a,
  b,
  start,
  division,
  complete
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [15:0] a        ;
input       [15:0] b        ;
input              start    ;
output reg  [31:0] division   ;
output reg         complete ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire        op_cnt_en   ;
wire        borrow      ;
wire [17:0] sub         ;
wire        div_en      ;

reg   [5:0] op_cnt      ;
reg  [32:0] div_ref     ;
reg  [31:0] div_val     ;

// logical description -------------

assign op_cnt_en = (op_cnt < 6'd32) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    op_cnt <= #P_DLY 6'd63 ;
  else if (start)
    op_cnt <= #P_DLY 6'd0 ;
  else if (op_cnt_en)
    op_cnt <= #P_DLY op_cnt + 6'd1 ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_ref <= #P_DLY 32'd0 ;
  else if (start)
    div_ref <= #P_DLY {16'b0,a} ;
  else if (~borrow & div_en)
    div_ref <= #P_DLY {sub[15:0],div_ref[14:0],1'b0} ;
  else if (div_en)
    div_ref <= #P_DLY div_ref << 1 ;

assign sub = {1'b0,div_ref[31:15]} - {2'b0,b} ;
assign borrow = sub[17] ;

assign div_en = (op_cnt <= 6'd31) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_val <= #P_DLY 32'd0 ;
  else if (start)
    div_val <= #P_DLY 32'd0 ;
  else if (div_en)
    div_val <= #P_DLY {div_val[30:0],~borrow} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    complete <= #P_DLY 1'b0 ;
  else 
    complete <= #P_DLY (op_cnt == 6'd32) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    division <= #P_DLY 32'd0 ;
  else 
    division <= #P_DLY div_val ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。

除算結果(商) は 整数部 16bit, 少数部 16bit の為、1/2^16 = 0.00001526 の誤差がある。
255/1023 の シミュレーション結果は 0.249252 で 計算値 0.249266862 とは
0.000014862 の差があるが、これは誤差範囲内。



2021年1月6日水曜日

verilog : 除算器

目的: 

除算器の構成、RTLについて記す。

仕様:

本除算器は、
  1. 演算は 16bit ÷ 16bit の符号なし整数 の 除算で、出力は 商と剰余 各16bit
  2. 複数クロックを使用して演算を行う。
  3. 開始パルスで演算を開始し、演算終了で終了信号を出力する。

除算方法:

除算は、回復法により行う。
除算の方法を下図に示す。
除算の手順は、
  1. 被除数の上位に除数のbit数分の 0 拡張を、除数に 1bit の 0拡張を行う。
  2. 被除数の上位bit から 除数 を減算する。
  3. 減算できる場合 (ボローが発生しない場合) は、減算した結果で被除数の上位bit を置き換えて 1bit 左シフトし、減算できない場合(ボローが発生した場合) は 被除数の上位 bit の置き換えは行わずに 1bit 左シフトを行う。
  4. また、商(初期値 0) を 1bit 左シフトし、最下位bit を ボローの反転値 とする。
  5. 2~5 を 被除数のbit数(拡張前) 分繰り返して商を得る。
  6. また、繰り返し終了後の被除数の拡張部分の値が 剰余となる。
被除数 3bit, 除数 3bit で 5÷2 を演算した場合の例を以下に示す。
被除数 3bit の為、3回繰り返して 商と剰余を得る。
右側に対応する 2進数での 割り算 の筆算 を示している。

ブロック図:

除算器のブロック図を以下に示す。

動作は、上述の除算方法の通り。

RTL:

上述のブロック図 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Divider 
//
//   Module Name : divid
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module divid (                          // Module name : divid
  CLR,                                  // port list
  CLK,
  a,
  b,
  start,
  division,
  remainder,
  complete
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [15:0] a        ;
input       [15:0] b        ;
input              start    ;
output reg  [15:0] division   ;
output reg  [15:0] remainder  ;
output reg         complete ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire        op_cnt_en   ;
wire        borrow      ;
wire [17:0] sub         ;
wire        div_en      ;

reg   [4:0] op_cnt      ;
reg  [32:0] div_ref     ;
reg  [15:0] div_val     ;

// logical description -------------

assign op_cnt_en = (op_cnt < 6'd16) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    op_cnt <= #P_DLY 5'd31 ;
  else if (start)
    op_cnt <= #P_DLY 5'd0 ;
  else if (op_cnt_en)
    op_cnt <= #P_DLY op_cnt + 5'd1 ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_ref <= #P_DLY 32'd0 ;
  else if (start)
    div_ref <= #P_DLY {16'b0,a} ;
  else if (~borrow & div_en)
    div_ref <= #P_DLY {sub[15:0],div_ref[14:0],1'b0} ;
  else if (div_en)
    div_ref <= #P_DLY div_ref << 1 ;

assign sub = {1'b0,div_ref[31:15]} - {2'b0,b} ;
assign borrow = sub[17] ;

assign div_en = (op_cnt <= 5'd15) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    div_val <= #P_DLY 16'd0 ;
  else if (start)
    div_val <= #P_DLY 16'd0 ;
  else if (div_en)
    div_val <= #P_DLY {div_val[14:0],~borrow} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    complete <= #P_DLY 1'b0 ;
  else 
    complete <= #P_DLY (op_cnt == 5'd16) ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    division <= #P_DLY 16'd0 ;
  else 
    division <= #P_DLY div_val ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    remainder <= #P_DLY 16'd0 ;
  else 
    remainder <= #P_DLY div_ref[31:16] ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。


2020年12月27日日曜日

verilog : 乗算器

 目的: 

乗算器の構成、RTLについて記す。

仕様:

本乗算器は、
  1. 演算は 16bit X 16bit の符号なしの乗算で、出力は 32bit
  2. 複数クロックを使用して演算を行い、回路規模、遅延時間の削減を図る。
  3. 開始パルスで演算を開始し、演算終了で終了信号を出力する。

ブロック図:

乗算器のブロック図を以下に示す。

ブロック図 1

16x16 乗算器_1

本回路の動作は以下の通り。
被乗数(a) に 乗数(b) を掛ける。
b の 各bit(桁) と a を掛けた(AND)結果(pd)を、各bit(桁)に応じてシフトし、1サイクル毎に加算していく。
op_cnt は pd を選択する為のカウンタで start 入力によりカウントを開始し、1サイクル毎に 加算する pd を選択する。
start から 乗数(b)のビット数分のカウントを行う間、加算のイネーブル(add_en)を生成して pd の加算を繰り返す。
乗数(b)のビット数分の加算が終了したら終了信号(complete) を出力する。

ブロック図 2

16x16 乗算器_2

本回路は、上のブロック図 1 の 回路規模削減を目指した修正版。
動作はブロック図 1と同様。
サイクル毎の選択は 乗数(b)のbit(桁) 選択を行い、選択後に 被定数(a)との乗算(AND) を行うことで AND 回路を 削減。
加算は乗算結果のbit数に1bitのbit拡張したbit数で行うことで 加算器の bit数を削減。
加算結果は 1bit シフトしながら FF に記憶していく。

RTL:

上述のブロック図 2 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//   16 x 16 bit Multiplier 
//
//   Module Name : mult_16
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module mult_16 (                        // Module name : mult_16
  CLR,                                  // port list
  CLK,
  a,
  b,
  start,
  result,
  complete
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [15:0] a        ;
input       [15:0] b        ;
input              start    ;
output reg  [31:0] result   ;
output             complete ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire        op_cnt_en   ;
wire        op_cnt_last ;
wire        pb          ;
wire [15:0] add_val     ;
wire [16:0] pval        ;

reg   [4:0] op_cnt      ;
reg         add_en      ;
 
// logical description -------------

assign op_cnt_en   = op_cnt <  5'd16 ; 
assign op_cnt_last = op_cnt == 5'd15 ; 

always @(posedge CLK or posedge CLR)
  if (CLR) 
    op_cnt  <= #P_DLY  5'h1f ;
  else if (start)
    op_cnt  <= #P_DLY  5'h0  ;
  else if (op_cnt_en)
    op_cnt  <= #P_DLY  op_cnt + 5'd1 ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    add_en <= #P_DLY 1'b0 ;
  else if (op_cnt_last)
    add_en <= #P_DLY 1'b0 ;
  else if (start)
    add_en <= #P_DLY 1'b1 ;

assign pb   = (op_cnt == 5'd0  ) ? b[0] :
              (op_cnt == 5'd1  ) ? b[1] : 
              (op_cnt == 5'd2  ) ? b[2] : 
              (op_cnt == 5'd3  ) ? b[3] : 
              (op_cnt == 5'd4  ) ? b[4] : 
              (op_cnt == 5'd5  ) ? b[5] : 
              (op_cnt == 5'd6  ) ? b[6] : 
              (op_cnt == 5'd7  ) ? b[7] : 
              (op_cnt == 5'd8  ) ? b[8] : 
              (op_cnt == 5'd9  ) ? b[9] : 
              (op_cnt == 5'd10 ) ? b[10]: 
              (op_cnt == 5'd11 ) ? b[11]: 
              (op_cnt == 5'd12 ) ? b[12]: 
              (op_cnt == 5'd13 ) ? b[13]: 
              (op_cnt == 5'd14 ) ? b[14]: 
              (op_cnt == 5'd15 ) ? b[15]: 1'bx ;

assign add_val = a & {16{pb}} ;

assign pval = {1'b0,result[31:16]} + {1'b0, add_val} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    result <= #P_DLY 32'h0 ;
  else if (start)
    result <= #P_DLY 32'h0 ;
  else if (add_en)
    result <= #P_DLY {pval,result[15:1]} ;

assign complete = op_cnt == 5'd16 ;


endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。




2020年12月9日水曜日

raspberry pi : WEB から LED 調光 ( php - C言語 間通信 )

 目的:

WEB画面から raspberry pi に 接続した LED の PWM制御による 調光 を行う。
php から Cプログラム へ メッセージキュー を使用したプロセス間通信を使用する。

環境/構成:

環境/構成は、 WEB から  LED ON/OFF と同じ。 
プロセス間通信については、WEB から  LED ON/OFF ( php - C言語 間通信 ) を参照。
PWM制御については、C言語で LED 調光 (PWM 制御) を参照。

phpファイル(WEB画面):

WEB画面は、ESP32/arduino:LED調光_スライダーで明るさを調整 と同じ画面。


以下に、phpファイル (HTML) を示す。

<?php
  $QKEY = 1111;
  $QUEUE = msg_get_queue($QKEY, 0666);

  session_start() ;
  if ($_SESSION['led_val'] == NULL ) $_SESSION['led_val'] = 0 ;
 
  if ($_GET['led_v'] != NULL) {
    $_SESSION['led_val'] = $_GET['led_v'] ;
    msg_send($QUEUE, "1111", "set_ledval " . $_SESSION['led_val'] . "\0" , FALSE) ;
    }

  if ($_GET['led_s'] != NULL) {
    $_SESSION['led_val'] = $_GET['led_v'] ;
    msg_send($QUEUE, "1111", "set_ledval " . $_SESSION['led_val'] . "\0" , FALSE) ;
    }

  if ($_GET['on'] == "ON") {
    $_SESSION['led_val'] = "255" ;
    msg_send($QUEUE, "1111", "led_on\0" , FALSE) ;
    }
  
  if ($_GET['off'] == "OFF") {
    $_SESSION['led_val'] = "0" ;
    msg_send($QUEUE, "1111", "led_off\0" , FALSE) ;
    }

  $led_brightness = $_SESSION['led_val'] ;
?>

<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>
<style>input.button  {margin:8px;width:100px;}
       input.button2 {margin-left:8px; width:40px;}
       input.text    {margin-left:8px; width:25px;}
       input.slid    {width:230px;}
       div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
       </style>
<title>Color LED Controller</title></head>

<body>
<div><p>LED ON/OFF</p>
  <form method='get' style='text-align:left' >
    <span style='padding-left:15pt; font-size:8pt ;text-align:left'> LED brightness (0-255)</span>
    <input class='text'  type='text' name='led_v' id='led_v' value=<?=$led_brightness?> >
    <input class='button2' type='submit' name='set' value='SET'>
  </form>

  <form name='slidform' method='get' style='text-align:left'>
    <input class='slid' type='range' name='led_s' value=<?=$led_brightness?> min='0' max='255' step='1' onchange='setval(this.value)' oninput='setval(this.value)' >
  </form> 

  <form method='get'>
    <input class='button' type='submit' name='on' value='ON'><input class='button' type='submit' name='off' value='OFF'><br>
  </form>

  </div>


<script>
function setval(ledval){
  var xhr = new XMLHttpRequest();
  xhr.open('get', 'pwm_resp.php?slid='+ledval );
  xhr.timeout = 1000 ;
  xhr.setRequestHeader('Cache-Control', 'no-cache');
  xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
  xhr.responseType = 'document' ;

  xhr.onreadystatechange = function() {
      if( (xhr.readyState == 4) && (xhr.status == 200) ) {
          document.getElementById('led_v').value = xhr.response.getElementById('output1').innerHTML;
      }
  }
  xhr.ontimeout = function(e) {
      xhr.abort() ;
  }
  xhr.send();
}

</script>
</body>
</html>

<?php 
  $led_brightness = $_GET['slid'] ;
  $QKEY = 1111;
  $QUEUE = msg_get_queue($QKEY, 0666);

  msg_send($QUEUE, "1111", "set_slidval " . $led_brightness . "\0" , FALSE) ;
?>

<!DOCTYPE html><html lang='ja'>
  <head> <title>Color LED Controller</title></head>
  <body>

  <output id='output1'> <?=$led_brightness?> </output>

  </body> </html>

処理の流れ:

  • php 本体では、各 GET 要求を受けたとき、メッセージキューに LED 操作のコマンドを送信する。また、HTML 中の変数($led_brightness) に値を設定する。
  • HTML中の変数($led_brightness) は、php のショートタグ( <?=*** ?> ) を使用して値に置き換える。
  • スライダー操作時は、javascript で XHRを使用して 値を XHRレスポンス用 php に送信する。
  • XHR レスポンス用 php では、送信された値を受け、メッセージキューに LED 操作のコマンドを送信し、受信した値をそのままレスポンスとして返す。ここでは、HTML(テキスト) でレスポンスを返している。

各処理の内容については、上述の参照ページを参照。

Cプログラム(LED調光):

Cプログラムは、 WEB から  LED ON/OFF ( php - C言語 間通信 ) の LED ON, OFF を PWM制御 ( C言語で LED 調光 (PWM 制御) ) に置き換えたものとなる。
プログラムを以下に示す。
#include <wiringPi.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <termios.h>
#include <fcntl.h>

// *****************************************************************************
// * 定義等                                                                    *
// *****************************************************************************
// メッセージキュー 用 定義 ----------------------------------------------------
#define BUFFSIZE 256                             // バッファサイズ
#define QKEY     (key_t)1111                     // メッセージキューの key
                                                 //
struct msgbuf{                                   // メッセージの構造体
  long int type;                                 // type は long int であること。
  char data[BUFFSIZE];                           // 
};                                               //
                                                 //
// LED ON/OFF 用 定義 ----------------------------------------------------------
#define led_pin 12                               // LED を接続する GPIO #
                                                 //
// *****************************************************************************
// * キーイベントの取得                                                        *
// *****************************************************************************
                                                 //
int kbhit(void) {                                //
  struct termios oldt, newt;                     //
  int ch;                                        //
  int oldf;                                      //
                                                 //
  tcgetattr(STDIN_FILENO, &oldt);                //
  newt = oldt;                                   //
  newt.c_lflag &= ~(ICANON | ECHO);              //
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);       //
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);        //
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);  //
                                                 //
  ch = getchar();                                //
                                                 //
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);       //
  fcntl(STDIN_FILENO, F_SETFL, oldf);            //
                                                 //
  if (ch != EOF) {                               //
  ungetc(ch, stdin);                             //
  return 1;                                      //
  }                                              //
                                                 //
  return 0;                                      //
}                                                //
                                                 //
// *****************************************************************************
// * メイン 関数                                                               *
// *****************************************************************************
int main() {                                     //
  int msqid;                                     // メッセージキュー ID 
  struct msgbuf message;                         // メッセージ 
  long int read_type = 0 ;                       // リードするメッセージタイプ
  char c ;                                       // 1文字入力用
  char buf[128] ;                                // キーボード入力用のバッファ
  int  p_buf = 0 ;                               // 入力位置
  char *cmd ;                                    // コマンド用バッファ
  char *prm1 ;                                   // パラメータ1用バッファ
  int  val = 0 ;                                 // 設定値
                                                 //
  // メッセージキューの作成,取得 -----------------------------------------------
  //   誰でも読み書き可能なキューを作成して、ID を取得する                    --
  errno = 0;                                     //
  if( (                                          // 
        msqid = msgget(QKEY, 0666 | IPC_CREAT)   // 0666:アクセス許可パラメータ
      ) == -1 ) {                                //
    perror("msgget failure");                    //   作成失敗時の処理
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  // wiringpi の設定 -----------------------------------------------------------
  wiringPiSetupGpio() ;                          //
  pinMode (led_pin, PWM_OUTPUT) ;                //   LED 調光
  pwmSetMode(PWM_MODE_MS) ;                      // PWM モード設定
  pwmSetClock(40) ;                              // PWM 分周比設定(レンジ当たりのクロック数)
  pwmSetRange(255) ;                             // PWM 分解能設定(1周期当たりのレンジ数)
                                                 //
  // メッセージを受信して LED の ON/OFF を行う ---------------------------------
  while(1){
    errno = 0 ;                                  //
    if (!(msgrcv( msqid, &message, BUFFSIZE,     // メッセージの受信 
                 read_type, IPC_NOWAIT) == -1)   //
        )                                        //
    {                                            // メッセージ受信時の処理
      // メッセージをコマンドとパラメータに分割 -//
      cmd = strtok(message.data, " ") ;          // 最初の文字列(" "まで) をコマンド
      prm1 = strtok(NULL, " ") ;                 // 次の文字列を パラメータ1
      printf("command : %s %s\n",cmd,prm1);      // 表示
                                                 //
      if (strcmp(cmd,"led_on") == 0) {           //    LED ON
        pwmWrite(led_pin, 256) ;                 //    LED 調光値設定(ON : 256)
      }                                          //
      if (strcmp(cmd,"led_off") == 0) {          //    LED OFF
        pwmWrite(led_pin, 0  ) ;                 //    LED 調光値設定(OFF : 0)
      }                                          //
      if (strcmp(cmd,"set_ledval") == 0) {       //    LED 調光値設定
        val = atoi (prm1) ;                      //    パラメータ1 を数値に変換
        pwmWrite(led_pin, val) ;                 //    LED 調光値設定
      }                                          //
      if (strcmp(cmd,"set_slidval") == 0) {      //    LED スライダー値設定
        val = atoi (prm1) ;                      //    パラメータ1 を数値に変換
        pwmWrite(led_pin, val) ;                 //    LED 調光値設定
      }                                          //
    }else{                                       // 受信失敗時
      if (errno != ENOMSG) {                     //   メッセージ無し以外は終了
        printf("msgrcv : errno = %x\n",errno) ;  //
        break ;                                  //
       }                                         //
    }                                            //
    // キーイベントを取得し、入力文字列が "exit" ならループを終了する。----------
    if (kbhit()) {                               //
      c = getchar() ;                            //  入力された文字を表示
      printf("%c",c) ;                           //
      if ( c == '\n' ) {                         //  リターン入力時
        if ( strcmp(buf,"exit") == 0 ) {         //    "exit" を入力ならループ終了
          break ;                                //
        } else {                                 //    "exit" でなければ、先頭に戻る
          p_buf = 0 ;                            // 
          buf[p_buf] = '\0' ;                    //
        }                                        //
      } else {                                   //  リターンでなければ、
        if (p_buf == 255) p_buf = 0 ;            //    バッファサイズを超える時は先頭へ
        buf[p_buf] = c ;                         //    バッファに入力文字を追加
        buf[p_buf + 1] = '\0'  ;                 //
        p_buf++ ;                                //    入力位置を +1
      }                                          //
    }                                            //
  }                                              //
                                                 //
  // メッセージキューを削除して終了 ----------------------------------------------
  errno = 0;                                     //
  if(msgctl(msqid, IPC_RMID, NULL) == -1){       //
    perror("msgctl failure");                    //
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  exit(EXIT_SUCCESS);                            //
                                                 //
}                                                //
                                                 //
                                                 //

メッセージキューに送信されたコマンドに従い、LED の値 を設定する。
本プログラムを sudo 付きで実行し、WEB から 上述のphp(html) を開いて 操作すると、スライダーに応じて LED の明るさが変わる。
端末から "exit(rtn)" を入力すると プログラムは停止する。

2020年12月5日土曜日

raspberry pi : C言語で LED 調光 (PWM 制御)

目的:

C言語で PWMを使用した LED調光を行う。

環境/構成:

PWM は 2系統あり、それぞれ割り当てることができる GPIO  は

  • PWM Channel 0 : GPIO12、GPIO18
  • PWM Channel 1 : GPIO13、GPIO19

である。

環境/構成は、C言語で LED ON/OFF と同様であるが、LED 接続回路 は 下図の通り

PWM に設定できる GPIO 4本にLED を接続。


PWM制御:

 wiringpi を使用して PWM制御を行うには、
  1. wiringPiSetupGpio で wiringpi の初期設定を行う。
    (Gpio でなくても良いが、ここでは Gpio番号を使用する前提とする。)
  2. pinMode で PWM_OUTPUT を指定する。
  3. pwmSetMode で PWM のモード (バランス/マーク・スペース) を指定する。
  4. pwmSetClock で 1レンジ当たりのクロック数を設定する。
  5. pwmSetRange で 1周期のレンジ数 (分解能) を設定する。
  6. pwmWrite で パルス幅('H' のレンジ数) を設定する。

を行う。

pinMode の設定:

pinMode (GPIO番号, PWM_OUTPUT)
でpinMode を設定する。
これを実行すると、PWMが初期状態 (バランスモード) に戻ると思われる。
( 設定した GPIO番号(channel) と異なるGPIO番号(channel) にも影響 )
この為、PWMの設定(モード,クロック,レンジ)は pinMode を設定した後に行う必要がある。

PWM のモード

PWM のモードには バランスモード とマーク・スペースモードがある。
マーク・スペースモード
一定周期で パルスが発生し、パルス幅を変化させる。
pwmSetMode(PWM_MODE_MS)
バランスモード
デューティーが 50% に近づくほど 周期が短くなる。
pwmSetMode(PWM_MODE_BAL)
モードの設定は、channel 0,1 共通。

パルス周期、パルス幅の設定

パルス周期、パルス幅の設定は、pwmSetClock, pwmSetRange, pwmWrite で行う。
パランスモードの場合、デューティー 0 (100%) の場合の周期が設定値になる模様。
ベースのクロックは 19.2MHz。
pwmSetClock(clock)
1レンジ当たりのクロック数を設定する。
1レンジの長さは (1/19.2MHz)*クロック数 となる。
クロック数の設定は、channel 0,1 共通。
pwmSetRange(range)
1周期のレンジ数(PWM周期の分解能) を設定する。
PWMの周期は レンジ数 * クロック数 * (1/19.2MHz) となる。
PWMの周波数は 19.2MHz/(レンジ数 * クロック数) となる。
レンジ数の設定は、channel 0,1 共通。
pwmWrite(GPIO,width)
GPIO番号とパルス幅(レンジ数)を設定する。
パルス幅(時間)は パルス幅(レンジ数) * クロック数 * (1/19.2MHz) となる。

pwmSetClock(40)
pwmSetRange(256)
pwmWrite(12,128)
の場合、
周波数 : 19.2/(40*256) = 0.001875MHz
= 1.875KHz
デューティ 50%

プログラム例:

C言語での PWM を使用した LED の 調光 の例を示す。
引数として、GPIO番号とパルス幅(レンジ数) を指定する。
1レンジ当たりのクロック数は 40, 1周期のレンジ数 は 256 固定。
尚、GPIO番号のチェックは行っていない。

#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>

#define LED_PIN 12

int main (int argc, char *argv[])
{
  int pin_no = 0 ;
  int num = 0 ;

  if (argc == 1) {
    pin_no = LED_PIN ;
    num = 256 ;
  } else if (argc == 2) {
    pin_no = atoi(argv[1]) ;
    num = 256 ;
  } else {
    pin_no = atoi(argv[1]) ;
    num    = atoi(argv[2]) ;
  }

    printf("pin_no : %d\n",pin_no) ;
    printf("num    : %d\n",num) ;

  wiringPiSetupGpio() ;
  pinMode (pin_no, PWM_OUTPUT) ;
  pwmSetMode(PWM_MODE_MS) ;
  pwmSetClock(40) ;
  pwmSetRange(256) ;

  pwmWrite(pin_no , num) ;

  return 0 ;
}

コンパイル 及び 実行:

コンパイルは、
gcc -o led_on led_on.c -lwiringPi

実行は、
sudo ./led_on 12 128
の様に行う。(GPIO番号 12 を デューティー 50% (パルス幅 128) で点灯)

実行すると、設定した GPIO番号に接続した LED が 点灯する。
尚、GPIO 12 と 18,  13 と 19 は 同じ PWM Channel  の為、片方の LED の 明るさを変えると もう一方の LED の明るさも変わる。
例えば、
GPIO#12 を パルス幅 128 で 点灯した後、GPIO#18 を パルス幅 64 で点灯すると、GPIO#12 の LED も GPIO#18 と 同じ明るさに変わる。

本プログラムでは、実行毎に pinMode の設定から行っているため、既に点灯(調光)したGPIO があると、後から実行した時の pinMode 設定から PWM設定完了までの間、先に点灯した GPIO の設定が変わってしまう。(一瞬の為、見ていてもわからないが、、、)
通常は先に、使用するGPIOの設定を全て行ってから、pwmWrite で パルス幅の設定のみを行うべきかと思う。

また、このプログラムの実行は sudo を付けて実行する必要がある。
sudo を付けない場合、

pinMode PWM: Unable to do this when using /dev/gpiomem. Try sudo?

の様なメッセージが表示され、実行できない。
/dev/gpiomem のパーミッション は、

crw-rw---- 1 root gpio 246, 0 12月  3 04:10 /dev/gpiomem

の様になっているが、gpio に所属しているユーザでも上のメッセージが表示された。
sudo 無しで実行できるようにしたいが、どうすれば良いか 不明。



 

2020年11月29日日曜日

raspberry pi : WEB から LED ON/OFF ( php - C言語 間通信 )

 目的:

WEB画面から raspberry pi に 接続した LED の ON/OFF を行う。
php から Cプログラム へ メッセージキュー を使用したプロセス間通信を使用する。

環境/構成:

環境/構成は、 WEB から  LED ON/OFF と同じ。 

プロセス間通信:

プロセス間通信にはいろいろな種類があるが、ここではメッセージキューを使用した通信を行い、php から Cプログラムに LED ON/OFF の指示を行う。

php から のメッセージ送信

php からメッセージを送信するには、

  1. msg_get_queue (int $key , int $permissions)
    で、指定された key でメッセージキューの作成または接続を行い、IDを取得する。
    prtmissions : 0666 (default 値) 。
  2. msg_send(SysvMessageQueue $queue ,  int $message_type ,
    string|int|float|bool $message , bool $serialize )
    で、メッセージの送信を行う。
    queue : 1. で取得した ID
    message_type : メッセージのタイプ (0 より大きな任意の数値)
    message : 送信するメッセージの本体
    serialize : ここでは FALSE を指定。(default は TRUE)

c プログラムでのメッセージ受信

  1. msgget(key_t key, int msgflg);
    で、指定された key で メッセージキューの作成または接続を行い、IDを取得する。
    msgflg : 下位9bit は permission。作成を行う場合は IPC_CREAT を指定する。
  2. msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
    で、メッセージの受信を行う。
    msgid : 1. で取得した ID
    msgp : メッセージの構造体へのポインタ
    msgsz : メッセージ構造体の中の データの最大バイト数
    msgtyp : メッセージのタイプ。0 を指定した場合は キューの最初のメッセージが読み込まれる。
    msgflg : メッセージフラグ。IPC_NOWAIT を指定した場合、キューにメッセイー時が無い場合に直ちに帰る。(errno には ENOMSG が設定)

phpファイル:

以下に、phpファイル を示す。
ここでは、key に "1111" を指定する。後述の Cプログラムの key と同じにする。
"ON", "OFF" の ボタンが押下された時、led_on, led_off の文字列をメッセージ送信する。
message_type は "1111" を指定しているが、特に意味はない。
<?php
$QKEY = 1111;
$QUEUE = msg_get_queue($QKEY, 0666);

if ($_GET['on'] == "ON") 
  msg_send($QUEUE, "1111", "led_on\0" , FALSE) ;

if ($_GET['off'] == "OFF") 
  msg_send($QUEUE, "1111", "led_off\0" , FALSE) ;
?>

<!DOCTYPE html><html lang='ja'>
  <head><meta charset='UTF-8'>
    <style>
      input {margin:8px;width:100px;}
      div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
    </style>
  
    <title> Color LED Controller </title>
  </head>
  
  <body>
    <div>
      <p>LED CONTROL</p>
      <form method='get'>
        <input type='submit' name='on' value='ON' />
        <input type='submit' name='off' value='OFF' />
      </form>
    </div>
  </body>

</html>

 

Cプログラム:

Cプログラムでは、php からの メッセージを受信し、メッセージに応じて LED の 点灯/消灯を行う。
メッセージキューの key は php と 同じ "1111" を使用する。
メッセージ受信時の msgtyp (read_type) は '0' を指定し、メッセージタイプに関わらず、先頭から受信する。
while 文で メッセージ受信をループ処理するが、同時にキーボードを監視し、"exit(rtn)"をタイプしたらプログラムを終了するようにする。キーボード入力を メッセージ受信と並行して行うためにキーイベントの取得(kbhit) を行うが、このコードは こちらのコードを使用させて頂いた。
その他説明等、コード中のコメントを参照のこと。

#include <wiringPi.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <termios.h>
#include <fcntl.h>

// *****************************************************************************
// * 定義等                                                                    *
// *****************************************************************************
// メッセージキュー 用 定義 ----------------------------------------------------
#define BUFFSIZE 256                             // バッファサイズ
#define QKEY     (key_t)1111                     // メッセージキューの key
                                                 //
struct msgbuf{                                   // メッセージの構造体
  long int type;                                 // type は long int であること。
  char data[BUFFSIZE];                           // 
};                                               //
                                                 //
// LED ON/OFF 用 定義 ----------------------------------------------------------
#define led_pin 12                               // LED を接続する GPIO #
                                                 //
// *****************************************************************************
// * キーイベントの取得                                                        *
// *****************************************************************************
                                                 //
int kbhit(void) {                                //
  struct termios oldt, newt;                     //
  int ch;                                        //
  int oldf;                                      //
                                                 //
  tcgetattr(STDIN_FILENO, &oldt);                //
  newt = oldt;                                   //
  newt.c_lflag &= ~(ICANON | ECHO);              //
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);       //
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);        //
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);  //
                                                 //
  ch = getchar();                                //
                                                 //
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);       //
  fcntl(STDIN_FILENO, F_SETFL, oldf);            //
                                                 //
  if (ch != EOF) {                               //
  ungetc(ch, stdin);                             //
  return 1;                                      //
  }                                              //
                                                 //
  return 0;                                      //
}                                                //
                                                 //
// *****************************************************************************
// * メイン 関数                                                               *
// *****************************************************************************
int main() {                                     //
  int msqid;                                     // メッセージキュー ID 
  struct msgbuf message;                         // メッセージ 
  long int read_type = 0 ;                       // リードするメッセージタイプ
  char c ;                                       // 1文字入力用
  char buf[128] ;                                // キーボード入力用のバッファ
  int  p_buf = 0 ;                               // 入力位置
                                                 //
  // メッセージキューの作成,取得 -----------------------------------------------
  //   誰でも読み書き可能なキューを作成して、ID を取得する                    --
  errno = 0;                                     //
  if( (                                          // 
        msqid = msgget(QKEY, 0666 | IPC_CREAT)   // 0666:アクセス許可パラメータ
      ) == -1 ) {                                //
    perror("msgget failure");                    //   作成失敗時の処理
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  // wiringpi の設定 -----------------------------------------------------------
  wiringPiSetupGpio() ;                          //
  pinMode (led_pin, OUTPUT) ;                    //
                                                 //
  // メッセージを受信して LED の ON/OFF を行う ---------------------------------
  while(1){
    errno = 0 ;                                  //
    if (!(msgrcv( msqid, &message, BUFFSIZE,     // メッセージの受信 
                 read_type, IPC_NOWAIT) == -1)   //
        )                                        //
    {                                            // メッセージ受信時の処理
      fprintf(stdout,"received message:\t%s\n",message.data);
      if (strcmp(message.data,"led_on") == 0) {  //
        digitalWrite (led_pin, HIGH) ;           //   LED 点灯
      }                                          //
      if (strcmp(message.data,"led_off") == 0) { //
        digitalWrite (led_pin, LOW) ;            //   LED 消灯
      }                                          //
    }else{                                       // 受信失敗時
      if (errno != ENOMSG) {                     //   メッセージ無し以外は終了
        printf("msgrcv : errno = %x\n",errno) ;  //
        break ;                                  //
       }                                         //
    }                                            //
    // キーイベントを取得し、入力文字列が "exit" ならループを終了する。----------
    if (kbhit()) {                               //
      c = getchar() ;                            //  入力された文字を表示
      printf("%c",c) ;                           //
      if ( c == '\n' ) {                         //  リターン入力時
        if ( strcmp(buf,"exit") == 0 ) {         //    "exit" を入力ならループ終了
          break ;                                //
        } else {                                 //    "exit" でなければ、先頭に戻る
          p_buf = 0 ;                            // 
          buf[p_buf] = '\0' ;                    //
        }                                        //
      } else {                                   //  リターンでなければ、
        if (p_buf == 255) p_buf = 0 ;            //    バッファサイズを超える時は先頭へ
        buf[p_buf] = c ;                         //    バッファに入力文字を追加
        buf[p_buf + 1] = '\0'  ;                 //
        p_buf++ ;                                //    入力位置を +1
      }                                          //
    }                                            //
  }                                              //
                                                 //
  // メッセージキューを削除して終了 ----------------------------------------------
  errno = 0;                                     //
  if(msgctl(msqid, IPC_RMID, NULL) == -1){       //
    perror("msgctl failure");                    //
    exit(EXIT_FAILURE);                          //
  }                                              //
                                                 //
  exit(EXIT_SUCCESS);                            //
                                                 //
}                                                //
                                                 //
                                                 //

コンパイルは、
gcc -o ledctl  ledctl.c -lwiringPi

実行:

raspberry pi で ledctl を実行
./ledctl
し、ブラウザから、

http://"raspberry pi の アドレス"/"html のディレクトリ"/led_ctl.php

にアクセスする。(led_ctl.php は 上で格納した php ファイル)
以下の様な画面が表示される。


ON ボタン押下 で LED ON,
OFF ボタン押下で LED OFF 

する。
Cプログラムの終了は、"exit(rtn)" の入力で終了する。
尚、ctrl-C で終了した場合等、メッセージキューが残ったままになる。
コマンドラインがら、
ipcs
で メッセージキュー の状態が確認できる。
メッセージキューの削除は、
sudo ipcrm -q [msqid]
で行う。
 ( msqid は、ipcs コマンド で 確認できる )




2020年11月24日火曜日

raspberry pi : WEB から LED ON/OFF

目的:

WEB画面から raspberry pi に 接続した LED の ON/OFF を行う。

環境/構成:

WEB画面から ON/OFF を行うため、

  • WEBサーバー (apache2)
  • php

のインストールを行い、php から LED ON, LED OFF のプログラムを実行する。
LED ON, LED OFF のプログラム、LED接続回路は こちら を参照。

アプリケーションインストール:

  • WEBサーバー(apache2) のインストール
    sudo apt install apache2
    インストール完了で apache が 起動する。
    ブラウザから、http://"raspberry pi の アドレス" へアクセスすると、
    "Apache2 Debian Default Page" が表示される。
  • php のインストール
    sudo apt install php
    php -v で、php のバージョンが表示される。
    また、

    php -r "echo date('Y-m-d');" で、日付が表示される。

html ( .php) ファイルの設置:

/var/www/html の下 に html 格納用のディレクトリを作成し、以下の様な html (.php)を格納する。

<?php
if ($_GET['on'] == "ON") system('./led_on') ;
if ($_GET['off'] == "OFF") system('./led_off') ;
?>

<!DOCTYPE html><html lang='ja'>
  <head><meta charset='UTF-8'>
    <style>
      input {margin:8px;width:100px;}
      div   {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;}
    </style>

    <title> Color LED Controller </title>
  </head>

  <body>
    <div>
      <p>LED ON/OFF</p>
      <form method='get'>
        <input type='submit' name='on' value='ON' />
        <input type='submit' name='off' value='OFF' />
      </form>
    </div>
  </body>

</html>

この php では、ON ボタン の押下で ./led_on を、OFF ボタン の押下で ./led_off を実行する。

この為、php と同じディレクトリに led_on, led_off の実行ファイルを格納する。
 ( led_on, led_off の実行ファイルは こちら を参照。)
 

php 実行ユーザのグループ設定:

led_on, led_off の 実行は root で行うか、実行ユーザが gpio グループに所属している必要がある。
php の実行ユーザ ( apach2 の実行ユーザ ) は、www-data である為、 www-data に gpio グループを追加する。

sudo usermod -aG gpio www-data

www-data に 追加されたことを確認する。

groups www-data

追加されていれば、一度 raspberry pi をリブートする。

sudo reboot
 

WEB アクセスで LED ON/OFF 実行:

ブラウザから、

http://"raspberry pi の アドレス"/"html のディレクトリ"/led_ctl.php

にアクセスする。(led_ctl.php は 上で格納した php ファイル)
以下の様な画面が表示される。


ON ボタン押下 で LED ON,
OFF ボタン押下で LED OFF 

する。




2020年11月23日月曜日

raspberry pi : C言語で LED ON/OFF

 目的:

C言語で LED ON/OFF (GPIO アクセス) を 行う。

環境/構成:

本体 : raspberry pi 3B
OS : Raspberry Pi OS Lite
ライブラリ : wiringpi
インストールは、こちら を参照

LED 接続回路 : 下図の通り

LED に接続する抵抗は、
GPIO の最大電流は 16mA 。
LEDでの電圧降下分として 2V 程度とすると
R = V/I = (3.3-2)/(16^-3) = 81.25Ω
精度,誤差 等を考慮すると、
100 Ω 以上 が必用と思われる。

ここでは余裕を見て 1KΩ を使用。
(LED の仕様 (電圧降下や明るさ具合)の
 考慮が必用。
 仕様したLEDは470Ωでも結構明るかった)


プログラム:

C言語で LED の ON (GPIO 12 へ '1' ライト), OFF (GPIO 12 へ '0' ライト) を行う。
プログラムでは、

  •  include ファイル として、<wiringPi.h> が必用。
  •  初期設定として、wiringPiSetupGpio() を実行。
  •  GPIO ピンのモード設定として pinMode (GPIO番号, OUTPUT) ; を実行。
  •  GPIOへのライトは、 digitalWrite (GPIO番号, レベル (0/1) ) ; を実行。

を行う。

wiringPiSetupGpio() は、 Broadcom の GPIOピン番号で アクセスを行う場合に使用する。
代わりに wiringPiSetup() を使用すると、wiringpi 番号 (wiringpi の ピン番号)でアクセスを行う。ここでは、GPIOピン番号でアクセスするようにする。

LED ON と LED OFF の サンプルプログラムは、以下の通り。

#include <wiringPi.h>
#define led_pin 12

int main (void)
{
  wiringPiSetupGpio() ;
  pinMode (led_pin, OUTPUT) ;

  digitalWrite (led_pin, HIGH) ;

  return 0 ;
}
#include <wiringPi.h>
#define led_pin 12

int main (void)
{
  wiringPiSetupGpio() ;
  pinMode (led_pin, OUTPUT) ;

  digitalWrite (led_pin, LOW) ;

  return 0 ;
}

コンパイル:

コンパイル時、lオプションで wiringPiを指定する。

gcc -o led_on led_on.c -lwiringPi
gcc -o led_off led_off.c -lwiringPi

これで、led_on と led_off の実行ファイルができる。

実行:

wiringPiSetupGpio() は、root 権限が必用な為、コンパイルした実行ファイルを実行する場合は、sudo を付ける必用がある。
但し、gpio グループに所属していれば、sudo を付けなくても実行可能。この為、GPIOアクセスを行うユーザは gpio グループに所属していた方が便利。
尚、pi ユーザは、gpio グループに所属している。

./led_on
で LED が 点灯
./led_off
で LED が消灯
する。



blogger : 画像のアップロードができない

現象:

blogger の投稿画面で "画像を挿入" のアイコンをクリックして 「パソコンからアップロード」を選択すると、

 There was an error!

Details:
Invalid credential (invalid picker token)

の表示が出て 画像をアップロードできない。(firefox を使用)

対処方法:

goggle chrome を使用する。
 ( google chrome を使用したら 画像のアップロードができた )

その他:

firefox を再起動すれば エラーが出なくなるかもしれないが、取り敢えずは google chrome を起動して編集することで、アップロードした。
色々、firefox で開いている途中だったので。
 ( 追記 )
別の記事では画像のアップロードができた。(firefox の再起動とかは行っていない)
原因は不明で、一時的な現象だった模様。


 


raspberry pi : wiringpi を使う

 目的:

c言語 から raspberry pi の GPIO 制御を行う為、wiringpi をインストールする
 * wiringpi は 非推奨とのこと。 pigpio を使用した方が良い。
  ( pigpio 使用例 : 
C言語で LED 調光 (pigpio を使用した PWM 制御)  )

インストール:

C言語から GPIO アクセスを行うためには wireingpi を使用するのが楽の様なので、
以下の手順でインストールする。 

cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb

尚、
sudo apt install wiringpi
でもインストールできるが、現時点(2020/11/23) ではバージョンは 2.5.0 がインストールされ、このバージョンは raspberry pi 4 には 対応していない。

 コマンドライン操作:

wiringpi をインストールすると、コマンドラインから直接 GPIO アクセス可能となる。
以下に、主なコマンドを示す。

情報表示
gpio -v : バージョン表示
gpio readall : ピンの状態を表示

ピンモード設定
gpio [-g] mode <pin> out : <pin> を 出力(out)に設定
gpio [-g] mode in : <pin> を 入力(in)に設定
* -g を付加した場合、<pin> は GPIO番号。付加しない場合は wiringpi PIN番号

IO操作
gpio [-g] write <pin> 0 : <pin> に 0 ('L') を出力
gpio [-g] write <pin> 1 : <pin> に 1 ('H') を出力
gpio [-g] read <pin> : <pin> の 値を取得

その他のコマンドは、Wiringpi のページの "The GPIO Utility" を参照。

wiringpi PIN番号は、以下 (gpio readall 結果例) を参照。
wPi が wiringpi PIN番号。 BCM は GPIO番号。