Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Verilog Implementation of 74HC595 Shift Register Driver

Tech May 9 3

74HC595 Overview

The 74HC595 is an 8-bit serial-in, parallel-out shift register featuring storage capabilities and tri-state outputs. This integrated circuit efficiently converts serial data into parallel output, making it ideal for applications requiring expanded output capacity while conserving FPGA I/O resources.

Pin Functionality

  1. SHCP: Shift register clock input - Data is shifted into the register on the rising edge of this signal
  2. STCP: Storage register clock input - After transferring the complete data sequence, a high-level clock signal activates to latch the data
  3. /OE: Output enable input - Typically active low (implementation-specific)
  4. DS: Serial data input - The data stream enters through this pin

These four signals are generated by our Verilog HDL module to properly drive the 74HC595 chip.

Timing Architecture

This implementation utilizes two cascaded 74HC595 devices to handle 12-bit serial data. The shift clock (SH_CP) is derived from a divided system clock signal. The storage clock (STCP) is asserted after all 12 bits have been transferred, effectively latching the data into the output registers. The output enable (/OE) is held at a low level, though in this specific design, it's configured as high due to board-level constraints.

Driver Implementation

module ShiftRegister_Controller(
    input                     sys_clk,
    input                     reset_n,

    input        [7:0]        segment_data,
    input        [3:0]        digit_select,

    output reg                shift_clk,
    output reg                storage_clk,
    output reg                data_serial,
    output                    output_enable
    );

// Internal signal declarations
reg                [2:0]        clock_divider = 3'd0;
reg                [3:0]        bit_counter = 4'd0;

wire            [11:0]        parallel_data;

// Clock divider process
always @(posedge sys_clk) begin
    if(!reset_n)
        clock_divider <= 3'd0;
    else if(clock_divider == 3)
        clock_divider <= 3'd0;
    else
        clock_divider <= clock_divider + 1'b1;
end

// Bit counter process
always @(posedge sys_clk) begin
    if(!reset_n)
        bit_counter <= 4'd0;
    else if((bit_counter == 11) && (clock_divider == 3))
        bit_counter <= 4'd0;
    else if(clock_divider == 3)
        bit_counter <= bit_counter + 1'b1;
    else
        bit_counter <= bit_counter;
end

// Shift clock generation
always @(posedge sys_clk) begin
    if(!reset_n)
        shift_clk <= 1'b0;
    else if(clock_divider >= 4'd2)
        shift_clk <= 1'b1;
    else
        shift_clk <= 1'b0;
end

// Storage clock generation
always @(posedge sys_clk) begin
    if(!reset_n)
        storage_clk <= 1'b0;
    else if((bit_counter == 4'd11) && (clock_divider == 3))
        storage_clk <= 1'b1;
    else
        storage_clk <= 1'b0;
end

// Parallel data concatenation
assign parallel_data = {segment_data[0],segment_data[1],segment_data[2],segment_data[3],
                        segment_data[4],segment_data[5],segment_data[6],segment_data[7],
                        digit_select};

// Serial data output
always @ (posedge sys_clk) begin
    if(reset_n == 1'b0) 
        data_serial <= 1'b0;
    else if(clock_divider == 3'd0)
        data_serial <= parallel_data[bit_counter];
    else
        data_serial <= data_serial;    
end

assign output_enable = 1'b1;

endmodule

Testbench

`timescale 1ns/1ps
module ShiftRegister_Controller_TB;
    reg                     system_clock;
    reg                     reset_n;

    reg        [7:0]        segment_data;
    reg        [3:0]        digit_select;

    wire                    shift_clk;
    wire                    storage_clk;
    wire                    data_serial;
    wire                    output_enable;

ShiftRegister_Controller Controller_DUT(
    .sys_clk              ( system_clock ),
    .reset_n              ( reset_n ),
    .segment_data          ( segment_data ),
    .digit_select          ( digit_select ),
    .shift_clk            ( shift_clk ),
    .storage_clk          ( storage_clk ),
    .data_serial          ( data_serial ),
    .output_enable        ( output_enable )
     ); 

// Clock generation
initial
    system_clock = 1'b0;
    always #10 system_clock = ~system_clock;

// Test sequence
initial
    begin
        #1;
        reset_n = 1'b0;
        segment_data = 8'd0;
        digit_select = 4'd0;
        #21;

        reset_n = 1'b1;
        #20;
        segment_data = 8'b1010_1010;
        digit_select = 4'b1111;
    end

endmodule

Simulation

The design has been verified using ModelSim simulation, confirming proper timing relationships and data transfer functionality.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.