Lab 2A: Build a Test Bench Room Builder

Table of Contents

Introduction

As you hopefully remember from the previous lab, our long term objective is to help guide a bear through the following maze.

Figure 1: Maze to the Forest

Towards that goal, in this lab you be writing code to create a software test-bench that can generate all the rooms by reading the left-most 4-switches, and turn on and off direction indicator LEDs based on the right-most 2-switches. To help you remember how everything should operate by the end of this lab, I have generated the following reference card.

PRINT OUT THE MAZE (FIGURE 1) AND THIS REFERENCE CARD (FIGURE 2) AND ALWAYS KEEP THEM WITH YOUR BOARD.

What is a Test Bench?

Over the semester, you will be writing assembly code subroutines to help our bear find his way out of the maze. But how do you know that a subroutine works unless you have built the whole thing? Testing subsystem elements has been a challenge since before computers were even invented. For electrical components, it was traditionally done on a “test bench” which was equipped with power supplies and signal generators to provide the input to the Device Under Test (DUT), also referred to as a Unit Under Test (UUT), and Volt Ohm Meters (VOM) and oscilloscopes to measure the output of the DUT. We have carried this nomenclature forward into the world of computer engineering.

To help us test our future software modules (DUTs), we will build a simple test bench comprised of switches to provide our inputs and the 7-segment display to let us view the output. As our design matures, we will no longer need our test bench and in fact in the latter labs you will not even use the switches. Specifically, in this lab, you will use the switches and seven-segment display to draw the different rooms that our bear may encounter in any maze and to provide him with directional information.

Ironically, one of the most difficult parts of any project is understanding what you (or the customer) want. Applying this principle to the task at hand, one of the most difficult parts of any lab is trying to understand what the instructor wants. To help you understand the overall objectives of a lab, I will from time-to-time include an “Owner’s Manual.” In these sections I will talk about how your program should operate when completed.

What is New?

Here are some of the new concepts you will be exploring in this lab.

  • Working with Bits
  • More on Simulation and Debugging
  • Uploading to the Arduino

The following instructions and assembly directives are used in Labs 1 and 2. New items are underlined.

AVR Assembly Instructions

Data Transfer
mov r8, r7 // Move data from register r7 into register r8
in r7, PINC // Input port C pins (0x09) into register R7
out PORTB, r7 // Output to Port B from register R7
Arithmetic and Logic
clr r16 // Clear register r16
ser r17 // Set register r17
Control Transfer
call WriteDisplay // Subroutine Call
rjmp loop
Bit and Bit-Test
bst r7,7 // Bit store from register r7 bit 7 to SREG T bit
bld r8,6 // Bit load from SREG T bit to register r8 bit 6

AVR Studio Assembly

Directives
.DEF spiLEDS = r9 // Replace spiLEDS with the text r9
.EQU seg_a = 0 // Replace seg_a with the number 0
.CSEG // Code Segment
.ORG 0x0000 // Code Origin
.INCLUDE “spi_shield.inc” // “ “ means the file is in the project folder
.INCLUDE  // < > means the file is in the AVR Studio folder
Labels
loop:
Comments
; // /* */

Working with the Arduino Shield

You will be using your Lab 1 spi_shield file for the remainder of the semester. Before we begin, let’s review how to use the subroutines included in spi_shield.inc.

To read the switches on the Arduino Shield, you call an assembly function named ReadSwitches which will return the state of the switches in register r6. To turn ON and OFF the 8 discrete LEDs on the shield, you write to register r8. To turn ON and OFF each segment of the 7-segment display, you write to register r7. To send the r8:r7 register pair to the Arduino Proto-shield, you call the WriteDisplay subroutine. The switches, LEDs, and 7-segment display on our Arduino Proto-shield implement positive logic, which means that for the switches UP = 1 and DOWN = 0, and for the lights ON = 1 and OFF = 0. Remember: changes made in the r8:r7 register pair (see Note 1) will not be displayed until you call WriteDisplay.

Note 1: The colon “:” means concatenate (i.e., combine) these two 8 bit registers to create a 16-bit register.

Create the Lab2 Project

