shigeの備忘録

日々の生活の備忘録です

Verilog-HDL SystemVerilogの作法勉強

ステッピングモーターを制御するsvコードを例にhdlの作法を勉強

Interface誌2022年12月号別冊付録「2500円ボードで始めるFPGA開発」の応用編
その2のコードを例にverilogのお作法を勉強。備忘録。

default nettypeでエラー防止

`default_nettype none


default_nettype none:
コード内で明示的にデータ型(wire や logic など)が宣言されていないネット(信号線)が存在 する場合に、エラーを発生させるようにするディレクティブ。
これにより、意図しない暗黙的なネットの生成を防ぎ、設計の意図を明確にすることができる。
他にも「default_nettype wire:」という宣言でm、明示的にデータ型が宣言されていないネットを
デフォルトでwire 型として扱うようにするディレクティブを比較的使う。


モジュールと#を使ったインスタンス

module top #(
  // Millisecond per step
  parameter MS_PER_STEP = 100
) (
  input  wire  clk,
  output logic phase_a,
  output logic phase_b
);

  // Timer
  logic overflow;
  timer #(MS_PER_STEP * 27000) timer_i (.*);

「#」はモジュールのパラメータ値を上書き(またはインスタンス化)するために使用される記号。
topの例では、モジュールのインスタンス化とパラメータの上書きを行っている。
top モジュール内で timer モジュールを timer_instance という名前でインスタンス化している。
timer #(MS_PER_STEP * 27000) の部分がパラメータの上書きを行っているところ。
「#(...)」 の括弧内には、上書きしたいパラメータの値を記述する。この例では、timer モジュールの
COUNT_MAX パラメータに対し、top モジュールで定義された (MS_PER_STEP と*27000)に再設定
パラメータ名は省略、定義順に値を指定できるが、可読性の観点から名前を指定する方法 が推奨。

//元のコードの省略したインスタンス化部分
timer #(MS_PER_STEP * 27000) timer_i (
    .clk(clk),
    .overflow(overflow)
  );

//推奨されるパラメータ名を明示的に指定した記述
timer #(
    .COUNT_MAX(MS_PER_STEP * 27000)
  ) timer_i (
    .clk(clk),
    .overflow(overflow)
  );


「(.*)」はポート接続の簡略記法で、timer モジュールと top モジュールの間で、同じ名前のポートを
自動的に接続。この場合、clk と overflow ポートが接続される。

//簡略化記法
  timer #(MS_PER_STEP * 27000) timer_i (.*);
// 簡略化していない記法
  timer #(MS_PER_STEP * 27000) timer_i (.clk(clk), .overflow(overflow));

timer #(MS_PER_STEP * 27000) timer_i ( は、timer モジュールを timer_i という名前でインスタンス化 し、その際に timer モジュールで定義されている COUNT_MAX 値を MS_PER_STEP * 27000 に再設定
(オーバーライド)
これにより、同じ timer モジュールを異なるパラメータ値で複数回インスタンス化し、それぞれ異 なる動作が可能。これは、再利用性の高い設計を実現するための重要な機能の一つ!

「#」はParameter Override Association List、またはParameter Override と呼ばれる。
文脈によっては、単に「ハッシュ記号」や「シャープ記号」と呼ばれることもある
パラメータ・オーバーライド。なんかかっこいい。

always_ff(順序回路)

  // Phase counter
  logic [1:0] phase_counter = 'd0;
  always_ff @ (posedge clk) begin
    if (overflow) begin
      phase_counter <= phase_counter + 'd1;
    end
  end


always_ff @ (posedge clk) begin ... end:  (posedge clk) で動作する順序回路(フリップフロップ
if (overflow) begin ... end: タイマーモジュールからの overflow 信号がHighになったとき、
つまり指定されたステップ間隔が経過したときに、内部の処理を実行
「<= 」はノンブロッキング代入と呼ばれ、クロックの立ち上がりエッジですべての ノンブロッキング代入が同時に実行されることを意味する。
順序回路は基本的にノンブロッキング代入を使う

always_comb(組み合わせ)回路

  // Phase output
  always_comb begin
    case (phase_counter)
      0: begin phase_a = 'b1; phase_b = 'b1; end
      1: begin phase_a = 'b0; phase_b = 'b1; end
      2: begin phase_a = 'b0; phase_b = 'b0; end
      3: begin phase_a = 'b1; phase_b = 'b0; end
    endcase
  end

endmodule


always_comb begin ... end: 入力信号の変化に即座に応答する組み合わせ回路を定義。
always_comb ブロック内のステートメントは、そのブロック内で参照されている入力信号 の値が変化すると、即座に再評価され、出力信号が更新されるべきであることを示す。
これは、現実世界の組み合わせ回路の動作(入力が変われば遅延なく出力も変わる)
をモデル化している。以下の特徴がある。
■イベント駆動ではない
always_ff のように特定のクロックエッジなどのイベントに
同期して動作するのではなく、入力信号の変化に敏感に反応。
■非ブロッキング代入 (<=) は推奨されない:
always_comb ブロック内では、通常ブロッキング代入 (=) を使用。これは、組み合わせ論
では信号の順序が重要ではなく、右辺の最新の値が即座に左辺に反映されるべきであるため。
ブロッキング代入 (<=) は、クロック同期された順序回路 (always_ff) で、同じクロックエッジ
での複数の代入を同時に行うために使用される。always_comb で非ブロッキング代入を使用すると
意図しない遅延や競合状態が発生する可能性がある。
■自動的な感性リスト(sensitivity list)
SystemVerilog では、always_comb ブロックは自動的な感性リストを持つ。つまりブロック内で
読み取られているすべての入力信号が、暗黙的に感性リストに追加される。
これにより、感性リストの記述ミスによるシミュレーションと合成の不一致を防ぐことができる。
Verilog HDL (Verilog-2001以降) でも同様の機能を持つシミュレータが多い


$clog2() システム関数

module timer #(
  parameter COUNT_MAX = 27000000
) (
  input  wire  clk,
  output logic overflow
);

  logic [$clog2(COUNT_MAX+1)-1:0] counter = 'd0;

  always_ff @ (posedge clk) begin
    if (counter == COUNT_MAX) begin
      counter  <= 'd0;
      overflow <= 'd1;
    end else begin
      counter  <= counter + 'd1;
      overflow <= 'd0;
    end
  end

endmodule

parameter COUNT_MAX = 27000000: COUNT_MAX という名前のパラメータを定義し、初期値を 27000000 に設定。これは、タイマーがオーバーフローするまでのカウント数を指定。
top モジュールで渡された 「MS_PER_STEP * 27000」 の値がここで使用される

logic [$clog2(COUNT_MAX+1)-1:0] は、クロックサイクルをカウントするために使用される。
COUNT_MAX を表現するために必要なビット数を自動的に計算する記述でlog2(n) の底が2の対数
を計算するシステム関数。これによりCOUNT_MAX の値が変わってもカウンタビットを調整できる。

verilog-HDL と SystemVerilogの差の部分

差は以下の4点※④は改定後のVerilog-HDLでも記述可能だが。
①logic データ型を wire および reg に置き換え: 出力ポートは reg 型として宣言し、always ブロック 内で値を代入.。wire は主にモジュール間の接続に使用。
②$clog2() システム関数を手動で計算する: カウンタのビット幅をパラメータで指定するように変更
③ポート接続の簡略記法 (.) を明示的な接続に置き換え
④always_comb 、always_ff を always @(
) に置き換え
 ※Verilog HDL (特に IEEE 1364-2001 以降) でも always_ff と always_comb は記述可能だが

//verilog-hdl
module top #(
  // Millisecond per step
  parameter MS_PER_STEP = 100,
  // Timer counter width (calculated based on COUNT_MAX)
  parameter TIMER_COUNT_WIDTH = 25 // Example: ceil(log2(MS_PER_STEP * 27000 + 1))
) (
  input  wire  clk,
  output reg phase_a,
  output reg phase_b
);
  // Timer
  wire overflow;
  timer #(MS_PER_STEP * 27000) timer_i (
    .clk(clk),
    .overflow(overflow)
  );
  // Phase counter
  reg [1:0] phase_counter = 2'd0;
  always @ (posedge clk) begin
    if (overflow) begin
      phase_counter <= phase_counter + 1'b1;
    end
  end

  // Phase output
  always @ (phase_counter) begin
    case (phase_counter)
      2'd0: begin phase_a = 1'b1; phase_b = 1'b1; end
      2'd1: begin phase_a = 1'b0; phase_b = 1'b1; end
      2'd2: begin phase_a = 1'b0; phase_b = 1'b0; end
      2'd3: begin phase_a = 1'b1; phase_b = 1'b0; end
      default: begin phase_a = 1'bx; phase_b = 1'bx; end // Avoid latch
    endcase
  end

endmodule
//SystemVerilog
module top #(
  // Millisecond per step
  parameter MS_PER_STEP = 100
) (
  input  wire  clk,
  output logic phase_a,
  output logic phase_b
);

  // Timer
  logic overflow;
  timer #(MS_PER_STEP * 27000) timer_i (.*);

  // Phase counter
  logic [1:0] phase_counter = 'd0;
  always_ff @ (posedge clk) begin
    if (overflow) begin
      phase_counter <= phase_counter + 'd1;
    end
  end

  // Phase output
  always_comb begin
    case (phase_counter)
      0: begin phase_a = 'b1; phase_b = 'b1; end
      1: begin phase_a = 'b0; phase_b = 'b1; end
      2: begin phase_a = 'b0; phase_b = 'b0; end
      3: begin phase_a = 'b1; phase_b = 'b0; end
    endcase
  end

endmodule
//verilog-hdl
module timer #(
  parameter COUNT_MAX = 27000000
) (
  input  wire  clk,
  output reg overflow
);

  reg [31:0] counter = 32'd0; // Increased width for safety

  always @ (posedge clk) begin
    if (counter == COUNT_MAX) begin
      counter  <= 32'd0;
      overflow <= 1'b1;
    end else begin
      counter  <= counter + 32'd1;
      overflow <= 1'b0;
    end
  end

endmodule
//SystemVerilog
module timer #(
  parameter COUNT_MAX = 27000000
) (
  input  wire  clk,
  output logic overflow
);

  logic [$clog2(COUNT_MAX+1)-1:0] counter = 'd0;

  always_ff @ (posedge clk) begin
    if (counter == COUNT_MAX) begin
      counter  <= 'd0;
      overflow <= 'd1;
    end else begin
      counter  <= counter + 'd1;
      overflow <= 'd0;
    end
  end

endmodule

GitHubでのバージョン管理 備忘録

 GitHubでのバージョン管理についてメモを残します。

 

 使用したコマンドは以下の通り。すべて覚えること。

    1.git init・・・ルートフォルダに.gitを作成し、Gitでの管理対象とする

    2.git add・・・GitHubにプッシュするファイルを選択する。

       全て上げる場合は [git add --all]

       例えば.pyのものだけプッシュしたい場合は[git add *.py]

    3.git reset・・・git addで追加したファイルを外す

  全て取り消す場合は [git reset ]

    4.git status・・・プッシュするファイルを確認する

    5.git commit -m "comment"・・・プッシュするファイルを紐づけする。-m ""はコメント。

    6.git log・・・紐づけした履歴を表示する

    7.git remote add origin https:GitHub...・・・GitHubにプッシュするリポジトリのURLを選択する

    8.git push origin ****(masterなど)・・・ 紐づけしたファイルを選択したリポジトリにアップロード(プッシュ)する

    9.git branch・・・リポジトリ内で、ブランチを作成する。現在のブランチを確認する。

10. git checkout ****・・・現在のブランチを移動する。

    

    

 

 

①Gitをインストール
Gitと同時に「Git Bash」もインストールされる。
・Git BashはcmdなどでGitの機能が使えるコマンドラインツール
・GitはGitHubと連携して、ソースコードをサーバ管理できるツール

 

GitHubのユーザー登録をする。
GitHubの「Create Repository」から「リモートリポジトリ」を作成する

 

③cmdにて管理したいソースコードのフォルダに移動する。
git init 
⇒.gitフォルダができる

 

④git addコマンドにてアップしたいファイルを選択する。
git add *.py などワイルドカードを使って選択することもできる
間違えて加えてしまった場合
git reset ./test2.md などで個別で戻す
またはgit resetで一括で戻す

addしたファイルは、git status で確認できる。

 

⑤アップしたいファイルが決まれば、git commit -mでコメントを残しつつコミットする
git commit -m "Ver1.0.0"
git log でコミット履歴がわかる

⑥git remote add originでリモートリポジトリに紐づけする
git remote add origin https://github.com/ShigeoYakuno/digital_yatai.git
git remote add origin と アップしたいリポジトリのURL+.git
この時点では、まだアップされない。紐づけされるだけ

 

GitHubにpushする
git push origin master

 

ちなみにリモート先とローカルのリポジトリが一致しなかった場合、

error: failed to push some refs to "URL"

が表示される。

 

個人開発などで、特に問題無い場合は簡単に下記で強制的にプッシュできる

git push --force origin master

 

■ブランチの操作

ブランチを作成する
⑧git branch Ver1.0.1
ブランチの確認
git branch
⇒*がついて緑色になる方が、現在のブランチ

⑨ブランチの移動
git checkout Ver1.0.1

⇒再度git branchすると、作成したブランチに*がつき、緑色になっている。

 

⑩ブランチをプッシュする

git push origin Ver1.0.1

GitHubにブランチが作成される。

 

以上です。

 

 

 

 以下は、参考にしたサイトです。

https://www.kagoya.jp/howto/it-glossary/develop/howtousegithub/

https://codelikes.com/git-add/

https://qiita.com/toshi-toma/items/d0efe37edc38f399c6a5

 

raspberry pi IoT rcloneとGoogle Cloudを使用して、Google Drive上にセンサデータをアップする方法  その② rclone紐づけ偏

①からの続きです。

 

Google Cloudアカウントなどを作ったPCにrcloneをダウンロードします。

Rclone downloads

 

任意のフォルダに解凍します。

ここではd:rcloneとします。

cmdより、同じフォルダに移動して、

rclone authorize "drive" "Client_ID" "Client_secret"と入力します。

IDとsecretは①で取得した値を使用します。

 

途中でブラウザが立ち上がり、アカウント認証が完了すれば、下記のように

Success!と表示されます。

①で記載しましたが、テストユーザーを一人も追加しない場合は、認証が拒否

されますので、注意が必要です。

cmdのほうにaccess tokenが表示されます。このtokenのためにPCにrcloneを入れました。これより先の作業ではPCは不要です。

 

 

access tokenは

Paste the following into your remote machine --->

<---End paste

の間の3行をコピーします。

 

 

いよいよraspberry piでの作業です。

 

インターネットに接続したラズパイより、LXターミナルで下記コマンドを実行します。

$ curl https://rclone.org/install.sh | sudo bash

少し時間がかかるかもしれませんが、インストールが完了すると思います。

その後

①rclone config 

 ⇒n にて新しい接続を作成します。

name は任意ですが、gdrive、googledriveなどにした方が無難でしょう。

 

②種類を選択するところ<strage>は、もちろんgoogle driveの番号を入れてください。

rcloneのバージョンによって番号が変わるようです。

 

③client_ID,crient_secretはその①で取得したIDを使用します。

④scopeは、特にセキュリティなど厳しくなければ「1」でよいでしょう

⑤service account pass は何も入力せず、enterで良いです

⑥edit advanced config はn

⑦use web browser automatically...も n

⑧config_token ここに先程PCで取得したaccess_tokenを入力します

⑨configure this as a shared drive  もn

⑩最後、remote接続し続けてOKか?みたいなところ y で終了

 

これでやっとrcloneとgoogle driveの紐づけが出来ました。

 

ためしにgoogle driveに何かフォルダを作成した状態で

「rclone lsd gdrive」 と入力し、フォルダが見れるか確認してください。

 

あとはラズパイのデータをgdriveに送りたい場合は、

rclone copy 送りたいファイルのパス gdrive:googledriveのフォルダ とすれば

送ることが出来ます。

 

                                以上

 

 

 

 

 

 

 

 

 

raspberry pi IoT rcloneとGoogle Cloudを使用して、Google Drive上にセンサデータをアップする方法  その① Google Cloud 登録偏

※RaspberryPi以外にアカウント作成や、rcloneとgoogleアカウントを紐づけ認証するためにインターネットに繋がるPC(rcloneをダウンロードすることになります)が1台必要です。

 

 

まずはRaspberryPi以外のPCでGoogle CloudでクライアントIDを作成します。

 

 

①赤枠部を押して、新しいプロジェクトを選択し、名前を入れて作成します。  

 

次にAPIとサービスから「ライブラリ」を選択します。

 

 

 

ライブラリの中から「Google Drive API」を選択し、「有効」にします。


 

次に「認証情報」より、「+認証情報を作成」を選択します。

 

OAuth同意画面が項目にありますので選択し、外部を選択し、作成します。

※OAuthとは、複数のWebサービスを連携して動作させるために使われる仕組みです

 

途中でメールアドレスを入力する箇所もありますが、google driveと紐づけしたい

アカウントのアドレスでかまいません。

 

再度認証情報の作成より、今度はOAuthクライアントIDの作成を選択します。

 

 

アプリケーションの種類は、「デスクトップアプリ」を選択します。


以上で、クライアントIDとクライアントシークレットの登録が出来ました。
この情報をrcloneに入力する必要があります。

 

またrcloneをgoogle cloudと紐づけする際、テストユーザーが一人も登録されていなければエラーになります。テストユーザーの登録を行います。こちらもgoogle driveと紐づけしたいアカウントのアドレスでかまいません。

 

 

  続く。。。

 

Raspberry Pi 無線でインターネット、有線でリモート接続を行う方法

Raspberry Piにモニターやキーボード、マウスを繋ぐと面倒なので

リモート接続を行うことはよくあると思います。

 

リモートアプリとしては

・XRDP

VNC

をよく使うと思います。

 

またインターネットに接続して、機能を追加することもよくあると思いますが、

何故かラズパイを、「インターネットに接続している無線LANに接続」しつつ、

プライベートIPにて「有線LANでPCとリモート接続」すると、インターネットに

繋がらないことがありました。

 

1つの解決方法として、eth0のdhcpcd.conf設定を変更することで両方が使えるように

なりましたので、備忘録として記載します。

 

インターネットへの接続が出来たかは、「ping google.com」でpingが返るかで判断

しました。

 

eth0のdhcpcd.confの設定を下記の通り変更しました。

static routers とstatic damain_name_servers の値を全て0にしています。

※設定変更後は再起動が必要です。

 

以上。

 

ラズパイで 複数のUARTを使用する

・まずはUARTを汎用通信ポートとして使用する に変更

 sudo raspi-config

            interface option

                   Serial Port  いいえ⇒はい⇒了解

         

                         

・どのUARTが有効なのかを確認する

 ls /dev  -l

   初期は

serial0 -> ttyS0

  で serial0には、ttyS0が割当たっていると思う。

 

 

・sudo nano /boot/config.txtの編集

 以下の3行を追加。

   

 uart4は、追加したいuartの番号とする。

 3つ使いたい場合は、さらに行を追加すればよい。

 uart2か4が良いみたい。3と5は癖がありそう。1は最初から有効。

 

 

RX23E セルフプログラミング 備忘録 CS+IDEの設定変更偏

RX23Eマイコンのセルフプログラムを実装しています。

はまったところを、備忘録として残します。

環境はCS+です。FITモジュールは使わず(参考程度)、自前で実装しています。

 

・アプリケーションノート R01AN2184JJ0510 Rev.5.10を参考に下記を追加

 

①メモリマップの変更

 RAMの任意の番地にRPFRAMを追加

 ROMの任意の番地にPFRAMを追加

②シンボルファイルの変更

 PFRAM=RPFRAMを追加。0~2は自分の環境では最初から入っていた。

 

以上です。

次はROMからRAMへコピーする箇所を残すつもりです。