Adam Szychulec
Published © GPL3+

7-Segment LED Display Hardware and VHDL Module for MiniZed

Actual PWM duty cycle on 7-segment LED display, driven by hardware (PL) and controlled by software (PS).

IntermediateFull instructions provided3 hours7,683

Things used in this project

Hardware components

MiniZed
Avnet MiniZed
×1
5641AS - Quad Digit LED Display
×1
Logic Level FET N-Channel
Logic Level FET N-Channel
2N7000
×1
Protyping board
×1
Through Hole Resistor, 300 ohm
Through Hole Resistor, 300 ohm
×8
Resistor 10k ohm
Resistor 10k ohm
×4
Through Hole Resistor, 220 kohm
Through Hole Resistor, 220 kohm
×4
61300611821
Femal header 6 pin
×1
61301311121
Male header 13 pin
×1
Male/Female Jumper Wires
Male/Female Jumper Wires
×13
Pmod HB3
Digilent Pmod HB3
×1
DC Motor, Miniature
DC Motor, Miniature
×1

Software apps and online services

Vivado Design Suite HLx Editions
AMD Vivado Design Suite HLx Editions

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, 0.022" Diameter
Solder Wire, 0.022" Diameter
Cable Cutter, 143mm
Cable Cutter, 143mm
wire
For PCB connections

Story

Read more

Schematics

SCH1

Board schematic Part 1

SCH2

Board schematic Part 2

SCH3

Board schematic Part 3

LED 7 segments

Segments of LED display

LED 7 Segment Internal con

Schematic of internal connections of 5641 AS 7 segments display

Code

main

VHDL
Submodules integration
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 09.02.2020 21:53:42
-- Design Name: 
-- Module Name: main - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity main is
Port 
(
    clk:       in std_logic;
    dat_in:    in std_logic_vector(15 downto 0);
    dp:        in std_logic_vector(3 downto 0);
    reset    : in std_logic;
    lcd_out:    out std_logic_vector (7 downto 0);
    seg_out:    out std_logic_vector (3 downto 0)
 );
end main;

architecture Behavioral of main is
signal num_sel: std_logic_vector (1 downto 0);
signal num_out: std_logic_vector (3 downto 0);
signal dp_out:  std_logic;

begin


u1: entity work.selector
    port map(clk=>clk, reset=>reset, sel=>num_sel);

u2: entity work.mux_16_to_4
    port map(input=>dat_in, sw=>num_sel, output=>num_out);

u3: entity work.seg_mux_4
    port map(input=>num_sel, enable=>'1', output=>seg_out);

u4: entity work.mux_4_to_1
    port map(input=>dp, sw=>num_sel, output=>dp_out);

u5: entity work.hex4b_to_lcd
    port map(input=>num_out, dot=>dp_out, output=>lcd_out);

end Behavioral;

16 to 4 multiplexer

VHDL
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 09.02.2020 19:45:14
-- Design Name: 
-- Module Name: mux_16_to_4 - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity mux_16_to_4 is
Port 
( 
    input  : in std_logic_vector (15 downto 0);
    sw     : in std_logic_vector (1 downto 0);
    output : out std_logic_vector (3 downto 0)
);
end mux_16_to_4;

architecture Behavioral of mux_16_to_4 is

begin
 with sw select
     output(3 downto 0) <=
        input(3 downto 0)   when "00",
        input(7 downto 4)   when "01",
        input(11 downto 8)  when "10",
        input(15 downto 12) when "11",
        "0000" when others; 

end Behavioral;

seg_mux_4

VHDL
LCD display select submodule
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 09.02.2020 21:03:42
-- Design Name: 
-- Module Name: seg_mux_4 - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity seg_mux_4 is
Port
(
    input:  in  std_logic_vector (1 downto 0);
    enable: in  std_logic;
    output: out std_logic_vector (3 downto 0)
 );
end seg_mux_4;

architecture Behavioral of seg_mux_4 is
begin

  output <= "0000" when (enable = '0') else
            "0001" when (input = "00") else
            "0010" when (input = "01") else
            "0100" when (input = "10") else
            "1000" when (input = "11") else
            "0000";

end Behavioral;

hex4b_to_lcd

VHDL
Converts 4bit binary number to LED display segments
----------------------------------------------------------------------------------
-- Company: 
-- Engineer:
-- 
-- Create Date: 09.02.2020 20:37:30
-- Design Name: 
-- Module Name: hex4b_to_lcd - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity hex4b_to_lcd is
Port 
( 
    input:  in  std_logic_vector(3 downto 0);
    dot:    in  std_logic;
    output: out std_logic_vector(7 downto 0)
);
end hex4b_to_lcd;

