Lab 5A: Take a Step and Enter a Room/ Indirect Addressing Mode

At present, you enter the room by hand (SW7 to SW4). In this lab you will write subroutines to teach your bear how to take a step and enter a room. To accomplish your task this lab includes a digital description of the maze. No more room switches!

FUTURE ALERT!
In the PreLab for Lab 06 you will be translating your flowchart from PreLab 1 into an assembly program. If you were asked to plot a new path through the maze, be sure and receive the instructor’s approval before doing the PreLab. If you are not sure, you are responsible for asking.

If you decide to work on the “Congratulatory Tune” section of the Bonus Lab for Lab 6, you will need to purchase an inexpensive speaker and a carbon film resistor, 270 ohms at 250 mW. You will be wiring the circuit as drawn in the Arduino Proto-Shield schematic.

What is New?

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

  • Working with the Indirect Addressing Mode

The indirect addressing mode instruction lpm is introduced in this lab.

Create the Lab05 Project

If you are using a lab computer I would recommend erasing everything in Drive D and using this area for our 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 Lab05 (see Lab 1 for detailed instructions)
  2. Copy over maze.inc, pseudo_instr.inc, spi_shield.inc, testbench.inc, and upload.bat from Lab 5.
  3. Open the upload.bat file in notepad (right-click edit) and change the file name from Lab04.hex to Lab05.hex
  4. Copy the text in Lab04.asm into Lab05.asm
  5. Update the information in the title block.
  6. Build your project and verify you are starting with zero errors and zero warnings.

Cleanup

Before we begin, lets do a little more house cleaning. The items preceded by an empty box ☐ are probably not done and you will need to take some action. The items preceded by a checked box most likely have been completed, but you should double check to avoid debugging your program.

☐ The SRAM variable dir should be initialized so the bear is facing North (dir = 0x03).
☐ Verify that SRAM variable room is initialized so the bear is in an empty room (room = 0x00).
☐ Verify that SRAM variable next_state is initialized to state S0 (next_state = 0x00)

Take a Step and Enter the Room

As mentioned in the introduction, you currently enter a room within the maze by hand (SW7 to SW4). In this lab you will rewrite subroutine TakeAStep and write a new subroutine named EnterRoom to navigate a digital version of the maze (maze.inc). No more room switches! To see how this will work open the Lab05A Arduino Sketch within the Arduino IDE, and follow the steps defined in the “Updated Owner’s Manual” located near the end of this lab.

Add the following code to the output decoder section of state S2.
loop:
:
case_S2:

cpi r20, S2 // test is optional
brne end_switch
// output decoder
:
lds r20, dir // input arguments are dir, col and row
lds r22, col
lds r24, row
rcall TakeAStep
sts col, r22 // update column and row
sts row, r24
rcall EnterRoom // inputs to EnterRoom are outputs from TakeAStep
mov r22, r24 // save a copy of # of bees in the room
cbr r24, 0xF0 // remove the # of bees from the room
sts room, r24 // save the room number
swap r22 // swap # of bees to the least significant nibble
cbr r22, 0xF0 // remove the room from the # of bees
sts bees, r22 // save number of # of bees in the room

Notice that the new code incorporates your original call to TakeAStep included in the output decoder section of state S2. This original version simply read switch values SW7 – SW4 and placed them in variable room. In this lab the subroutines TakeAStep and EnterRoom perform the same function, without the switches. Here is what is happening in the code you just added; TakeAStep takes as input arguments row, col, and dir and computes the coordinates of the room the bear is entering. Consequently, it outputs the row and col address of this new room. EnterRoom takes these coordinates (row, col) as input arguments (r24, r22), computes an address within the encoded maze (maze.inc) and returns the room and bees at this address (r24 = bees:room).

The program then isolates the room from the bees and saves both into their respective variables (room and bees).

Once again notice that to maintain C++ compliance, arguments are sent in registers r24, r22, and r20. Function return values (bees:room) are contained in registers r24.

If you were to assemble your program now, you would receive a large number of errors, as the assembler looks for variables and a subroutine that is not there. We will be defining those variables at the beginning of the next section and writing the missing subroutine (EnterRoom) shortly.

Take a Step

Before we rewrite TakeAStep define three new SRAM variables to hold our current location (row and col) in the maze and the number of bees in a room.

.DSEG
room: .BYTE 1
dir: .BYTE 1
next_state: .BYTE 1 // FSM next state
walk: .BYTE 1
row: .BYTE 1 // the bear is in the room at this row
col: .BYTE 1 // and column address
bees: .BYTE 1

