Author Topic: 16 bit to 4 digit 7 segment decoder  (Read 15426 times)

0 Members and 1 Guest are viewing this topic.

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
16 bit to 4 digit 7 segment decoder
« on: December 19, 2019, 08:27:08 am »
I have a (couple of) 4 digit 7 segment display module (NSB3881) and want to use it to plug into data and address buses of hobby projects to display bus values. The 7seg unit is common cathode and has all the segment lines (a-g/dp) connected over all 4 digits.

I want to make a self-contained module with a 0.1" header that can be plugged into breadboards (5V logic).

So I started to try to program a 2-digit version into a GAL22V10 (winCupl) but the segment mapping table generated too many product terms.
My other thought was to use a cheap micro (preferably Atmel/AVR - don't know PIC and don't have the programmer for it) to read the bus signals and output the 7seg data for each digit. It would need 16 (bus data) + 8 (a-g/dp) + 4 (digit common cathodes) = 28 IO pins. (would like a reset and an optional latch too => 30 IO pins).

Then I thought that perhaps there is a(nother) clever way to solve this problem and came here for inspiration.
Suggestions?
« Last Edit: December 19, 2019, 08:30:14 am by obiwanjacobi »
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline ChristofferB

  • Frequent Contributor
  • **
  • Posts: 929
  • Country: dk
  • Chemistry phd student!
    • My channel:
Re: 16 bit to 4 digit 7 segment decoder
« Reply #1 on: December 19, 2019, 10:38:26 am »
The simplest (and oldschoolest) way of making a logic look up table like that is using Eproms or Eeproms. You'll need an eprom per segment though.

--chris
--Christoffer //IG:Chromatogiraffery
Check out my scientific instruments diy (GC, HPLC, NMR, etc) Channel: https://www.youtube.com/channel/UCZ8l6SdZuRuoSdze1dIpzAQ
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #2 on: December 19, 2019, 10:48:13 am »
The simplest (and oldschoolest) way of making a logic look up table like that is using Eproms or Eeproms. You'll need an eprom per segment though.

Ouch. I know this method and would like to avoid it. I would also need logic to multiplex the 4 digits.
I want to keep the chip count down and the module as small as possible.

Meantime I remembered 5V cpld's like the Xilinx XC9572XL (*). Not too expensive and should be a one chip solution...

*) Edit: this is a 3V3 version! See this post for the correct info.
« Last Edit: December 20, 2019, 08:49:23 pm by obiwanjacobi »
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline Ed.Kloonk

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: au
  • Cat video aficionado
Re: 16 bit to 4 digit 7 segment decoder
« Reply #3 on: December 19, 2019, 11:32:55 am »
Youtuber Ben Eater uses an arduino to do the dirty work. Get one with enough I/O pins.

@ 10m 55s

« Last Edit: December 19, 2019, 11:37:36 am by Ed.Kloonk »
iratus parum formica
 

Offline Buriedcode

  • Super Contributor
  • ***
  • Posts: 1718
  • Country: gb
Re: 16 bit to 4 digit 7 segment decoder
« Reply #4 on: December 19, 2019, 04:13:56 pm »
You could use a 40-pin Arduino, like the MajorCore or MightyCore.  Atmega8515 isn't that expensive, and has 35 IO.  Only suggesting Arduino because it'll be slightly quicker to develop with, but if you're already set up with AVRs then might as well go bare metal.
 
The following users thanked this post: obiwanjacobi

Online Benta

  • Super Contributor
  • ***
  • Posts: 6420
  • Country: de
Re: 16 bit to 4 digit 7 segment decoder
« Reply #5 on: December 19, 2019, 04:25:01 pm »
No reason to make it so complicated, it's a multiplexed display with 7+1(dp) segment lines and 4 common lines. You only need to do the 4-bit to 7-segment decoding once.
However, you do need to build a small state machine to do the multiplexing. Basically just a decoded 2-bit counter with 4 outputs.
 

Online Peabody

  • Super Contributor
  • ***
  • Posts: 2247
  • Country: us
Re: 16 bit to 4 digit 7 segment decoder
« Reply #6 on: December 19, 2019, 04:32:41 pm »
So you're going to display the bus states in hex, and they will change state slowly enough that you can make sense of the display in real time?  You must have a very slow clock.

There are BCD to 7-segment decoders, but I don't know of one that does binary to 7-segment.  And even if you find one, you still have the multiplexing issue to deal with.

In the Arduino world, I think you would need something like a Mega to get that many I/O pins. But perhaps you could use shift registers to reduce the pin count.

This looks to be a pretty challenging project unless you use some kind of programmable logic for it.  I wonder if it might make more sense to use two 8-bit buffers to directly drive 16 LEDs divided into groups of 4, one group for each nibble.
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #7 on: December 19, 2019, 04:39:14 pm »
No reason to make it so complicated, it's a multiplexed display with 7+1(dp) segment lines and 4 common lines. You only need to do the 4-bit to 7-segment decoding once.
However, you do need to build a small state machine to do the multiplexing. Basically just a decoded 2-bit counter with 4 outputs.

