Scrolling through my Twitter feed one day last year, I saw this really cool looking little 7-segment ICs which turned out to be the now-vintage QDSP-6061 5-digit bubble display from HP. So naturally, I immediately jumped on eBay to buy myself a few to play around with. They're so cool, just look at them:
The QDSP-6061 5-digit IC is comprised of five common cathode 7-segment displays. This means that the cathode of each segment's LED diode is tied to a single pin and when that one pin is connected to ground, all 7 LEDs' cathodes are connected to ground. Then each segment is illuminated as the corresponding LED anode is connected to the voltage source.
Another thing to note about the internal hardware of the QDSP-6061 is that the anodes for each the five 7-segment displays are tied to one pin. So the 5 anodes for the 'a' segment of each display are all tied to pin 14 of the QDSP-6061's package, the 5 anodes for the 'b' segment of each display are all tied to pin 12, 5 anodes for the 'c' segment of each display are all tied to pin 3, 5 anodes for the 'd' segment of each display are all tied to pin 6, and so on.
I could only find the datasheet for the 4-digit version of this chip (QDSP-6064 - which I went ahead an attached below) so I had to do some probing to figure out the full pin-out for the 5-digit QDSP-6061:
- Pin 1: Cathode for digit 1
- Pin 2: Segment e
- Pin 3: Segment c
- Pin 4: Cathode for digit 3
- Pin 5: Segment dp (decimal point)
- Pin 6: Segment d
- Pin 7: Cathode for digit 5
- Pin 8: Segment g
- Pin 9: Cathode for digit 4
- Pin 10: Segment f
- Pin 11: Not connected N/C
- Pin 12: Segment b
- Pin 13: Cathode for digit 2
- Pin 14: Segment a
And if you're not familiar, the small white dot on the bottom side of the IC denotes pin 1:
Since the cathode needs to be connected to ground, I chose to use a simple NPN BJT transistor to act as a switch to connect the cathode pins to ground when a logic level high signal is applied to its base from the FPGA (with a 6.8k-ohm resistor on each BJT base).
I chose to use my Arty Z7-20 FPGA development board for this because of its handy Arduino header I/O, which are 3.3v logic. Thus in order to knock it down to the forward voltage range of the LEDs in the QDSP-6061 (1.6v - 2.0v) and limit the current appropriately, I put 680-ohm resistors on the input on each anode pin.
With a bit of jumper wire spaghetti magic, I got the simple circuit built up.
I decided on 2N3904 transistors since they're super common and I have quite a few on hand. I figured that there had to be some level of delay from when the logic level is set high on the base of the 2N3904 to when the collector is connected to the emitter and provides a path to turn on the LED (essentially the slew of the transistor). And since I'm working with an FPGA, I though this delay could potentially be impactful from a timing perspective so I modeled it using LTSpice.
Since I'm running the logic of my FPGA design at 100MHz, the transition time of the logic will be 10ns, and I added 20ns to account for propagation delay through jumper wires and the breadboard. This calculation showed that the slew of the 2N3904 would add about 100ns or 0.1us of delay between the I/O pin of the FPGA going high and the LED of the segment illuminating.
Next I created a new project targeting Arty Z7 in Vivado 2021.2:
As with pretty all of the new Vivado projects I create for Zynq-based FPGAs, the first step is to create a new block design, and add the Zynq processing system IP block. Then apply the block automation that appears afterwards to apply the Arty Z7 board presets to the Zynq PS IP block. I also added a few other GPIOs from the Board tab for the buttons and switches, but this is optional and not necessary to this project.
To add the custom Verilog to drive the QDSP-6061, I created a new source file (Flow Navigator window > Add Sources > Add or create design sources).
Since it's the new year, I thought it'd be fun to have the QDSP-6061 scrolling text across it saying "hello 2022". After some research and trial+error, I found that each 7 segment display needs to hold its output for 1 millisecond for it to appear stable to the human eye, therefore the bubble display needs to be set to a 1kHz refresh rate.
Furthermore, since the 7 segment displays in the QDSP-6061 are common cathode and each digit has their respective anodes for a given segment tied together (i.e. - the anode for each 'a' segment of all five displays are tied together) this means that the Verilog code can only drive one digit at a time by setting the appropriate character on the 8 anode segments, then connecting the corresponding digit's cathode to ground. Since I have the programmable logic of the Arty running at 100MHz (10ns per clock cycle) and the refresh rate of each digit can't be much faster than 1kHz (1 ms), being constrained to driving one digit at a time shouldn't be an issue since the transition time between switching which digit is currently being driven is only going to be 10ns - 40ns. This boils down to needing a loop that drives each of the 5 digits for 1ms at a time in a round-robin type fashion.
For the scrolling text part, this required another loop to update the character register for each digit after the round-robin loop has finished a set number of cycles. This set number of cycles dictates how fast the phrase "hello 2022" scrolls from right to left across the QDSP-6061. I found that 255 cycles was a nice not too fast or slow speed. This loop incremented a counter every 255 cycles that updated the character register for each of the 5 digits for the previous loop to them multiplex between for each of the 1ms cycles. See my Verilog code attached below.
Once I had the Verilog written, I added the module for bubble display to block diagram by right-clicking in a blank space area and selecting the option to Add Module... Vivado will automatically detect any valid Verilog modules (or VHDL if you have the project settings set to VHDL) present in any design source files to allow you to add it to the block design.
The connection automation feature of the block design will detect the clock port on the module and offer you the option to auto-connect it to the logic clock output from the Zynq PS IP block. This will also auto-connect the reset port to the appropriate reset line.
With the block design now complete, I regenerated the layout to make it look pretty (circle arrow icon at top of block design window) and validated the design (checked box icon at top of block design window) to make sure it was free of any critical warnings or errors. After validation, I saved the block design:
and created an HDL wrapper for it, selecting the option to allow Vivado to auto-manage it for me:
Next, I added constraints for the pin-out of the Arduino header on Arty Z7. You can find the master constraints files for all Digilent boards such as the Arty Z7 in their repository here.
I copy+pasted over the constraints for the package pins IO0 - IO12 on header J4 and replaced the port names with my cathode and anode register names:
## ChipKit Outer Digital Header - J4
set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {bubble_display_cathodeReg[0]}]; #IO_L5P_T0_34 Sch=CK_IO0 QDSP-6061 pin 1
set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[3]}]; #IO_L2N_T0_34 Sch=CK_IO1 QDSP-6061 pin 2
set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[5]}]; #IO_L3P_T0_DQS_PUDC_B_34 Sch=CK_IO2 QDSP-6061 pin 3
set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {bubble_display_cathodeReg[2]}]; #IO_L3N_T0_DQS_34 Sch=CK_IO3 QDSP-6061 pin 4
set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[0]}]; #IO_L10P_T1_34 Sch=CK_IO4 QDSP-6061 pin 5
set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[4]}]; #IO_L5N_T0_34 Sch=CK_IO5 QDSP-6061 pin 6
set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {bubble_display_cathodeReg[4]}]; #IO_L19P_T3_34 Sch=CK_IO6 QDSP-6061 pin 7
set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[1]}]; #IO_L9N_T1_DQS_34 Sch=CK_IO7 QDSP-6061 pin 8
set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {bubble_display_cathodeReg[3]}]; #IO_L21P_T3_DQS_34 Sch=CK_IO8 QDSP-6061 pin 9
set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[2]}]; #IO_L21N_T3_DQS_34 Sch=CK_IO9 QDSP-6061 pin 10
set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[6]}]; #IO_L9P_T1_DQS_34 Sch=CK_IO10 QDSP-6061 pin 12
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {bubble_display_cathodeReg[1]}]; #IO_L19N_T3_VREF_34 Sch=CK_IO11 QDSP-6061 pin 13
set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {bubble_display_anodeReg[7]}]; #IO_L23N_T3_34 Sch=CK_IO12 QDSP-6061 pin 14
Finally, I ran synthesis, implementation (place & route), and generates a bitstream. Once that was completed, I exported the hardware platform including the bitstream:
In order to boot up the Zynq ARM-core and program the bitstream onto the FPGA, I created a Vitis project, starting with a new platform project based on the exported hardware platform from Vivado:
After the platform project is generated, it will show as out of date since it has not been compiled (built) yet, so I always from a quick build of the platform project. Next I created a new application project using Hello World template:
Since I'm mainly focusing on the execution of the bitstream, I didn't bother with editing any of the code in the main function of the Hello World template and ran a build of the project after it generated.
Testing the Bubble DisplaysAs a quick way to get the bitstream on the FPGA and running quickly, I simply ran a single application debug run on hardware:
Once the bitstream was uploaded and programmed onto the FPGA, I saw the logic kick in immediately to start the text scrolling across the QDSP-6061:
I'm definitely going to layout a fun little PCB to transfer this circuit to. I think something in the form of an Arduino shield to fit directly onto the Arty would be a fun thing to have.
Comments