It is good programming style to always initialize variables as soon as you define them. At the beginning of the maze we want the bear located in row = 0x14 and col = 0x00. In the reset section of your program initialize SRAM variables row and col to these values. Next, initialize variable bees = 0 indicating that the bear has not yet encountered any bees. Do not forget to comment your code.

Now, write a subroutine to modify these variables containing the bear’s current room location (row and col) based on the direction you want the bear to walk. Specifically, translate the following truth table into assembly code. You may use any technique you like.

Table 1: Modification of row and column based on direction bear is facing.
dir row col Comment
00 + take a step South by incrementing the row
01 + take a step East by incrementing the column
10 take a step West by incrementing the column
11 take a step North by decrementing the row

Do not forget to add your own comments to your code.

; —— Take A Step ——
; Called from INT0_ISR and main loop for animated version
; input r24, r22, r20 = row, col, dir
; output r24, r22 = row, col
; No other registers are modified by this subroutine.
; note: This simplified version can walk through walls
; ————————-
TakeAStep:

; push registers modified by your subroutine
; based on direction (r20) incr/decr row/col as defined in Table 5.1
; pop registers modified by your subroutine
ret

The simplest solution conceptually would be to implement a high level language if-then-else construct in assembly using cpi and brne, or bst and brts instructions. For additional assistance review your Lab03A code (TurnLeft, TurnRight, WhichWay).

Creative Corner – TakeAStep using Indirect Addressing Mode

The indirect addressing mode is the most elegant, the most difficult to understand, and of course, the method I used to program the TakeAStep subroutine. The lookup table solution shown in the Arduino Sketch Lab05A, would be implemented in assembly using the lpm instruction. My AVR Studio version of Lab05A uses the ijmp instruction. Please remember to indicate on the cover sheet of your lab report if you implemented this Creative Corner version of the subroutine.

Define the Maze

Before we can enter a room we must define all the rooms in the maze. Here you will use the maze you created in Prelab 5 (if you did not complete the prelab, you can find the maze without the bees here). Move your maze.inc file into the Lab05 project folder.

Figure 1: The Maze

Open the maze.inc file you created in the pre-lab (File > Open File…).

Figure 2: An Encoded Maze (maze.inc file without Bees)

Unlike Figure 2, your version should include the bees in the maze. Before we continue, let’s review how the maze is constructed (prelab 05). As you can see in Figure 2, I have organized the rows and columns of the table to match our maze (Figure 1). Each entry in the table defines the room and bees at that row and column address. The definition of the room corresponds to the switch positions you have been manually entering up to this point in the course. For example; after taking his first step, the bear is in the room at column address 0016 and row address 1316. Looking at our maze (Figure 1), we see at these coordinates is a room with only a west facing wall. The Programmer’s Reference Card (see Figure 3), tells us that a room with only a west facing wall is encoded as 01002 = 0x04. Looking at the first entry in the last line of the table, we see our room encoded as 0x04.

Figure 3: Programmer’s Reference Card

Include your definition of the maze by adding the following include assembly directive to your program.

.ORG 0x0100 // bypass IVT
.INCLUDE “spi_shield.inc”
.INCLUDE “testbench.inc” // DrawRoom and DrawDirection
.INCLUDE “maze.inc”

reset:

Enter the Room

Now that our bear has taken a step and we have our maze encoded, it is time to write the EnterRoom subroutine. The TakeAStep subroutine has already updated variables row and col to correspond to the coordinates of room we are currently in, so now all we have to do is translate that information into the a byte index into table theMaze. With a sharp pencil (or your smart device) and a little math you will discover that the byte index of a room as a function of the row and column is given by the equation 20 x row + col.

Do not forget to add your own comments. Please, do not copy and paste my explanatory text.

; ————————–
; —— Enter a Room ——
; Called from main program
; input r22, r24 = col, row
; output r24 = bees:room
; no other registers are modified by this subroutine.
EnterRoom:

; Push registers modified by your subroutine, including ZH and ZL.
; Do not push registers used to return values r24 and r22.
Write the code to save registers here
// Step 1: Base Address
ldi ZL,low(theMaze<<1) // load base address of theMaze into Z.
ldi ZH,high(theMaze<<1)
// Step 2: Calculate Byte Index
Using instructions mul, add, and adc, compute the index of the room by writing the code to implement equation 2010*row+col here. Be careful this is a 16-bit number so you need to add the carry (adc) into the most significant byte. To add only the carry, set a scratch register to zero (clr r2) and add it along with the carry (adc r1, r2).
// Step 3: Add Index to the Base Address and Load Room with Bees
Add the 16-bit index to the base address of theMaze by writing the code to implement equation ZH:ZL = ZH:ZL + r1:r0 here. Again, you will need to use both the add and adc instruction to add these two 16-bit numbers together.
; load the room and bees from program memory using the indirect addressing mode.
lpm r24,Z // load the room with # of bees indirect

; pop registers modified by your subroutine, including ZL and ZH
Write the code to pop the registers here.
ret

Test Your Program

You may upload your program to quickly check to see if it works. An updated owner’s manual is provided in the next section to help you step through the maze. I would be surprised if your program works the first time in which case you will need to simulate the steps defined in the owner’s manual. See “Simulation and Debugging” for help here.

Updated Owner’s Manual

Open the Lab05A Arduino Sketch within the Arduino IDE, and follow these steps to see how your program should navigate the maze.

  1. After you upload and run the program, no room should be displayed (the bear is outside the maze). Place both direction switches up, all other switches should be in the down (off) position.
  2. The North direction 7-segment LED should be blinking telling the bear to walk North.
  3. Push the button telling the bear to take a step. The bear should now be shown in the first room – a room with a west facing wall.
  4. Point the bear in the direction you want him to proceed by setting the direction switches.
  5. Push the button to provide the bear with the direction you wish him to walk. The bear now takes a step (TakeAStep) and enters the next room (EnterRoom) as defined by your encoded maze (maze.inc) file. You should now see the room displayed along with the direction in which the bear was told to walk (note: the direction may not be visible if it is obscured by a wall).
  6. Repeat steps 4 and 5 to verify the basic operation of the program. You do not need to guide the bear all the way to the forest.

Simulation and Debugging

Set a break point at your call to  ReadSwitches and at the beginning of the  INTO_ISR. Run  to the first break point and set direction switches so the bear is facing north, we no longer use the room switches.

Step over  the ReadSwitches subroutine. Register R06 should be equal to three (0x03). Initiate an external interrupt by toggling PIND bit 2 as described in Lab  and duplicated here.

  1. Check PIND bit 2
  2. Take at least two steps 2x . The check mark may disappear after the first step, this is due to the simulation of an internal synchronization circuit. It should reappear after the second step.
  3. Uncheck PIND bit 2.
  4. Single step the program . You should within a few steps find yourself in the interrupt vector table (IVT). Take the jump into the INT0_ISR. Set a breakpoint or step to your call to TakeAStep. SRAM variable row and register R24 should equal 0x14 (decimal 20) and variable col and register R22 should equal 0x00. The direction and register r20 should be three (0x03).
  5. Step over  TakeAStep. You have just told the bear to take a step in the North direction, so register R24 = 0x13 and R22 = 0x00. If they are not, then you should repeat steps 1 to 3 and this time step into  TakeAStep and locate the bug.
  6. Step to and over  EnterRoom. The bear should now have entered the first room, one with a west facing wall, which means register R24 = 0x04. If the bear is not in this room, then you should repeat steps 1 to 4 and this time step into  EnterRoom and locate the bug.
    Review the “Define the Maze” Section of this lab if you are not sure why R24 should equal 0x04.
  7. Congratulations, your bear has now taken his first step and entered the maze. You now can upload your program and manually walk the bear around the maze. If you run into a bug along the way you should return to the simulator and manually enter the row and column just before the bug was discovered on the board and then repeat steps 1 to 5 having the bear enter the problematic room.

Design Challenge A – Room with Bees (1 – 3 points)

This is the first of two design challenges. You can skip these sections if you are happy receiving a passing grade (“C”) on the lab. If you want to receive an good or excellent grade you will need to accept one or more of the challenges.

In the Pre-Lab you encoded the number of bees in the room. Modify your program so as the bear walks into a room with bees, the number of bees in the room is displayed on the seven segment display for at least half a second (500 ms). After this delay the room is again displayed. This modification should not affect the performance of the rest of the lab.

Lab Demonstration

You may be asked to…

  1. Simulate an external interrupt
  2. Demonstrate using AVR Studio that the SRAM variable room is updated every time the button is pressed.
  3. Demonstrate the correct operation of your program as defined in your “Owner’s Manual” found at the beginning of this lab.

Make a backup copy of your project folder before moving to Lab 05B