Exactly this.  :-+
But how to make it as small as possible? A 40-pin MCU (DIP) does not sound small.
I am leaning toward a 5V CPLD at this point - I need (roughly) about 3-times the capacity of a 22V10.

(bare metal AVR is no problem)

Edit: I need about 20 pins to interface with the bus (16-bit + power + 2 spare - like latch)
So a 40-pin MCU could just fit if I use a single row header. The display module itself has 16 0.1" pins.
« Last Edit: December 19, 2019, 04:43:22 pm by obiwanjacobi »
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: 16 bit to 4 digit 7 segment decoder
« Reply #8 on: December 19, 2019, 04:53:08 pm »
My other thought was to use a cheap micro (preferably Atmel/AVR - don't know PIC and don't have the programmer for it) to read the bus signals and output the 7seg data for each digit. It would need 16 (bus data) + 8 (a-g/dp) + 4 (digit common cathodes) = 28 IO pins. (would like a reset and an optional latch too => 30 IO pins).

Use a MCP23017 to read the bus?
The further a society drifts from truth, the more it will hate those who speak it.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15798
  • Country: fr
Re: 16 bit to 4 digit 7 segment decoder
« Reply #9 on: December 19, 2019, 05:02:16 pm »
This would be a simple job for a CPLD/small FPGA, or even for an MCU.

If you want a ready-made integrated solution, you can consider the very famous TIL311 displays, hard to find these days, awfully expensive.
You also have the MC14495 which can still be found in some shops - awfully expensive as well.

If you have access to EEPROMs/Flash chips and would prefer to use them instead of CPLDs or FPGAs, you can always write the conversion tables inside. For instance, you could use one per 8 bit of data (thus controlling 2 hex digits): this would only require a 512x8 memory (the address would be your 8 bits of data, plus a digit index bit, the data would be driving your segments, and it would be a multiplexing display.) Will require an extra multiplexing clock signal. Doing the same with only one chip for 16 bits would require 18 bits of address - thus a 256Kx8 memory, and a small 2-bit counter (for the 4 digits, whereas for only 2 digits, all you need is a clock). Still doable though, as 256Kx8 flash chips can be had for relatively cheap these days, and a 2-bit counter would be dead easy to implement with one simple logic IC.

« Last Edit: December 19, 2019, 05:04:02 pm by SiliconWizard »
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #10 on: December 19, 2019, 05:02:39 pm »
So you're going to display the bus states in hex, and they will change state slowly enough that you can make sense of the display in real time?  You must have a very slow clock.

There are BCD to 7-segment decoders, but I don't know of one that does binary to 7-segment.  And even if you find one, you still have the multiplexing issue to deal with.

In the Arduino world, I think you would need something like a Mega to get that many I/O pins. But perhaps you could use shift registers to reduce the pin count.

This looks to be a pretty challenging project unless you use some kind of programmable logic for it.  I wonder if it might make more sense to use two 8-bit buffers to directly drive 16 LEDs divided into groups of 4, one group for each nibble.

Yes it will be a slow clock - its for debugging only. I also want an extra latch pin on there so I can use it to capture values based on specific conditions (which I can program into a GAL if needed).

The registers with leds are useful, sure. But for address- and data buses I think in hex values. I will make that a module as well with the same pinout so I can swap them out if needed. I have led-bars and a couple of hundred 3mm leds in several colors. That is not the problem.  ;D
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #11 on: December 19, 2019, 05:07:40 pm »
This would be a simple job for a CPLD/small FPGA, or even for an MCU.

If you want a ready-made integrated solution, you can consider the very famous TIL311 displays, hard to find these days, awfully expensive.
You also have the MC14495 which can still be found in some shops - awfully expensive as well.

If you have access to EEPROMs/Flash chips and would prefer to use them instead of CPLDs or FPGAs, you can always write the conversion tables inside. For instance, you could use one per 8 bit of data (thus controlling 2 hex digits): this would only require a 512x8 memory (the address would be your 8 bits of data, plus a digit index bit, the data would be driving your segments, and it would be a multiplexing display.) Will require an extra multiplexing clock signal. Doing the same with only one chip for 16 bits would require 18 bits of address - thus a 256Kx8 memory, and a small counter (for the 4 digits, whereas for only 2 digits, all you need is a clock). Still doable though, as 256Kx8 flash chips can be had for relatively cheap these days, and a 2-bit counter would be dead easy to implement with one simple logic IC.

Yes, CPLD and MCU seem the most feasible options at this time.

TIL311's are too expensive indeed - I have a few but they're in use. I really wanted to used these NSB3881 displays I had laying around as a cheap alternative.

I know about using an EPROM to do a lookup table but with all the support logic to multiplex 4 digits (and perhaps an internal clock / NE555) it gets pretty big. I was looking for a way to shrink that down.
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #12 on: December 19, 2019, 05:17:31 pm »
My other thought was to use a cheap micro (preferably Atmel/AVR - don't know PIC and don't have the programmer for it) to read the bus signals and output the 7seg data for each digit. It would need 16 (bus data) + 8 (a-g/dp) + 4 (digit common cathodes) = 28 IO pins. (would like a reset and an optional latch too => 30 IO pins).