If you are using a lab computer I would recommend erasing everything in Drive D and using this area for your project. Do not forget to save often. At the end of the lab do not forget to save to your Flash drive.

  1. Open AVR Studio and create a new Project named Lab2 (see Lab 1 for detailed instructions)
  2. Copy over your spi_shield.inc written in Lab 1.
  3. Copy the text in Lab1.asm into Lab2.asm
  4. Update the title block
  5. Build your project and verify you are starting with zero errors and zero warnings.

Add Software Wires to Make a Room

First delete the line wiring the switches to the seven segment display.
mov r7, r6 // wire to 7-segment display
This should leave only the line wiring the switches to the discrete LEDs.
mov r8, r6 // wire to discrete LEDs
Next make the changes to the code after the label loop as shown here.

You should now be able to create all the rooms in the maze by toggling the 4 most significant switches. Let’s make sure by simulating your program.

Debug Workshop 3 – Simulate Your Program

You must complete this section before starting lab 3. You may/will be tested on the information contained in any Debug Workshop plus you will need to demonstrate proficiency with the simulator (i.e., debugger) as part of the sign-off for this lab sequence (both Parts A and B).

Once your program has assembled successfully enter AVR Studio’s debug mode by pressing the Assemble and Run  icon.

If closed, expand the Registers folder in the Processor pane and PORTC and PORTD in the I/O View pane within AVR Studio. Select PORTD. In the window below the I/O View, and shown in Figure 1, you will notice that PORTD has three rows of eight bits, represented by square boxes.

Figure 3: General Purpose I/O Port D Registers

Each box corresponds to a flip-flop or pin as defined in the table “Port Pin Configurations.”

Table 1: Port Pin Configurations
DDRXn PORTXn I/O Pull-up Comments
0 0 Input No Read “Synchronized” PINXn
0 1 Input Yes
1 X Output N/A Write bit to PORTXn

Looking at Figure 1, let’s start with the top row and the Port D Data Direction Register (DDRD). Each box in this row corresponds to flip-flop. As defined in Table 1, if this box is filled in (Flip-Flop DDRXn = 1) then this port pin will be an output. Conversely, if the box is not selected then the port pin will be an input. The second row of Figure 1 may be visualized as a physical Port D pin (PIND). If you want to simulate a change on an input pin, say from a switch being toggled, this is the box you would set (input = 1) or clear (input = 0). The third row contains the Port D register (PORTD). Each box in this row corresponds to flip-flop PORTxn. As described in Table 1, these flip-flops are interpreted differently based on if the port pin is defined as an input (DDRXn = 0) or an output (DDRXn = 1). If DDRXn = 0, then the corresponding PORTXn flip-flop adds (PORTXn = 1) or removes (PORTXn = 0) a Pull-up resistor (see fourth column in Table 1). If DDRXn = 1, then the corresponding PORTXn flip-flop defines the output state of the pin. If you want to see how your program modifies a pin defined as an output, PORTXn is the box you would look at.

For our application, all Port D pins are to be inputs with pull-up resistors assigned to the two most significant inputs wired to the two most significant (left-most) switches. In this case all the boxes in the DDRC (top row) would be empty (logic 0) and the two most significant boxes of the last row would be filled in (logic 1) as shown in Figure 1. Set a break-point at the line that calls our readSwitches subroutine.

Run to this line  and verify that the PORTD registers have been initialized in Figure 1. Next simulate turning on the switch on the left by selecting the left most check-box in PIND. Now step over the call to readSwitches . The subroutine still runs, AVR Studio simply does not show you the step-by-step details. Verify that register R06 = 0x80. This means ReadSwitches read PIND pin 7 and moved it into register r6.

Single step  your program to the line…

bld r7,6

Verify that the most significant bit of register r6 has been copied to the SREG T bit. Based on your program the other SREG bits may be different from the ones shown below. At this time we are only concerned with the T bit.

Now execute the line we are on and verify that the T-bit has been moved to bit 6 of register r7.

From our prelab we know that this corresponds to Segment g on our 7 segment display – a south facing wall

Figure 4: Wiring of Switches to 7 segment display Segments

In a similar fashion, verify that the code you wrote in your pre-lab is wiring the other switches to their respective segments as defined in Figure 2.

