Let's take a look at Step 2, what happens in your application code in the main function. This slide shows the main function source code for the example code we're running. It's divided into three tasks. One, you print the Hello World message the moment you start the main function, then use some CMSIS functions which we'll look into into more detail later to set up and enable an interrupt known as TIM0_IRQn. This means timer 0 interrupt. It is the device specific timer 0 interrupt on a Cortex-M3 fixed virtual platform for the MPS 2 development board. It's an external interrupt that is part of the nested vector interrupt controller or the NVIC and they're enabling it using CMSIS functions. Then the third and final task in this main function is to set that interrupt to pending using more CMSIS functions to trigger it and see how the exception handling process works on a Cortex-M3 device. The print f function on a Fast Model or fixed visual platform, by default uses a feature called semi hosting. If you look at tarmac traced eventually in this call to print f, we will find that instruction line with the instruction BKPT, or break point. This is a special semi hosting instruction that only works on debuggers or things like Fast Models. It does not work on hardware or RTL. If you try to execute this program containing an instruction like this on RTL, you will get a hard fault. That's because RTL doesn't support semi hosting, and semi hosting is really only for debugging with a debugger connected or simulating a device functionally using something like a Fast Model. The reason we bring this up is if you're using an RTL simulation or something like a Cycle Model, and you're getting a hard fault and you can't tell why, a common culprit is the fact that semi hosting was left enabled. Just search through your tarmac trace and see if you hit a BKPT instruction. If you're doing that in your RTL, turn on semi hosting and the new code should start working again. The next step in our main function was to configure that external interrupt. Timer 0, which is on a Cortex-M3 device external interrupt number 2. For this purpose, we are using the CMSIS function NVIC, nested vector interrupt controller _SetPriority, and we're passing two arguments. One is this preprocessor macro TIM0_IRQn, and then something 1. What is that? Well, let's look at this documentation screenshot from the CMSIS documentation. This function sets the priority for the interrupt specified by this string here. The priority to the second field specifies the interrupt priority value, where lower values indicate a higher priority. The default priority is 0 for every interrupt which is the highest possible priority. What we're doing is we're saying set this external timer interrupt to the second highest possible priority that is 1. The values and meanings of all of these external interrupts are defined in the device header file for CMSIS. You can read more about that on the CMSIS website. Let's look at what this function does internally using tarmac trace. Eventually, if you dig down through it, this function will include an STRB instruction which writes a byte to this address. You can see it's writing a byte because it is an MW1 or memory write 1 instruction trace event, and it's writing to the address hex e000e402, and it's right the hex value 20. If you're trying to debug this by hand or without tarmac trace, you'd struggle a little bit because this address, unless you know where to look in the r1, you won't know what it means. Tarmac trace translates memory-mapped addresses for Cortex and devices into their human readable names and shows you what is actually happening. When you write to a system registered as a memory map like this, you actually get the human readable name using an R identifier entry in the tarmac trace. What we actually do when we write to this address is we'd write to the register NVIC_IPR0, that is NVIC interrupt priority register 0. If you look in the r1, this register is in fact located in this address range, and it is part of the set of interrupt priority registers. Let's dig into what's actually being written to that register. Each of the NVIC interrupt priority registers is divided into four fields. Each of these four fields corresponds to individual interrupts. This external timer interrupt is interrupt number 2 on Cortex-M3, as we mentioned earlier, so we need to write to the field that corresponds to interrupt number 2, that is the third field from least significant to most significant bits. That's why this instruction is writing to this byte in the register. However, there's something curious going on here. We said set the value for the priority of this interrupt to 1, but actually what we're doing is we're writing the hex value 20 into this field. Why is that? The reason is that the architecture is a bit odd but for a good reason. Specifically, this implementation has only three bits associated for the priority of an interrupt, and the way it's organized is to use the most significant three bits of the available eight bits. Why would you want to do that? Well, think of it this way. Code written for an NVIC like this should be something that you can put across to multiple different devices, each of which might implement a different number of bits for your interrupt priorities. Mathematically speaking, the most significant bits have the most entropy, so to keep the values of your interrupt priorities reasonably effective, even if you port to a device with a different number of bits, you want to preserve the bits with the highest entropy and therefore you left a line those bits instead of using the bottom bits. Say that you had a device which used all eight bits of priority, and you are using all of those bits to do very fine configurations of interrupts. Then you chose to run your bit of code on a device that only used three bits of priority. Well, if you had thrown away all of the top bits, you will lose the most significant bits of your priority and you might end up with your system behaving completely unexpectedly. Whereas if you keep the most significant bits and you only throw away the least significant bits, then the most important part of your priority bits remains. There's a bit of a disconnect here between what you would write in C code or what you would write conceptually and what the architecture would do. The good news is that if you're using CMSIS, you don't have to worry about any of this. The header falls in CMSIS, figure all of this out by using C print and processing, and make sure to write the correct value out. The other thing is, when you are writing these complicated system registers which you need to write a specific field of specific registers, tarmac trace will just give you the human readable names. You don't need to figure out the memory mapping yourself. Makes it a bit easy to debug.