Use a MCP23017 to read the bus?

(had to look up the part - so I may not understand how it operates...)
As a shift register and read it with a (small) MCU to do the I2C and drive the 7seg leds?

Yes, could work. 2 chips would not be ideal but it does bring down the width of the module...
The small MCU could be an ATtiny with at least 8+4 outputs (in addition to the I2C interface)....
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: 16 bit to 4 digit 7 segment decoder
« Reply #13 on: December 19, 2019, 05:26:33 pm »
(had to look up the part - so I may not understand how it operates...)
As a shift register and read it with a (small) MCU to do the I2C and drive the 7seg leds?

Yes, could work. 2 chips would not be ideal but it does bring down the width of the module...
The small MCU could be an ATtiny with at least 8+4 outputs (in addition to the I2C interface)....

Exactly, that's the idea.  :-+
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline David Hess

  • Super Contributor
  • ***
  • Posts: 17428
  • Country: us
  • DavidH
Re: 16 bit to 4 digit 7 segment decoder
« Reply #14 on: December 19, 2019, 05:38:58 pm »
Requiring 16 bits of binary input on the microcontroller really hurts the pin count.  What I would at least consider is using a pair of external 8 bit parallel-in serial-out shift registers so the 16 bits of binary data can be latched and then read in serially which will only require 3 pins instead of 16 pins.  The 74165, in whatever logic family you need, is commonly used for this function.

This also allows the input latches to be remotely located and the word width is easily expandable.  One strobe simultaneously latches every input even with multiple 8 bit latches so discontinuity is less of a problem.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15798
  • Country: fr
Re: 16 bit to 4 digit 7 segment decoder
« Reply #15 on: December 19, 2019, 05:47:26 pm »
I know about using an EPROM to do a lookup table but with all the support logic to multiplex 4 digits (and perhaps an internal clock / NE555) it gets pretty big. I was looking for a way to shrink that down.

That's why I suggested going for two-digit pairs. You'd just need to duplicate it to get your 16 bits. The multiplexing would only require a single clock, and an inverter - which you can design around a 2-gate schmitt trigger inverter such as the 74LVC2G14 for instance: one inverter for the clock, the other to toggle between the two digits.

You can actually do the same with a larger EEPROM/Flash: a 128Kx16 (I saw you can find Flash parallel 128Kx16 chips for about $1 from Microchip for instance), driving 2 digits at a time instead of one. Then the multiplexing signal would need to be only one bit as above, and you can implement the multiplexing the exact same way with just one additional chip.

This would be for the "vintage approach".

Sure, unless you're very against using an MCU, this will be your simplest bet here. Don't bother using extra interface chips IMO. You can easily find MCUs with enough IOs for very cheap (and you could actually add additional interfaces in it apart from the parallel data for reusing it in other settings...)

 

Online Benta

  • Super Contributor
  • ***
  • Posts: 6420
  • Country: de
Re: 16 bit to 4 digit 7 segment decoder
« Reply #16 on: December 19, 2019, 05:48:20 pm »
You need to partition this correctly. My suggestion would be two parts operating independently/asynchronously from each other:

1: the bus capture part. I 've no idea of the signals you want to read, but it's output should be a static 16-bit state, IOW a "bus capture register".

2: the display part which does the 4-bit -> 7-segment decoding and multiplexing. This part would be constantly scanning the 16-bit value from the "bus capture register".

If the 16-bit value changes quickly, you might experience a bit of "ghosting" in the display. If this is a problem, you'll need an extra 16-bit latch at the input of the display part.

This is just a suggestion on the "logic architecture" (not the implementation), but I'm certain a CPLD could do the job perfectly.

« Last Edit: December 19, 2019, 05:51:32 pm by Benta »
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #17 on: December 19, 2019, 06:43:19 pm »
You can actually do the same with a larger EEPROM/Flash: a 128Kx16 (I saw you can find Flash parallel 128Kx16 chips for about $1 from Microchip for instance), driving 2 digits at a time instead of one. Then the multiplexing signal would need to be only one bit as above, and you can implement the multiplexing the exact same way with just one additional chip.

Sure, unless you're very against using an MCU, this will be your simplest bet here. Don't bother using extra interface chips IMO. You can easily find MCUs with enough IOs for very cheap (and you could actually add additional interfaces in it apart from the parallel data for reusing it in other settings...)

The display unit has its segments connected across the 4 digits, so I cannot use a 16-bit lookup table output. I need to multiplex its common cathodes for each digit.

You need to partition this correctly. My suggestion would be two parts operating independently/asynchronously from each other:

1: the bus capture part. I 've no idea of the signals you want to read, but it's output should be a static 16-bit state, IOW a "bus capture register".

2: the display part which does the 4-bit -> 7-segment decoding and multiplexing. This part would be constantly scanning the 16-bit value from the "bus capture register".

If the 16-bit value changes quickly, you might experience a bit of "ghosting" in the display. If this is a problem, you'll need an extra 16-bit latch at the input of the display part.