Making Your Code More Readable

Open the spi_shield.inc file (double-click in Project window) in AVR Studio.

As touched on in Lab 1 and covered in more detail here in Appendix A, the m328pdef.inc include file makes our code more readable by the use of equates (.EQU) and define (.DEF) assembly directives. The equate assembly directive performs a numeric substitution. Simply put, whenever the assembler encounters text which has an equate assigned to it, it replaces the text with the numeric value defined in the equate statement. For example, in m328pdef, the text PORTD is equated to the number 0x0b.

.EQU PORTD = 0x0b

Consequently, whenever the assembler encounters the text PORTD it substitutes the number 0x0b.

The define (.DEF) assembly directive works in a similar fashion performing a textual substitution. Simply put, whenever the assembler encounters text which has a define statement assigned to it, it replaces the text with the text value in the define statement. For example, in m328pdef, the text XH is defined as meaning the text r27.

.DEF XH = r27

Consequently, whenever the assembler encounters the text XH it substitutes the text r27. Following the lead of m328pdef, I have added a few definition and equates of my own in spi_shield.inc to make working with the proto-shield a little easier.

; SPI interface registers
.DEF spiLEDS=r8
.DEF spi7SEG=r7

; Switches
.DEF switch=r6

; 7-segment display
.EQU seg_a=0
.EQU seg_b=1
.EQU seg_c=2
.EQU seg_d=3
.EQU seq_e=4
.EQU seg_f=5
.EQU seg_g=6
.EQU seg_dp=7

To read the switches on the Arduino Shield you call readSwitches which returns the state of the switches in register r6. Now, instead of writing r6 to look at the switches you can use the more descriptive word switch, which means the same thing (.DEF switch=r6). To turn ON and OFF the 8 discrete LEDs on the shield you used to write to register r8. Now you can use the more descriptive mnemonic spiLEDs (.DEF spiLEDS=r8).

For example here is the instruction wiring the switches to the discrete LEDs.

mov r8, r6 // wire to discrete LEDs

By replacing the register numbers with the more descriptive mnemonics the instruction becomes much more understandable.

mov spiLEDS, switch // wire to discrete LEDs

Now lets make your code more readable. When specifying a single discrete LED bit, the number of the bit was clear enough (7, 6, 5,… 0). For the 7-segment display knowing which segment is which is a little more confusing. The final series of equates lets you specify the segment (bit) you want to work with by name (seg_dp, seg_g, seg_f, …seg_a) as defined in Figure 3 7 Segment display.

Figure 5: 7 Segment Display

Now let’s use our newly created define assembly directives to make our code more readable. For example the two lines wiring the leftmost switch with its corresponding south wall segment…

bst r6,7 // wire switch 7 to segment g (south wall)
bld r7,6
now becomes much more readable..
bst switch,7 // wire switch 7 to segment g (south wall)
bld spi7SEG,seg_g

Following my example rewrite your code to make it more understandable.

This completes Lab 2A. You will be continuing with this code in Lab 2B. The submission for Lab 2 is the combination of both Lab 2A and 2B.

You are finally ready to upload and test your program on your Arduino.

How to Upload your Hex file using AVR Dude

If you have not done so already, download and install AVR Studio, WinAVR, and Arduino IDE from http://www.atmel.com/dyn/products/tools_card.asp?tool_id=2725, http://sourceforge.net/projects/winavr/, and http://arduino.cc/en/Main/Software

If you are running Windows 7 and have an Arduino Duemilanove (not an Arduino Uno) you may need to download the Virtual COM Port Drivers from Future Technology Devices, used by the winAVR software to upload programs to your board.

At this time you should have verified that your Arduino works by uploading and running blink from the Arduino IDE (Integrated Development Environment) and that the Protoshield works by running sketch_shiftOut_16-bit. Instructions are provided in “How to Build the Arduino Proto-Shield.”

Open notepad from your computer and type in the following two commands:

avrdude -p m328p -c arduino -P \\.\COM4 -b 115200 -U flash:w:Lab2.hex
pause

You will need to confirm which com port the Arduino UNO is using, so you may have to change it from COM4 to the correct number. Additionally, the file name has to match exactly. If you named your project lab_2, the file name to use will be lab_2.hex .