architecture Behavioral of hex4b_to_lcd is

begin
 with input select
     output(6 downto 0) <=
        "0111111" when "0000",
        "0000110" when "0001",
        "1011011" when "0010",
        "1001111" when "0011",
        "1100110" when "0100",
        "1101101" when "0101",
        "1111101" when "0110",
        "0000111" when "0111",
        "1111111" when "1000",
        "1101111" when "1001",
        "1110111" when "1010", --a
        "1111100" when "1011", --b
        "0111001" when "1100", --c
        "1011110" when "1101", --d
        "1111001" when "1110", --e
        "1110001" when others; --f
  output(7) <= dot;

end Behavioral;

helloworlds

C/C++
C application
#include <stdio.h>
#include "platform.h"
#include "xparameters.h"
#include "xil_printf.h"
#include "xgpiops.h"
#include "sleep.h"
#include "xil_exception.h"
#include "xttcps.h"
#include "xscugic.h"
#include "xgpio.h"

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define GPIO_EXAMPLE_DEVICE_ID  XPAR_GPIO_0_DEVICE_ID

/*
 * The following constant is used to determine which channel of the GPIO is
 * used for the LED if there are 2 channels supported.
 */
#define GPIO_CHANNEL 1

/*
 * The following constant is used to wait after an LED is turned on to make
 * sure that it is visible to the human eye.  This constant might need to be
 * tuned for faster or slower processor speeds.
 */
#define LOOP_DELAY     1000000

#define LED_MASK 0x0FFFF


#define GPIO_DEVICE_ID  	XPAR_XGPIOPS_0_DEVICE_ID
#define INTC_DEVICE_ID		XPAR_SCUGIC_0_DEVICE_ID
#define	TICK_TIMER_FREQ_HZ	100
#define TTC_TICK_DEVICE_ID	XPAR_XTTCPS_0_DEVICE_ID
#define TTC_TICK_INTR_ID	XPAR_XTTCPS_0_INTR

static void TickHandler(void *CallBackRef);
int SetupTicker(XTtcPs *TtcPsInst, u16 DeviceID, u16 TtcTickIntrID,
		XScuGic *InterruptController);
static int SetupInterruptSystem(u16 IntcDeviceID, XScuGic *IntcInstancePtr);
int SetupTimer(u16 DeviceID, XTtcPs *TtcPsInst);
void set_pwm(u32 cycle);
void display_menu();

typedef struct {
	u32 OutputHz; /* Output frequency */
	XInterval Interval; /* Interval value */
	u8 Prescaler; /* Prescaler value */
	u16 Options; /* Option settings */
} TmrCntrSetup;

/*
 * The following are declared globally so they are zeroed and so they are
 * easily accessible from a debugger
 */

XGpio GpioPL; /* The Instance of the GPIO Driver */

XGpioPs Gpio;
XGpioPs_Config *ConfigPtr;
XTtcPs_Config *TtcConfig;
XTtcPs ttcTimer;
TmrCntrSetup *TimerSetup;
XScuGic InterruptController; /* Interrupt controller instance */
XTtcPs TtcPsInst;
u32 MatchValue;
static TmrCntrSetup SettingsTable = { TICK_TIMER_FREQ_HZ, 0, 0, 0 };

uint8_t set_7seg_dec(uint16_t dec_num, uint8_t dp)
{
	uint32_t seg7_out;

	seg7_out = 0; // set 0 output
	seg7_out = dp<<16; // set decimal point

	seg7_out  |= (seg7_out & LED_MASK) | (dec_num % 10)*0x01;
	seg7_out  |= (seg7_out & LED_MASK) | (dec_num / 10)%10*0x10;
	seg7_out  |= (seg7_out & LED_MASK) | (dec_num / 100)%10*0x100;
	seg7_out  |= (seg7_out & LED_MASK) | (dec_num / 1000)%10*0x1000;


	XGpio_DiscreteWrite(&GpioPL, GPIO_CHANNEL, seg7_out);

	return 0;
}

