Skip to content

Keil uVision5 ​

Experiments 1 and 2 are pure ARM assembly. They run in Keil's built-in simulator on a generic ARM Cortex-M4 (ARMCM4), so you need no board. This guide installs Keil, builds a project from an empty folder, runs a tiny program, and shows you the debugger windows you will use in every lab. The lab PCs already have Keil installed.

Windows only

Keil uVision5 runs on Windows. On a Mac, use a Windows virtual machine (Parallels, UTM or VMware Fusion) or a lab PC.

The whole thing in 30 seconds (once you've done it before)
  1. Project → New µVision Project… → new folder → name it → Save.
  2. Device: ARM → ARM Cortex M4 → ARMCM4 → OK.
  3. Run-Time Environment: tick nothing → OK.
  4. Right-click Source Group 1 → Add New Item… → Asm File (.s) → main.s.
  5. Alt+F7: Target → default compiler version 6; Asm → armasm (Arm Syntax); Debug → Use Simulator, untick Run to main().
  6. F7 to build, Ctrl+F5 to debug, F11 to step.

Step 1: Install Keil MDK ​

  1. Download MDK from keil.arm.com. The free Community or evaluation edition is enough: its 32 KB code limit is far more than any program in this lab.
  2. Run the installer as administrator and accept the defaults.
  3. When it finishes, the Pack Installer opens and updates its index. Wait until the status bar says ONLINE.
  4. The ARMCM4 device comes from the ARM::Cortex_DFP pack, which MDK normally installs for you. If it is not listed under Packs, search for ARMCM4 and click Install.

Step 2: Make a folder for the project ​

Keil creates several files per project, so give each experiment its own folder. For example:

text
C:\ENCS5101\Exp1

Keep the path simple

Avoid spaces, Arabic letters and OneDrive-synced folders (such as Desktop or Documents when OneDrive is on). Long or unusual paths are the most common cause of strange build errors. C:\ENCS5101\... is safe.

Step 3: Create the project ​

  1. Open Keil uVision5.
  2. If a previous project opens automatically, close it with Project → Close Project.
  3. Click Project → New µVision Project….
  4. Browse to your folder (C:\ENCS5101\Exp1), type a name such as exp1 and click Save.
Project menu with New µVision Project highlighted
Create New Project dialog saving exp1 in C:\ENCS5101\Exp1

Step 4: Choose the ARMCM4 device ​

The Select Device for Target window opens right after you save.

  1. Make sure the drop-down at the top-left says Software Packs.
  2. Expand ARM → ARM Cortex M4 and select ARMCM4.
  3. Click OK.
Select Device for Target with ARM, ARM Cortex M4, ARMCM4 selected

ARMCM4 vs. ARMCM4_FP

Either works for these experiments. ARMCM4_FP also has the floating-point unit, which experiments 1 and 2 do not use. Pick plain ARMCM4.

I don't see "ARM Cortex M4" in the list

The ARM::Cortex_DFP pack is missing. Click Cancel, open Project → Manage → Pack Installer…, search for ARMCM4, click Install next to ARM::Cortex_DFP, then go back to Project → Options for Target → Device to choose it.

Step 5: Skip the Run-Time Environment ​

Next, the Manage Run-Time Environment window opens. It offers ready-made software such as a startup file.

Leave every box unticked and click OK.

Manage Run-Time Environment with nothing selected

Why nothing?

In experiments 1 and 2 your own program provides the vector table (the RESET area with __Vectors and Reset_Handler). If you also tick Device → Startup, Keil adds a second vector table and the build fails with Symbol __Vectors multiply defined. You can reopen this window at any time from Project → Manage → Run-Time Environment….

Step 6: Add an assembly source file ​

The Project panel on the left now shows Target 1 → Source Group 1, empty.

  1. Right-click Source Group 1 → Add New Item to Group 'Source Group 1'….
  2. Choose Asm File (.s).
  3. Name it main.s and click Add.
Right-click menu on Source Group 1 with Add New Item highlighted
Add New Item dialog with Asm File selected and main.s as the name

main.s opens in the editor. Paste this test program and press Ctrl+S:

asm
        AREA    RESET, CODE, READONLY
        EXPORT  __Vectors
__Vectors
        DCD     0x20001000          ; Initial stack pointer
        DCD     Reset_Handler       ; Reset vector: execution starts here

        AREA    MYCODE, CODE, READONLY
        ENTRY
        EXPORT  Reset_Handler
Reset_Handler
        MOV     R0, #5              ; R0 = 5
        MOV     R1, #7              ; R1 = 7
        ADDS    R2, R0, R1          ; R2 = R0 + R1 = 12, and update the flags
        SUBS    R3, R0, R0          ; R3 = 0, so the Z flag becomes 1
STOP    B       STOP                ; Loop here forever
        END

Every program in experiments 1 and 2 has this same shape:

PartWhat it does
AREA RESETThe vector table. The first word is the initial stack pointer; the second is the address of the first instruction to run.
AREA MYCODE + ENTRYYour code. Reset_Handler is where the processor starts after reset.
STOP B STOPAn infinite loop. There is no operating system to "return" to, so a program must never run off the end.
ENDTells the assembler the file is finished. Anything after it is ignored.

Indentation matters

In Keil assembly, labels (__Vectors, Reset_Handler, STOP) start in the first column. Instructions and directives (AREA, MOV, DCD…) must be indented by at least one space or tab. An unindented MOV is read as a label and causes errors.

Step 7: Set the project options ​

Open Project → Options for Target 'Target 1'… (Alt+F7, or the magic-wand icon in the toolbar). You only need to touch three tabs.

Target tab ​

Check that ARM Compiler says Use default compiler version 6. Leave the memory areas as they are (IROM1 at 0x0, IRAM1 at 0x20000000).

Options for Target, Target tab, with ARM Compiler set to the default version 6

Asm tab ​

Set Assembler Option to armasm (Arm Syntax). The lab code uses Arm syntax (AREA, DCD, END); the other choices expect GNU syntax and reject it.

Options for Target, Asm tab, Assembler Option set to armasm (Arm Syntax)

Debug tab ​

  1. On the left half, select Use Simulator.
  2. Untick Run to main(). There is no main in an assembly program.
  3. Click OK.
Options for Target, Debug tab, Use Simulator selected

Step 8: Build ​

Click Project → Build Target (F7, or the icon with a downward arrow into a box). Watch the Build Output panel at the bottom. A good build ends with:

text
".\Objects\exp1.axf" - 0 Error(s), 0 Warning(s).
Build Output panel showing 0 Error(s), 0 Warning(s)

If there are errors, double-click the first error line in Build Output: Keil jumps to the line that caused it. Always fix the first error first; later ones are often caused by it. See Troubleshooting for the usual suspects.

Step 9: Run it in the debugger ​

Start the debugger with Debug → Start/Stop Debug Session (Ctrl+F5, or the magnifier-over-a-chip icon). Click OK on the EVALUATION MODE notice if it appears.

The layout changes. The yellow arrow in the editor marks the next instruction to run: the first MOV in Reset_Handler.

The debug session layout with the Registers, Disassembly and editor windows labelled

Step through the program ​

Press Step (F11) once per instruction and watch the Registers window. The registers that just changed are highlighted in blue.

  1. After the first step, R0 = 0x00000005.
  2. After the second, R1 = 0x00000007.
  3. After ADDS, R2 = 0x0000000C (12 in decimal).
  4. After SUBS, R3 = 0x00000000. Expand xPSR: the Z flag is now 1.
Registers window after ADDS, with R2 = 0x0000000C highlighted and xPSR expanded

The controls you'll use every lab ​

ActionKeyWhat it does
StepF11Run one instruction. Enters subroutines (BL).
Step OverF10Run one instruction, but treat a BL call as a single step.
Step OutCtrl+F11Run until the current subroutine returns.
RunF5Run until a breakpoint (or forever).
Stoptoolbar ⏹Pause a running program.
Resettoolbar RSTGo back to the start of the program.
BreakpointF9Toggle a breakpoint on the current line. Clicking the grey margin left of a line does the same.
Run to cursorCtrl+F10Run until the line the cursor is on.
End debuggingCtrl+F5Leave the debugger and go back to editing.

Edits need a rebuild

You cannot edit and continue. To change the program: stop debugging (Ctrl+F5), edit, rebuild (F7), and start debugging again.

Look at memory ​

From Example 2 of Experiment 1 on you load and store data. To see memory:

  1. View → Memory Windows → Memory 1.
  2. Type an address in the Address box, such as 0x20000000 (start of RAM), and press Enter.
  3. Right-click inside the window to change how values are shown (for example Unsigned → Int to see 32-bit words instead of bytes).

You can also type a label from your program, such as Reset_Handler, in the address box.

Memory 1 window showing RAM at 0x20000000 as 32-bit words

Other useful views ​

  • View → Disassembly Window: the actual machine instructions, with their addresses and encodings. Useful when the assembler expands a pseudo-instruction such as LDR R0, =value or MOV32.
  • View → Watch Windows → Watch 1: type a register or label name to keep an eye on it.
  • In the Registers window, Internal → States counts clock cycles and Sec shows elapsed time.

Step 10: Reuse the project for more examples ​

Each experiment has several examples, and each one has its own RESET vector table, so only one of them can be in the build at a time. Two good ways to handle this:

  • One project per experiment, one file per example. Add each example as its own .s file. Right-click every file you are not running → Options for File '…' → untick Include in Target Build. The excluded files show a small red mark in the Project panel.
  • One project per example. Repeat this guide in a new folder. Slower, but impossible to mix up.
Options for File dialog with Include in Target Build unticked

What's in the project folder ​

File/folderWhat it is
exp1.uvprojxThe project. Double-click this to reopen the project later.
exp1.uvoptxYour window layout and debug settings.
main.sYour source code.
Objects\, Listings\Build output. Safe to delete; Keil recreates them on the next build.

To hand in a project, zip the whole folder. Delete Objects\ first to keep it small.

Troubleshooting ​

Message or symptomCause and fix
Symbol __Vectors multiply definedEither Device → Startup is ticked in the Run-Time Environment (Step 5), or two example files are both in the build (Step 10).
error: unknown directive / unexpected token on AREAThe assembler is set to GNU syntax. Set Asm → Assembler Option to armasm (Arm Syntax) (Step 6).
A1163E: Unknown opcode on a line that looks fineThe instruction isn't indented, so it was read as a label. Indent it.
A1167E: Invalid line startA label is indented, or there is a stray character in the first column. Labels go in column one.
L6236E: No section matches selector - no section to be FIRST/LASTThe vector table is missing. Check your file starts with AREA RESET and that the file is in the build.
*** error 65: access violation at 0x40... while runningThe program touched a peripheral address (0x400xxxxx). The generic ARMCM4 simulator has no peripherals, so only use RAM (0x20000000 up) and your own code.
The file has no syntax colouring and isn't builtIt was saved without the .s extension. Remove it from the project, rename it to main.s, and add it back with Add Existing Files to Group….
Nothing happens when you press StepYou're not in a debug session. Press Ctrl+F5 first.