In order to save the file as a batch file in the same folder as the project, make sure to add .bat to the end of the name and make sure that the Save as type option is set to all files instead of text document. You can name the batch file whatever you like but it is suggested to be upload328P.bat . You can copy this file and make modifications to the contents in order to upload future labs.

Here is a short description the options and how you will need to modify them. For a complete list of avrdude command line options go to http://www.nongnu.org/avrdude/user-manual/avrdude_4.html#SEC4 her

-p partno Use -p ? option in the command window (Windows - R Open:cmd) to get a list of part numbers 
-c programmer-id You can also use stk500v1
-P port Set to your port number. The \\.\ provides support for com port numbers greater then 7.
-b baudrate For the Arduino Uno keep the baud rate at 115200. For the Arduino Duemilanove change the baud rate to 57600 
-U memtype:op:filename[:format] Enter the name of your file (ex. Blink.hex)
memtype flash The flash ROM of the device.
op w Read the specified file and write it to the specified device memory.

In the future if you need to create a new batch file or if you modified this one; be sure to save the file with a .bat extension (not .txt) in the folder containing your hex file (look in the folder named ‘default’).
To find your port number, in the control panel open the Device Manager, expand Ports (COM & LPT). Look for the Arduino, it should say something like USB Serial Port (COM4).

Using Notepad change the port setting in the upload.bat file to this port number.

To upload your program run the batch file (right-click open or double-click). For the Arduino Duemilanove you may to simultaneously press the reset button. The order is not important; but both must be done within less than a second of each other. Don’t panic if you get it wrong. You will simply see the message including the text “not in sync.” Wait until you see the line “Press any key to continue . . .” press any key and then try again.

Appendix A The m328pdef Include File

Open the m328pdef.inc file (double-click in Project window) in AVR Studio.

Each port register (DDRXn, PORTXn, and PINXn) has its own unique address within both the Data Memory and I/O area of the ATmega microcontroller as defined in Table A.1. For this lab we will use the I/O address of each of our ports.

Table A.1: General Purpose Digital I/O Port Register Definitions

Table A.1 General Purpose Digital I/O Port Register Definitions

You can find the original version of this table in the ATmega328P doc8161.pdf document in Section 30 “Register Summary.” A similar version is in Appendix B ATmega328P Registers and specifically, Section B.1 Register Summary of your textbook. The I/O address of each register is shown on the left (see Table above). The Data Memory address is shown in parenthesis. For example, you can input register PINC from the address 0x06. Where the 0x simple means this is a hexadecimal number (0x06 = 0616).

While we could use the actual address in our assembly instruction; our code is more readable if we use its mnemonic (i.e., PINC = 0616). The “equating” of these mnemonics with their corresponding values is done in the m328pdef.inc “include” document. This is a text document so you can open it in AVRStudio or even Notepad at any time and take a look at what is going on under the hood. Here is the relevant section for our ports…

.EQU PORTD = 0x0b
.EQU DDRD = 0x0a
.EQU PIND = 0x09
.EQU PORTC = 0x08
.EQU DDRC = 0x07
.EQU PINC = 0x06
.EQU PORTB = 0x05
.EQU DDRB = 0x04
.EQU PINB = 0x03

The “dot” tell the assembler that this line is talking to the assembler and not to be turned into a machine instruction. The mnemonic equ tells the assembler to make the following equate. For example, the first line would tell the assembler to replace PORTD with the value 0B16 whenever it comes across it in the assembly code portion of the program.

To have the assembler read (include) the m328pdef.inc text file we use the include assembly directive. One again an “assembly directive” is an instruction to the Assembler; in contrast with an Assembly instruction which the assembler turns into an ATmega328P machine instruction.

.INCLUDE 

Because it is so important to remember when a line is intended for the Assembler (Assembly Directive) and when a line is to be converted to a machine instruction intended for the ATMega328P microcontroller (Assembly Instruction), I always capitalize Assembly Directives and place in lower case letters Assembly Instructions. AVR Studio is not case sensitive, so this convention is not required for your assembly program to assemble correctly – it is however required by the instructor.