EECS 373 Lab 3: Introduction
to Memory Mapped IO
Copyright © 2012
See posted lab schedule for due dates, in-lab, and post-lab due dates.
Microprocessor chips generally include many system components such as
memory, standard peripheral interfaces, interrupt controllers, Ethernet
interfaces,etc and are more accurately referred to as SOCs or a system
a chip. Recently, manufactures have included FPGAs as yet another
component. The FPGA is generally "connected" to the microprocessor
a system peripheral bus.
In this lab we will explore how to develop custom peripheral hardware
SmartFusion FPGA using the Libero CAD tools. In addition, you will
learn the fundamentals of memory mapped IO (MMIO). You will learn how
to interface the ARM peripheral bus (APB3) to registers created in
There is no Pre-Lab assignment for this lab. However, the In-Lab is a
tutorial that you can begin and potentially complete on your own. Feel
free to get started although you may eventually require instructor
The In-Lab assignment is a tutorial listed in the references on the
side bar. For the most it is directed or cookbook. It is designed
to give all the background you need to create custom hardware in the
FPGA that is interfaced to the Cortex M3s peripheral bus. Be sure
and take advantage of the staffed hours for support for pesky CAD tool
For the post lab you will provide software and hardware that will allow
you to toggle a LED from 2 times per second to once every 3
seconds. The rate will be controlled with the push buttons. One
push button will be used to increase the rate and the other push button
to decrease the rate. For example, to increase the rate each push of a
button will increase the from a 1/2 second period to a 3 second period
in increments of 1/2 second. See the following table.
One way of doing this is to create a software delay loop for 1/2
second, create an MMIO registers for the switches and LEDs and
simply adjust the loop delay in response to switch presses.
While the software delay would be adequate for this type of
application, software delays can vary from system interrupts, changes
clock speeds, compilation optimization and other factors.
Hardware timers are generally provided in systems to avoid these
effects operating independently of the processor. We will create our
own simple hardware timer in the FPGA and
interface to it with MMIO registers.
The Timer Design
To simplify the timer design, we will use a down counter. You will need
to create a Verilog counter that will can be loaded with a starting
value (Pre Loadable Counter). The counter will decrement for each clock
transition. When the counter reaches zero, it should stay in that
state until a counter starting value is loaded into
At 100MHz you will need
300,000,000 counts for a 3 second delay or log(base 2) of 300,000,000 =
28.16 bits. So the counter register must be at least 29bits. To
accomodate signed numbers, you will need one more bit. Since the
synthesis tool will like extend a 30 bit counter to a 32 bit primitive
on the FPGA, you might as well make it a 32 bit counter.
So, down counting from 300,000,000 should take 3 seconds . Down
counting from 50,000,000 should take 1/2 second.
Although a Verilog 32 bit down counter that stops at zero
count may seem simple at first , a good
synchronous design is not immediately obvious. To that end, the
following working down counter Verilog is provided. Be sure to use this! The "data_in
and data_out" are generalized data paths or ports to the counter. You
can change these or connect to them as necessary. Note, in the
following context data_out should be declared as a 32 bit reg.
//32 bit down counter with read/write counter register
reg [31:0] counter;
always @(posedge PCLK) //io register interface to timer
if ( (counter < 32'h7FFFFFFF) && (counter > 32'h1) ) //limit counting to signed numbers
counter <= counter - 1;
counter <= 0;
data_out <= counter;
counter <= data_in;
Timer APB3 Interface
The interface needs to be read/write so the application software can
set the starting value and monitor the count value. Refer to the MMIO
tutorial to see how the andor read write APB3 register is implemented.
It is possible to interface the counter register directly to the APB3
data path. Like the andor example in the tutorial, combine your
application specific logic (the timer) and the APB3 interface in the
same Verilog file.
Switch Debouncing and APB3
To increment or decrement your timer you will need to detect push
button transitions or edges. Since the switches bounce, more then
one high to low transition can occur for a single swtich press or
release . To debounce the switch you first synchronize the switch to
the system clock and then sample the switch after an estimated bounce
One way to do this is discussed here. A
slightly adapted version of the code is provided below. Use PCLK for
the clk., bouncy switch source for PB and debounced switch for PB_state.
module PushButton_Debouncer(clk, PB, PB_state);
input clk; // "clk" is the clock
input PB; // "PB" is the glitched, asynchronous, active low push-button signal
output PB_state; // 1 while the push-button is active (down)
// First use two flipflops to synchronize the PB signal the "clk" clock domain
reg PB_sync_0; always @(posedge clk) PB_sync_0 <= ~PB; // invert PB to make PB_sync_0 active high
reg PB_sync_1; always @(posedge clk) PB_sync_1 <= PB_sync_0;
// Next declare a 16-bits counter
reg [15:0] PB_cnt;
// When the push-button is pushed or released, we increment the counter
// The counter has to be maxed out before we decide that the push-button state has changed
reg PB_state; // state of the push-button (0 when up, 1 when down)
wire PB_idle = (PB_state==PB_sync_1);
wire PB_cnt_max = &PB_cnt; // true when all bits of PB_cnt are 1's
always @(posedge clk)
PB_cnt <= 0; // nothing's going on
PB_cnt <= PB_cnt + 1; // something's going on, increment the counter
if(PB_cnt_max) PB_state <= ~PB_state; // if the counter is maxed out, PB changed!
The ABP3 interface need be read only. Refer to your tutorial example as
a reference. You can combine the debouncer above and the APB3 interface
Verilog into one file. You will have to port for 2 switch inputs.
LED ABP3 Interface
This need be a write only APB3 interface with a port for one LED.
MMIO Organization for the Timer
- Get started early on the post lab and take advantage of the
hours. There are many steps to this design that can be troublesome and
take time to debug.
- You can modify the andor tutorial project to develop
but we recommend starting a new project.
- Not all errors are revealed with Verilog syntax check or design
rules checks. Many error will not be revealed until synthesis. It
will be updated in the
top_level design when you close Synplify. Also, Use the Synplify
debugging information suggestions introduced in the tutorial.
Alternatively, Click on
the error log button in Synplify application and look for the error
messages. They are usually very descriptive. You can click on the error
and it will take you to the file. You can even modify the file with
Synplify, save and try to Synthesize again without returning to Libero.
When you close Synplify, you will prompted to update the
Summary of Steps to Create Custom
Hardware With Libero
Refer to the andor tutorial you did for the In-Lab
- Create a Libero project
- Create MMS component (timer_mss) consisting of:
Create Smart Design component (timer_top) and set as "Root" or
top level design.
Instantiate MMS component (timer_mss) in timer_top.
Create a Switch APB3 interface and instantiate
Create a LED APB3 interface and instantiate in
Create a Timer APB3 register interface and
instantiate in timer_top.
Add an APB3 core with 3 slave ports.
Make all connections in timer_top.
Save timer_top and Generate
Synthesize and Check for Errors!
Provide Pin Connections to LED and Switches
Place and Route, Generate FPGA file(Designer)
- Master Reset to Fabric
- Clock to Fabric
- APB3 Master Fabric Interface
Suggested Development and Debugging
- Begin by testing the switches and LEDs. Write a simple read/write
software loop like the one in the tutorial to test.
- Test the timer by setting a break point immediately after
writing a starting value and then reading the timer. You should see a
few decrements in the read value from the starting value. Add a few
instruction in between the write and read if necessary.
- If steps one and two work, set the blink rate to 1Hz and see if
- Finally, add software to modify the blink rate with the switch
Post Lab Deliverables
1) Provide a copy of your
2) Provide a copy of your timer and switch APB3 register interface
3 ) Demonstrate the operation of your timer and software
application on or before
the due date to one of the 373 lab instructors.
4) Answers the following questions:
Revise answer sheet.
- What addresses generate the PSELs for the Switch, LED and Counter
- What is the maximum delay possible with this timer application
assuming the counter register uses signed numbers?
- What delay in ms does the above debouncer example provide to 2
You can use the Answer
Sheet to provide the dated
signature, answers to the questions and group identification.
If you sample the switches after the timer delay, you will have to wait
as much as 3 seconds. To make the switches more responsive, you need to
detect the edges in the delay loop. Modify your software to detect
switch presses in the dealy loop for faster response and extra credit.