Bug Keys (5)

bugkey10

今、6個の短点を送出しています。赤色のトレースは、短点の接点から得られた信号で、黄色のトレースは、FPGA内の簡単なデバウンス回路からのものです。

同じデバイスの中に、マークとスペースの長さを測定する回路を含ませることは容易です。

bugkey9

上の図に含まれる数値を読み取れば、あなたはRの短いスクリプトを書くことができます。

% R
> dat_v=c(1034, 883, 1028, 889, 1003, 923, 1053, 871, 1024, 901, 1048)
> barplot(dat_v, col=c("blue", "green"))

bugkey11

青色の棒はマーク(low)の長さに、緑色の棒はスペース(high)の長さに対応します。あなたは、マークとスペースとの比が1.0ではなく、さらなる調整が必要であることに、直ちに気が付きます。

バグキー (3)

bugkey6

現在のバウンスを除去する論理は完全からはほど遠いのですが、次のステップに進みましょう。

SignalTap IIを用いてキャプチャされた信号は、例えば、CSVファイルにエクスポートすることができます。従って、あなたはデータを種々の方法で加工することができます。

bugkey7

この波形は連続するドットの最初の8個(最後は不完全ですが)を示しています。

bugkey8

マークとスペースの長さがバーグラフとして表されています。1,000という値は、50mSに対応することに注意して下さい。

バグキー (2)

bugkey3

もし、あなたのバグキーをFPGAの入力ポートに繋ぐと、上の図に示したような信号を観測することができます。(図をクリックすると拡大されます。)

あなたは緑色の円で示したように、立ち上がり縁では必ずしもコンタクト・バウンスが無いことに気が付くでしょう。しかし、それを常に期待することは出来ません。また黄色の円で示したように、時々は比較的長時間のバウンスが起こることにも注意して下さい。

bugkey4

このようなバウンスを遅延をもたらすこと無く排除するために、簡単なロジックが用いられています。OUT_KEYという信号を見て下さい。

MAX 10のA/D変換器

adc12bitA

https://www.altera.com/en_US/pdfs/literature/hb/max-10/ug_m10_adc.pdf

内蔵の12-bit 1M sample/sec A/D変換器を用いて、私の4-bit D/A変換器の出力をデジタイズしています。

adc12bit

ディジタル化されたデータは、配列に格納され、printf文を用いて、JTAG UART経由で取得されます。

// Nios II - Prog/main.c
#define NDATA 1024
int data [ NDATA ];

for ( i= 0; i< NDATA; i++) {
    printf ( "%d ¥n", data [ i ] );
}

Small newlib C Library

smallClibrary2

あなたは、コードのフットプリントを小さくするために、small newlib libraryを使うことができますが、勿論、そこには困ったこともあります。

smallClibrary
https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/nios2/n2sw_nii5v2.pdf

なので、これらの入力ルーチンを使うときには注意をして下さい。

// Nios II - Prog/main.c
#include "sys/alt_stdio.h"

