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
//===========================================================

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.