This is only a preview of the April 2019 issue of Silicon Chip. You can view 38 of the 96 pages in the full issue, including the advertisments. For full access, purchase the issue for $10.00 or subscribe for access to the latest issues. Items relevant to "Flip-dot Message Display":
Items relevant to "Introducing the iCEstick: an easy way to program FPGAs":
Items relevant to "Ultra low noise remote controlled stereo preamp – Part 2":
Items relevant to "iCEstick VGA Terminal":
Items relevant to "Arduino Seismograph revisited – improving sensitivity":
Purchase a printed copy of this issue for $10.00. |
Want to give a project the retrocomputer look? Or do you just need a
convenient way to display a screen full
of text on a low-cost monitor? Then
this nifty project is for you! It generates
a VGA signal akin to some-thing from
an early PC or even a Commodore 64
or Amiga. It does this using a low-cost
iCEstick FPGA development board
and a very simple add-on board and is
controlled via a serial port.
iCEstick
VGA TERMINAL
F
ollowing on from our review of
the iCEstick and IceStudio software (page 32 of this issue), we
delved in to see if we could do something more useful and exciting to do
than flashing a LED.
After all, field programmable gate
arrays (FPGAs) are considerably more
capable than microcontrollers. So we
had to think of an application that
couldn’t be done with a 555
timer IC or the most basic micro you can buy!
So we’ve come up with some
‘code’ which configures the
FPGA chip (an iCE40HX-1k) on
the iCEstick to generate VGAcompatible video signals using the
eight digital outputs available on its
PMOD connector.
The output is displayed as 16 rows
and 32 columns of text, with selectable foreground and background colours for each 8x8 pixel character. The
colours come from a palette of 16, chosen from 64 possibilities. The graphics
ROM includes pseudo-graphics characters to create block graphics, boxes
and shaded regions.
58
Silicon Chip
The module is controlled by a serial
(UART) data line running at 9600 baud
which accepts regular ASCII characters, LF, CR and FF control codes, as
well as the pseudo-graphics above
ASCII code point 127. There are also
control codes to set the
colours.
This
project could be
used as the starting point of
a more ambitious FPGA-based project, or you could combine it with a
microcontroller of your choice, using
the serial port as your micro’s display
interface to the VGA monitor, to display text and graphics.
Note that when it comes to FPGAs,
it no longer makes sense to refer to
the code as ‘software’. The IceStudio
software takes our HDL (hardware de-
by Tim Blythman
Australia’s electronics magazine
scription language) and synthesises it
into a bitstream.
This bitstream could be considered
an equivalent to a binary firmware
image; it can be stored in a
computer file or uploaded to
an EEPROM on a target system. But rather than being a
sequence of instructions for
a processor to execute, it describes how the various elements within the FPGA are
connected or configured. For more
detail on this aspect, see the tutorial
starting on page 32.
For this article, we’re providing a
complete IDE project which you can
open up and use straight away. But it’s
also a great starting point for experimentation, and a wonderful tool for
learning about how FPGAs work (and
about digital logic in general).
Circuit description
Most of the hardware required is on
the pre-built iCEstick module. A small
breakout board that we’ve designed
plugs into the 12-pin PMOD connector, converting the digital signals from
siliconchip.com.au
Here’s the complete (!) project attached to the iCEstick, which in turn
plugs into a free USB socket.
Operating principles
We’re generating a 640x480 pixel
1.1kW
CON1
7
2
8
3
9
4
10
5
11
6
12
Fig.1: the circuit for
our VGA adaptor is
TO iCEstick
delightfully simple,
since so much of the
hard work is done
SC
by reconfiguring the
20 1 9
blocks inside the FPGA.
Three resistive two-bit DACs are formed
by the 1.1kand 560resistors, to
control the red, green and blue voltage
levels on the VGA connector. The HSYNC
and VSYNC pulses are digital signals
fed straight to the VGA socket, with 68
series resistors for safety. The unusual
pin numbering of CON1 is to match the
numbering on the iCEstick; they are
treated as two side-by-side SIL headers,
even though it’s physically a DIL header.
CON1
6
VGA OUTPUT
CON2
560
RED
1.1k
GREEN
560
BLUE
1.1k
560
6
1
7
2
8
3
9
4
10
5
1.1kW
11
12
13
HSYNC
14
VSYNC
15
2x
68
icestick VGA ADAPTOR
siliconchip.com.au
1
2 3 4
560W
CON2
VGA
out
560W
7
1
(under)
to
iCEstick
1.1kW
560W
68W
1.1k
1
VGA signal, which involves scanning
800x525 pixels. The extra pixels are
hidden in black borders outside the
normal display area of the screen (in
the front/back porch and rescan areas).
For a standard 60Hz monitor update
rate, we need a 25.2MHz pixel clock
(800 x 525 x 60Hz).
Our alphanumeric terminal occupies a central 512x384 pixel region
of the 640x480 display image, with
black borders around the edge. We’ve
done this because the 512x384 pixel
region maps to 32x16 alphanumeric
characters, and 32x16 = 512 which is
the number of bytes in each block of
RAM within the FPGA.
It would be possible to combine
multiple RAM blocks to allow a larger
character display (possibly filling the
screen), but that would complicate the
code design somewhat. Making the relevant changes could be a good exercise
for readers who really want to delve
into FPGA programming.
68W
those voltages are reversed, pin 2 is at
around 1.1V.
By using various combinations of
levels on the red, green and blue lines,
we can generate 4 x 4 x 4 = 64 different colours on the screen.
The 560Ω and 1.1kΩ resistor values
have been chosen to avoid exceeding
the FPGA’s 8mA per pin sink/source
current rating. We found that on some
monitors, this resulted in colours
which were a bit dark, so you may
wish to try slightly lower values (eg,
470Ω and 910Ω or 430Ω and 820Ω).
If you are unsure, stick with the suggested values.
All timing and signal generation
is done within the FPGA. We won’t
claim the output is fully VGA compliant, but we have had no troubles
using it with a few different monitors
we used for testing.
12
the iCEstick into signals which are fed
to the VGA connector, to generate VGA
video. The circuit diagram of this addon board is shown in Fig.1.
The horizontal synchronisation
(HSYNC) and vertical synchronisation (VSYNC) lines are effectively
fed digital pulses via series resistors,
which provide a degree of protection
to the FPGA in case of static electricity and so on.
The red, green and blue VGA signals
are formed by primitive 2-bit DACs,
made using pairs of resistors in a 2:1
ratio, giving four evenly spaced voltage
levels between fully off and fully on.
For example, if pins 3 and 9 of CON1
are held low (0V), then 0V is applied to
pin 2 of CON2, the green signal. If both
these pins are high (3.3V), then pin 2
of CON2 is at 3.3V. If pin 3 of CON1 is
high (3.3V) and pin 9 is low (0V) then
the voltage divider formed by the 560Ω
and 1.1kΩ resistors means that around
2.2V is fed to pin 2 of CON2, while if
SC
20 1 9
Fig.2: fit the resistors to the PCB
where shown here, then the VGA
socket, which goes on the same side
as the resistors, and finally the 6x2
pin header, on the opposite side.
The resulting assembly then plugs
straight into the iCEstick and a
standard VGA monitor cable.
5
6 7 8 9 10
11 12 13 14 15
VGA socket – looking at pins.
Australia’s electronics magazine
April 2019 59
Screen1: this is a broad map of the functional parts of the “iCEstick VGA Terminal.ice” project. You will need to
install IceStudio, download and open that file and zoom in to see the detail of each block.
The FPGA scans the 800x525 area,
uses its video RAM to determine
which character should be displayed
at any given point, then uses the font
ROM to determine whether the foreground or background colour should
be displayed for each pixel. The
HSYNC signal is pulsed at the end of
each horizontal scan (ending a line),
and the VSYNC pin is pulsed every
vertical scan (ending a frame).
Generating the clocks
Since the iCEstick only has a 12MHz
oscillator, we need to use the iCE40HX-1k’s phase-locked loop (PLL) to
bring that up to around 25MHz. We are
generating a 100.5MHz signal, which
we divide by four to get 25.125MHz.
This is the closest the PLL can get to
our target frequency of 25.2MHz, using a 12MHz source. This small error
doesn’t end up causing any problems.
This clock signal is divided by a
factor of 800 in the FPGA, to give a
31.4kHz line clock, then again by 525
to give the frame/screen refresh clock
of 59.8Hz. That’s 0.2Hz slower than
our target of 60Hz, but it isn’t uncommon to see video refresh rates that are
not an exact number of hertz, and virtually all monitors will handle this.
We have created a 10-bit horizontal pixel counter in the FPGA which
starts at zero and counts up to 799,
Fig.3: this shows
how font glyphs
are converted into
bitmap values, by
adding the value
of the pixels that
should show the
foreground colour.
IceStudio expects
hexadecimal
numbers in the font
ROM, so you will
need to convert
the decimal sums
to hexadecimal
format (eg, using
a programmer’s
calculator).
60
Silicon Chip
Australia’s electronics magazine
incrementing on each clock pulse (at
25.125MHz), then resets back to zero.
Each time it resets, the 10-bit vertical pixel counter is incremented, and
it’s reset to zero as soon as it exceeds
524. So these two counters allow us to
keep track of which pixel is currently
being emitted.
When these pixel values are within
the 512x384 active area in the middle
of the screen, they are further divided
by 16 (horizontal) and 24 (vertical) to
determine which character position is
currently being displayed. The FPGA
then retrieves the 8-bit ASCII character value and two 4-bit colour (background/foreground) values from its
video RAM.
The 4-bit colour values are then
used to look up the 16-entry palette
to determine the 6-bit colour values
to use as the foreground and the background for the character currently being emitted. Similarly, the ASCII character value is used to look up an entry
in the font ROM.
All these lookups culminate in a
pixel colour value which is then fed
to the RGB outputs (pins 2-4 and 8-10).
At the same time, the HSYNC (pin 1)
and VSYNC (pin 7) lines are driven
based on the horizontal and vertical
counters, to generate the required sync
pulses for the monitor.
siliconchip.com.au
Screen2: if you have successfully built the hardware and
programmed the FPGA, you will be greeted by this display
on your VGA monitor.
In more detail, when the horizontal
pixel counter is between 0-511, that is
the active part of the display, and the
RGB outputs are driven. The rest of the
time, the RGB outputs remain low, so
the front porch, back porch and borders are black. When the horizontal
counter is between 592 and 688, pin 7
is set high, creating the HSYNC pulse.
Similarly, the vertical (line) pixel
clock counts from zero to 524, with
the RGB outputs active from 0-383,
and VSYNC is driven high on lines
443-445. The lines between 446 and
524 are the vertical refresh period, so
the RGB outputs remain low.
These sync values have been chosen
by trial and error, to centre the display
on our test monitor.
They can be changed in the FPGA
configuration to adjust the location on
your monitor, although the differences between the values should remain
the same to maintain the same sync
pulse widths.
Implementing this in the FPGA
We’re using the IceStudio software
to demonstrate what can be done using this software, and while the IceStudio project looks quite complicated,
it can be broken down into small, easy
to understand functional blocks that
each accomplish one small task.
We hope this gives you an insight
on how easy it is to jump into creating
your own projects with Verilog inside
IceStudio; keep in mind as you work
with FPGAs that the outcome is actually an arrangement of logic gates and
flip-flops that all work simultaneously, rather than code that is processed
in sequence.
Screen1 shows the IceStudio project in its entirety. The FPGA is configured by connecting various blocks
together, and we’ve labelled groups
siliconchip.com.au
Screen3: in the window that appears after clicking View
→ Command Output, the folder containing the generated
Verilog file is visible (highlighted section). Open this folder
and find the file named “main.v”, which is the generated
Verilog equivalent of the IceStudio project.
of blocks to indicate their purpose.
If you want to examine the design in
more detail as we explain what each
block does, skip to the section below
titled “Installing the software on your
computer”, then come back and read
the following description.
Clock generation is performed by
the area marked PLL in the project
window. The code in this block contains synthesiser directives that describe how to configure the PLL. The
iCEcube2 software that we reviewed
in our iCEstick tutorial on page 32 is
capable of generating PLL configuration data if you want to experiment
with this block.
To the right of the PLL block and the
left of the HSYNC/VSYNC sections are
the clock dividers.
The small blue block divides the
100.5MHz clock by four to give the
25.125MHz pixel clock, which is then
divided by 800 to give the line clock.
This is in turn divided by 525 to give
the frame clock.
The ACTIVE VIDEO DETECT sectioncompares the pixel and line clocks
to the fixed values indicated above,
producing two outputs which are both
high when the current pixel is part of
the 512x384 pixel active area. These
are fed to the colour decoder, which
generates black unless both (horizontal
and vertical) active video bits are set.
Below ACTIVE VIDEO DETECT is a
section which divides the pixel count
by two to create indexes for the font
ROM. The line count is effectively divided by three, to create the vertical
font index.
But rather than using a divider,
which would be quite large and complex to implement in the FPGA, instead, a separate counter is used,
which is only incremented on every
third pulse from the line clock, then
Australia’s electronics magazine
reset when it reaches 128 (ie, 384 ÷ 3).
Serial data handling
The FPGA needs to accept serial
data from the host, both for configuration and to update the displayed
characters and/or colours. The UART
block is shown to the left of the PLL
in Screen1. This is made using opensource Verilog code that is available
at https://github.com/cyrozap/osdvu,
which also includes a description of
how to interface to it.
We don’t need to send any data back
to the host, so we removed the transmit-specific sections, to save FPGA
resources.
While a microcontroller would wait
and then branch to code to read from
a buffer when the host is sending data
to it, the FPGA is always ready to react, and the data from the UART is
put into the video RAM within nanoseconds of it arriving, simultaneously
with the video output tasks occurring
elsewhere on the chip.
The UART decoder filters the incoming serial data and also holds a vid-
Parts list – iCEstick
VGA Terminal
1 Lattice iCEstick FPGA development
board
[Mouser 842-ICE40HX1KSTICKEV,
Digikey 220-2656-ND]
1 double-sided PCB, code 02103191,
49.5 x 32mm
1 2x6 male pin header (CON1)
1 DE-15 (or HD-15) high-density 15pin female D-connector (CON2)
[AMP 1-1734530-1,
MULTICOMP SPC15430]
Resistors (all 1/4W 1% metal film)
3 1.1kW 3 560W 2 68W
April 2019 61
Screen4: the default character map/font for the iCEstick VGA
Terminal. It can be changed by editing the font ROM blocks.
The first three lines are the standard ASCII characters at
positions 32-127, followed by some pseudo-graphics characters that can be used to draw boxes, bar graphs and so on.
eo RAM pointer. This filtering checks
the three high order bits of each received character. If all of these are low,
then received serial data ASCII value
is less than 32. That means that it is
a control byte and processed as such.
The control bytes work as follows.
A carriage return (code 13) causes the
video RAM pointer to be reset to the
start of its line by ANDing its value
with 32. A line feed (code 10) moves
the pointer to the next line by adding
32, and a form feed (code 12) moves the
cursor to position zero by resetting the
pointer, as though starting a new page.
If the received data value is 32 or
higher (and thus an ASCII character),
the received character is written to the
video RAM at a position corresponding to the pointer’s value and the pointer is incremented by one. Thus characters received consecutively appear
at consecutive locations on the display
The currently selected foreground
and background colour combination is
also written to a separate RAM which
is used to later decode the colour data
for display.
Other control codes are decoded by
the small block to the left of the colour
decoder. Code 14 sets a flag so that the
background colour is set, while code
15 sets the flag to the foreground. If a
value from 16 to 31 is received, it is
sent to the foreground or background
register per the flag.
Because all except the lower four
bits are ignored here, code 16 selects
colour 0 and code 31 selects colour 15
from the palette.
Screen6 shows the default palette
of colours that are available.
The video RAM section takes an
62
Silicon Chip
Screen5: the RX (receive) pin of the UART module can be changed using
this drop-down box. Not all pins in the list can be used; for example, we
are already using all the PMOD pins for the VGA output.
address value made from combining
parts of the horizontal and vertical
‘scan’ position. The small code box on
the left just combines the bits to create
a linear address.
Video RAM
The larger box is the video RAM
itself. This has been coded in a specific way to use part of the iCE40HX1k’s BRAM (block RAM). If not done
in quite the right way, the memory is
synthesised from flip-flops instead of
using the dedicated block RAM. This
alternative is a very poor use of resources; as an experiment, we tried
this, and found that the 512 bytes of
RAM took about half of the FPGA’s
flip-flop resource.
The iCE40HX-1k contains 16 separate 512-byte blocks of double-ported
RAM. The double-port feature means
that it can be read and written at the
same time, which is essential in our
application because we may be trying
to change the display at the same time
that the VGA display logic is reading
from it (as it is reading video RAM almost constantly).
The small beige block above the
video RAM initialises it at startup to
display some splash-screen text. If you
Australia’s electronics magazine
don’t want this, replace the contents
of the beige block with zeroes, or your
own hexadecimal values for a custom
splash screen.
The small block to the right of the
video RAM generates an address into
the font ROM, based on the displayed
character value from video RAM and
the vertical position of the scan.
Font ROM
The font ROM consists of three
BRAM blocks, each fed by a separate
initialising block. While implemented
using RAM blocks, there are no connections to the write lines, so they remain unchanged as long as the FPGA is
powered, and are effectively read-only.
By using multiple BRAM blocks and
a four-way multiplexer, we can overcome the 512 byte limit of each block
(hint: this might be a good way to expand the video RAM). Each BRAM
block encodes 64 characters in eight
bytes each, for a total of 512 bytes.
There’s room to add a fourth BRAM
block below, but we only need 192
characters in the font ROM, so we have
not done so.
Each byte of the font ROM encodes a
horizontal line of eight pixels as a bitmap. The small block next to the font
siliconchip.com.au
Screen6: these
are the colour
combinations that
can be displayed
by the iCEstick
VGA Terminal.
The characters
shown at each
column are
combined with
the Control key
to create the
foreground colour
shown in many
serial terminal
programs. These
16 colours are
selected from a
set of 64 possible
colours; you can
modify the ROM
values in the
IceStudio project
to choose different
ones.
ROM decodes the horizontal character
sub-position into a single bit; it is effectively an eight-to-one multiplexer.
The output of the font ROM is a single
bit indicating whether the foreground
or background should be displayed for
the current pixel.
Colour
In a similar fashion to the way the
video RAM is read, data is read from
the colour RAM to determine the
combination of foreground and background colours to be displayed at the
current scan position. This is a separate RAM block that uses the same address and clock lines as video RAM
as its input. The output of the colour
RAM is fed to the colour decoder.
The colour decoder has a pair of
small 6x16 bit ROMs, which are initialised by the beige blocks above them.
These decode the 4-bit colour palette
index value into the necessary output
pin states to generate that specific colour in the palette. The two blocks are
identical; one is used to decode the
foreground colour and one the background colour, to simplify the following logic.
The colours have been chosen based
on those used in the venerable Comsiliconchip.com.au
modore 64, which also had a 16-colour display.
To the right of the ROMs are a row
of multiplexers, one for each output
pin involved in driving the VGA colour lines. The multiplexer chooses between the foreground and background
colours according to the line from the
font ROM.
This is followed by an AND gate.
The data from the multiplexer is
ANDed with a bit that indicates if the
current scan position is inside the
central 512x384 pixel box, in which
case the foreground or background
colour is produced. Otherwise, the
result is low, so the outputs of all the
AND gates are low and therefore all
the output pins are low and black is
displayed.
Finally, a D-flipflop is used to buffer this signal into the output pins, so
that their states only change on the
pixel clock. This ensures our pixels
are not subject to jitter and thus line
up squarely on the screen. The result
is a very stable display.
Installing the software on
your computer
To build this project, you need to
install the IceStudio integrated develAustralia’s electronics magazine
opment environment (IDE) software.
There are versions available for Linux,
Windows and macOS. If you’ve been
reading our FPGA tutorial, starting
on page 32, you may have already installed it. Otherwise, follow the installation instructions at: https://github.
com/FPGAwars/icestudio
We used version 0.4.0. Once installed, you should also install the
toolchain and enable the driver for the
iCEstick (only needed on Windows).
If you’re unsure how to do this, read
the aforementioned tutorial, which explains this in detail, or read the IceStudio documentation at: https://icestudio.readthedocs.io/en/latest/
Now download the “iCEstick VGA
Terminal.ice” file from our website
and open it in IceStudio. You will see
something similar to what’s shown in
Screen1 above, and you can now examine the blocks in closer detail.
If you need to change any of the
configuration parameters, such as the
serial port baud rate, these are ‘hard
coded’ into the project, so you will
need to change the .ice file using the
IDE graphical interface.
Other settings that can be changed
include the colour palette and font
glyphs. Details on how to change all
these parameters are given below.
By default, the serial interface is
connected to iCEstick’s USB/serial
converter IC, but this could be remapped to an external I/O pin for interfacing with a microcontroller such as
an Arduino board or MicroMite.
Construction
As you can see from the PCB overlay diagram, Fig.2, there are few components on the board so it shouldn’t
take long to build.
The board is coded 02103191 and
measures 49.5 x 32mm.
Start by fitting the two 68resistors;
these are closest to CON2. Bend the
legs at right angles, put through the
holes and splay the legs to hold in
place. Solder and trim the leads just
above the solder fillet on the reverse
of the board. Fit the 560Ω and 1.1kΩ
resistors using a similar procedure.
Now mount the VGA socket next,
ensuring it is properly seated and
flush with the PCB. Solder the larger
mechanical pins, turning up your soldering iron temperature if necessary.
Carefully solder the fine pins of
the signal lines to avoid bridging adjacent pins.
April 2019 63
“[“, “\”, “]”, “^” and “_”, respectively.
You can now use the iCEstick VGA
Terminal as-is, or you may wish to experiment further to see what is possible with IceStudio.
Debugging the project
The VGA Adaptor simply plugs into
the matching socket on the iCEstick
PCB, while the socket at left connects
to the VGA screen/monitor.
You may find it easier to work with
the centre row of pins first, and ensure
that they are soldered and tidy before
accessing the outer rows, which have
more surrounding space to work with.
Finally, fit the 2x6 pin header. This
sits underneath the PCB, on the opposite side to the other components, and
is soldered from the top.
Avoid excessive heat, as this may
melt the plastic shroud, putting the
pins out of alignment.
Check that there are no solder bridges or short circuits, and plug the board
into the PMOD header of the iCEstick.
The VGA socket faces away from the
USB plug of the iCEstick.
Plug a VGA cable from the VGA
socket to a monitor or television.
Building and uploading the
code
With the “iCEstick VGA Terminal.ice” file open in IceStudio, select
the iCEstick from the Select → Board
menu. To synthesise the design, click
Tools → Build, and when the green
“Build done” message appears, click
Tools → Upload.
The keyboard shortcuts for these
commands are Ctrl-B and Ctrl-U respectively.
Now connect a VGA monitor and
check to see if you have a display,
similar to that shown in Screen2. If
you have a terminal program installed,
such as TeraTerm, PuTTY or even the
Arduino IDE, figure out which serial
port the iCEstick is using and open
a connection to it at 9600 baud with
eight bits, no parity (8-N-1).
Type into the terminal, and you
should see text appear on the screen.
If the ‘Enter’ key generates a CR/LF
pair in your terminal program, pressing Enter should cause subsequent text
to appear at the start of the next line.
Assuming your terminal program supports control codes (which most do,
except for the Arduino IDE), you can
change the colours by using control
key combinations.
ASCII control codes 1-26 correspond to pressing Ctrl and one of the
letters A-Z on the keyboard; as A is
the first letter of the alphabet, Ctrl-A
sends control code 1. Press Ctrl-N or
Ctrl-O to switch between setting the
foreground or background colour, and
press Ctrl-P through to Ctrl-Z to change
that colour.
The five remaining codes between
27 and 31 map to a combination of
Ctrl plus another key, those keys being
WOW! A high performance, Arduino-based, digital
LC METER
that measures from
PicoFarads to Farads &
NanoHenries to Henries!
See SILICON CHIP
June 2018
(Article 11099)
Uses Arduino Uno
Just look at these incredible features:
(or equivalent)
Inductance measurement range 10nH – 1H (+) l Capacitance measurement range 0.1pF – 1F (+)
l Advanced calibration l Continuous drift compensation l Long-term averaging l Automatic component detection
You’ll find this advanced Digital LC Meter is one of the handiest devices you can have on your workbench!
l
Specialised and hard-to-get parts are available from the SILICON CHIP Online Shop:
PCB (incl. headers)
20x4 alphanumeric LCD
1nF 1% NPO/C0G capacitors
Custom laser-cut Acrylic Case:
(SC 04106181) $750
(SC 4203) $1500
(SC 4273) (Pk 2): $500
(SC 4609) $750
All other components (including Arduino Uno) are commonly available from your normal parts supplier
64
Silicon Chip
Australia’s electronics magazine
While the block-and-wire methodology of creating a design does not leave
much opportunity for errors, manually
entered code blocks certainly could be
erroneous, and thus can cause a build
error. In this case, you will see a red
bar appear instead of “Build done” after attempting a build.
It’s possible to view the entire Verilog file that is generated during the
build process. IceStudio converts the
graphical design into a text-based (Verilog) HDL file, then builds that into the
binary bitstream. That’s an intensive
process which involves figuring out
which FPGA resources can be used to
create the required logic and how they
should ideally be interconnected, so
it can take some time.
To view the generated Verilog,
click on the View → Command Output menu option and open the folder
shown in Screen3. In this folder, there
is a “main.v” file, which is the Verilog
code that IceStudio has generated.
If you do get a build error, scroll
towards the bottom of the Command
Output window and you should see
an error message indicating the line
number on which the error occurred
(and the nature of the error). This, in
combination with the generated Verilog, should help lead you to the source
of the error.
It’s a good idea to open “main.v”
in a text editor which displays line
numbers. When building the project,
you may also see some warnings; most
warnings can safely be ignored.
Verilog code blocks
Now that you know how to debug
the code, you may wish to dabble with
the Verilog inside the code blocks in
this project. Here are some tips to get
you started; but don’t think this is the
complete book on Verilog coding! Like
the C language, all statements end with
a semi-colon.
Some lines in the Verilog code are
direct assignments, such as the following used to generate the HSYNC signal.
These generate simple digital logic:
assign out = ((count < stop) &&
(count >= start)) ? 1 : 0;
siliconchip.com.au
Here, the ternary operator (? :) assigns the “out” register the value of 1
(high) if the value of “count” is less
than “stop” and equal to or greater
than “start”. Otherwise, “out” is assigned the value 0 (low).
This could pass for valid C code,
apart from the ‘assign’ keyword, but
it should be remembered that we are
synthesising hardware in the form of
logic gates rather than compiling machine code.
At a few places in this project, we
want to increment a counter based on
an input, for example:
sidered to occur simultaneously.
If a specific order of assignment is
needed, then the “=” blocking assignment operator can be used to enforce
this, particularly if the result of one
expression depends on the result of a
previous expression.
The memory block demonstrates a
few other features of Verilog. Using this
specific form of assignment is needed
to enforce the use of block RAM, as
mentioned earlier:
reg [7:0] mem [511:0];
always <at>(posedge wclk) begin
if (write_en)
mem[waddr] <= din;
end
reg [9:0] counter = 0;
always <at>(posedge clk)
begin
counter <= (counter ==
div - 1) ? 0 : counter + 1;
clkout <= (counter <
div/2) ? 1 : 0;
end
This code is in the block that divides
the pixel clock down to a line clock.
The first line specifies that “counter”
is a 10-bit register, and is set to zero
on power-up.
The second line indicates that the
following sequence will only occur on
the positive edge of the “clk” signal.
The resulting synthesis will use flipflops to retain the state of the registers
between “clk” pulses.
The begin/end statements are used
to group the two following lines so
that they both occur inside the ‘always’ block.
Here, “counter” is incremented (ie,
its value is increased by one), unless it
has reached one less than the value of
“div”, in which case it is reset to zero.
Thus, “counter” counts from zero
to div-1, which gives us our horizontal pixel position in the “counter”
register.
The “clkout” register is set to one
while “counter” is in the bottom half
of its cycle (less than div/2), and zero
when it is in the top half, thus dividing the incoming “clk” signal by the
ratio of “div”.
This “clkout” signal is fed into another similar code block, so that every
time the horizontal counter reaches
zero, the vertical counter is incremented. This is how our raster is generated.
You might note that these registers
are loaded with a “<=” symbol instead
of a “=”.
The “<=” means that they are nonblocking assignments, so they are consiliconchip.com.au
always <at>(posedge rclk) begin
dout <= mem[raddr];
end
initial begin
if (MEM)
$readmemh(MEM,mem);
end
Note that the CLOCK_DIVIDE value
is determined by dividing 12,000,000
by four times the baud rate (or
3,000,000 divided by the baud rate)
and choosing the next lower integer.
Choosing the next lower integer
means the baud rate is slightly faster
than desired, but this will handle receiving a steady stream of characters
better than a slightly slower baud rate.
Changing the font
The font ROM consists of groups of
eight 8-bit hexadecimal values inside
the three FONT blocks. The top-most
block encodes ASCII codes 0-63, the
second 64-127, and the third 128-191.
The most significant bit is at left,
and the least significant bit at right,
with the data in rows in order from
top to bottom.
Refer to Fig.3, which shows how the
letter “A” is encoded (it is found at addresses 0x08 to 0x0F near the top of
the second font ROM block).
The whole font is shown in Screen4.
Changing the colours
The first line defines an internal register file “mem”, which has 512 (5110) eight-bit (7-0) elements, effectively,
an array. The first “always” block is responsible for writing to the memory,
where the 8-bit value “din” is stored
at position “waddr” in “mem” on the
positive edge of “wclk”, but only if
“write_en” is high (one).
The second “always” block performs a read, loading the value of
the memory (mem) at “raddr” to the
“dout” register on the rising edge of
“rclk”. Block RAM is always synchronous (requiring a clock) on the iCEstick’s iCE40HX-1k.
The colours are formed by a similar
bitmap, with sixteen 6-bit hexadecimal entries.
The two most significant bits are
for the blue level, the middle two bits
for the green, and the bottom two bits
for red.
Thus 0x00 is black and 0x3F is
white, as per the first two entries, with
the third entry 0x03 being red.
Because the foreground and background colours are stored in separate
ROMs, you could provide different
colour maps for each, but that might
be a bit confusing to use.
Changing the baud rate
Finally, you may wish to map the
serial data to a different pin, so you
aren’t using the USB/serial converter.
This is done by changing the pin connected to the “rx” input of the UART
module, as shown in Screen5.
We recommend using the “TR” or
“BR” groups of pins for I/O; these are
the rows of solder pads along the edges
of the board.
Refer to the iCEstick manual to
check which pin is which.
Take care as the pins are only rated
for 3.3V I/O levels, so directly connecting a 5V microcontroller is not
recommended, and a level converter
or voltage divider should definitely be
used in that case.
SC
We suggested earlier that some of
the features such as baud rate, graphics and colours can easily be modified.
The baud rate is controlled by a single
value within the UART block.
Around line 26 inside the UART
block is the definition of the CLOCK_
DIVIDE parameter.
You can select 115200 baud by
commenting (adding ‘//’ to the start
of) this line:
parameter CLOCK_DIVIDE = 312;
of
and removing the ‘//’ from the start
//parameter CLOCK_DIVIDE = 26;
Australia’s electronics magazine
I/O pin assignments
April 2019 65
|