Appendix B: Running Keil Tools B.1 INTRODUCTION The RealView Microcontroller Development Kit that is available from http:/­/­www.­ keil.­com/­demo simulates not only an ARM microprocessor but a complete microcontroller. A wide variety of microcontrollers are available in the tools, and their peripherals can be driven with inputs to exercise I/O pins, A/D converters, UARTs, etc. For the purpose of simulating the microcontrollers described in each chapter, we’ll need a way to write assembly code without having to read one hundred pages of manuals, so here’s where we bend the rules a bit. While Keil does not formally support building projects in assembly only, it can be done quite easily and the tools provide a nice development environment in which to build your code. There is, however, a rather heretical approach taken when using the RVMDK tools to write only assembly. For starters, code begins at address 0x00000000 on the ARM7TDMI, which is where the exception vector table normally sits, so we can put code there as long as we don’t require exception handling. Second, the tools normally expect a default reset handler to be in place, and we don’t really want to use that. We therefore create our program in such a way that the tools believe it to be the reset handler. Writing code for the Cortex-M4 works the same way—we will be leaving out exception handlers and assembly code normally created when compiling C code. To run a simple program, you first need to specify a particular device to simulate. You then create a project, write your code, and add it to your project. Finally, you build the project and start up the debugger to step through your code. NB: This appendix uses Version 4.73, so if you are using Version 5.0 or above, be sure to download the software pack that supports the legacy ARM7 and ARM9 microcontrollers. B.2 WORKING WITH AN ARM7TDMI This section can be read in conjunction with Chapter 3, since you’re likely to look for a way to run your first assembly programs without having to download and build a simulator. If you are learning to program an ARM7- or ARM9-based device, then the procedure for running short blocks of assembly is quite easy. Be aware of how many rules of professional programming are being thrown out the window, but since the goal is to learn to walk before you learn to run, it’s permitted to ignore a few things for now. B.2.1 Creating an ARM7TDMI Project and Selecting a Device Let’s begin by creating a new project file. Start the RVMDK tools and choose New μVision Project from the Project menu, as shown in Figure B.1. Give your project a name. As an example, you could call it My First Program, as shown in Figure B.2. The project file can include source files of code, including C, C++ and assembly, library files, header files, etc., along with environment options 399 400 Appendix B FIGURE B.1 Creating a new project. FIGURE B.2 Naming the project. that you can save (see the µVision IDE User’s Guide included with the software for all the different options available). You might wish to create a new folder for each project, just to keep things simple. At this point the tools will ask you to specify a device to simulate. To continue our example, choose one of the LPC21xx parts from NXP, such as the LPC2104. This is an ARM7-based microcontroller with a few peripherals. You will find all of the available parts in the device database window shown in Figure B.3. Scroll down until you come to the NXP parts and select LPC2104. Notice that the tools detail all of the peripherals and memory options when you choose the device. When you click OK, a dialog box will appear asking if you want to include startup code for this device. Click No, since we are only making a small assembly program and will not need all of the initialization code. B.2.2 Creating Application Code Now that the project has been created and a device chosen, you will need to create a source file. From the File menu, choose New to create your assembly file with the editor. If you like, you can directly copy the small program from Figure B.4 as an Appendix B 401 FIGURE B.3 Device database dialog box. FIGURE B.4 Sample code. example. The latest versions of RVMDK now require a reset handler to be found, and normally this is included in the startup file. However, we have elected not to use this file, so the workaround is to mark your assembly code as the reset handler and declare it globally. Notice the first line of code is the GLOBAL directive. You should also call the block of code reset (or Reset—it is case insensitive) with the AREA directive. After the ENTRY directive, the label Reset _ Handler should be placed at the top of your code. You can follow this with another label if you like, say Main or MyCode, but just be sure to include the first label. The remaining code would appear as examples do in the book. Choose Save As from the File menu, and give it a name, such as My First Program.s, being sure to include the “.s” extension on the file. The window should change, showing legal instructions in boldface type, and comments and constants in different colors. The assembly file must be added to the project. In the Project Workspace window on the left, click on the plus sign to expand the Target 1 folder. Right click on the Source Group 1 folder, then choose Add Files to Group “Source Group 1” as 402 Appendix B FIGURE B.5 Adding a source file to the project. shown in Figure B.5. A dialog box will appear. In the dropdown menu called Files of Type, choose Asm Source file to show all of the assembly files in your folder. Select the file you just created and saved. Click Add, and then Close. B.2.3 Building the Project and Running Code To build the project, select Build target or Rebuild all target files from the Project menu. You will get a warning about the fact that Reset_Handler does not exist, but you can ignore it. Now that the executable has been produced, you can use the debugger for simulation. From the Debug menu, choose Start/Stop Debug Session. FIGURE B.6 Running code in the debugger. Appendix B 403 This puts you into a debug session (shown in Figure B.6) and produces new windows, including the Register window and the Memory window. You can single-step through the code, watching each instruction execute by clicking on the Step Into button on the toolbar or choosing Step from the Debug menu. At this point, you can also view and change the contents of the register file, and view and change memory locations by typing in the address of interest. When you are finished, choose Start/ Stop Debug Session again from the Debug menu. Once you’ve completed a simple example, go back and read the µVision IDE User’s Guide, which is available in the Help menu. Many integrated development environments are similar, so if you have already used one from a different vendor, you may find this one very familiar. B.3 WORKING WITH A CORTEX-M4 Huge simplifications allow us to make a working environment for Cortex-M4 devices. Unless specific requirements are added for handling exceptions, such as hard faults or interrupts, you must be very careful when writing code since an unexpected condition will send you into the weeds. With the debugging tools available to you, however, most errors can be caught and corrected without too much difficulty. As with the ARM7TDMI projects, you might choose to read this section before reading Chapter 3. B.3.1 Creating a Cortex-M4 Project and Selecting a Device First, we’ll create a new project file. Start the RVMDK tools and choose New µVision Project from the Project menu, as shown in Figure B.7. Give your project a name. As an example, you could call it My First M4 Program, as shown in Figure B.8. The project file can include source files of code, including C, C++ and assembly, library files, header files, etc., along with environment options that you can save (see the µVision IDE User’s Guide included with the software for all the different options available). You might wish to create a new folder for each project, just to keep things simple. At this point the tools will ask you to specify a device to simulate. To continue our example, choose one of the Tiva parts from TI, such as the LM4F120H5QR (this part number is equivalent to the TM4C1233H6PM). This is a Cortex-M4-based FIGURE B.7 Creating a new project. 404 Appendix B FIGURE B.8 Naming the project. FIGURE B.9 Device database dialog box. microcontroller with a number of peripherals. You will find all of the available parts in the device database window shown in Figure B.9. Scroll down until you come to the TI parts and select LM4F120H5QR. Notice that the tools detail all of the peripherals and memory options when you choose the device. When you click OK, a dialog box will appear asking if you want to include startup code for this device. Click Yes, since we can make a running example quickly using the initialization code. B.3.2 Creating Application Code Now that the project has been created and a device chosen, you will need a source file. Rather than create one from scratch, we will simply edit the Startup.s file that we included in the last section. Locate the file by clicking on the +sign by the Source Group 1 icon in the Project window on the left. You should see one file called Startup.s. Open the file by double-clicking on the name. At this point, you can insert your code. Let’s use the example in Chapter 3 for computing a factorial function. You Appendix B 405 FIGURE B.10 Sample code. will need to delete the code between the labels Reset_Handler and NmiSR. Add your code after the label Reset_Handler, adding an ENTRY directive so that the code looks like that in Figure B.10. Comment out the code in the section for handling stack and heap memory locations, since we won’t immediately need any of this. Simply add a semicolon to the beginning of each line, so that the code looks like: ;************************************************************* ; ; The function expected of the C library startup code for ; defining the stack and heap memory locations. For the C ; library version of the startup code, provide this function ; so that the C library initialization code can find out ; the location of the stack and heap. ; ;************************************************************* ; IF :DEF: __MICROLIB ; EXPORT __initial_sp ; EXPORT __heap_base ; EXPORT __heap_limit ; ELSE ; IMPORT __use_two_region_memory ; EXPORT __user_initial_stackheap ;__user_initial_stackheap ; LDR R0, =HeapMem ; LDR R1, =(StackMem + Stack) ; LDR R2, =(HeapMem + Heap) ; LDR R3, =StackMem ; BX LR ; ENDIF 406 Appendix B FIGURE B.11 Running code in the debugger. B.3.3 Building the Project and Running Code To build the project, select Build target or Rebuild all target files from the Project menu. You will get a warning, but you can ignore it. Now that the executable has been produced, you can use the debugger for simulation. From the Debug menu, choose Start/Stop Debug Session. This puts you into a debug session (shown in Figure B.11) and produces new windows, including the Register window and the Memory window. You can single-step through the code, watching each instruction execute by clicking on the Step Into button on the toolbar or choosing Step from the Debug menu. At this point, you can also view and change the contents of the register file, and view and change memory locations by typing in the address of interest. When you are finished, choose Start/Stop Debug Session again from the Debug menu. Once you’ve completed a simple example, go back and read the µVision IDE User’s Guide, which is available in the Help menu. Many integrated development environments are similar, so if you have already used one from a different vendor, you may find this one very familiar.