while (1) {
    c = alt_getchar();
    alt_putchar(c);

UART IPコア

uart

よく使われる機能を実現するには、IPコアを用いることができます。1つの例はUARTです。stdoutは、今ここにリダイレクトされています。

// Nios II - Prog/main.c
while(1) {
    printf("U3U"); // 0x55, 0x33, 0x55
    usleep(10000);

uart3

Qsys は、IP機能とサブシステムとを図面的に接続するためのシステム統合ツールです。

uart2

スタートビットが1個、8個のデータビット(LSBから)にパリティビットは無し、ストップビットが1個です。

uart4

MAX 10とNIOS II

neos

アルテラのNios IIは、32-bitのRISCアーキテクチャプロセッサのソフトコアで、MAX 10 FPGAに組み込むことができます。

短いCのプログラムを書いて、FPGAボード上のSDRAMチップのチェックをしています。

sdramcheck

FPGA CW Keyer (12)

dash4

短点と長点とのレシオは、通常の1:3から異ならせることも可能です。

parameter COUNT_DOT   = 32'h0010_0000;
parameter COUNT_DASH  = 32'h0040_0000;
parameter COUNT_SPACE = 32'h0010_0000;
//
if ( shift_reg [5] )
begin
    count_max <= COUNT_DASH;
    count     <= 32'h0000_0000;
    r_state   <=  4'b0001; // next state is DASH
end

このようにすれば、状態遷移もより単純になります。

shannon

図面は、シャノンの非常に有名な論文からです。

FPGA CW Keyer (11)

cwkeyer

テキストからモールス符号への変換をしているだけです。ソースコードは最適ではありませんが、動作はします。

//===========================================================
//  FPGA CW Keyer (MAX10 10M08SAE144C8GES)
//===========================================================
`define POW_ON_RESET_MAX 16'hffff
module FPGA
(
	input  wire CLK48,			// pin  27, 48MHz Clock
	output wire[2:0] LED,		// pin [122:120], LED Output [Green, Blue, Red]
	output wire KEY_OUT			// pin 132, CN2-5, key output
	);

//--------------------------
// Internal Power on Reset
//--------------------------
wire reset_n ;							// Internal Reset Signal
reg  pow_on_reset_n ;					// power-up level = Low
reg  [15:0] pow_on_reset_count ;		// power-up level = Low

always @(posedge CLK48)
begin
	if (pow_on_reset_count != `POW_ON_RESET_MAX)
	begin
		pow_on_reset_n			<= 1'b0;
		pow_on_reset_count	<= pow_on_reset_count + 16'h0001;
	end
	else
	begin
		pow_on_reset_n			<= 1'b1;
		pow_on_reset_count	<= pow_on_reset_count;
	end
end

assign reset_n	= pow_on_reset_n;

//--------- counter for dot clock ---------------------
parameter COUNT_PERIOD = 32'h0010_0000;

reg [31:0] count;
wire count_up /* synthesis keep */;

always @ (posedge CLK48 or negedge reset_n)
begin
	if ( reset_n == 1'b0 )
	begin
		count <= 32'h0000_0000;
	end
	else
	begin
		if ( count == (COUNT_PERIOD - 32'h0000_0001) )
		begin
			count <= 32'h0000_0000;
		end
		else
		begin
			count <= count + 32'h0000_0001;
		end
	end
end

assign count_up   = ( count ==  (COUNT_PERIOD - 1) )? 1'b1 : 1'b0;

//--------- 10-bit morse code table (7-bit data and 3-bit length)
parameter N_CODE = 32;
reg [4:0] morse_code;
reg [9:0] code_pattern;

always @(morse_code)
begin
	case (morse_code)
		5'b0_0000: code_pattern <= 10'b01_00000_010; // a
		5'b0_0001: code_pattern <= 10'b1000_000_100; // b
		5'b0_0010: code_pattern <= 10'b1010_000_100; // c
		5'b0_0011: code_pattern <= 10'b100_0000_011; // d
		5'b0_0100: code_pattern <= 10'b0_000000_001; // e
		5'b0_0101: code_pattern <= 10'b0010_000_100; // f
		5'b0_0110: code_pattern <= 10'b110_0000_011; // g
		5'b0_0111: code_pattern <= 10'b0000_000_100; // h
		5'b0_1000: code_pattern <= 10'b00_00000_010; // i
		5'b0_1001: code_pattern <= 10'b0111_000_100; // j
		5'b0_1010: code_pattern <= 10'b101_0000_011; // k
		5'b0_1011: code_pattern <= 10'b0100_000_100; // l
		5'b0_1100: code_pattern <= 10'b11_00000_010; // m
		5'b0_1101: code_pattern <= 10'b10_00000_010; // n
		5'b0_1110: code_pattern <= 10'b111_0000_011; // o
		5'b0_1111: code_pattern <= 10'b0110_000_100; // p
		5'b1_0000: code_pattern <= 10'b1101_000_100; // q
		5'b1_0001: code_pattern <= 10'b010_0000_011; // r
		5'b1_0010: code_pattern <= 10'b000_0000_011; // s
		5'b1_0011: code_pattern <= 10'b1_000000_001; // t
		5'b1_0100: code_pattern <= 10'b001_0000_011; // u
		5'b1_0101: code_pattern <= 10'b0001_000_100; // v
		5'b1_0110: code_pattern <= 10'b011_0000_011; // w
		5'b1_0111: code_pattern <= 10'b1001_000_100; // x
		5'b1_1000: code_pattern <= 10'b1011_000_100; // y
		5'b1_1001: code_pattern <= 10'b1100_000_100; // z
		5'b1_1010: code_pattern <= 10'b00000_00_101; // 0
		5'b1_1011: code_pattern <= 10'b01111_00_101; // 1
		5'b1_1100: code_pattern <= 10'b00111_00_101; // 2
		5'b1_1101: code_pattern <= 10'b00011_00_101; // 3
		5'b1_1110: code_pattern <= 10'b00001_00_101; // 4
		5'b1_1111: code_pattern <= 10'b1000101__111; // <BK>
		default  : code_pattern <= 10'b00_00000_000; // default
	endcase
end

//--------- morse code state transition and output ------------
reg  [3:0] r_state;
reg key_out;
reg [6:0] shift_reg;
reg [2:0] length;

always @ (r_state)
begin
	case(r_state)
		4'b0000: begin key_out <= 1'b0; end		// idle
		4'b0001: begin key_out <= 1'b1; end		// dash 1
		4'b0010: begin key_out <= 1'b1; end		// dash 2
		4'b0011: begin key_out <= 1'b1; end		// dash 3
		4'b0100: begin key_out <= 1'b0; end		// char space 1
		4'b0101: begin key_out <= 1'b1; end		// dot  1
		4'b0110: begin key_out <= 1'b0; end		// word space 1
		4'b0111: begin key_out <= 1'b0; end		// word space 2
		4'b1000: begin key_out <= 1'b0; end
		4'b1001: begin key_out <= 1'b0; end
		4'b1010: begin key_out <= 1'b0; end
		4'b1011: begin key_out <= 1'b0; end
		4'b1100: begin key_out <= 1'b0; end
		4'b1101: begin key_out <= 1'b0; end
		4'b1110: begin key_out <= 1'b0; end
		4'b1111: begin key_out <= 1'b0; end
	endcase
end

assign KEY_OUT = key_out;

always @ (posedge CLK48 or negedge reset_n)
begin
	if ( reset_n == 1'b0 )
	begin
		r_state <= 4'b0000;
		morse_code <= 5'b0_0000;
	end
	else
	begin
	if(count_up)
	begin
		case (r_state)
			4'b0000:
				begin
					r_state <= 4'b0001;
				end
			4'b0001:
				begin
					r_state <= 4'b0010;
				end
			4'b0010:
				begin
					r_state <= 4'b0011;
				end
			4'b0011:
				begin
					r_state <= 4'b0100;
				end
			4'b0100:
				if(length != 3'b000)
				begin
					if(shift_reg[5]) // not MSB because before shift
					begin
						r_state <= 4'b0001;
					end
					else
					begin
						r_state <= 4'b0101;
					end
					shift_reg <= {shift_reg[5:0], 1'b0};
					length <= length - 3'b001;
				end
				else
				begin
					r_state <= 4'b0110;
				end
			4'b0101:
				begin
					r_state <= 4'b0100;
				end
			4'b0110:
				begin
					shift_reg		<= code_pattern[9:3];
					length	<= code_pattern[2:0] - 3'b001;
					if(morse_code == (N_CODE - 1) )
					begin
						morse_code <= 5'b0_0000;
					end
					else
					begin
						morse_code <= morse_code + 5'b0_0001;
					end
					r_state <= 4'b0111;
				end
			4'b0111:
				begin
					if(shift_reg[6])
					begin
						r_state <= 4'b0001;
					end
					else
					begin
						r_state <= 4'b0101;
					end
				end
			default:
			begin
				r_state <= r_state;
			end
		endcase
	end
	else
	begin
		r_state <= r_state;
	end
	end
end

//----------------
// LED Output
//----------------
reg [2:0] myled   ;

always @(posedge CLK48, negedge reset_n)
begin
	if (reset_n == 1'b0 )
	begin
		myled <= 3'b001;
	end
	else
	begin
		myled <= r_state[2:0];
	end
end
assign LED = ~myled;

//===========================================================
endmodule
//===========================================================