This is just a suggestion on the "logic architecture" (not the implementation), but I'm certain a CPLD could do the job perfectly.

I don't see how this will be a problem in practice. I will use it as a debug aid where the clock speeds will be human-readably slow. Or I will add (hardware or software) logic to detect a specific circumstance that will trigger a capture, which will be displayed.

Attached is a picture of the display module together with a 40-pin DIP (the Z80 was on top of the pile) to give an impression of the physical dimensions.
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline ebclr

  • Super Contributor
  • ***
  • Posts: 2331
  • Country: 00
Re: 16 bit to 4 digit 7 segment decoder
« Reply #18 on: December 19, 2019, 07:28:18 pm »
Do you really need to read static address, because a display will only do that?

I guess is a better option to buy a DSLlogic or any other logic analyzer, you will get the same thing but dynamic

If for some special application, you really need that, a PIC, STM 8051 or even Arduino will do that very easily with the help of a display driver like  LIKE TM1638 , Assuming will be for a static use since you can't  see on high speed
 

Online oPossum

  • Super Contributor
  • ***
  • Posts: 1472
  • Country: us
  • Very dangerous - may attack at any time
Re: 16 bit to 4 digit 7 segment decoder
« Reply #19 on: December 19, 2019, 11:09:16 pm »
I have a (couple of) 4 digit 7 segment display module (NSB3881) and want to use it to plug into data and address buses of hobby projects to display bus values. The 7seg unit is common cathode and has all the segment lines (a-g/dp) connected over all 4 digits.

So I started to try to program a 2-digit version into a GAL22V10 (winCupl) but the segment mapping table generated too many product terms.

I have been working on a similar project. I chose to use a 16V8 GAL for two multiplexed 7 seven segment displays. Code is in VHDL and fits. I haven't yet built and tested this so there is a chance it doesn't work.

VHDL
Code: [Select]
entity hex_to_seven_seg_mux is

port(
    mux:       in  std_logic;
    hex_in_a:  in  std_logic_vector ( 3 downto 0 );
    hex_in_b:  in  std_logic_vector ( 3 downto 0 );
    seg_a_out: out std_logic ;
    seg_b_out: out std_logic ;
    seg_c_out: out std_logic ;
    seg_d_out: out std_logic ;
    seg_e_out: out std_logic ;
    seg_f_out: out std_logic ;
    seg_g_out: out std_logic  );

end;

architecture Hex_to_seven_seg_mux of hex_to_seven_seg_mux is

signal polarity: std_logic := '1';
signal hex_in: std_logic_vector(3 downto 0);
signal seg_a: std_logic;
signal seg_b: std_logic;
signal seg_c: std_logic;
signal seg_d: std_logic;
signal seg_e: std_logic;
signal seg_f: std_logic;
signal seg_g: std_logic;

begin
    process (mux, hex_in_a, hex_in_b, polarity)
    begin
        if mux = '0' then
            hex_in <= hex_in_a;
        else
            hex_in <= hex_in_b;
        end if;

        case hex_in is
            when "0000" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '0';
            when "0001" => seg_a <= '0'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '0'; seg_g <= '0';
            when "0010" => seg_a <= '1'; seg_b <= '1'; seg_c <= '0'; seg_d <= '1'; seg_e <= '1'; seg_f <= '0'; seg_g <= '1';
            when "0011" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '0'; seg_f <= '0'; seg_g <= '1';
            when "0100" => seg_a <= '0'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '1'; seg_g <= '1';
            when "0101" => seg_a <= '1'; seg_b <= '0'; seg_c <= '1'; seg_d <= '1'; seg_e <= '0'; seg_f <= '1'; seg_g <= '1';
            when "0110" => seg_a <= '1'; seg_b <= '0'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "0111" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '0'; seg_g <= '0';
            when "1000" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1001" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '1'; seg_g <= '1';
            when "1010" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1011" => seg_a <= '0'; seg_b <= '0'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1100" => seg_a <= '1'; seg_b <= '0'; seg_c <= '0'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '0';
            when "1101" => seg_a <= '0'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '0'; seg_g <= '1';
            when "1110" => seg_a <= '1'; seg_b <= '0'; seg_c <= '0'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1111" => seg_a <= '1'; seg_b <= '0'; seg_c <= '0'; seg_d <= '0'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            --when others => seg_a <= '0'; seg_b <= '0'; seg_c <= '0'; seg_d <= '0'; seg_e <= '0'; seg_f <= '0'; seg_g <= '0';
        end case;

        if polarity = '1' then
            seg_a_out <= seg_a;
            seg_b_out <= seg_b;
            seg_c_out <= seg_c;
            seg_d_out <= seg_d;
            seg_e_out <= seg_e;
            seg_f_out <= seg_f;
            seg_g_out <= seg_g;
        else
            seg_a_out <= not seg_a;
            seg_b_out <= not seg_b;
            seg_c_out <= not seg_c;
            seg_d_out <= not seg_d;
            seg_e_out <= not seg_e;
            seg_f_out <= not seg_f;
            seg_g_out <= not seg_g;
        end if;
    end process;

end Hex_to_seven_seg_mux;


