 We're now going to have a look at our first hands-on. So we're going to actually show you how to get started using the SDM32 in Assembler so that we can do our first example. So the goal of this section is to get familiar with the default configuration of the SDM32 after reset. So you'll see when we start our assembly what mode we're in first and how we need to change that mode. We need to play around with the Keil tool. So you're going to get your first hands-on with the MDK Keil or MDK Arm, which is the Keil U-Vision tool. This will be our IDE. This is where we're going to edit the code and compile the code and debug the code. And all of this is going to be done on the SDM32 F072 nuclear board. So we're going to build our application for the SDM32 nuclear board. So after the reset, the default configuration that the CMSIS source files will normally put the device into is the core will be in single stack mode. So the SDM32 has the capability of dual stack. This is so that we can run an operating system or an RTOS. And you'll also have full access rights to all the registers from the main program. So there's no restrictions on anything you're doing with inside the software. The system clocked by default is the HSI 8 MHz for the SDM32 F072 RB. This might be different for different SDM32s, so always remember to check what your default clock source is. The flash will be configured in zero weight states because we're not running the core at high speeds when we start up. So the flash is always set to zero weight states. The peripheral clock for low power reasons is only connected to the essential peripherals at start up. So that is the flash, the RAM, and the interrupt controller. No other peripherals have the peripheral clock enabled at this time. It's up to you, within your software, to switch these clocks on as and when you need them to run your application. Finally, most of the IO pins, except the debug pins, are configured as floating inputs. Again, this will depend on families. Some of the families like the L4 family, all the pins by default are configured as analog inputs. Again, you'll have to check that, but this particular device, the SDM32 F072, all inputs are configured as floating inputs as the default state or the reset state. Our minimum code that we need, we need to define an interrupt vector table because we have to have our reset vector to start the code off, and we have to have a procedure of some sort, so our main procedure, which is our LED toggling application. So first thing we need to do, we need to connect our nuclear board to our laptops. So this is done via your mini USB cable, and windows will then go off and install multiple drivers. The SDM32 nuclear board is a multi-product, so it will appear as about three different things within Device Manager. It'll appear as a disk drive. This is so that we can use the embed functionality. It'll appear as a virtual COM port, so that we can use the serial port on the microcontroller at the bottom half of the board to communicate to the microcontroller on the top half of the board back to the PC through the USB cable. So it'll be a virtual COM port set up. And it'll also appear as a USB ST debug dongle, which is the ST link, which is the top half of the board, as you can see in the picture on the screen. Once Windows has done its magic and installed all the drivers, we're then in a position to start our hands-on. So I'm going to give you some more explanation of what we're going to do during this first hands-on. So what we're going to do, we are going to toggle the green LED, which is connected to port A5 of our nuclear board that we're using. This means that we need to pay attention to GPIO port A, and we have to look at pin number five. So the operations that we need to do to configure our or toggle our GPIO port A5 is we need to connect a clock so that we can load the information into the registers. The peripherals are synchronous, so we have to have the clock to latch the program data in there. We need to configure PA5 as output push pull. Remember the default state or the reset state is floating input. And then we need to toggle PA5, so we need to change the data register from high to low so that we can see the LED switching on and off. The clock connections to our peripherals are going to look similar to this slide. So the GPIOs are connected to the high speed bus inside the STM32F0, and by default they are not enabled. So we have to enable the GPIO A clock. Clock registers inside the STM32 are in the reset and clock control segment of the device. And then we need to go and find the AHB enable register, so AHBENR register. So this we'll be looking inside our reference manual in a few minutes to go and find where this or the address of where this RCC AHBENR register is located. All the other peripherals as you can see down here connected to the peripheral bus are disabled. We don't need to enable any of these peripherals, so we can leave them as they are. That has a different register, so that is the RCC APBENR, so the Advanced Peripheral Bus Enable Register. And again that will be in the same chapter as our AHBENR register. So we only have to enable one clock to make our example work in this hands-on. Our GPIO configuration mode, so by default is input floating. So this is the normal reset condition of the GPIO pins on the STM32F072. But we need to change that to be output push-pull. So we need to set some registers to enable it so that we can drive the LED that is connected to our pin. So we'll have to find the register to enable our GPIO to be output push-pull. So this will be in the GPIO section of the reference manual. And it is the MODER register that we will need to be looking for for this one. So this is the value that we will need to load into our MODER register, which is 400 hexadecimal, so that PA5 is configured as output push-pull mode. Also on the screen there at the top, you can see the value of 20,000 hexadecimal. That's the value that we will need to load into our AHBENR register, so that we have the clock connected to GPIO port A. The remaining configuration register for the GPIO, the output type, internal pull-up pull-down register and output speed register, we don't need to change them. The reset conditions of those registers is perfect for what we want to do in our hands-on example. To toggle PA5, we will need to write to the output data register. Now, we've got multiple ways of setting the bits in the STM32. We have the output data register, which is the logical register you would expect to write information to for them to appear on output pins. But we also have a bit set reset register, which gives us a bit more flexibility. So the bit reset register is doing atomic operations on a single bit inside GPIO port A. Whereas if we write to the output data register, we're writing to all 16 bits of that GPIO port. This means, so that we don't change any other bits when we want to pin 5, we have to do a read, modify and write. So that means we have to do three instructions to actually change the bit using the output data register. This can potentially cause some issues if an interrupt arrives during our read, modify and write cycle. So if the interrupt arrives while we're doing the modify part, goes off to the interrupt service routine, changes one of the values on port A. Therefore, the information that we would end up writing back when we resume, because our information that we have read from the data register and pushed onto the stack, when we restore that, that information is no longer valid and we will be writing incorrect information back to the rest of GPIO port A. So using the bit reset register is a lot safer as an operation and it's more efficient as an operation. In the bit reset register, the lower 16 bits controlling the set function, the upper 16 bits of the bit reset register word are controlling the reset part of the register or the individual bit. Some people might say, what would happen if you put 20 hex into the low half and 200,000 hex as is displayed on the screen there in the top half, which means we want to set pin 5 and we want to reset pin 5 in the same transaction. If you try to do that, then the set function or the lower 16 bits would take priority and your upper 16 bit, which is the reset part, would get ignored at that point. So you would actually only end up setting the bit in port A and not doing an instant set reset of the device. We also have another register called the bit reset register, which has the reset parts in the lower 16 bits of the word based register. So if you don't want to play around with masks when you're using the bit reset register, then you can use the same mask on the bit reset register for high and the same mask again on the bit reset register for doing the low parts. So you've got a bit of control there of what is going on inside the device for controlling these bits. So we're going to use the bit set reset register in our hands-on to control our LED so that we can either load 20 hexadecimal in or 200,000 hexadecimal in to do the set and the reset of our green LED on our target port. So now we're going to start the hands-on. Before we do that, we will now need to go to our user disk software and extract it to our hard disk somewhere. This is so that we can get the hands-on part for our hands-on session and we will be using this for the template of where the structure of the rest of our code is. So we are going to find certain elements of our code, but we're going to use a template which is included in this user disk so that we can get started. So we will need to extract our user disk to somewhere on the hard drive so that we can find a template of the main code structure that we will be using to copy and paste. So we're not going to write the whole application ourselves. We're just going to write one or two lines, or three lines to be exact, and then we will build the code and run using the Kyle Microvision Toolchain. So I've now created a folder on the root of C. So to keep the path name as short as possible, I've created a folder called hands underscore on underscore 8 to 32. So this is my core folder for storing my project workspace for the hands-on. And you can see in this folder I have already extracted the three hands-on that we need for the rest of the day. So I've gone and done the first hands-on which we're about to commence, which is number three. Then we'll start after lunch with hands-on number five, and then finally at the end of the day we'll do hands-on number seven. So these numbers are relative to the slide packs that we are following through for each of these parts of the workshop. So the next thing we need to do is open our Kyle Tool. So I will launch our Kyle Microvision Tool. There we go. And we now need to create a brand new project. So we want to go to Project and New Microvision Project. So this is now where we need to define a location on our hard disk to save the project. And we need to give our project a name. So I am going to go to my hands-on folder. I'm going to create a new folder called Lab1. And I'm going to give my project a name. I'll call it Lab1 as well. So I'm trying my best not to put any spaces in the pathing of our project. The C compiler for Kyle, so the ARM compiler which is part of Kyle, can handle spaces inside the path names, but not all C compilers can handle spaces. So I'm trying my best not to put any spaces in the path name. I will go Save and it creates my project. Next we want to select the device that is on our nuclear board. So we can either search through the packs that we've got. So hopefully you should be able to see ARM and ST Microelectronics with the F0 series pack available to you. If you can't, then you need to go to the pack installer and follow the instructions for installing the F0 library pack. But the quickest way to find the device that we want to use is to search. So you just start by typing in the part number, which is the STM32F072RB. And you can see the list has now reduced. And it's the RBTX device, which is the one we need. Select that and click OK. As we're using assembly only, we don't want to add any runtime environment libraries to the project. So we don't need to select anything from this screen, so we just click OK for that screen. And now we have a project created. You can see this in the left hand side of the window in the project space of the screen. Now we need to add a file to our project. So we want to go on to the source group one, which is underneath the target one project. And we want to right click and add new item to the group. And we are doing this as an assembly project. So we want to add an assembly file. And we want to give this a name. So I will call this main. So I have now got a file in my project called main.s. And I'm now ready to start writing code for my project. As I said earlier, we're going to copy the majority of the project from a template. So I now go back to my extracted folders. And I've got template. And inside there, I've got template.s. If I double click on that, I get my code that I need to copy. So you want to select all this code in here. So if you do control A and then control C to copy, go back to your kyle environment and paste it where my cursor is flashing here on line one. And there we have our project copied in. So there are a couple of lines that you need to edit inside there. So you should have a total of 31 lines when you copy and paste the project in. And now we are ready to start editing code. So before we start editing the code, let's just have a quick look at the template we've just pasted in. So you can see there our stack pointer has been equated to a particular value. Then there's some definitions for the arm itself, which is the preserve eight, which is the eight bit alignment of the stack. Use form instruction, so form, which will be the form two instructions. Then we defined an area to be read only and it's going to contain our data. Then we have our vector table, which if you remember from the documentation, the first element of the vector table is the initial stack pointer, which has already been equated right up there on line one. So that's getting loaded into one of the core registers, R13, which is where the stack pointer is located. Then we hit the second element of our vector table, which is our reset handler. And that will then jump us down in the code to line number 10, which is where our software starts. And again, after the reset handler, you've got the second area, which is defined as the code area. So that is where the code information is now stored. Then we hit an entry point where the first line of our reset handler is a PROC, which is the start of a procedure. It is an assembly directive. Then we'll go through section where we need to define our reset and clock control, AHBENR register. So we've got a couple of loads, then a logical awe, and then we'll store the answer back into the R1 register, which is the address of our RCC AHBENR value. Then we do the same again for our mod ER register. So we will load the registers, do a logical awe to set the particular bit we need to do, and then store the register back again. And then we'll load the BSRR values into register number one also. And then our two values for set and clear will get loaded into register zero and register two. And then all we're doing down at lines 27 and 28, which is our loop, is storing either pin five set or pin five clear into our register R1, which is our bit set reset register. And then that will carry on going round its continual loop for all eternity. You have to finish the code off with an end P, so that's the end of the procedure. So that's the end of the reset handling procedure. And then as an assembly directive, you have to end the file, which is just end. So this is the code now that we're going to start editing. Before we do the editing, there are a couple of settings that we need to finalize inside the tool. So we need to define what our debug tool is for the programming of the SDM32. And to do that, you can either go into project and options for group source one group, or you can click on this little magic wand icon here, which will take you to options for target. You can also right click on target one to get options for target as well. So there's three different ways you can get to the screen. So these are the configuration settings that you need to look at. And it's the debug tool that we want to go and change the settings for. By default, Kyle will automatically select its debug tool, which is the U-link. We need to change that to be an ST-link debugger. Then we need to go and make sure that all the settings have been brought in correctly. So we go into settings. If your target board is connected to your PC, you should see the debug cell inside your nuclear board. It should be visible. And we need to check to make sure the flash downloader is available. So the flash downloader is there for the F-0 128K variant. Another item that we need to tick is the reset and run. So this means as soon as the system has finished programming, it will automatically reset the target board without you having to do any other intervention. So we need to tick this box as well. Then we can say OK to that screen and OK to that screen. So now we're in the position to start editing our code. So this is what we need to do now. So we need to fill in these three labels with their registrages. So these relate to the 1A, 1B and 1C highlighted in our code. And to do this, we will need to open the reference manual, which is RM underscore STM32F072 from our user disk documentations folder. And we now need to go and find where the addresses of these three registers are located. We go to the contents. We need to look at the system and memory overview. We need to expand that. And then we want to have a look at the memory organization. And it was the boundary addresses that we're interested in. So chapter 2.2.2. And this is now showing us our boundary addresses. Make that smaller so that you can see it clearer. So to actually find the full address, we will need to find the boundary address or the starting boundary address and then add to it the actual offset address for that particular register. So I will talk you through the first one. So the first item we're looking for was the RCC underscore AHBENR register. So therefore our boundary address for our RCC segment starts at 0x40021000. And now we need to add to that the offset for the particular register we're interested in which is the AHBENR register. So we now click on this hyperlink just to the right of the RCC section which will jump us through the reference manual to our register map. And we're now looking for the AHBENR register which has an offset of 14. So therefore our value we need to put into our code is 0x4002100 plus the 14 offset which will be 14. So if I go back to my kyle environment 0x40021014. So that's the first one complete. So I'll give you a bit of time now to go through the GPIOAMODER register and the BSRR register. So you need to go back to your reference manual back to chapter 2.2.2 to find your boundary address. And then you need to click on the hyperlink next to the GPIO port A to jump down to the memory map for that section of GPIO port A to find out the two offsets for the two remaining registers. So hopefully you've now found the two remaining register addresses. Now you're going to start at 48000000. So I'll go and add that to my kyle environment now. 0x4800000. That one's the same because it's in port A. 0x4800000. And now we need to find our offset. So for the MODER register it is actually 00. So therefore we don't have to change anything there. One zero missing. And for our BSRR register scroll down the reference manual. And there's our BSRR register which is an offset of 18. So now we can build our code which is either F7 or the build icon there. I have lost my equal signs. Apologies. There we go. So I've got zero errors and one warning. Some of you might have had a build failure there. If you have you will need to go into the options for target. Into the linker file and make sure this tick box here is actually ticked. I don't know what kyle does but for some people it's automatically ticked. For some people it isn't. So you will need to make sure that that is ticked. You can do okay and you can press your F7 and build again so that you will get zero errors. We can actually get rid of the warning by editing the linker file. So the linker file that's been brought in is a default script and we need to do a bit of editing from the default script so that we don't actually get our warning file. So to do this we need to go to our options for target. We need to go into our linker tab and now we need to untick our use memory layout and edit our lab one dot scatter file. So we can okay that and it should have opened in the background. And we need to delete line number eight. We need to delete that line and we need to replace dot any with an asterisk and that's it. It's all we need to do so that we can actually get rid of our warning. So if I now go file save and now close that and if I go project rebuild all targets we now get zero errors and zero warnings. So now we can actually program our board so we need to start a debug session now. So you can either go into the debug on the menu up there and start debug session or we can press the debug icon on our toolbar which is there. So this will now go and flash our program into our target board and it hits a break point at the start of our main code. So we have the options here now of run, stop, step into, step over and run to cursor. So you got all the normal debug functions available to you inside the Kyle Microvision Toolchain. So if you actually run the code because we have no software delay loop, your LED will probably now look fairly dim on your target board as it's blinking on and off at a fairly fast rate. So if we stop our software and if we now put a break point in on our two STR lines, so line 27 and 28, so you have to click on the dark grey part in the margin to enable a break point. So if I now click run, we hit the next break point, my LED for line 28 means it's switched on and when I break on line 27 my LED is switched off and you can now toggle between those two break points like keep clicking on the run button or pressing F5 on your keyboard and your LED on your target board should now be blinking on and off as you keep toggling between these two pins. So what have we learned? So you've now seen what's needed in software wise to actually run the microcontroller from the reset point all the way to running a particular procedure which in our case is blinking an LED or toggling an LED. You've seen how quickly and easy it is to start using the Keil Microvision Toolchain. So you've been able to get up and running within a few minutes there creating a project and programming a device. And you've now had your first attempt at debugging an actual live application which is our toggling of LED application. But one question you might want to ask is our application robust? So we've done our very basic application there but is it actually robust? So what would happen if we forgot to connect a clock or forgot to configure the clock correctly? Or what would happen if we decided to do a byte-wise transaction rather than a word-wise transaction? To do this with our simple code it's fairly easy. All we've got to do is add two more interrupt vectors into our software loop. So we would now need to add our hard fault interrupt and our non-maskable interrupt. So these will capture those particular issues within our software. So these are actually, as we said earlier, the gray section of the interrupt vector table. These are the ARM-based interrupts which are there to help you trap faults within the software. So now we just need to add some extra code to achieve this. So we're going to force our software to be damaged. So I'll show you that in the code in a few seconds. And we are going to add two more lines into our vector table. So we already have our stack pointer line and our reset handle line. So we're now going to add our NMI handler and our hard fault handler. And then at the bottom of the code below where we've been hitting our break points we need to put these two extra procedures so that we can trap our software if it does go off into one of these fault conditions. So we're now going to add this bit of code to our application and rebuild our application so that we've added this extra robustness to our application. So I'm going to stop my debug environment. I'm going to add two more lines to my vector table right at the bottom of the code at line number 33. I will now paste in my two procedures to trap the errors. So now I need to force one of the errors. So I'm going to rather than doing a word-wise address I'm going to do a bike-wise address. So I'm not going to stick to a 32-bit boundary. So this should trigger my hard fault handler to get stuck. So I will also add a break point into my hard fault handler. So I will now go project and build the target. I will now re-enter debug, run the code. So we hit our first break point because our first break point has not actually loaded R1 value into R0. Remember R1 value now is incorrect. So next time I run, I have now jumped off onto our hard fault handler because the value in R1 is incorrect at that point. So the value that we're loading into R0 register is no longer correct and that has generated a fault in the system. But because of the hard fault handler, we can now trap that fault. We can now go and read through the code, find out where our mistake was which is on line 25 because I forced the mistake. And now your code is more robust. You write what happens in the hard fault handler to try and analyze the code or while you're debugging your application, you can make sure that you don't have those particular errors in your code. Okay, thank you. This is the end of the first hands-on. So after the lunch break, we will carry on with a bit more theory and then a couple more hands-on examples.