rust runs on EVERYTHING (no operating system, just Rust)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the Raspberry Pi is one of the best boards you can use to learn embedded programming in minutes you can have Linux on this thing and use it for your next iot or embedded project but in this video we are going to do a blink LED entirely in Rust with no Linux yup you heard me right no operating system no Linux just pure bare metal rust the way we'll do this is we'll write a custom kernel and rust that is flat and runs bare metal put it on the Raspberry Pi and then use that to Blink an LED you can take this code further to do uart communication or maybe even write your own kernel for your own OS written completely in Rust let's get started the video today will be using the raspberry pi 3 Model B we'll have an LED hung off of pin 21 gpio pin 21 and then we'll use that with a 470 Ohm resistor to tie back into ground on the Raspberry Pi okay so to get started we'll have to first make our cargo project again my assumption here is you have rust installed you have rust up installed and you can use cargo to create projects right so we're going to say cargo new will do my my rusty pie and we'll CD into that application real quick and then we'll code this directory opening it up this will show us we have a few things created by default by the rust you know cargo manager you have the cargo file here and our main source code file so if we do basic things like cargo build we'll build our project and we'll get a Target binary built for the uh the Linux environment we have running so a few things wrong with that first we don't want to use Linux a and then B we don't want to use the x86 Intel processor right so to change the processor to the arm chip that is based on the Raspberry Pi we have to do a few things so we're going to make a folder called dot cargo and then inside that file we are going to make a actually let's do touch config it's a config file you'll see that appear here in code and then to add the arm build chain we'll say for the build phase the target is always the arm v7a none the nun means there's no underlying operating system and then the extended ABI for the hardware so this will say by default we build for the arm tool chain V7 which is 32-bit awesome so if you go back we try to build again we'll actually run into a lot of issues so what's going on here is the code is written for the Linux environment using the standard library but the build chain is not so we have to modify this code pretty heavily to make sure that the code is designed for the embedded platform so we'll delete all this code we'll do a few things to start so step one if you're doing any embedded rust you have to do the no standard Line This Means essentially it tells the rust compiler hey don't incorporate the standard Library do completely bare metal code and then also we're going to do no main so no main what that does it tells rust compiler we are not going to use the main function as our entry point we are going to take care of the entry point ourselves and that's kind of a bigger part of this video is making sure that the code is organized in a way that our start function gets ran first we're going to use the function start as our entry point it's going to return nothing and to confirm that to the compiler we have to do an infinite loop at the end so this means return nothing it never returns and we Loop forever to confirm that also we need to make sure that the start symbol is globally accessible meaning the Linker can see it at link time to make sure that it's ordered the right way the way we do that is we say that it's a public function and also it's an extern C which means we expose that symbol to the Linker and to make sure that the name is manageable we say no mangle because by default it might mangle this name we want to make sure that in the link environment the symbol name is start okay awesome so we can also do is try to build again we'll probably get a panic Handler error so to make the processor happy we have to provide a Handler for the processor to use if it goes into a panic state so like a hard fall a soft fault a bus error stuff like that so we are going to create our Panic Candler here and we'll describe it with the Panic Handler option here versus the function is called uh not public it's called Panic it takes a reference to a panic info type it also does not return and to make the compiler happy we will also just infinitely Loop here you know in theory you could do some kind of debug output with the console but we're not going to deal with that and we have to actually include this type as well so to include the Panic info type we do use Core X core panic Panic info and then this should make it happy yeah cool so we have created a bare metal project that compiles an elf that has a start symbol and it has a panic symbol okay not a lot really going on here and there's actually a few issues with this so if you do object dump on our binary so it's in Target the build shame name debug and then my my rusty pie if you look at the binary a couple things are wrong with this first the binary has a lot of extra information above it above the entry point because essentially we're going to take this image that we're creating we're going to put it on the SD card plug it into the Raspberry Pi and it has to run at start so two things have to happen one start needs to be at the beginning of the image and start also needs to be at hex 8000 hex 8000 is the Base address of images that go onto the Raspberry Pi that's where they're loaded by the bootloader so we need to fix this using a Linker script if you've watched my previous videos I've used a Linker script in the past with the bare metal video to make sure that start is loaded at the right address we're actually just going to go ahead and borrow the Linker script and add a couple things to it to make sure that it does what we want it to do so we're gonna go ahead and grab that real quick Link in the description for those that are following along call it linker.ld okay and here's the script again from a previous video I'm not going to walk through this in too much detail but essentially what we're doing is we say the entry point is start that's not super important the big thing here if you set the Base address of the image to hex 8000 and then we say the text segment is next and then follow along with follow-on segments after that one thing we do need to do is make sure that the start symbol is at the very beginning of this image like for example if I made another function called the function Foo let's do I i32 and it returns an i32 and it returns uh one I plus one or whatever right there is a possibility that at compile time and Link time foo gets put above start and then it jumps into food to start the program we don't want that so we need to use a cool thing called Global assembly to make sure that this symbol is put at the beginning of the image we'll do that with the following code so use boot we need to include a cool module called Global assembly and Global assembly is going to be a macro that we say dot section dot text Dot start and we end this is the semicolon what this does is it says all the code below me is in the dot text Dot start section and then we can use that section name in the Linker file to make sure that it gets included before the rest of the code so that means that start will come before anything else we're going to delete this because we don't actually care about this okay so we'll do cargo build again nothing will change because we actually need to make sure that we invoke the cargo build chain with our Linker script being included so we'll do the following command to do that so instead of using cargo build we're going to say cargo rust C so this adds a compiler flag and it says we add a link ARG that the Linker script is equal to our local linker.ld and we should see nothing that happens here I want to make it very clear if you modify the Linker script at all the build chain actually won't run until you delete your targets what it does is it scans all of your source code and only builds your project if it sees that source code has changed but if a link or script doesn't change it's not actually scanning that so I would say anytime you edit your Linker script to perfect yourself from going crazy uh Delete the target folder so we're going to actually RM Tech RF Target folder and then rebuild in the little object dump oh hello object dump cool so now a couple things have happened things have changed uh first we have the text section at the beginning of the uh the program the start symbol AS is first and then also the start symbol is loaded at hex 8000 so perfect we are we are golden the final thing we need to do to make this image usable on the Raspberry Pi is we need to extract away all of the extra information that came with the elf right so if you're familiar with you know Linux programming when you produce files that get produced as this elf file this executable and linkable format that Linux is familiar with right we need to rip the code out of the elf file and put into a flat binary file the way we do that is actually pretty simple we're going to use Arm none eabi object copy and we're going to say the output format will be a flat binary we're going to take in our Target file here my rusty Pi the elf we're going to Output it locally and call it kernel 7 dot image so now if we do a file on this it's just okay this is actually a an error it's not real but if we look at it in xxd we can tell that it's just flat code this is actually the arm instructions for the start function so that's it this is all we care about is getting the text out of that that code okay great so in theory if we put this kernel 7 image on a Raspberry Pi right now it would run our infinite Loop code with start which not very exciting so now what we're going to do is we're going to make the code actually turn the Raspberry Pi's pin 21 as I showed you in the schematic before on and off so for doing gpio we need to consult the broadcom 2837 arm peripheral data sheet when you're doing any kind of embedded programming you need to figure out what are the addresses that I'm concerned with to make things happen on the chip so looking at the the data sheet here and again link I'll put this in the description if you want to follow along we are mostly concerned with this complicated graphic here it's really not that bad called the memory map and essentially it tells us that the i o peripherals for the bus addresses live at this location but in the actual Physical Realm the physical addresses that live somewhere else we're not going to worry about the picture too much but we are going to worry about this line here this gets a lot of people in trouble when they're doing embedded programming you just need to understand that if the data sheet says this address 7e you actually need to use is 3F that has to do with the way that the buses are set up the bus address is this but when you're actually writing to it using data the physical address you need to use 3F don't worry about that too much but we're going to do now is we're actually going to read the data sheet and go to the gpio section which will leave us on page 89 yep boom 89 we'll go there right now eight nine and this is going to describe to us how do we use the gpio interface on the chip to make the pin go on and off right a lot of stuff going on here the only things we care about are going to be the function selectors and the set and the clear okay because the function selectors if you haven't done embedded programming before we have to tell the PIN to be an output that's step one and then step two we need to set the pin and clear the PIN to make the pin go on and off you know hot cold five volts ground whatever you want to call it so we need to figure out how do we actually set the PIN to be a gpio pin so essentially the way that this works is if we wanted to modify pin 9 for example right if we wanted it to be an output we would write one two bits 29 through 27. and so talking about pin 21 we need to do the same thing we need to write bit one two bits five through three so essentially removing the one into the third position so that's what we're going to do here and again that address is probably in the data sheet right here so what was it it was three e or seven e two zero zero zero zero eight so we're gonna copy that and we're gonna make it a comment this is going to be our F cell 2 and again remember the 3E becomes 3F okay so that's step one that's just this is to turn the PIN turn pin 21 into an output okay now that it's an output you know we're at the code for that here in a second but once it's an output we need to then turn it on okay turn it on we will do the same thing we need to use the output set 0 or 1. I forgot which one it is we'll go check it out real quick okay so we need to do output register set zero because by setting the nth bit we turn on that pin so we want to set the 21st bit turn on the 21st pin and that address is where again we'll check it out on the data sheet here that's going to live at hex 0 1 C okay so we'll copy this down 3f20001c that's going to be gpio one set we're going to set that to pin 21. so again this turns it into an output this turns pin 21 on and then same thing we need to turn the pin off using the exact same methodology so if this is the output set the output clear lives at 28. three F two zero zero zero two eight gpio one clear one Twenty One turns pin 21 off okay great so now we need to actually implement this code in Rust uh there are a couple ways we can do this I'm going to be completely transparent I'm not going to do it the most clean and efficient way uh but what we're going to do here is in our our start function we're going to do a few things unfortunately all of this code is going to be unsafe I know some restations may be mad leave a comment if you're mad we'll talk about it we'll figure it out okay not a big deal um so the unsafe code is going to do a few things first we need to you know set the F cell pin to be you know one left shift by three to turn 21 into an output so it will do that this will use as a core pointer write volatile and we'll say hex 3 f 2 0 0 0 8 as a mutable u32 pointer and we're going to write the value one left shifted by three or yeah for this one it's three we'll close that off so comment turn pin 21 into an output cool so what we've done here is we've literally just treated this address as a pointer to a u32 and written this thing here so now the pin is output awesome so then we're going to do a loop because this is where we're going to get into our while loop for turning the pin on and off we're going to do core pointer right volatile same exact thing and we're going to write to this address here as a mute 32 pointer we're going to say left shift 121 and then we can actually just copy this line right here paste it and set it to 28. and now this will turn the pin on and off so turn pin on turn pin off it's a pretty pretty cool the issue here is if we do this this will happen so fast our eyes won't actually be able to see the pin turn on and off so we need to actually include a loop of knobs to give a artificial delay in the in the program so we will do that is we'll do another loop we'll do four nothing in one dot dot five thousand or I think it's 50 000 is good and we'll say use the assembly macro and do not forget to make this work we need to use core Arc assembly we can actually just copy and paste this twice so make sure you put a semicolon here and put it at the end now we could do our real C command again build it with no issues and let's make sure that in our actual program we object dump it and now there's more code right so I just want to make sure the code actually compiles it gets included when you're doing Linker through like this sometimes the compiler decides hey you're not going to use that code so we're not going to include it but here in the assembly you'll kind of see at an extremely high level uh the code turns on WE load up the address of the F cell 3f208 and we store 8 there which is one left shifted by three so we're good and then we set the pin on do some sleeping let me set the pin off so we're all good to go this code should should work so step one to get our code running on our Raspberry Pi we'll have to do a few things the first one is do the object copy command again that pulls the text out of the image and puts it into this kernel7 dot image file here to get it to run on a Raspberry Pi we'll have to include this kernel 7 dot image as well as three other files to make sure that the program runs based off the way the bootloader expects it on the Raspberry Pi so we're gonna go make a new window we're going to open Firefox we're gonna go to the Raspberry Pi firmware folder or firmware repo and we're going to download three things from this refill so go to boot we have to download first the fix up.dat file download that start dot elf and bootcode.bin so we're going to in our Mount folder copy downloads bootcode dot bin downloads Dart dot elf and downloads uh what is it fix up.dat copy them here as well as make a new file called config.txt and to say that arm 64-bit equals zero to make sure we tell the bootloader to load into a 32-bit environment okay once we have that we'll then finally copy our my rusty pie kernel kernel7. image Here and Now with those files available remove LOL because that's not relevant um we have the necessary files to get it booted on a Raspberry Pi so take those files take a FAT32 formatted SD card put those files on that SD card plug it in and we'll see what happens anyway guys that's it for now thanks for watching negative numbers are actually kind of weird you should go check out this video to figure out how they work go go click okay goodbye
Info
Channel: Low Level Learning
Views: 349,982
Rating: undefined out of 5
Keywords: rust, embedded rust, rust programming, baremetal rust, raspberry pi, pico, rpi, microcontroller, arduino, maker, craft, hobby, electronics, wires, temperature, safety, project, board, electric, leds, led, thonny, python, micropython, os, ide, onewire, ds18b20, circuitpython, review, launch, measure, probe, rp2040, specs, specifications, how to, guide, programming, Pico emulation, retro games raspberry pi pico, etaprime, eta prime, raspberry pi pico, arm cortex m0+, low cost
Id: jZT8APrzvc4
Channel Id: undefined
Length: 18min 9sec (1089 seconds)
Published: Fri Sep 02 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.