Bare-Metal MCU #6: Compilers, Assemblers, and Friends

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Thanks!

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/neuromonkey πŸ“…οΈŽ︎ Aug 03 2020 πŸ—«︎ replies

Any particular reason for choosing the STM8 as the final step?

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/polprog πŸ“…οΈŽ︎ Aug 03 2020 πŸ—«︎ replies

I can't tell you how much you're helping me to understand the world of the microcontrollers with you videos.
I'm close to finish a career in electronics engineering and I can't believe that at college 90% of what we were taught was Arduino. Now, when I have to use a different framework to develop for any microcontroller at my job it always seems difficult to me and I have to go and study a lot of things on my own that I should have learned before.

I wish I've had a teacher like you back then..

Thank you so much for making this videos!! Keep up the good work

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/napchecked πŸ“…οΈŽ︎ Aug 09 2020 πŸ—«︎ replies
Captions
greetings and welcome back today we're going to learn about compilers and a few other things associated with it like linkers and optimization i'm going to try to keep the content of this video pretty generic so that way it's not applicable to just avr microcontrollers but you could also take this knowledge and use it for stm microcontrollers as well eventually our goal is to program an stm8 so i don't want to spend too much time learning just avr and then having to throw that all away and relearn it again all for just stm microcontrollers so let's get started the main purpose of a compiler is to take code that humans write and turn it into something that the processor knows how to execute in this case we can use this example of i equals i plus one and our goal is to convert it into machine code so that way our microcontroller can do something with that it's very common to store the machine code in a dot hex file so that way it's easy for a human to read but also for the programmer to transfer over to your microcontroller for something even as simple as i equals i plus one there's many different ways that you could translate that into machine code and one example of that is to take i and load it from memory which is this first section we're pulling it out of ram memory and putting it into the processor once it's in the processor we can increment that value by one so we add one to it and then we take that value and store it back into memory if you were to write this in avr assembly this is what it would look like on the right we're telling this to load some data from address in ram memory 22 into something called register 24 then we do this add word instruction where we add a hard coded one to whatever is in register 24 and then we store back whatever was in register 24 into memory address 22. my goal for this video is not to teach you how to write avr assembly code however i do want to focus on these three instructions because it's really simple and we'll convert this over to machine code to have a better understanding of what compilers are doing behind the scenes and this would be one way to execute this i equals i plus one instruction in c after you've got that in assembly and you figured out what instructions you want to do it's extremely easy to translate that into machine code which are the ones and zeros that make your microcontroller tick the program that converts assembly code into machine code is called an assembler and this is something that you can really do by hand what we're going to do here is we're going to take this add iw instruction and we're going to convert this over into its machine code which is a result of 0196 and we're going to do this by hand by referencing the avr data sheet this data sheet is documented online if you search for avr instruction set it gives you a list of all of the assembly commands that avr based microcontrollers are capable of understanding so in here we have this add iw which is add immediate to word and that means that we are going to add a hard-coded value which in our case is going to be the number one to a word and for simplicity a word is just some number being stored in a register now we can look at the details on how this adiw instruction works and there are some limitations to it firstly we can add any immediate value between 0 and 63. so we couldn't add any large numbers but if we're just trying to increase the value by 1 we could use this we also can only operate this on four register pairs so that is registers 24 26 28 and 30. for this case let's assume that we chose register 24 and that's where our value i was currently loaded reminder this is just to add one to that so we're going to say that 24 already has our value i and our goal is to add one to that so what we can do is we can take this little data sheet here and we can read what the op code is or the command to execute it we can see that it always begins with one zero zero one zero one one zero and that's called the op code which is right here that means we are executing an add immediate toward instruction after that we have some parts that we can put in whatever we want and it's split into k k d d k k kkk so we know that we want to use register 24 which means that we're going to use a d value of 0 and that's because there's two d's here two-bit number which means that we can represent any number between zero and three and those are what translate into what is shown here so we're going to use 24 which means that we're going to set our d value equal to 0 which is 0 0 when you use a 2-bit number finally we have the number k which is the number that we want to add into that register so in our case we want to add one and one in binary is just all zeros followed by a one so if we plug our information back into this formula that we've got here we end up with this number at the bottom the green section is the op code we have the blue section which is the number that we want to add and it's kind of split up here which is a little annoying but zero zero finished over here zero zero zero one and then our register is specified in red as these two zeros which will be register 24 and this number here converted into hex is 0x9601 just a reminder most calculator apps have a programmer mode so windows has one for sure mac has one for sure and the way that you switch this in mac is to go to the view drop down and say programmer mode which now gives us options to see all these different things we can set this to hexadecimal here punch in our binary number which is one zero zero one zero one one zero then all zeros and a one and we end up with our 9601 which matches up appropriately with this okay cool so now we know how to take that add immediate to word instruction reference the data sheet and convert that into the ones and zeros ourselves in order to calculate the machine code for it so if you were to look at this which is our second instruction in this set it translates over here to 0196 and you might realize that that's kind of backwards-ish from what we were looking at before and that's because avr uses little endian format which means that we do the little byte first so when we chop it up into bytes which is every two digits in hexadecimal we kind of write those in reverse so 9601 becomes 0196 any assembly code can be directly translated into machine code and vice versa machine code could be reverse compiled or reverse assembled into the assembly now modern day assemblers do give you a lot of extra features that allow to save some time when you're writing assembly code but for the sake of this video i'm just going to pretend that machine code and assembly are identical there's many different ways that you could turn i equals i plus one into assembly code or therefore machine code and the example that i gave here isn't really the best way of doing it there's there is a better way of doing that but that's what sets apart a good compiler from a bad compiler and sometimes this is the make or break between how quick your program is able to run and how compact your program is when it's compiled one such compiler for turning c code into avr based instruction set is something called avrgcc and this is the compiler that comes bundled up with arduino so let's take a look at how arduino compiles your code here we have our infamous blink example so let's push this on to an arduino uno and see what's happening behind the scenes so in order to do that i need to go to my tools and select my board this is going to go to an arduino genuine uno port doesn't matter since i'm using a usb programmer i have to specify that here is usb tiny isp which is all set and now that we're done with that we can go to the sketch drop down and hit upload using programmer and this will compile the sketch which we can see here and then upload it now i have verbose mode turned on which is in the preferences for arduino and i'm going to scroll all the way up to the top we can see that there's a lot of calls to this program called avrgcc and it even tells us where it lives on my mac that's under the applications folder arduino.app contents java hardware tools avr bin and so forth this will be in a different location if you're running windows or linux as well and then everything that comes after it is all of the arguments that tells the compiler how to compile your code in my previous video we took advantage that avr dude came bundled with arduino but for this video i'm going to show you what it's like if you were to completely ditch arduino and we'll install it manually we could use the avr gcc that came with arduino and we could just reference it by running it from the folder that it lives in but i'm going to install it as if i didn't have arduino so these are the instructions on how you should be able to install avrgcc i'm running a mac so i was able to test this out and know that everything works here i did a quick google search and this is what it looks like you need to do for linux and windows you have to download a exe file i haven't tested these so if you find out that these do or don't work please let me know in the comments and i'll update the video description but i did test the mac install as a reminder avrgcc is a compiler to compile avr code my goal with this video series is to not specifically focus on avr but rather teach you the basics of compiler so that way you can apply it to other things so instead of just jumping into a how to use avr gcc i'm going to kind of go into how to figure it out for yourself in order to learn how to run a program there's a thing called man pages and the way that you can access that on a mac or on linux is to open up a terminal and type in man and then the name of the program which is avrgcc and it will give you a giant dump of all of the documentation on how to run this let's take a peek at how to find out all the information about avrgcc so in a terminal on mac or linux you type in man avr gcc and it will give us the manual for this and this is a massive massive massive data sheet this just goes on and on and on one little tip that makes it really handy to search data sheets is to take advantage of the commands that you can do i don't know if this editor is vim itself but it's very similar you've got this little colon in the bottom left hand corner where you can execute commands if you type in slash and then what you want to search for so like mmcu and you hit enter it will search the entire document for mmcu and it shows up here and if you want to jump to the next entry just hit n on your keyboard n n n and it will keep jumping between all of these avr gcc works for more than just avr based microcontrollers you can see that there's also some arm base options and we've got blackfin and c6x but the part that we really care about is avr and it gives us a little description of some of the flags that you can use when you're compiling avr code the one that we care about mostly is this first one which is dash mmcu why do we need to tell the compiler which microcontroller we're using well if you look at an example of one of the instructions that's documented in the instruction set for avr they have this little part here that says this instruction is not available in all devices refer to the device specific instruction set summary and if you look further down in the data sheet it will tell you which devices have support for which instructions so not all instructions are supported by all microcontrollers and because of that it's important that we tell the compiler which instructions it's allowed to use and which ones it's not allowed to use because of this there is a giant list of all supported microcontrollers and if you look far enough down in the manual pages you will find the atmega328 family so we've got the 328p as well as the 328pb and all of these fall under the category of avr5 which is the avr5 instruction set if we don't tell the compiler which instruction set to use it will default to avr too with just this little bits of knowledge we are able to run a bare bones compile command so what we need to do is we need to say the name of the program which is avrgcc we need to tell it which microcontroller we're using so the compiler knows which instruction sets it's allowed to use and finally we need to tell it our c source file here so if we have a program called dummy.c and we're trying to compile it for an atmega328p we just need to do avr dash gcc specify the dash mmcu flag of atmega328p or we could hard code in avr5 here and then our file if we don't specify any other flags the compiler is just going to use some defaults for us and one of those defaults is what to save the output file as so if we don't tell it specifically what we want the file name to be saved as using the dash o flag then it will save it as a file called a dot now let's reference the code that we wrote in the first two videos here which is a very simple blink example that we tried to avoid using any arduino code possible so i'm going to open this up in vim vmw.c and we're going to essentially copy this and then work from there so we've got our define statements define uh and now we have to call port b so i'm going to call this port b i did it mitch port b before just so i wasn't copying any arduino slang we're going to do byte star 0x25 here and we're going to do that same thing here except this one's going to be called ddrb and this one is byte24 and there was one thing that i forgot to add in that screenshot we had to put this volatile keyword in there which is kind of not necessary right now but we're going to do it anyway that tells the compiler to not try to optimize this code out next we have this void setup which is what gets called first in arduino where we set the ddrb equal to 32 we're going to come down to our loop void loop we're going to do our port b equals 32 we're going to do a for loop here 4 long i equals zero i is less than some big number just to give us a long delay one one two three one two three that should be long enough i plus plus and here we're just doing some dummy code to execute we'll just repeat the same code that we had before which is port b equals 32. we're going to repeat that exact same thing for turning the light off so port b equals zero which will turn off all the ports on port b all the pins on part b do another for loop long i equals zero i is less than 100 000 i plus plus and port b equals zero so that will just begin by turning our pin on which is pin 13 and doing that over and over again 100 thousand times and then turning off over and over again a hundred thousand times and loop so this is where we left off last time let's see what happens when we try to compile this now to compile we said that we wanted to use avr gcc we want to specify our microcontroller which is dash mmcu equals atmega328 and p doesn't really matter all that much for this and now we want to say our input file which is dummy.c and you can hit tab to autocomplete and if we try to compile this it's going to throw all sorts of errors and the first one that stands out is this byte pointer that's because it doesn't understand what a byte is and it has a few basic data types that it does understand so what we're going to do instead of a byte we'll jump back into our vim is instead of using byte we're going to use a character now a character goes from negative 128 up to positive 127. so what we're going to do here is not just use a regular character because it's signed we're going to use an unsigned and an unsigned character then goes from 0 up to 255 which is therefore a byte we're going to do that here as well unsigned character pointer and let's try to compile this code again we're going to hit up twice to run our code and now it's yelling at us here saying an undefined reference to main well what this means is the structure of our code doesn't work so arduino uses setup and loop in order to run but that's not anywhere in c the way that c works is it expects there to be a very special method called main and it expects it to be an int main and then with no arguments or you can pass in some arguments if you want and this is what is normally going to run so we're going to use this instead of our setup method here so i'm just going to get rid of this and we're going to go paste it up here and we're going to get rid of our setup line altogether what we're going to do here is we're going to put our loop code in here we're going to say while one which is an infinite loop we're going to loop over and over again forever and i'm going to go into visual block mode here yank all this code paste it back over here and tab things over a little bit so it looks cleaner and get rid of our extra line that we've got here so now this is what our code looks like everything lives inside of this main method we've got our while loop which is going to be our infinite loop to keep turning things on and off and we should be good to go let's try and com let's compile this one more time and everything seems to work and if i type in ls we can see everything that's in here and we've got our a dot out which is our binary file now if we want to peek into the contents of this a dot out we could type in hex dump which will show us the entire binary contents in hexadecimal for a.out this is what it looks like it's extremely long there's a lot of stuff going on in here and this is the compiled code we have this a dot out file which is now technically machine code but the question is can we just upload that to our microcontroller i don't actually know the answer to that i do know that the standard is that everyone converts that file into a dot hex file and then you upload that instead in order to translate that machine code into a dot hex file there's a program that comes bundled up with avr gcc and that's called avr obj copy so if you installed avr gcc you should already have this command on here and if you just type this into a command prompt blank and you just type in avr obj copy it's going to say hey you you forgot a few things maybe you should try some of these commands and this gives us a bunch of different options and the ones that we care about are this dash o flag and the dash j flag dash o is what we're going to specify our output target as so we need to specify that we want our format to be a dot hex file this dash j has something to do with the contents of what a compiled file looks like so this is what a bare bones command looks like we type in avr object copy which is our program name we have to specify the output format and that would be done with this dash o capital o i hex and then we specify the file that we want to read from which is our a.out file which was generated from our compiled code and our output file would become a.hex the reason that we're using this ihex file is because that was one of the formats that avr dude supports as an input file and i'm sure that you can find some other output formats that this avr object copy supports and avrdude supports but hexadecimal seems to be the most common so we're going to go with that if you were to break down the contents of that a.out file it would fall into something that looks similar to this at the very beginning we have this section called the text section then we have the data section then we have something called the stack we've got some free empty space and a heap and this is what your program generally looks like however the only parts that we really care about for our microcontroller is the text section and that is where all of our code lives and then this data section and data is just where it kind of dumps a bunch of memory and that's usually how it's organized is two separate sections it could be interleaved but it's almost always done like this we don't really care about our stack free space or heap so we can tell avr object copy to only use this text and data which will make our hex file much much smaller which then allows us to put more data on our microcontroller by using this dash j flag so if we want to just use the dot text and data we do dash j.text and dash j.data and it will ignore everything else so this is kind of the recommended minimal format of this command which would be then avr object copy our output format as intel hex jtext j.data and our input file is a.out and our output format is a error output file is a.hex so let's give this a shot we've got our files here we have a.out and then our original source code dummy.c and we're going to do avr object copy obj copy and we want to specify the output format capital o i hex for intel hex format we want to do just the dot text and just the dot data section from that our input file is a.out and our output file we're going to call it a dot hex so after we're done with that seems to run just fine we can do a we can do cat to just show us the data this will dump the hex file that we've got a dot hex tab to complete and this is what it looks like so this is the intel hex format and this is our blink example after it's been compiled and then translated into hit intel hex format and this is something that avr dude is able to read i've got my cheat sheet from my previous video on how to run avr dude one of the things that we do need to look up though is where this avrdude.com file is there's one that's bundled with arduino but since i'm trying to distance myself from the whole arduino ide we need to find that on our own so i'm just going to open up a file search here and i'm just going to search for avrdude avrdude.conf which is the name of the file should show up a couple of results because some are arduino let's see this is part of mightycore which is arduino i don't want to use that one it looks like this is also arduino which there we go so this is the one that comes pre-installed this is the default configuration file that comes when you install avr dude on your computer on your own so i'm going to copy this as a path which if you hold the option key on a mac or alt on windows you can copy it as a path name so now i've got that in my clipboard and let's actually run this command so avr dude dash capital c for our path and i'm just going to paste that in there there's our configuration file yeah we'll do dash v for verbose so we can see extra stuff the chip our target chip is dash p at mega 328 p our programmer is dash c usb tiny now if you're using an arduino as isp you have to specify a couple of other commands in here which are covered in my other video and now the data dump what we actually want dash used for a user program our goal is to flash something we're going to flash we're going to specifically write data and now the path to our sketch and since we're in the folder that we want we just want to do our a dot hex file so i can run that we can see a lot of stuff happens and let's check if that did anything all right we can see that our led is blinking it's blinking very slow but that's just because we chose an arbitrary amount of time to wait but it looks like our code compiled copied and uploaded to our microcontroller now you know the basics of how to compile code that an avr microcontroller can understand in order to write practical code there's still a few other things that you need to learn specifically linkers and optimizations that's going to help you write larger code maybe tie in some libraries and also make sure that your code size stays tiny enough so that way you can pack more onto your microcontroller unfortunately i ran out of time for this video because it took a little bit longer to cover the intro than it was expected to but i will push everything else into another video and i'll see you next time
Info
Channel: Mitch Davis
Views: 6,173
Rating: 4.9864407 out of 5
Keywords:
Id: 7lcY5tcP_ow
Channel Id: undefined
Length: 23min 36sec (1416 seconds)
Published: Sat Aug 01 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.