`default_nettype none /////////////////////////////////////////////////////////////////////////////// // // 6.111 Remote Control Transmitter Module V2.0 // // Created: February 29, 2009 // Author: Adam Lerer, // Updated GPH October 6, 2010 // - fixed 40Khz modulation, repeat commands exaclty every 45ms. // /////////////////////////////////////////////////////////////////////////////// // // 6.111 FPGA Labkit -- Template Toplevel Module // // For Labkit Revision 004 // Created: October 31, 2004, from revision 003 file // Author: Nathan Ickes, 6.111 staff // /////////////////////////////////////////////////////////////////////////////// module labkit( // Remove comment from any signals you use in your design! // AC97 /* output wire beep, audio_reset_b, ac97_synch, ac97_sdata_out, input wire ac97_bit_clock, ac97_sdata_in, */ // VGA /* output wire [7:0] vga_out_red, vga_out_green, vga_out_blue, output wire vga_out_sync_b, vga_out_blank_b, vga_out_pixel_clock, vga_out_hsync, vga_out_vsync, */ // NTSC OUT /* output wire [9:0] tv_out_ycrcb, output wire tv_out_reset_b, tv_out_clock, tv_out_i2c_clock, tv_out_i2c_data, output wire tv_out_pal_ntsc, tv_out_hsync_b, tv_out_vsync_b, tv_out_blank_b, output wire tv_out_subcar_reset; */ // NTSC IN /* input wire [19:0] tv_in_ycrcb, input wire tv_in_data_valid, tv_in_line_clock1, tv_in_line_clock2, tv_in_aef, tv_in_hff, tv_in_aff, output wire tv_in_i2c_clock, tv_in_fifo_read, tv_in_fifo_clock, tv_in_iso, tv_in_reset_b, tv_in_clock, inout wire tv_in_i2c_data, */ // ZBT RAMS /* inout wire [35:0] ram0_data, output wire [18:0] ram0_address, output wire ram0_adv_ld, ram0_clk, ram0_cen_b, ram0_ce_b, ram0_oe_b, ram0_we_b, output wire [3:0] ram0_bwe_b, inout wire [35:0]ram1_data, output wire [18:0]ram1_address, output wire ram1_adv_ld, ram1_clk, ram1_cen_b, ram1_ce_b, ram1_oe_b, ram1_we_b, output wire [3:0] ram1_bwe_b, input wire clock_feedback_in, output wire clock_feedback_out, */ // FLASH /* inout wire [15:0] flash_data, output wire [23:0] flash_address, output wire flash_ce_b, flash_oe_b, flash_we_b, flash_reset_b, flash_byte_b, input wire flash_sts, */ // RS232 /* output wire rs232_txd, rs232_rts, input wire rs232_rxd, rs232_cts, */ // PS2 //input wire mouse_clock, mouse_data, //input wire keyboard_clock, keyboard_data, // FLUORESCENT DISPLAY output wire disp_blank, disp_clock, disp_rs, disp_ce_b, disp_reset_b, input wire disp_data_in, output wire disp_data_out, // SYSTEM ACE /* inout wire [15:0] systemace_data, output wire [6:0] systemace_address, output wire systemace_ce_b, systemace_we_b, systemace_oe_b, input wire systemace_irq, systemace_mpbrdy, */ // BUTTONS, SWITCHES, LEDS //input wire button0, //input wire button1, //input wire button2, //input wire button3, //input wire button_enter, //input wire button_right, //input wire button_left, input wire button_down, input wire button_up, //input wire [7:0] switch, //output wire [7:0] led, // USER CONNECTORS, DAUGHTER CARD, LOGIC ANALYZER //inout wire [31:0] user1, inout wire [31:0] user2, inout wire [31:0] user3, //inout wire [31:0] user4, //inout wire [43:0] daughtercard, //output wire [15:0] analyzer1_data, output wire analyzer1_clock, //output wire [15:0] analyzer2_data, output wire analyzer2_clock, //output wire [15:0] analyzer3_data, output wire analyzer3_clock, //output wire [15:0] analyzer4_data, output wire analyzer4_clock, // CLOCKS //input wire clock1, //input wire clock2, input wire clock_27mhz ); //////////////////////////////////////////////////////////////////////////// // // Reset Generation // // A shift register primitive is used to generate an active-high reset // signal that remains high for 16 clock cycles after configuration finishes // and the FPGA's internal clocks begin toggling. // //////////////////////////////////////////////////////////////////////////// wire reset_init; SRL16 reset_sr(.D(1'b0), .CLK(clock_27mhz), .Q(reset_init), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1)); defparam reset_sr.INIT = 16'hFFFF; // debounce the down button for reset wire button_down_debounced; debounce db_down(0, clock_27mhz, button_down, button_down_debounced); // reset is the OR of button down and the FPGA reset wire reset = reset_init | ~button_down_debounced; // for the test transmission wire button_up_debounced; debounce db_up(reset, clock_27mhz, button_up, button_up_debounced); /////////////////////////////////////////////////////////////////////////////////////////// // // This is the transmitter for the remote. Set transmit_address and/or // transmit_command for the desired function. This example hard codes the up // button to "channel up" // // Insert your Verilog here to control the TV. // // // wire [4:0] transmit_address = 5'h1; //address is 1 for TV wire [6:0] transmit_command = 7'h10; //command is 16 (hex 10) for channel up wire transmit = ~button_up_debounced; //up button controls transmit for now wire [43:0] my_hex_data = 44'b0; // use this to display the decoded commands and for debug // // // // //////////////////////////////////////////////////////////////////////////////////////////// remote_transmitter transmitter (.clk(clock_27mhz), .reset(reset), .address(transmit_address), .command(transmit_command), .transmit(transmit), .signal_out(user3[31])); display_16hex disp(reset, clock_27mhz, {my_hex_data, 3'b0,transmit, //1 if transmitting 3'b0,transmit_address, //signal_out address (2 digits) 1'b0,transmit_command}, //signal_out command (2 digits) disp_blank, disp_clock, disp_rs, disp_ce_b, disp_reset_b, disp_data_out); endmodule /////////////////////////////////////////////////////////////////////////////// // // 6.111 Remote Control Transmitter Module // // Outputs a 12-bit Sony remote control signal based on the Sony Infrared Command // (SIRC) specification. signal_out can be used to control a TSKS400S Infrared // Emitting Diode, using a BJT to produce a stronger driving signal. // SIRC uses pulse-width modulation to encode the 10-bit signal, with a 600us // base frequency modulated by a 40kHz square wave with 25% duty cycle. // // Created: February 29, 2009 // Author: Adam Lerer, // Updated October 4, 2010 - fixed 40Khz modulation, inserted 45ms between commands // /////////////////////////////////////////////////////////////////////////////// module remote_transmitter (input wire clk, //27 mhz clock input wire reset, //FPGA reset input wire [4:0] address, // 5-bit signal address input wire [6:0] command, // 7-bit signal command input wire transmit, // transmission occurs when transmit is asserted output wire signal_out); //output to IR transmitter wire [11:0] value = {address, command}; //the value to be transmitted // here we count the number of "ones" in the signal and pad the wait state to start the // next command sequence exactly 45ms later. wire [3:0] sum_ones = address[4] + address[3] + address[2] + address[1] + address[0] + command[6] + command[5] + command[4] + command[3] + command[2] + command[1] + command[0]; wire[9:0] WAIT_TO_45MS = 10'd368 - (sum_ones*8); // reg [2:0] next_state; // cur_value latches the value input when the transmission begins, // and gets right shifted in order to transmit each successive bit reg [11:0] cur_value; // cur_bit keeps track of how many bits have been transmitted reg [3:0] cur_bit; reg [2:0] state; wire [9:0] timer_length; // large number of future options localparam IDLE = 3'd0; localparam WAIT = 3'd1; localparam START = 3'd2; localparam TRANS = 3'd3; localparam BIT = 3'd4; // this counter is used to modulate the transmitted signal // by a 40kHz 25% duty cycle square wave gph 10/2/2010 reg [10:0] mod_count; wire start_timer; wire expired; timer t (.clk(clk), .reset(reset), .start_timer(start_timer), .length(timer_length), .expired(expired)); always@(posedge clk) begin // signal modulation mod_count <= (mod_count == 674) ? 0 : mod_count + 1; // was 1349 if (reset) state <= IDLE; else begin if (state == START) begin cur_bit <= 0; cur_value <= value; end // when a bit finishes being transmitted, left shift cur_value // so that the next bit can be transmitted, and increment cur_bit if (state == BIT && next_state == TRANS) begin cur_bit <= cur_bit + 1; cur_value <= {1'b0, cur_value[11:1]}; end state <= next_state; end end always@* begin case(state) IDLE: next_state = transmit ? WAIT : IDLE; WAIT: next_state = expired ? (transmit ? START : IDLE) : WAIT; START: next_state = expired ? TRANS : START; TRANS: next_state = expired ? BIT : TRANS; BIT : next_state = expired ? (cur_bit == 11 ? WAIT : TRANS) : BIT; default: next_state = IDLE; endcase end // always start the timer on a state transition assign start_timer = (state != next_state); assign timer_length = (next_state == WAIT) ? WAIT_TO_45MS : // was 63; 600-4-24-6 = 566 (next_state == START) ? 10'd32 : (next_state == TRANS) ? 10'd8 : (next_state == BIT ) ? (cur_value[0] ? 10'd16 : 10'd8 ) : 10'd0; assign signal_out = ((state == START) || (state == BIT)) && (mod_count < 169); // was 338 gph endmodule /////////////////////////////////////////////////////////////////////////////// // A programmable timer with 75us increments. When start_timer is asserted, // the timer latches length, and asserts expired for one clock cycle // after 'length' 75us intervals have passed. e.g. if length is 10, timer will // assert expired after 750us. /////////////////////////////////////////////////////////////////////////////// module timer (input wire clk, input wire reset, input wire start_timer, input wire [9:0] length, output wire expired); wire enable; divider_600us sc(.clk(clk),.reset(start_timer),.enable(enable)); reg [9:0] count_length; reg [9:0] count; reg counting; always@(posedge clk) begin if (reset) counting <= 0; else if (start_timer) begin count_length <= length; count <= 0; counting <= 1; end else if (counting && enable) count <= count + 1; else if (expired) counting <= 0; end assign expired = (counting && (count == count_length)); endmodule /////////////////////////////////////////////////////////////////////////////// // enable goes high every 75us, providing 8x oversampling for // 600us width signal (with 27mhz clock) /////////////////////////////////////////////////////////////////////////////// module divider_600us (input wire clk, input wire reset, output wire enable); reg [10:0] count; always@(posedge clk) begin if (reset) count <= 0; else if (count == 2024) count <= 0; else count <= count + 1; end assign enable = (count == 2024); endmodule // Switch Debounce Module // use your system clock for the clock input // to produce a synchronous, debounced output module debounce #(parameter DELAY=270000) // .01 sec with a 27Mhz clock (input reset, clock, noisy, output reg clean); reg [18:0] count; reg new; always @(posedge clock) if (reset) begin count <= 0; new <= noisy; clean <= noisy; end else if (noisy != new) begin new <= noisy; count <= 0; end else if (count == DELAY) clean <= new; else count <= count+1; endmodule /////////////////////////////////////////////////////////////////////////////// // // 6.111 FPGA Labkit -- Hex display driver // // File: display_16hex.v // Date: 24-Sep-05 // // Created: April 27, 2004 // Author: Nathan Ickes // // 24-Sep-05 Ike: updated to use new reset-once state machine, remove clear // 28-Nov-06 CJT: fixed race condition between CE and RS (thanks Javier!) // // This verilog module drives the labkit hex dot matrix displays, and puts // up 16 hexadecimal digits (8 bytes). These are passed to the module // through a 64 bit wire ("data"), asynchronously. // /////////////////////////////////////////////////////////////////////////////// module display_16hex (reset, clock_27mhz, data, disp_blank, disp_clock, disp_rs, disp_ce_b, disp_reset_b, disp_data_out); input reset, clock_27mhz; // clock and reset (active high reset) input [63:0] data; // 16 hex nibbles to display output disp_blank, disp_clock, disp_data_out, disp_rs, disp_ce_b, disp_reset_b; reg disp_data_out, disp_rs, disp_ce_b, disp_reset_b; //////////////////////////////////////////////////////////////////////////// // // Display Clock // // Generate a 500kHz clock for driving the displays. // //////////////////////////////////////////////////////////////////////////// reg [4:0] count; reg [7:0] reset_count; reg clock; wire dreset; always @(posedge clock_27mhz) begin if (reset) begin count = 0; clock = 0; end else if (count == 26) begin clock = ~clock; count = 5'h00; end else count = count+1; end always @(posedge clock_27mhz) if (reset) reset_count <= 100; else reset_count <= (reset_count==0) ? 0 : reset_count-1; assign dreset = (reset_count != 0); assign disp_clock = ~clock; //////////////////////////////////////////////////////////////////////////// // // Display State Machine // //////////////////////////////////////////////////////////////////////////// reg [7:0] state; // FSM state reg [9:0] dot_index; // index to current dot being clocked out reg [31:0] control; // control register reg [3:0] char_index; // index of current character reg [39:0] dots; // dots for a single digit reg [3:0] nibble; // hex nibble of current character assign disp_blank = 1'b0; // low <= not blanked always @(posedge clock) if (dreset) begin state <= 0; dot_index <= 0; control <= 32'h7F7F7F7F; end else casex (state) 8'h00: begin // Reset displays disp_data_out <= 1'b0; disp_rs <= 1'b0; // dot register disp_ce_b <= 1'b1; disp_reset_b <= 1'b0; dot_index <= 0; state <= state+1; end 8'h01: begin // End reset disp_reset_b <= 1'b1; state <= state+1; end 8'h02: begin // Initialize dot register (set all dots to zero) disp_ce_b <= 1'b0; disp_data_out <= 1'b0; // dot_index[0]; if (dot_index == 639) state <= state+1; else dot_index <= dot_index+1; end 8'h03: begin // Latch dot data disp_ce_b <= 1'b1; dot_index <= 31; // re-purpose to init ctrl reg disp_rs <= 1'b1; // Select the control register state <= state+1; end 8'h04: begin // Setup the control register disp_ce_b <= 1'b0; disp_data_out <= control[31]; control <= {control[30:0], 1'b0}; // shift left if (dot_index == 0) state <= state+1; else dot_index <= dot_index-1; end 8'h05: begin // Latch the control register data / dot data disp_ce_b <= 1'b1; dot_index <= 39; // init for single char char_index <= 15; // start with MS char state <= state+1; disp_rs <= 1'b0; // Select the dot register end 8'h06: begin // Load the user's dot data into the dot reg, char by char disp_ce_b <= 1'b0; disp_data_out <= dots[dot_index]; // dot data from msb if (dot_index == 0) if (char_index == 0) state <= 5; // all done, latch data else begin char_index <= char_index - 1; // goto next char dot_index <= 39; end else dot_index <= dot_index-1; // else loop thru all dots end endcase always @ (data or char_index) case (char_index) 4'h0: nibble <= data[3:0]; 4'h1: nibble <= data[7:4]; 4'h2: nibble <= data[11:8]; 4'h3: nibble <= data[15:12]; 4'h4: nibble <= data[19:16]; 4'h5: nibble <= data[23:20]; 4'h6: nibble <= data[27:24]; 4'h7: nibble <= data[31:28]; 4'h8: nibble <= data[35:32]; 4'h9: nibble <= data[39:36]; 4'hA: nibble <= data[43:40]; 4'hB: nibble <= data[47:44]; 4'hC: nibble <= data[51:48]; 4'hD: nibble <= data[55:52]; 4'hE: nibble <= data[59:56]; 4'hF: nibble <= data[63:60]; endcase always @(nibble) case (nibble) 4'h0: dots <= 40'b00111110_01010001_01001001_01000101_00111110; 4'h1: dots <= 40'b00000000_01000010_01111111_01000000_00000000; 4'h2: dots <= 40'b01100010_01010001_01001001_01001001_01000110; 4'h3: dots <= 40'b00100010_01000001_01001001_01001001_00110110; 4'h4: dots <= 40'b00011000_00010100_00010010_01111111_00010000; 4'h5: dots <= 40'b00100111_01000101_01000101_01000101_00111001; 4'h6: dots <= 40'b00111100_01001010_01001001_01001001_00110000; 4'h7: dots <= 40'b00000001_01110001_00001001_00000101_00000011; 4'h8: dots <= 40'b00110110_01001001_01001001_01001001_00110110; 4'h9: dots <= 40'b00000110_01001001_01001001_00101001_00011110; 4'hA: dots <= 40'b01111110_00001001_00001001_00001001_01111110; 4'hB: dots <= 40'b01111111_01001001_01001001_01001001_00110110; 4'hC: dots <= 40'b00111110_01000001_01000001_01000001_00100010; 4'hD: dots <= 40'b01111111_01000001_01000001_01000001_00111110; 4'hE: dots <= 40'b01111111_01001001_01001001_01001001_01000001; 4'hF: dots <= 40'b01111111_00001001_00001001_00001001_00000001; endcase endmodule // pulse synchronizer module synchronize #(parameter NSYNC = 2) // number of sync flops. must be >= 2 (input clk,in, output reg out); reg [NSYNC-2:0] sync; always @ (posedge clk) begin {out,sync} <= {sync[NSYNC-2:0],in}; end endmodule