Boolean equations
Code: [Select]
seg_a_out     = !(   !mux &  hex_in_a_3_ & !hex_in_a_2_ &  hex_in_a_1_ &  hex_in_a_0_ 
                 #   !mux &  hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_ &  hex_in_a_0_
                 #   !mux & !hex_in_a_3_ & !hex_in_a_2_ & !hex_in_a_1_ &  hex_in_a_0_
                 #   !mux & !hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_ & !hex_in_a_0_
                 #    mux &  hex_in_b_3_ & !hex_in_b_2_ &  hex_in_b_1_ &  hex_in_b_0_
                 #    mux &  hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_ &  hex_in_b_0_
                 #    mux & !hex_in_b_3_ & !hex_in_b_2_ & !hex_in_b_1_ &  hex_in_b_0_
                 #    mux & !hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_ & !hex_in_b_0_ );

seg_b_out     = !(   !mux &  hex_in_a_3_ &  hex_in_a_2_ &                !hex_in_a_0_
                 #   !mux &  hex_in_a_3_ &                 hex_in_a_1_ &  hex_in_a_0_
                 #   !mux & !hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_ &  hex_in_a_0_
                 #   !mux &                 hex_in_a_2_ &  hex_in_a_1_ & !hex_in_a_0_
                 #    mux &  hex_in_b_3_ &  hex_in_b_2_ &                !hex_in_b_0_
                 #    mux &  hex_in_b_3_ &                 hex_in_b_1_ &  hex_in_b_0_
                 #    mux & !hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_ &  hex_in_b_0_
                 #    mux &                 hex_in_b_2_ &  hex_in_b_1_ & !hex_in_b_0_ );

seg_c_out     = !(   !mux &  hex_in_a_3_ &  hex_in_a_2_ &                !hex_in_a_0_
                 #   !mux &  hex_in_a_3_ &  hex_in_a_2_ &  hex_in_a_1_
                 #   !mux & !hex_in_a_3_ & !hex_in_a_2_ &  hex_in_a_1_ & !hex_in_a_0_
                 #    mux &  hex_in_b_3_ &  hex_in_b_2_ &                !hex_in_b_0_
                 #    mux &  hex_in_b_3_ &  hex_in_b_2_ &  hex_in_b_1_
                 #    mux & !hex_in_b_3_ & !hex_in_b_2_ &  hex_in_b_1_ & !hex_in_b_0_ );

seg_d_out     = !(   !mux &                 hex_in_a_2_ &  hex_in_a_1_ &  hex_in_a_0_
                 #   !mux &                !hex_in_a_2_ & !hex_in_a_1_ &  hex_in_a_0_
                 #   !mux &  hex_in_a_3_ & !hex_in_a_2_ &  hex_in_a_1_ & !hex_in_a_0_
                 #   !mux & !hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_ & !hex_in_a_0_
                 #    mux &                 hex_in_b_2_ &  hex_in_b_1_ &  hex_in_b_0_
                 #    mux &                !hex_in_b_2_ & !hex_in_b_1_ &  hex_in_b_0_
                 #    mux &  hex_in_b_3_ & !hex_in_b_2_ &  hex_in_b_1_ & !hex_in_b_0_
                 #    mux & !hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_ & !hex_in_b_0_ );

seg_e_out     = !(   !mux & !hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_
                 #   !mux & !hex_in_a_3_ &                                hex_in_a_0_
                 #   !mux &                !hex_in_a_2_ & !hex_in_a_1_ &  hex_in_a_0_
                 #    mux & !hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_
                 #    mux & !hex_in_b_3_ &                                hex_in_b_0_
                 #    mux &                !hex_in_b_2_ & !hex_in_b_1_ &  hex_in_b_0_ );

seg_f_out     = !(   !mux & !hex_in_a_3_ &                 hex_in_a_1_ &  hex_in_a_0_
                 #   !mux & !hex_in_a_3_ & !hex_in_a_2_ &  hex_in_a_1_
                 #   !mux & !hex_in_a_3_ & !hex_in_a_2_ &                 hex_in_a_0_
                 #   !mux &  hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_ &  hex_in_a_0_
                 #    mux & !hex_in_b_3_ &                 hex_in_b_1_ &  hex_in_b_0_
                 #    mux & !hex_in_b_3_ & !hex_in_b_2_ &  hex_in_b_1_
                 #    mux & !hex_in_b_3_ & !hex_in_b_2_ &                 hex_in_b_0_
                 #    mux &  hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_ &  hex_in_b_0_ );

seg_g_out     = !(   !mux & !hex_in_a_3_ & !hex_in_a_2_ & !hex_in_a_1_
                 #   !mux & !hex_in_a_3_ &  hex_in_a_2_ &  hex_in_a_1_ &  hex_in_a_0_
                 #   !mux &  hex_in_a_3_ &  hex_in_a_2_ & !hex_in_a_1_ & !hex_in_a_0_
                 #    mux & !hex_in_b_3_ & !hex_in_b_2_ & !hex_in_b_1_
                 #    mux & !hex_in_b_3_ &  hex_in_b_2_ &  hex_in_b_1_ &  hex_in_b_0_
                 #    mux &  hex_in_b_3_ &  hex_in_b_2_ & !hex_in_b_1_ & !hex_in_b_0_ );



Schematic attached.
 
« Last Edit: December 20, 2019, 12:25:50 am by oPossum »
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #20 on: December 20, 2019, 07:26:49 am »
That is awesome!

I have to see why mine is so different (made with WinCupl) - I'm on a different computer now.
I had a 22V10 and also had the multiplexer in there. I could see the at several (seg) outputs I exceeded the max number of product terms.

But I do not think I can make it work for a 16-bit bus. I would need 2 chips and some way of syncing them up.

----

I think -based on ebay prices- a single 40-pin ATMega8515 is the cheapest as it stand now. It would also be the simplest construction/wiring.
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Online oPossum

  • Super Contributor
  • ***
  • Posts: 1472
  • Country: us
  • Very dangerous - may attack at any time
Re: 16 bit to 4 digit 7 segment decoder
« Reply #21 on: December 20, 2019, 10:52:35 am »
But I do not think I can make it work for a 16-bit bus. I would need 2 chips and some way of syncing them up.

I am not suggesting this is a good way, but I think it would work.

Code: [Select]
entity hex_to_7_seg_multi is

port(
    hex_in_a:  in  std_logic_vector ( 3 downto 0 );
    hex_in_b:  in  std_logic_vector ( 3 downto 0 );
    enable_a:  in  std_logic;
    enable_b:  in  std_logic;
    seg_a_out: out std_logic;
    seg_b_out: out std_logic;
    seg_c_out: out std_logic;
    seg_d_out: out std_logic;
    seg_e_out: out std_logic;
    seg_f_out: out std_logic;
    seg_g_out: out std_logic);

attribute LOC: string;
attribute LOC of hex_in_a:  signal is "5 4 3 2";
attribute LOC of hex_in_b:  signal is "9 8 7 6";
attribute LOC of enable_a:  signal is "10";
attribute LOC of enable_b:  signal is "11";
-- Gnd 12

attribute LOC of seg_a_out: signal is "15";
attribute LOC of seg_b_out: signal is "16";
attribute LOC of seg_c_out: signal is "17";
attribute LOC of seg_d_out: signal is "18";
attribute LOC of seg_e_out: signal is "19";
attribute LOC of seg_f_out: signal is "20";
attribute LOC of seg_g_out: signal is "21";
-- Vcc 24

end;

architecture Hex_to_7_seg_multi of hex_to_7_seg_multi is

signal polarity: std_logic := '0';
signal hex_in: std_logic_vector(3 downto 0);
signal seg_a: std_logic;
signal seg_b: std_logic;
signal seg_c: std_logic;
signal seg_d: std_logic;
signal seg_e: std_logic;
signal seg_f: std_logic;
signal seg_g: std_logic;
signal enabled: std_logic;

ATTRIBUTE SYN_KEEP : integer;
ATTRIBUTE SYN_KEEP OF enabled : SIGNAL IS 1;

ATTRIBUTE OPT : string;
ATTRIBUTE OPT OF enabled: SIGNAL IS "KEEP";

begin
    process (enable_a, enable_b, hex_in_a, hex_in_b, polarity, enabled)
    begin
        if enable_b = '1' then
            hex_in <= hex_in_b;
        else
            hex_in <= hex_in_a;
        end if;
 
        case hex_in is
            when "0000" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '0';
            when "0001" => seg_a <= '0'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '0'; seg_g <= '0';
            when "0010" => seg_a <= '1'; seg_b <= '1'; seg_c <= '0'; seg_d <= '1'; seg_e <= '1'; seg_f <= '0'; seg_g <= '1';
            when "0011" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '0'; seg_f <= '0'; seg_g <= '1';
            when "0100" => seg_a <= '0'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '1'; seg_g <= '1';
            when "0101" => seg_a <= '1'; seg_b <= '0'; seg_c <= '1'; seg_d <= '1'; seg_e <= '0'; seg_f <= '1'; seg_g <= '1';
            when "0110" => seg_a <= '1'; seg_b <= '0'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "0111" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '0'; seg_g <= '0';
            when "1000" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1001" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '0'; seg_f <= '1'; seg_g <= '1';
            when "1010" => seg_a <= '1'; seg_b <= '1'; seg_c <= '1'; seg_d <= '0'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1011" => seg_a <= '0'; seg_b <= '0'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1100" => seg_a <= '1'; seg_b <= '0'; seg_c <= '0'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '0';
            when "1101" => seg_a <= '0'; seg_b <= '1'; seg_c <= '1'; seg_d <= '1'; seg_e <= '1'; seg_f <= '0'; seg_g <= '1';
            when "1110" => seg_a <= '1'; seg_b <= '0'; seg_c <= '0'; seg_d <= '1'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
            when "1111" => seg_a <= '1'; seg_b <= '0'; seg_c <= '0'; seg_d <= '0'; seg_e <= '1'; seg_f <= '1'; seg_g <= '1';
        end case;

        enabled <= enable_a or enable_b;

        if enabled = '1' then
            if polarity = '1' then
                seg_a_out <= seg_a;
                seg_b_out <= seg_b;
                seg_c_out <= seg_c;
                seg_d_out <= seg_d;
                seg_e_out <= seg_e;
                seg_f_out <= seg_f;
                seg_g_out <= seg_g;
            else
                seg_a_out <= not seg_a;
                seg_b_out <= not seg_b;
                seg_c_out <= not seg_c;
                seg_d_out <= not seg_d;
                seg_e_out <= not seg_e;
                seg_f_out <= not seg_f;
                seg_g_out <= not seg_g;
            end if;
        else
            seg_a_out <= 'Z';
            seg_b_out <= 'Z';
            seg_c_out <= 'Z';
            seg_d_out <= 'Z';
            seg_e_out <= 'Z';
            seg_f_out <= 'Z';
            seg_g_out <= 'Z';
        end if;

    end process;

end Hex_to_7_seg_multi;
« Last Edit: December 20, 2019, 10:55:52 am by oPossum »
 
The following users thanked this post: obiwanjacobi

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 21227
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: 16 bit to 4 digit 7 segment decoder
« Reply #22 on: December 20, 2019, 11:06:46 am »
I think -based on ebay prices- a single 40-pin ATMega8515 is the cheapest as it stand now. It would also be the simplest construction/wiring.

To minimise pins, check out the concepts behind "charlieplexing".
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 
The following users thanked this post: Prehistoricman

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #23 on: December 20, 2019, 12:00:41 pm »
I am not suggesting this is a good way, but I think it would work.
...

Yes, I would need to use the OE of the GALs. But I would like to program the multiplexer FF inside GAL/GALs as well. Then you'll end up with almost two identical GALs... I would use an extra input to sync up the second GAL with the first (have a couple of free inputs).

I have to look at you solution in greater detail and compare it to my design (that was too big). Perhaps I can find a way to slim it down...?

---

To minimise pins, check out the concepts behind "charlieplexing".

Post #1
I have a (couple of) 4 digit 7 segment display module (NSB3881) and want to use it to plug into data and address buses of hobby projects to display bus values. The 7seg unit is common cathode and has all the segment lines (a-g/dp) connected over all 4 digits.

I do not know how to charlieplex common cathode segements...  :-//
(I am not intimate with the finer details of charlieplexing)
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline obiwanjacobiTopic starter

  • Super Contributor
  • ***
  • Posts: 1013
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: 16 bit to 4 digit 7 segment decoder
« Reply #24 on: December 20, 2019, 04:15:57 pm »
@oPossum

I have tried your (first) example and copied the boolean expressions and it works fine.

I think my initial CUPL code was too 'abstract' for the compiler to optimize well...

This code:

Code: [Select]
Name     2-Digit 7-Segment Decoder;
PartNo   2D7SDecoder-01;
Date     18-12-2019;
Revision 01;
Designer Marc Jacobi;
Company  Canned Bytes;
Assembly unknown;
Location unknown;
Device   g22v10;
/*Format   j ;*/


/** input pins **/

PIN 1 = CLK;
PIN 2 = D0;
PIN 3 = D1;
PIN 4 = D2;
PIN 5 = D3;
PIN 6 = D4;
PIN 7 = D5;
PIN 8 = D6;
PIN 9 = D7;

/** output pins **/

PIN 14 = a;
PIN 15 = b;
PIN 16 = c;
PIN 17 = d;
PIN 18 = e;
PIN 19 = f;
PIN 20 = g;
PIN 21 = dp;
PIN 22 = n1;
PIN 23 = n2;

/* not used */
n1.ar = 'b'0;
n1.sp = 'b'0;

n1.d = !n1;
n2 = !n1;

dec0 = (D0 & n1) # (D4 & !n1);
dec1 = (D1 & n1) # (D5 & !n1);
dec2 = (D2 & n1) # (D6 & !n1);
dec3 = (D3 & n1) # (D7 & !n1);

FIELD decode = [dec3, dec2, dec1, dec0];
FIELD output = [dp, g, f, e, d, c, b, a];

TABLE decode => output
{
0 => 'b'00111111;
1 => 'b'00000110;
2 => 'b'01011011;
3 => 'b'01001111;
4 => 'b'01100110;
5 => 'b'01101101;
6 => 'b'01111101;
7 => 'b'00000111;
8 => 'b'01111111;
9 => 'b'01101111;
A => 'b'11110111;
B => 'b'11111100;
C => 'b'10111001;
D => 'b'11011110;
E => 'b'11111011;
F => 'b'11110001;
}

resulted in these equations

Code: [Select]
a =>
    D4 & D5 & D6 & D7 & !n1
  # !D4 & D7 & !n1
  # D0 & D1 & D2 & D3 & n1
  # !D0 & D3 & n1
  # !D0 & !D2 & !D3 & n1
  # !D4 & !D6 & !D7 & !n1
  # D0 & D1 & !D3 & n1
  # D4 & D5 & !D7 & !n1
  # !D0 & D1 & D2 & !D3 & n1
  # D0 & !D1 & D2 & !D3 & n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D1 & !D2 & D3 & n1
  # !D5 & !D6 & D7 & !n1

b =>
    !D4 & D5 & D7 & !n1
  # !D0 & D1 & D3 & n1
  # !D0 & !D1 & !D3 & n1
  # !D2 & !D3 & n1
  # !D4 & !D5 & !D7 & !n1
  # !D6 & !D7 & !n1
  # D0 & D1 & !D3 & n1
  # D4 & D5 & !D7 & !n1
  # D0 & !D1 & D2 & D3 & n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D1 & !D2 & D3 & n1
  # !D5 & !D6 & D7 & !n1

c =>
    !D4 & D5 & !D6 & D7 & !n1
  # !D0 & D1 & !D2 & D3 & n1
  # D0 & D1 & !D2 & n1
  # !D1 & !D3 & n1
  # D4 & D5 & !D6 & !n1
  # !D5 & !D6 & !D7 & !n1
  # !D4 & !D5 & D6 & !D7 & !n1
  # D0 & D1 & !D3 & n1
  # D4 & D5 & !D7 & !n1
  # D0 & !D1 & D2 & D3 & n1
  # !D0 & D1 & D2 & !D3 & n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D1 & !D2 & D3 & n1
  # !D5 & !D6 & D7 & !n1

d =>
    !D4 & D5 & D6 & D7 & !n1
  # !D0 & D1 & D2 & D3 & n1
  # !D0 & !D2 & !D3 & n1
  # D0 & D1 & !D2 & n1
  # !D0 & !D1 & D2 & D3 & n1
  # !D4 & !D6 & !D7 & !n1
  # D4 & D5 & !D6 & !n1
  # !D4 & !D5 & D6 & D7 & !n1
  # D0 & !D1 & D2 & D3 & n1
  # !D0 & D1 & D2 & !D3 & n1
  # D0 & !D1 & D2 & !D3 & n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D1 & !D2 & D3 & n1
  # !D5 & !D6 & D7 & !n1

dec0 =>
    D0 & n1
  # D4 & !n1

dec1 =>
    D1 & n1
  # D5 & !n1

dec2 =>
    D2 & n1
  # D6 & !n1

dec3 =>
    D3 & n1
  # D7 & !n1

decode =>
    dec3 , dec2 , dec1 , dec0

dp =>
    D5 & D7 & !n1
  # D1 & D3 & n1
  # !D0 & !D1 & D2 & D3 & n1
  # !D4 & !D5 & D6 & D7 & !n1
  # D0 & !D1 & D2 & D3 & n1
  # D4 & !D5 & D6 & D7 & !n1

e =>
    D5 & D7 & !n1
  # !D4 & D7 & !n1
  # D1 & D3 & n1
  # !D0 & D3 & n1
  # !D0 & !D2 & !D3 & n1
  # !D4 & !D6 & !D7 & !n1
  # D0 & !D1 & D2 & D3 & n1
  # !D0 & D1 & D2 & !D3 & n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D4 & D5 & D6 & !D7 & !n1

f =>
    D5 & D7 & !n1
  # !D4 & D7 & !n1
  # D1 & D3 & n1
  # !D0 & D3 & n1
  # !D0 & !D1 & !D3 & n1
  # !D4 & !D5 & !D7 & !n1
  # !D0 & D1 & D2 & !D3 & n1
  # D0 & !D1 & D2 & !D3 & n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D1 & !D2 & D3 & n1
  # !D5 & !D6 & D7 & !n1

g =>
    D5 & D7 & !n1
  # !D4 & D5 & !D6 & !D7 & !n1
  # D1 & D3 & n1
  # !D0 & !D1 & D2 & !D3 & n1
  # D1 & !D2 & !D3 & n1
  # D4 & D5 & !D6 & !n1
  # !D4 & !D5 & D6 & !D7 & !n1
  # D0 & !D1 & D2 & D3 & n1
  # !D0 & D1 & D2 & !D3 & n1
  # D0 & !D1 & D2 & !D3 & n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D1 & !D2 & D3 & n1
  # !D5 & !D6 & D7 & !n1

n1.d  =>
    D5 & D7 & !n1
  # !D4 & !D5 & D6 & D7 & !n1
  # !D6 & !D7 & !n1
  # !D4 & !D5 & D6 & !D7 & !n1
  # D4 & D5 & !D7 & !n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D5 & !D6 & D7 & !n1

n1.ar  =>
    0

n1.sp  =>
    0

n2 =>
    D5 & D7 & !n1
  # !D4 & !D5 & D6 & D7 & !n1
  # !D6 & !D7 & !n1
  # !D4 & !D5 & D6 & !D7 & !n1
  # D4 & D5 & !D7 & !n1
  # D4 & !D5 & D6 & D7 & !n1
  # !D4 & D5 & D6 & !D7 & !n1
  # D4 & !D5 & D6 & !D7 & !n1
  # !D5 & !D6 & D7 & !n1

output =>
    dp , g , f , e , d , c , b , a

Have not taken the time to analyze what went wrong here...
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf