I really appreciate that you keep it short and focus on the content. I immediately subscribed because you don't waste our time to remind us to do so. Thanks
Wow you this must be among the most underrated channels in the whole UA-cam. Very nice. It would be interesting to expand the example to program a timer to interrupt the CPU instead of using a counter 👍
@@LowLevelTV oh you are saying most of your audience is college students? 😂 I've been into embedded development for several years and I think your videos are really good, and can benefit a great range of individuals, from gifted high school kids to seasoned developers that might be new to a platform and need a quick start. Very good job!👍👍
very helpful and clear to understand. Thank you for taking the time to explain. I believe that is a RPi 3 and it is worth noting that RPi 2 functions differently to RPi 3 in terms of direct register control.
@@LowLevelTV It may be more useful to target the Raspberry Pi Zeros. These are cheaper and would be a more logical choice to base a low-level hardware project on, I think. Also, some people (like me) would be afraid to brick the more expensive Pis... Low level Pico programming would also be interesting and useful!
Looks like this is ARMv7A code, how do I run it on an ARMv8A machine? (Apparently it is backwards compatible in “AArch32 mode” but I’m not sure how to do that.
Oh good point I didn't even consider the new Pi's are AARCH64. I can make a tutorial on this. The answer is you'll need to write some code to jump into AARCH32 mode, which I'm fairly sure is similar to how you enter thumb mode. Obviously you'll need to check the Datasheet of the other chip, as the GPIO address/structure probably changed.
@@LowLevelTV yeah the data sheet is a bit different for each SoC! I would love a tutorial on jumping between AArch32 and 64. I’m sure it’s fairly easy as you say but there isn’t much info online yet as the 64 bit Pis are quite new! No rush though, I’m sure you’re busy; but you’ve got some great embedded software programming videos out now and I think this would help a few people in your audience
This is a nice example, thank you for that. However, in reality there are a few things that make this much more complicated if you want to really have control over the system. Modern application processors, like the Arm SOC on the RPI, require a lot of tedious setup to bring them out of there power-on state to a useful and safe operating state. The RPI bootloader does the bare minimum of that, but not all of it. Understanding the required configuration and writing code to set it up can easily take tens of hours. It would be great if you could dedicate a video to some if these issues!
There's a library available for the pi that enables it to act as a RF transmitter with a wire antenna on a GPIO. There seems to be little detail about the operation, would be intesested in a breakdown of this code on the pi processor
Greetings, the explanation is: - GPFSEL Registers are 32 bits wide, with 30-31 bits not used (“reserved”), this gives us 0-29 bits for GPIO function selection - GPIO function selection is 3 bits wide per pin (3:26 in video) - thus GPFSEL0 covers GPIO0-9, SEL1 - 10-19, SEL2 - 20-29 PIN numbers
thank you for your tutorial, how exactly did you put the code on raspberry pi? didnt you just replaced the kernel.img file and left everything else untouched or how?
come on, tried so many things with it, and even your .img file, it just didnt work... something its here wrong, but i dont know what, there could be so many reasons..
@@drominitoketchup Ah! Okay. Yes, that has quite different architecture to what he was talking about at the time. I'm still not entirely sure, but I think this was done on a Pi 3B, or similar. Unfortunately, it doesn't have enough detail of what to actually do to get the code onto the card, for me, but I'm fairly certain this wouldn't work on a Pi4 or Pi 5.
I'm trying this on a Raspberry Pi 3B+ (which appears to be used in the video) and there are a few things confusing me here... 1: LLL is writing Armv7 Assembly, but the CPU on the RasPi 3B+ is an Armv8 CPU - the assembly language is different between these 2 architectures. Do we have to convert the Armv7 to Armv8 ourselves? I could probably do this, but I don't know if this is a red herring or not. 2: How is the kernal.img file written to the SD card? Do you flash it using something like the Raspberry Pi Imager or balenaEtcher, or do you just format it as FAT32 and copy the .img file across to it? 3: Is kernel7.img the right file name? When I flash an OS like Raspberry Pi OS to an SD Card I see a kernel8.img, but no kernel7.img. I've played around with some of this and I'm kinda at the point where I'm wondering how the example in the video even works at all. 😅 I have a similar LED setup to the one shown in the video and when I probe the GPIO pins I don't see the voltage changing as you would expect it to. I'm new-ish to Assembly and have never done Baremetal programming before - so to start with I just kinda wanted to take code someone else has written and run it without making any mods to make sure I've got the process right - which I feel like I don't because I can't get this to work.
Sooo after a bit of playing I'm now ✨ englightened ✨. Take some of this with a grain of salt - as I said before I'm a newbie, but this is my understanding for anyone else feeling stuck. Item 1: You can make a 64bit Arm CPU boot in to a 32bit mode by calling the Kernel Image file 'kernel7.img'. Item 2: You can just copy the file across to a FAT32 SD card. It's important that there's only one kernel*.img file on the SD card. You will also need 'bootcode.bin' and 'start.elf'. If you're new to this like me then the easiest way to do this is to flash Raspberry Pi OS to an SD card and delete all the files apart from 'bootcode.bin' and 'start.elf'. Then copy over your kernel*.img file. You should end-up with three files: bootcode.bin, start.elf, and kernel*.img. Item 3: Related to item 1. Low Level Learning wrote Armv7 Assembly, which is a 32bit architecture. It seems you can make a Raspberry Pi boot in to 32 bit mode by calling the kernel file kernel7.img. It's also worth going through the process of converting LLL's code from Armv7 to Armv8. I managed to port it over and found it a useful experience (you'll need to call your kernel file kernel8.img!). After I did that I started poking around the datasheets to figure out how to make different GPIOs toggle. Now I can flash TWO LED's at the same time! 🙂
Why does the OS let you access the address directly using assembly but not when using C, thus all this stuff about kernel drivers and interface files when using C. If I can access an address directly using assembly can I make a C-callable assembly method?
@@Daweim0 Okay, I guess I don't understand how one can program a Raspberry PI without an OS which this one seemed to have giving it was using lxterminal
He sets the GPIO Function select 2 register (Table 6-4 in the documentation). He sets bits 5-3 to be 001 (output), but the bits 2-0 are still to the right of it so it becomes 001000 which is equal to 8.
I am very confused as to why registers are r0 and not w0/x0. I find it very hard to understand what isa this is. I thought this is armv8-a? but that would mean that it's x0 and not r0?
This is nice.... but I'm learning ARM for the STM32.... so as much STM32 specific stuff would be ideal. :) Any idea why it's "kernel7"? Where does the "7" come from?
Hi, I translated this code to 64 bit arm assembly and trying to run it on rpi4, but with no effect. Do I have to remove everything from boot partition leaving only kernel file? Actually I also tried that exact kernel7.img file from your git repository on a rpi zero and it didn't work as well :( I tried putting it in boot partition and root but it didn't work. What am I missing?
Greetings from the Internet, bold programmer. Just guessing, there's only ten people on the planet who are actually doing 64-bit assembly to the RPI4 at this time. Grimm's technique is to lookup the GPIO offset from /dev/gpiomem. Pretty sure I'm using the 64-bit Ubuntu image for the Pi in my own testing. Note that the register syntax is different for ARM8, you use X0 for example. In my build file I use this technique for determining the number of bits we're running under and then steering as appropriate. ```#!/bin/sh BITS=`getconf LONG_BIT` echo "$BITS-bit detected" as -o helloworld.o helloworld-$BITS.s ld -o bin/helloworld helloworld.o``` Note that you'd then have two versions of your assembly file with '32' and '64' there at the end of the filename. github.com/Michael-Grimm/GPIO-ARM-64-bit-assembly
Not sure I have ever heard address decoding described as a "physical address", not sure I like it, it grates in the same way as people who start sentences with "so" ....
@@LowLevelTV I'm just showing my age, when I was a lad (working with z80s) we only had "addresses, pages and offsets", but I guess we did not have MMUs ;-)
It's so frustrating how many assumptions are made even in the data sheet which means relatively new learners who don't know these funky embedded considerations will be walking blind. For example, in the latest BCM2835 peripheral datasheet on Pi's site, they state "Physical addresses range from 0x20000000 to 0x20FFFFFF for peripherals..." When THE HECK DID THEY CHANGE IT FROM 0x3F00_0000 to 0x2000_0000??????
@@maximilien7737 I don't think it should matter. The... I forget what they called it, I think "architecture" is the same for a number of models. So you can use the same datasheet. I'll check again when I'm in front of my laptop.
You just explained it amazingly. How can I contact you? (as my discord access is denied) I would love to contact you to know something regarding baremetal project
Great stuff! This episode is my first baby step in ARM bare metal coding!
we love u dave 🫶
I really appreciate that you keep it short and focus on the content.
I immediately subscribed because you don't waste our time to remind us to do so.
Thanks
Wow you this must be among the most underrated channels in the whole UA-cam. Very nice. It would be interesting to expand the example to program a timer to interrupt the CPU instead of using a counter 👍
Thank you sir! Hopefully the onset of the fall semester will bring on more views teehee.
Great suggestion!
@@LowLevelTV oh you are saying most of your audience is college students? 😂 I've been into embedded development for several years and I think your videos are really good, and can benefit a great range of individuals, from gifted high school kids to seasoned developers that might be new to a platform and need a quick start. Very good job!👍👍
Very interesting video !!! You give so much information in only 8 minutes ! Well done. now I want to try some bare metal programming 😀
Go for it!
You are doing God’s work with this channel
very helpful and clear to understand. Thank you for taking the time to explain. I believe that is a RPi 3 and it is worth noting that RPi 2 functions differently to RPi 3 in terms of direct register control.
Thank you!
I'll probably continue this series and port it to the Pi 4 at some point :)
@@LowLevelTV It may be more useful to target the Raspberry Pi Zeros. These are cheaper and would be a more logical choice to base a low-level hardware project on, I think. Also, some people (like me) would be afraid to brick the more expensive Pis... Low level Pico programming would also be interesting and useful!
@@Andreas-gh6is Pi Zero would be same chip as Pi 1, isn't it?
@@Andreas-gh6is how would you brick it if you can just insert a fresh OS age if you mess it up?
Great explanation! 👍🏻
Looks like this is ARMv7A code, how do I run it on an ARMv8A machine? (Apparently it is backwards compatible in “AArch32 mode” but I’m not sure how to do that.
Oh good point I didn't even consider the new Pi's are AARCH64. I can make a tutorial on this. The answer is you'll need to write some code to jump into AARCH32 mode, which I'm fairly sure is similar to how you enter thumb mode.
Obviously you'll need to check the Datasheet of the other chip, as the GPIO address/structure probably changed.
@@LowLevelTV yeah the data sheet is a bit different for each SoC! I would love a tutorial on jumping between AArch32 and 64. I’m sure it’s fairly easy as you say but there isn’t much info online yet as the 64 bit Pis are quite new! No rush though, I’m sure you’re busy; but you’ve got some great embedded software programming videos out now and I think this would help a few people in your audience
@@gregoryfenn1462 I would love to see that too.
This is a nice example, thank you for that. However, in reality there are a few things that make this much more complicated if you want to really have control over the system. Modern application processors, like the Arm SOC on the RPI, require a lot of tedious setup to bring them out of there power-on state to a useful and safe operating state. The RPI bootloader does the bare minimum of that, but not all of it. Understanding the required configuration and writing code to set it up can easily take tens of hours. It would be great if you could dedicate a video to some if these issues!
This is so amazing!! Thanks a lot for making this video.
Wow this is amazing!!! Good job!
Thank you!
Brilliant as always. Love the bare-metal ASM.
There's a library available for the pi that enables it to act as a RF transmitter with a wire antenna on a GPIO. There seems to be little detail about the operation, would be intesested in a breakdown of this code on the pi processor
Amazing, such projects were my dream, great content keep up the good work.
Do I have to flash the kernel7.img in the SD card or make a file system inside the SD card and copy the kernel7.img there?
Good question. You just drop the kernel7.img file onto an SD card that is formatted normally for a Raspberry Pi.
@@LowLevelTV in which directory ? /boot ...
@@jyvben1520 in the root directory
@@LowLevelTV:
Interesting video. 👍
Mr. LLL, so we need a RASPBIAN-OS con the SDCard, and move the KERNEL7 compiled file to the card? and boot up.
can you tell me how you connect the cables to the pi? in interested where the white cable goes plus where goes the cable under the lan port
how did you put the kernel image on the sd card? with dd ? or can somehow the cpu without any rom read filesystems ?!
Hello, does anyone know why we had to choose GPSFEL2 rather than any of the others? Thanks
Greetings, the explanation is:
- GPFSEL Registers are 32 bits wide, with 30-31 bits not used (“reserved”), this gives us 0-29 bits for GPIO function selection
- GPIO function selection is 3 bits wide per pin (3:26 in video)
- thus GPFSEL0 covers GPIO0-9, SEL1 - 10-19, SEL2 - 20-29 PIN numbers
thank you for your tutorial, how exactly did you put the code on raspberry pi? didnt you just replaced the kernel.img file and left everything else untouched or how?
same question!
I don't understand where you got the 0x3f200000 from
See section 1.2.3 & 1.2.4 from the documentation. It explains why you use 0x3f instead of 0x7E.
What is the name of development environment you are using???
How is a make file created???
Is there a library where you can flash it using python, c# or c++ ? I made a game with pico but would like to try on its big sister
come on, tried so many things with it, and even your .img file, it just didnt work...
something its here wrong, but i dont know what, there could be so many reasons..
Out of curiosity, which model of Pi are you trying it with?
@@TooSlowTubeRasPI 5
@@drominitoketchup Ah! Okay. Yes, that has quite different architecture to what he was talking about at the time. I'm still not entirely sure, but I think this was done on a Pi 3B, or similar. Unfortunately, it doesn't have enough detail of what to actually do to get the code onto the card, for me, but I'm fairly certain this wouldn't work on a Pi4 or Pi 5.
can I make in C to control via registers?
I'm trying this on a Raspberry Pi 3B+ (which appears to be used in the video) and there are a few things confusing me here...
1: LLL is writing Armv7 Assembly, but the CPU on the RasPi 3B+ is an Armv8 CPU - the assembly language is different between these 2 architectures. Do we have to convert the Armv7 to Armv8 ourselves? I could probably do this, but I don't know if this is a red herring or not.
2: How is the kernal.img file written to the SD card? Do you flash it using something like the Raspberry Pi Imager or balenaEtcher, or do you just format it as FAT32 and copy the .img file across to it?
3: Is kernel7.img the right file name? When I flash an OS like Raspberry Pi OS to an SD Card I see a kernel8.img, but no kernel7.img.
I've played around with some of this and I'm kinda at the point where I'm wondering how the example in the video even works at all. 😅 I have a similar LED setup to the one shown in the video and when I probe the GPIO pins I don't see the voltage changing as you would expect it to.
I'm new-ish to Assembly and have never done Baremetal programming before - so to start with I just kinda wanted to take code someone else has written and run it without making any mods to make sure I've got the process right - which I feel like I don't because I can't get this to work.
Sooo after a bit of playing I'm now ✨ englightened ✨. Take some of this with a grain of salt - as I said before I'm a newbie, but this is my understanding for anyone else feeling stuck.
Item 1: You can make a 64bit Arm CPU boot in to a 32bit mode by calling the Kernel Image file 'kernel7.img'.
Item 2: You can just copy the file across to a FAT32 SD card. It's important that there's only one kernel*.img file on the SD card. You will also need 'bootcode.bin' and 'start.elf'. If you're new to this like me then the easiest way to do this is to flash Raspberry Pi OS to an SD card and delete all the files apart from 'bootcode.bin' and 'start.elf'. Then copy over your kernel*.img file. You should end-up with three files: bootcode.bin, start.elf, and kernel*.img.
Item 3: Related to item 1. Low Level Learning wrote Armv7 Assembly, which is a 32bit architecture. It seems you can make a Raspberry Pi boot in to 32 bit mode by calling the kernel file kernel7.img.
It's also worth going through the process of converting LLL's code from Armv7 to Armv8. I managed to port it over and found it a useful experience (you'll need to call your kernel file kernel8.img!). After I did that I started poking around the datasheets to figure out how to make different GPIOs toggle. Now I can flash TWO LED's at the same time! 🙂
@@PokehTube thank you a lot for your comment, honestly it needed to be told
Why does the OS let you access the address directly using assembly but not when using C, thus all this stuff about kernel drivers and interface files when using C. If I can access an address directly using assembly can I make a C-callable assembly method?
There is no os in this video's method
@@Daweim0 Okay, I guess I don't understand how one can program a Raspberry PI without an OS which this one seemed to have giving it was using lxterminal
I'm just curious, how does setting pin 21 as output with bits 5-3 translate to 0x8
He sets the GPIO Function select 2 register (Table 6-4 in the documentation). He sets bits 5-3 to be 001 (output), but the bits 2-0 are still to the right of it so it becomes 001000 which is equal to 8.
Please do more!!
That's what she said.
I am very confused as to why registers are r0 and not w0/x0.
I find it very hard to understand what isa this is. I thought this is armv8-a? but that would mean that it's x0 and not r0?
He actually uses armv7 so 32 bit instead armv8 64 bit
wait. the official docs have an error in them?
This is nice.... but I'm learning ARM for the STM32.... so as much STM32 specific stuff would be ideal. :)
Any idea why it's "kernel7"? Where does the "7" come from?
I think its armv7 and armv8 where armv8 means 64 bit so 7 means 32
ARM for STM32 is very different from a SoC. The STM32 is a microcontroller and doesn't have a ROM or a kernel.
Can you do this to rp2040 on pico pi
Hi, I translated this code to 64 bit arm assembly and trying to run it on rpi4, but with no effect. Do I have to remove everything from boot partition leaving only kernel file? Actually I also tried that exact kernel7.img file from your git repository on a rpi zero and it didn't work as well :( I tried putting it in boot partition and root but it didn't work. What am I missing?
Different raspberry pis might have different addresses. Maybe
Greetings from the Internet, bold programmer. Just guessing, there's only ten people on the planet who are actually doing 64-bit assembly to the RPI4 at this time. Grimm's technique is to lookup the GPIO offset from /dev/gpiomem. Pretty sure I'm using the 64-bit Ubuntu image for the Pi in my own testing. Note that the register syntax is different for ARM8, you use X0 for example. In my build file I use this technique for determining the number of bits we're running under and then steering as appropriate. ```#!/bin/sh
BITS=`getconf LONG_BIT`
echo "$BITS-bit detected"
as -o helloworld.o helloworld-$BITS.s
ld -o bin/helloworld helloworld.o``` Note that you'd then have two versions of your assembly file with '32' and '64' there at the end of the filename. github.com/Michael-Grimm/GPIO-ARM-64-bit-assembly
Can you please do a video on how to write embedded software? like the procedure.
I think he's doing an entire channel on writing embedded software.... and you're looking at it right now.
Hi. Great video! How you figured out that actual address is not 0x7E2... but 0x3F2... ?
It’s in the data sheet! Not very obvious but they have a paragraph about the memory map.
Not sure I have ever heard address decoding described as a "physical address", not sure I like it, it grates in the same way as people who start sentences with "so" ....
Its pretty common to refer to an address not translated by an MMU or Kernel as a physical address, as it maps either directly to RAM or a peripheral
@@LowLevelTV I'm just showing my age, when I was a lad (working with z80s) we only had "addresses, pages and offsets", but I guess we did not have MMUs ;-)
Ahh haha I see I see
gracias, me sirvió.
Cool!
Why
eor r10,r10,r10
why not just
ldr r10, 0
?
In fact why not just dec r2 under it underflows and loop off the flag?
amazing
Interesting
Tyty
It's so frustrating how many assumptions are made even in the data sheet which means relatively new learners who don't know these funky embedded considerations will be walking blind.
For example, in the latest BCM2835 peripheral datasheet on Pi's site, they state
"Physical addresses range from 0x20000000 to 0x20FFFFFF for peripherals..."
When THE HECK DID THEY CHANGE IT FROM 0x3F00_0000 to 0x2000_0000??????
that's for the Rasp 3B (not +) right ?
@@maximilien7737 I don't think it should matter. The... I forget what they called it, I think "architecture" is the same for a number of models. So you can use the same datasheet. I'll check again when I'm in front of my laptop.
next episode - "we develop a complete embedded real-time operating system! " (RTOS)
HA!
Whoa
This should be paid content, thank you
You just explained it amazingly. How can I contact you? (as my discord access is denied) I would love to contact you to know something regarding baremetal project