int main() {
	u8 DutyCycle;
	char key_input;

	int Status;
	volatile int Delay;
	uint32_t byte, l_byte;
	uint32_t lcd_dec=0;

	init_platform();

	TmrCntrSetup SettingsTable = { TICK_TIMER_FREQ_HZ, 0, 0, 0 };

	ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
	XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
	XGpioPs_SetDirectionPin(&Gpio, 54, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, 54, 1);
	XGpioPs_WritePin(&Gpio, 54, 0x1);

	printf("www.adiuvoengineering.com\n\r");
	printf("DC Motor Control Example\n\r");

	SetupInterruptSystem(INTC_DEVICE_ID, &InterruptController);
	SetupTicker(&ttcTimer, TTC_TICK_DEVICE_ID, TTC_TICK_INTR_ID,
			&InterruptController);


	byte = 0x20000;

	/* Initialize the GPIO driver */
	Status = XGpio_Initialize(&GpioPL, GPIO_EXAMPLE_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("Gpio Initialization Failed\r\n");
		return XST_FAILURE;
	}

	print("Write byte.\n\r");

	/* Set the direction for all signals as  output */
	XGpio_SetDataDirection(&GpioPL, GPIO_CHANNEL, 0x00);

	/* Write inital data */
	XGpio_DiscreteWrite(&GpioPL, GPIO_CHANNEL, byte);

//	while (1) {
//
//		if (lcd_dec == 1000) lcd_dec = 0;
////		byte = 0x20000;
//		lcd_dec ++;
//		set_7seg_dec(lcd_dec, 0x02);
////		byte |= (byte & 0x0ffff) | (lcd_dec % 10)*0x01;
////		byte |= (byte & 0x0ffff) | (lcd_dec / 10)%10*0x10;
////		byte |= (byte & 0x0ffff) | (lcd_dec / 100)%10*0x100;
////		byte |= (byte & 0x0ffff) | (lcd_dec / 1000)%10*0x1000;
////
////
////		XGpio_DiscreteWrite(&GpioPL, GPIO_CHANNEL, byte);
//
//
////		byte = inbyte(); // get byte from stdin (uart1)
////
////		if(l_byte != byte)
////		{
////			/* Set counter as output value of port */
////			XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, byte);
////			/*Send byte to stdout*/
////			xil_printf("0x%02x\r\n", byte);
////			/*Save last value*/
////			l_byte = byte;
////		}
//
////		/* Wait a small amount of time so the LED is visible */
////		for (Delay = 0; Delay < LED_DELAY; Delay++);
////
////		/* Clear the LED bit */
////		XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);
//
//		/* Wait a small amount of time  */
//		for (Delay = 0; Delay < LOOP_DELAY; Delay++);
//	}


	while (1) {
		display_menu();
		read(1, (char*) &key_input, 1);
		printf("Echo %c\n\r", key_input);
		switch (key_input) {
//			case 0: // forward
//
//				set_pwm(0);
//				usleep(1000000);
//
//				set_pwm(DutyCycle);
//			break;
//			case 1: //reverse
//
//				//set_pwm(0);
//				//usleep(1000000);
//				//XGpioPs_WritePin(&Gpio, 54, 0x1);
//				//set_pwm(DutyCycle);
//			break;
		case '1': //stop
			set_pwm(0);
			break;
		case '2': //25%
			printf("25%\n\r");
			DutyCycle = 25;
			set_pwm(DutyCycle);
			break;
		case '3': //33%
			DutyCycle = 33;
			set_pwm(DutyCycle);
			break;
		case '4': //50%
			DutyCycle = 50;
			set_pwm(DutyCycle);
			break;
		case '5': //66%
			DutyCycle = 66;
			set_pwm(DutyCycle);
			break;
		case '6': //75%
			DutyCycle = 75;
			set_pwm(DutyCycle);
			break;
		case '7': //100%
			DutyCycle = 100;
			set_pwm(DutyCycle);
			break;
		}
	}
	cleanup_platform();
	return 0;
}
void display_menu() {
//Clear the screen
	printf("\033[2J");
//Display the main menu
	printf("*******************************************\n");
	printf("****      www.adiuvoengineering.com    ****\n");
	printf("****      Motor Control Example        ****\n");
	printf("*******************************************\n");
	printf("\n");
	printf("   MM10 Motor Control   \n");
	printf("------------------------------------------\n");
	printf("\n");
	printf("Select a Speed:\n");
	printf("  (1)   - Stop\n");
	printf("  (2)   - 25%\n");
	printf("  (3)   - 33%\n");
	printf("  (4)   - 50%\n");
	printf("  (5)   - 66%\n");
	printf("  (6)   - 75%\n");
	printf("  (7)   - 100%\n");
	printf("\n");
}

void set_pwm(u32 cycle) {
	u32 MatchValue;

	set_7seg_dec(cycle*10, 2);
	MatchValue = (TimerSetup->Interval * cycle) / 100;
	XTtcPs_SetMatchValue(&ttcTimer, 0, MatchValue);
}

int SetupTicker(XTtcPs *TtcPsInst, u16 DeviceID, u16 TtcTickIntrID,
		XScuGic *InterruptController) {
	int Status;
	TmrCntrSetup *TimerSetup;
	XTtcPs *TtcPsTick;
	TimerSetup = &SettingsTable;

	TimerSetup->Options |= (XTTCPS_OPTION_INTERVAL_MODE |
	XTTCPS_OPTION_MATCH_MODE | XTTCPS_OPTION_WAVE_POLARITY);
	Status = SetupTimer(DeviceID, TtcPsInst);

	if (Status != XST_SUCCESS) {
		return Status;
	}

	TtcPsTick = TtcPsInst;
	Status = XScuGic_Connect(InterruptController, TtcTickIntrID,
			(Xil_InterruptHandler) TickHandler, (void *) TtcPsTick);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	XScuGic_Enable(InterruptController, TtcTickIntrID);
	XTtcPs_EnableInterrupts(TtcPsTick, XTTCPS_IXR_INTERVAL_MASK);
	XTtcPs_Start(TtcPsTick);
	return Status;
}

static int SetupInterruptSystem(u16 IntcDeviceID, XScuGic *IntcInstancePtr) {
	int Status;
	XScuGic_Config *IntcConfig;
	IntcConfig = XScuGic_LookupConfig(IntcDeviceID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}
	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
			IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
			(Xil_ExceptionHandler) XScuGic_InterruptHandler, IntcInstancePtr);
	Xil_ExceptionEnable();
	return XST_SUCCESS;
}

int SetupTimer(u16 DeviceID, XTtcPs *TtcPsInst) {
	int Status;
	XTtcPs_Config *Config;
	XTtcPs *Timer;
	TmrCntrSetup *TimerSetup;
	TimerSetup = &SettingsTable;
	Timer = TtcPsInst;
	Config = XTtcPs_LookupConfig(DeviceID);
	if (NULL == Config) {
		return XST_FAILURE;
	}
	Status = XTtcPs_CfgInitialize(Timer, Config, Config->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	XTtcPs_SetOptions(Timer, TimerSetup->Options);
	XTtcPs_CalcIntervalFromFreq(Timer, TimerSetup->OutputHz,
			&(TimerSetup->Interval), &(TimerSetup->Prescaler));
	XTtcPs_SetInterval(Timer, TimerSetup->Interval);
	XTtcPs_SetPrescaler(Timer, TimerSetup->Prescaler);
	return XST_SUCCESS;
}

static void TickHandler(void *CallBackRef) {
	u32 StatusEvent;
	/*
	 * Read the interrupt status, then write it back to clear the interrupt.
	 */
	StatusEvent = XTtcPs_GetInterruptStatus((XTtcPs * )CallBackRef);
	XTtcPs_ClearInterruptStatus((XTtcPs * )CallBackRef, StatusEvent);
//printf("timer\n\r");
	/*update the flag if interrupt has been occurred*/
//UpdateFlag = TRUE;
}

selector

VHDL
Divides clock and create sw signal for other submodules
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 09.02.2020 21:27:32
-- Design Name: 
-- Module Name: selector - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity selector is
Port 
( 
    clk, reset: in std_logic;
    sel: out std_logic_vector(1 downto 0)
);
end selector;

architecture Behavioral of selector is
    signal state, next_state: unsigned(17 downto 0);
    begin
    
    --register
    process(clk, reset)
    begin
      if reset='1' then
      state <= (others=>'0');
    elsif (clk'event and clk='1') then
      state <= next_state;
    end if;
    end process;
    
    --next state logic
    next_state <= state + 1;
    
    --output clk/2^16 for 50MHz around 800 Hz out
    sel <= std_logic_vector(state(17 downto 16));
end Behavioral;

4 to 1 multiplexer

VHDL
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 10.02.2020 22:12:40
-- Design Name: 
-- Module Name: mux_4_to_1 - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity mux_4_to_1 is
Port 
( 
    input  : in std_logic_vector (3 downto 0);
    sw     : in std_logic_vector (1 downto 0);
    output : out std_logic 
);
end mux_4_to_1;

architecture Behavioral of mux_4_to_1 is

begin
 with sw select
     output <=
        input(0)  when "00",
        input(1)  when "01",
        input(2)  when "10",
        input(3)  when "11",
        '0' when others; 

end Behavioral;

Repository

Credits

Adam Szychulec

Adam Szychulec

1 project • 3 followers
Electronics Design Engineer, UAV payload systems, FPGA & SoC enthusiast
Thanks to Adam Taylor.

Comments