 Okay. Hello, everyone. Thank you for coming. I'm Nikolai Kondrashov. Just waiting for a sound check. Is it working? Okay. I'm Nikolai Kondrashov, and I'm here to present to you how to, very quickly, how to produce a firmware for a microcontroller from scratch without using any libraries. I only got 25 minutes, so I'm going to go very fast. These slides are available on FOSDEM page and also on my Twitter page right now, if you'd like to see them closer. So, I do this stuff as my hobby. I have not studied at the university. Actually, I dropped out twice and haven't finished my university. So, if I can do it, you can certainly do it. So, what we're going to be talking about. I just was playing with Biglebone Black and trying some assembly stuff. Then I decided to build something and bought an Arduino. And I burned it. And I thought, that's a bit of expensive if I buy it again, original Arduino. So, I found these little boards which have this microcontroller on them and they cost, with the stuff that you need to program, it costs like three and a half euros with delivery. So, you can start easily. You can buy ten of them and burn them all and learn from that. So, this is the stuff that I was able to build with it. This is out of Lego and Scandar and Printer parts and then some E-prom dumping and then this little Christmas present for my wife. And this is what I'm working on right now. This is a printer interface for the ZX Spectrum for the bus of the ZX Spectrum, not the serial one. You will still need one library and that's your library that you're going to use. And what I should call a documentation stack because there are layers and layers of it. So, the first of course is the board documentation. And by the way, have anybody programmed a microcontroller here before? Okay, anybody, anything except Arduino? Wow, that's all. Where did it come? Okay. So, I hope I will be able to tell you something new. So, starting with the board documentation, you can find it on the web with this name of the board and there is a manufacturer's website. There is some stuff. Then there is of course the data sheet for the microcontroller on the board and the microcontroller family reference manual which is the biggest one here and this is the one that you will use the most because it has the description of how everything works or the peripherals, how they are connected and what to do with them. Then there's the programmers manual which gives you programming tricks and things. And of course the technical reference manual for the Cortex-Temps 3 which is the CPU on that microcontroller and then the finally the architecture reference manual. To find out all the things that you need, this is basically all that you need, maybe just a little extra. And then this is a lot of documentation like two and a half thousands of pages but don't be afraid of them. They are very well written. These specific ones and I expect many microcontrollers have very well written documentation which tell you what to do. So the board from the top is USB socket, boot configuration pins, reset button, MCU, the 8 MHz system clock, crystal 32 kHz real-time clock and power and user led and the serial wire debug header. So if you look at the first page of the data sheet, you could see that it's maximum speed is 72 MHz which has 1.25 MHz which is 180 times more than that spectrum that you saw before. And it also has single cycle multiplication and hardware division which is amazing. It has not that much memory, actually less than the first ZX spectrum head but it's enough for the microcontroller. And lots of pins although this specific chip has not 80 but less and most of them are 5-volt tolerant which is great for experiments and for 5-volt logic and of course plenty of peripherals. So how to get your program? So you got to look at the data sheet first and it says that bootloader is located in system memory, whatever that is and you can reprogram the flash by usart1. I can't say anything else but reference manual says that you can affect what memory is mapped and which memory is used for booting using the boot pins and then this specific configuration will boot us the system memory which is where the bookloader is. And if you look at the board documentation, it also repeats this table here the ISP which is in-circuit system programmer, in system programmer, I'm sorry it's basically the same thing as the bootloader in this case and if you take a look at the default configuration you need to change just this jumper. Then finally you need to find out where to actually connect where the bootloader is listening for usart and that's visible in the separate document that I've not mentioned before. It's a big document summarizing all the configurations of the bootloaders and all the boards that ST produces from this family and it says that there's the R-axis on PA-10 and the R-axis on PA-9 and here's the pinouts basically mapped out for you. Don't forget to cross the serial text and the R-axis usual and you can supply the power from the serial cable and you can find out that for some reason it doesn't work very reliably and sometimes it doesn't turn on I don't know maybe the cable is not very good done or the voltage regulation doesn't work very well so in that case you can just take a separate mini-USB cable, micro-USB cable and connect it but don't forget to disconnect the VCC. By the way, if you manage to give me any questions there is a player present for the best question is one development kit. So that's how it will look if you connect everything and power it on. Then what to do, how to flash it, you can just basically look for it in your Linux distros and you will find STM search into flash which is exactly the tool that you could use for that and it has a ton of features and it works very reliably for me. So while we don't have a program yet we can already use that tool to verify that everything is connected right and everything works and find out the board parameters so you can see that this one is 128 kilobytes of memory which is normal for all the recent boards like this. Then before I go into the next section you have to remember this one thing so I guess the embedded engineers don't often say this but it is easy and fun to do this. Well, of course, unless you're paid for it. So there's an initial very steep ramp in knowledge but once you get past the basics it's really easy and fun and if you don't have a deadline it's very satisfying. So of course we're going to blink the LED and we'll start by finding where the LED is connected and this is the manufacturer's schematic, this is all of it basically and there is the LED Google Translate says that it says D2 is programmable. So this is the one we need but it's very curiously connected that it's... I know it is connected to the powers directly and it's cathode is connected to PC-13 which means that to turn this LED on we need to pull the pin down which would be counterproductive. If you write one you'll expect the LED to light up but we need to do the reverse here and that's because as the pin description table in the datasheet says there's a little footnote there on this pin description number five and it says that this is connected to the power switch which has only very limited current capacity 3 mA which is not enough to drive the LED so you should not do that to use it as the current source it also limits the speed to 2 mHz and must not be used as the current source to drive the LED and so the board creators were very economical and they used one of the most useless pins to drive the LED because it doesn't say that you cannot use it as the current sync so next so we are ready to sketch out our program what we need to do is to configure the PC-13 pin we need to train output 2 mHz max speed and we need to do an infinite loop and wait a little bit and then toggle the LED that's all we need to do, there's a little more but we'll see just in a moment so we have our program but we need to tell the microcontroller to run it somehow so the vector table comes in but first before that we need to see the ARM CPU reset behavior and we're not going to go through all of that it's just a piece of the end here it says that the CPU gets the vector table address from the V2R register well actually some of the highest bits then it takes from that vector address the first entry which is 4 bytes and puts it into the stack pointer which is the stack is full descending stack that means that the stack pointer should point right above the stack area it always points to the last entry that is pushed last so our stack pointer should point right above the stack pointer then it takes the next 4 byte entry from the vector table and branches to it, that's our reset handler so what we need to do is we need to somehow locate the stack we put this right here, it's not normally done that but we can do that there's the vector table so we put our stack address that is above the stack and we put our reset handler but next we don't know what's the actual vector V2R register at the reset and we don't know where we should put the vector table we don't know how so if we take a look at the architecture reference manual it says that it is zero normally but it can be overridden by implementation so we check the implementation and it says on system reset the vector table is fixed at address zero which is great for us so let's look at what's happening at address zero it's memory map from the datasheet and here we see that at address zero we can have either flash or system memory remember that system memory that's where the boot loader lives but we can also have flash and it's dependent on the boot pins from that table which means that basically what we need to do is to put our vector table at the start of the flash at address zero but we also see that flash memory is normally leaving at 0, 8 and all zeros so we need to make our code be aware that its location will be there and furthermore we can while we're here we can check where our SRAM is that's where we should put our stack and all our global variables so we can tell that to linker using the linker script so first we'll define the memory regions the flash where it starts, how long it is being safe saying that 64 kilobytes that's what we certainly get but usually it's 128 we tell it that it's a read-only executable region and then we tell that SRAM is read-write and non-executable where it starts and how long it is then we can start putting in sections we have the special section vectors that goes to flash first because it has to be at the start then we put the code next then we put the read-only data which we don't have yet and then we have the global variables going into SRAM so now we still need to tell the compiler to put our vector table into the vectors section and we use that using the GCC attributes and we tell it like put it into vectors section so it ends up at the start of the flash now next so ARM uses memory map.io which means that you talk to peripherals by writing to addresses using the same instructions that you would use for accessing memory and this is the area where all the STM peripherals leave this little piece in the address space at this address and here they are all of them there will be several instances of the same peripheral type and they would have the same register set and the same semantics and everything just different base addresses so they don't say it anywhere in the manual that's normal but you actually have to enable your peripherals before you use them which is not the same for all microcontrollers and CPUs like for example for AVR stars I could see you don't have to enable much to start using peripherals you just can't go at it but for example for AM335X and Bigelbond Black you have to enable power as well as clock and for this microcontroller you just have to enable clock so what you see here is the clock tree don't be scared it's not too bad and what it says in the manual is that at this set the microcontroller is running from the internal oscillator it's called a high-speed internal oscillator which is basically an NRC oscillator here it's running on tape microhertz that's how we are able to start executing anything before we have the clock configured so it doesn't say where our GPIOC port is connected here on this diagram so we can dig further at the system architecture and we can see that the GPIOC is located here connected via APB2 bus via HB system bus so that's where it's probably on the clock diagram and if you look here still closer here it says that it's connected here and we can try to trace out how the clock gets there so what we need to do is probably control APB2 bus settings to enable the peripheral and we didn't actually need to know all that we can just look at the registers for reset and clock control peripheral and see that there is a register at this address and this bit and it controls how the clock to dot port c finally we need to determine where the peripheral leaves and it's this address here now we can actually enable our port we take the peripheral address at the register address and then we write the bit for there all port is enabled now we can start configuring it so I usually read the whole peripheral manual before using it but we just run through the registers so there are two configuration registers because there are 16 pins and which requires four pins for configuration so there's configuration register low configuration register high then we have the input register to read the data from the port output data register to output data to the port and then we have the set reset register to atomically set or reset register the pins and reset register probably legacy just for resetting pins and finally the lock register which allows us to lock configuration for example to avoid damaging hardware if our program goes haywire so there is also a table describing all the possible configurations of the pins but we just need the channel purpose output open drain we need to set these bits in these fields in the register for 2MHz and then we can use ODR register to control the output so on the typical IO pin diagram we'll be writing to output data register reading from it because we're toggling it we'll be controlling the output by turning on and off this NMOS here so when we have one we'll have high impedance on the pin like nothing is connected that's what we need for the LED to prevent any damage to the pin and when it's zero it connects it to ground allowing the current to flow and light the LED so this is the configuration register high because it's pin number 13 so it gets the high register this is its address and we need these two fields number 13 mode and 13 configuration and we need the output mode max speed 2MHz as I said before and we need the general purpose output open drain configuration and finally the port peripheral address is here in the memory map now we're able to configure our port we write the register address and this is a bit of a math here for you it didn't have to be like that it's just fancy so finally we need to control the pin this is our output data register this address and we need the bit 13 to control it and we can write it down the register address and here we are toggling the bit what's left is just the weight and we can shortcut here and just do the weight like this so then we need to build it so you need the bare metal tool arm tool chain it's available for example in Debian install it and then we can ask the compiler to use the Cortex M3 to build for Cortex M3 CPU just compile, don't link because it will just use its linker linker script instead and then we tell the linker use this our linker script and output an L file and then while we're still here we can take a look at our L file and see where everything went so our vectors table went right to the start of the flash over there and they say it bytes long our reset routine went right after that in flash and our stack is allocated to be in them and at the start of SRAM so now we can convert that L file to a binary like pure binary basically what we're going to be flashing we can take a look at it again and see that the first entry is the end of our stack and the second entry is our reset handler and it has a bit one set to indicate that it's a thumb mode which is the only mode available for this CPU and finally the rest is our reset handler so to flash it we use STM32 flash we tell it flash that binary file and verify whatever you write and there's our board on USB 0 it takes very little while because it's very short and now we're able to run it but first we need to switch the boot pins back to have the flash mapped at the boot hub so that our program can be there at the 0 and our vector table so we just put it back in the default position and that's how it would look very exciting so another takeaway another takeaway is that all this hardware people worked hard on it and they had lots of customers before you and lots of engineers before you and they tailored it exactly to your default use cases exactly what you want to try to do when you just start with your hardware so in the end you will need to tweak a few bits to start working to start your peripheral going so it is going to get you very far okay so obviously you don't want to always copy those register addresses and all the layouts, all the time in your program so you can write a library and different people do it differently some people do it very in a very weird way, especially hardware engineers I'm sorry but it's up to them and somebody will see my way is very weird one so I just take register location into structure and store the peripheral addresses and then I describe all the bits all the bit locations and everything using Microsoft that's probably the most boring part of making things work from scratch where you have to copy these cryptic register names from the manuals and everything it reminds me of how I used to type in the programs from the magazines in the past so next, the default clock is 8 MHz and the maximum is 72 MHz if you want to do something fast you got to change that I'm not going to explain how to do that but here is approximately how it would look you go through the external oscillator and it's more stable than the RC oscillator you go through the PLL and tell it to multiply by 9 to get 72 MHz and switch to PLL when it's ready and then you have your 72 MHz clock there are a couple gotchas like this one so if you go very fast with your clock the flash won't be able to keep up and then you have to configure flash so it tells the CPU to wait while it fetches the data otherwise the CPU won't be able to read its code and won't be able to execute anything which has actually happened to me I was crashing my head and this was one little thing I was able to find eventually so and then for example the APB-1 bus it has the maximum speed of 36 MHz so you have to set up dividers to lower the clock speed for that bus this is all the code that it takes to get to 72 MHz from my library I'm not going to talk about that ok so if you want more peripherals remember the documentation specifies lots of steps that you need to take exactly the registers you need to modify to get to specific application like communicating with the VRU ZART with DMA or things like that and each peripheral has descriptions how to do this application or to that application and they usually go to great length and more complex case than you need initially and which means like this has transmitter procedure then receive its procedure but it boils down to this if you want to just receive a bit, receive a byte and send a byte and this is all configuration like from enabling the clock and everything that's all you need I didn't test it but there is a all links you can go and take a look at the code and try this out similarly with the timers and the PWEM for example very popular application it describes everything that you need to do all the registers and everything and then this is all it takes to blink an LED on a pin using PWEM and ADC very simple again single conversion mode and the continuous conversion is also not that hard so that's all the code including calibration and enabling everything and receiving the value from ADC SPI, same thing very well described transmission reception and that's all the code configurates a lot of bits there but you just copy that from the manual and finally go and experiment okay any questions so what kind of tools or techniques that you use in order to make your programs on this well you can always toggle a pin or light an LED that's what I do I just put so I have something, there's a cool project called black magic probe if you have two of those you can flash it on one of them and then contact using serial wire debugger and you have like a full gdp using that thing yeah this serial wire debug of course you can use but I don't bother I just light an LED because my programs are usually not that complicated or I use the toggle a pin and watch with the scope and see like what's the timing and things like that okay yes can we use the SPM utilities to read the firmware back from the chip I think so yeah I think you can read the it comes by default with something that blinks so you can read that if you want anybody yes is there a specific reason for you not using the C++ that thing it's a very there's a very simple reason I don't like C++ I know it's very useful but it's just my personal preference maybe I'll come around I started the C++ I was reading beyond style strap for the night you know like so anybody else anyway you don't have space for the STL okay thank you very much and the bug infection please come