Это видео недоступно.
Сожалеем об этом.
Fixing HORRIBLE Embedded Rust So You Don’t Have To
HTML-код
- Опубликовано: 14 авг 2024
- In my previous Rust video, I did some pretty hacky code to get my Raspberry Pi to Blink an LED. We used the Raspberry Pi Datasheet to come up with some hacky unsafe code that enabled a GPIO pin to be an output, and then blinked it on and off. We did this ALL BAREMETAL with no operating system underneath our code.
The code WORKED. But, it doesn't port well, and it's not very RUSTY. In this video, I'll take my previous embedded Rust code and make it more Rusty by creating parts to a Peripheral Access Crate. A Peripheral Access Crate or PAC is a component to a Hardware Abstraction Layer in Rust. Hardware Abstraction Layers abstract away the memory addresses and pointers to memory mapped IO to make programming embedded systems a little easier.
🏫 COURSES 🏫
C Programming 101 for Aspiring Embedded Developers: www.udemy.com/...
🔥 SOCIALS 🔥
Low Level Merch!: www.linktr.ee/...
Follow me on Twitter: / lowleveltweets
Follow me on Twitch: / lowlevellearning
Join me on Discord!: / discord
0:00 Intro
0:21 Code Review
0:41 Lets Code!
0:59 Making a Clean Interface
1:37 Datasheet 4 Life
2:30 Match Statements
3:46 Unsafe but LESS
4:21 Binary Math
6:35 PUT IT BACK
7:20 One Down Two to Go
7:47 NEXT!
9:29 DOUBLE KILL
10:13 Linker Hack
11:03 Outro
COME HANG OUT ON TWITCH KEKW www.twitch.tv/lowlevellearning
This is now much more explicit, but not quite Rust-y yet. One of Rust's great things is that it helps prevent logic bugs (such as writing to a non-output pin) using the typesystem (technically you can do some of that in C, but in Rust it's the idiomatic way).
The GPIO could return an OutPin for example, and that OutPin would have the set method instead, guaranteeing that you never write to a non-output and letting you not have to use the pin number again.
The GPIO could even return an Option, which would be None if it's already used, by you or an other program (since it's DMA, other programs that use the GPIO would also need to set the same registers)
Make invalid states unrepresentable.
Love your videos, but an error message of "Something has gone terribly wrong" is questionable at best when it comes to advice aimed at improving code 😅
Lol... concur. You should never get to that part of the code, but agree that maybe the error message isn't great XD
It would totally be possible to enter that code path since the function accepts a u32 and not like an enum or something, but yeah I totally hear what you're saying. But you know what they say...one good error message is worth 1000 GitHub Issues 😅
In my opinion this error shouldn't even exist. The function type signature indicates it takes in a `u32`, but it really doesn't. It takes in a `Pin`. In most languages you'd blindly take in a u32 and throw an exception when it's out of range (which is conceptually what we have with that `panic!`). That's terrible practice. In any language that has a decent type system, there is no reason not to use total functions everywhere.
It was incredibly frustrating to watch this video because the code that was written isn't Rust; at its core, it's a C program with Rust syntax slapped on.
@@emilien.breton all these languages but you choose to speak with the truth lmaoo
@@emilien.breton I agree, I’d probably pass in a enum variant of Pin.
Read-modify-write operations for set/clear registers are useless. The whole purpose of set/clear registers is to avoid RMW, even datasheet states this:
> Separating the set and clear functions removes the need for read-modify-write operations.
Also there are 6 GPIO Function Select registers, not just 3.
If you really want a proper way of implementing a PAC, see svd2rust, it generates code which is much closer to idiomatic Rust.
Agree, embedded processors have dedicated instructions and registers so you can toggle or set specific bits in one go, using read modify write slows it down significantly.
I came here to say this - as you say it's right there in the data sheet shown in the video - you don't need to mask the bits that you're _not_ setting, specifically to avoid a RMW operation.
I also came here to say this, I see I’m a year too late though 😂
I've not used this chip, but don't think you need to read-modify-write GPIO_SET0 and GPIO_CLR0. Just set-and-forget - it allows for very fast pin toggling and is inherently thread safe in multi-threaded environments.
Unsafe blocks are also expressions, you can do let value = unsafe { ... }.
Any expression inside of the unsafe block will be hoisted out by the compiler, as in,
the type of the expression inside the unsafe block == the expression type of the unsafe block itself.
Nice video :)
Obviously all personal preference, but I would not use a u32 as the input type for a pin number, and instead use an enum of all the possible valid pins. It's pedantry, but an obvious bug in your current code is I could call set(1000000) to access a completely non-existent pin. You could use an if/match statement to ensure only valid u32's are passed in, but then you're potentially sacrificing performance at runtime which could instead be done at compile time.
Otherwise, love the video, this is exactly how I imagine the unsafe block should be used in Rust; creating islands of danger that can be thoroughly scrutinized.
"bug" this is so funny, i dont use rust but it looks like you're creating problems that don't exist, it falls onto the developer to put a existent pin number and the way i see it would be a constant anyway that can then be used in some kind of assertion test, its not like it will use pin numbers given by the end-user or something.
I would go a step further and have pins themselves be raii objects so you can only write to a pin if it's already been set to an output
In the STM32 crates I've seen, they do exactly that one type for an uninitialized pin, one for an input pin, one for each kind of output pin..... "make invalid states unrepresentable".
At 6:08 the '~' is the right operation since we want a bitwise not while the '!' is a logical not and since mask is a shifted 3 which is a truthy value it will be turned into a 0 clearing the entire register!
Crap I totally missed that. Thank you!
Thanks, I was thinking "Why did Rust make that change from C?"
In rust '!' *is* the bitwise not when used with integers. It's only logical not when used with booleans.
I do wonder if Rust will ever use ~ as bitwise not as I believe the original reason it wasn't is that in the early days of rust ~ was to box objects.
@@JeffHanke what?? why would rust do this? i guess it isnt C but still..
I would suggest creating a gpio *module* rather than an empty struct to hold all of your functions and constants if you're not going to store any state in the GPIO struct itself. That way, users may simply `use gpio::set_output;` and do `set_output(21);` directly in their code.
You could then also remove the prefixes from all of your consts.
you'd just have this:
mod gpio {
/// function select zero
const FSEL0: u32 = // value;
// more private constants...
pub fn set_output(pin: u32) {
// code
}
// more public functions...
}
// example thing you can now do
use gpio::set_output;
What’s the advantage of using a zero sized type over a module in this case?
In the current case probably none, but note that some chips have multiple GPIO peripherals at different addresses and you'll probably want something like the struct to help model that.
Later on, the functions shown in the video could be moved to a trait, which the zero sized struct could implement.
@@BambeH this makes sense with what @Peter Hansen said
Again, watching a perfect example of quality stuff
How about creating some longer and structured courses for rust on embedded?
In the works!
@@LowLevelLearning I'd love that! Great follow up video, but I am also very happy you made these "mistakes" in the first one! Great way to build up and show what is the idea behind Rust, to abstract these unsafe interactions into a safe(r) interface. Can't wait to grab my little RaspberryPi once I finished moving and follow these videos again hands on :)
@@LowLevelLearning ETA? I am a rust beginner and I want to get into embedded. This would be awesome.
These two videos on the Raspberry Pi cleared up so many things for me it's insane, thank you very much and keep on with this high quality content.
How about concurrency? Should you have lock/mutex/disable interrupt around the read, change, write operations to avoid skipping a bit clear/set? Or will the above layer always run from the same thread?
So you would have to worry about concurrency if there was any actual multithreading code in this. There is not
This is kernel code, so it is in full control of what runs when. Threads are not a concern until you write the threads into existence!)
Some general thoguhts:
* If you are going for read-modify(reading comments, it might be not the best approach, don't know), it'd be cleaner to make something like `unsafe fn read_write_volatile(address: *mut u32, f:F) where F:FnOnce(u32)->u32`
So for example `set` would become `unsafe {read_write_volatile(GPIO_SET0, |x| {x | (1
Hi, I'm quite new to electronics and I have a doubt. If you are setting how to interpret a pin could you use that function to return a pin struct that holds all the relevant information to put it on and off? That way you can't possibly act on a pin you haven't set previously
I REALLY love Rust content. You inspired me to start low level development myself, and I only use Rust. Rust gang for the win!!
I am fairly new at programming, I understand nothing at your videos (except the beginner tutorial ones about C) but I still enjoy watching all of them. The smallest amount of knowledge I might get is precious to me. Thank you for the great videos and keep them coming :))
It takes time! You'll get there.
@@LowLevelLearning Thanks for the encouragement :))
Why not using a HAL crate to use the GPIO enums, etc defined for that specific board (quite new to rust, and to embedded programming in it, it might be a silly question)
That is the idiomatic way to do it.
I'm not him but I feel like those videos are specifically to do stuff "from scratch".
He even says at the beginning that he's going to build a PAC in the video which would be the basis for a HAL.
You should replace the two "set" and "clear" functions with one with an additional parameter taking an enum with variants "clear" and "set" instead of copying the code twice.
You could have two wrapper functions and then call a private function with your enum variant passed in.
@@tagged5life yes thats possible but I don't really see the point. It's basically like a setter method for an enum field. Why would you make an extra function for each variant? You could also use a bool.
Thanks for using large font in this video. Really appreciate it.
No problem!
I think implementing the Drop trait for the GPIO struct might make the code even better.
Haha shit fixing my typo removed the heart from the comment 😂
But whatever now it says correctly struct instead of strict
I'm at a bit of a loss here. What did this refactoring achieve apart from giving the pin addresses a name? It seems like the same unsafe code as it was, with some syntactic sugar, in the end being much more complicated than it has to be. Is it some Rust thing? Does it do magic in the background?
Based on how I understand it, the refactoring *Low Level Learning* has done here is meant to the reduce the amount of code inside of an unsafe block, because, when you put code in the unsafe block, you are telling the Rust compiler that you know what you are doing and thus it *doesn't need to check for violations of the **_memory management rules_* typically imposed on Rust code.
Because Rust's memory management rules that the compiler forces you to follow are there for a reason (and is a selling point for Rust in comparison to other Low-Level programming languages like C or C++), you typically don't want to use unsafe blocks unless if you _really_ have to (like reading or writing volatile data, which is typically a memory violation under the memory management rules but is crucial in Embedded Systems Programming).
If there is too much code inside the unsafe block, especially if it is doing more than just simply reading or writing data to a volatile memory location, then there is a chance that there might be problems regarding memory that Rust will simply ignore - *defeating the entire purpose of using Rust of all languages.*
Thus, it is important to only use unsafe blocks _just_ for reading or writing volatile data and nothing else. Otherwise, you are creating problems you could easily have avoided. (Not to say that the refactoring could've been improved to make the code more readable or easier to debug).
(If I am wrong (_and I might be, since I am new to Rust_) about something I said, let me know so I can correct it.)
Does the compiler inline functions if it can or is every function you write going to require a CALL and RET (I guess this is ARM so really it would be BL and BX LR?)
It's optimized by LLVM which probably has inlining conditions documented somewhere
In my experience rust almost always inlines small functions, especially if they are used only once. This would be controlled generally by the optimization level (O3 for fastest code, more inlines, Oz for smallest code, less inlines) and by #inline[always/never] attribute on a per-function basis.
Is it possible to replace the delay with a mills function? just to not stuff the memory with nops.
Any working code is infinitely better than the crashing one 🙄
Good tutorial, next a proper sleep/delay function?
Good idea!
Can you make more videos about RPiPico programing in rust? Especially about proper flexible inline assembler with input, output and clobber registers.
What is the point if you wrapped both read and write into an unsafe block?
Will it really become safe if you make operations on it in rust?
Does rust have the equivalent of C++'s "enum class"? I would make enum classes for the pin/register values so that I would enforce type safety in the public API (or, in this case, the GPIO struct's functions)
uhhhh maybe look into rust enums??
@@finnmonstar Sure. If I wanted to learn about Rust. However, I only wanted to point out a possible direction based on the language I know, in case there is something equivalent in Rust.
@@sledgex9 I do not know that much C++. Maybe I can help you with C features, but I know nothing about the former. The language is too bloated and complicated for my taste. Anyway, tell me the features "enum classes" have in C++. Maybe I can help you with feature parity across Rust and that language you mentioned.
@@finnmonstar In C++ "enum" doesn't create a strong type (for a lack of a better word). Enum values are implicitly converted to/from ints when passed around. You can even accidentally pass the value of the wrong enum type into a function that expects another enum type and the compiler will happily accept it. However "enum class" (or strongly typed enums) don't allow for implicit int conversion nor do they allow you to pass the wrong enum type to the function. The compiler catches those errors. Since Rust is more new I assume that its "enum" will behave more like "enum class". It wouldn't make sense for Rust to adopt the old C/C++ style of enums.
@@sledgex9 You are right about that. In Rust you need to convert everything to the right type, even 32-bit integers to 64-bit ones.
since all blocks return a value, you can just use:
let mut val = unsafe {
core::ptr::read_volatile(...)
}
Hi is it even necessary to read the set register, setting the bit and then setting the register? Shouldn't also work if you remove line 68 and only set one bit and write it to the register so that the register "or"-s it itself?
Processors don't allow you to write just one bit. If want to ensure that you're only changing the one but you care about then you need to read in the whole word; make just the specific change you want to that value and then write that "surgically" modified word back.
@@adrianbool4568 The GPIO_SET and GPIO_CLEAR registers are special write-only hardware registers, this is not actually a memory address that would persist. By writing a full u32 value with just one bit set, you are effectively just setting or clearing that one pin without interfering with other pins.
@@animowany111 Oh, OK, thanks for letting me know! Sure makes the code easier & safer like that!
I dont understand why we need to do the bit manipulations instead of directly setting the value
Have you tried zig?
I have, and I helped write the code from the stream where we work shopped the example code.
Zig is fine, but the DX is trash and the documentation is balls. Rust wins over zig for me but I'll still give it a chance in the near future as an exercise in futility hahahah.
zigma balls lmaoo
Was anyone able to compile for rp4 64 bit? I think the target triplet should look like this armv8-none-eabihf However rust says it cannot add a target of armv8-none
Correct target name is aarch64-unknown-none
@@paulsimon1494 yup. thanks
This is Awesome! Is there a IDE like Eclipse where you can debug the Code and see the Content of Valuables by stepping slowly through the Code? I'm happy that i found your Channel!
someone who is starting out now and wants to learn a low level language, which one would you recommend _C_ or _Rust_ ?
Start with C in my opinion. Rust is awesome but you need to know a decent amount about programming for it to make sense. C has far less abstractions
@@LowLevelLearning Cool, thanks mate.
you could add debug attributes to remove the "not-used" warnings :)
nice - cheers for showing _both_ ways
You bet
the 50000 "nop" s cause me mental pain
49999, because 1..50000 it includes neither 0, nor 50000
I don't know what is good "very low-level" rust. But Having a "safe" function that is not thread-safe doesn't feel right. (concurrent calls to set or clear are potential race conditions)
Could someone tell me if this tutorial works on Windows. If so, could you reply to this comment with a link to your project on github, because I tried the tutorial and it doesn't work for me on Windows?
How dare you make this so much simpler! You must maintain the dark arts of firmware!!!
_Leaves no spaces between math operators_
Me: The code is terrible. It must be rewritten.
This code is unsafe, let's fix it with more unsafe blocks 😁
more smaller blocks with limited scope > one big one that could be doing anything
also after the cleanup it's clearer what the code is doing
Just re-write it in Ada, do it right the from the start.
Rust is Ada for the 21st century. ;)
Magic numbers kinda suck too, but that's a mistake in all languages. Also... What's up with that noop? Are there not proper timers?
Also ... Screw make. Get Meson and Ninja. Much much better
the unsafe is merely refactored out. i really dont get why you wouldnt stick with the tried and tested c
You concentrate the unsafe code in a few, marked locations. The rest of the program can then enjoy the benefits of rust, and you know where to look if you encounter weird behavior.
Very nice explanations about low level rust!
What is this desktop environment? I heard a windows sound in one of your videos, is that a WSL? What is this windows manager?
Do you have a video explaining your desktop setup? Looks really curious.
Good stuff. Thanks,
which window manager are you using. I3 ?
Yea
@@LowLevelLearning Noice
Might std::hint::spin_loop be a better alternative than a tight loop of nops?
no_std :(
@@LowLevelLearning Ah of course 😄Maybe the core::arch intrinsics used to implement it for your specific platform? I'm not familiar enough with Arm to tell if it's supported though
@@LowLevelLearning core::hint::spin_loop exists
oh, you're overestimating me by a lot. I will definitely have to
Rust is like putting training wheels on a ninja bike. C being the ninja bike. (bait)
No, but it is like putting a roll cage on one. Useful, but only an incremental change.
RustberryPi when?
Gee, no bitfields in Rust?
now do this to all the other videos my child
Yes Jesus 🙏
the forth programming language is way easier than Rust for embedded stuff. Rust just seems overly complicated for simple stuff.
Amen, have you tried flashforth for embedded ?
I'll have to give it a try!
C will live forever
@@memcpy yeah, and mecrisp forth for ARM make it easy to turn off and on gpio pins
It’s been ages that I’ve used it. And it was quite hard to learn for a C/assembly programmer. But when you grasp the concept of “everything goes over the stack” it clicks.
... by rewriting it in C!
Couldn't you just have XOR'd the Val with itself to make sure it is 0?
Sure but then you’re destroying any state that was already there, which would suck if you want to use multiple pins on the same port
Oh! You just need a new language! More sAfE! 🤣
Ironically, you ended up with the same unsafe code you had in the beginning. The only difference is that they are wrapped in small functions so you don't see a big unsafe block in the main function.
which then makes it easier to debug individually rather than as one whole swathe of danger
Isn't that the definition of abstraction?
so in rust you must replace an unsafe code with another unsafe code, it's like the language was not meant for embedded systems
🤔
well atleast the whole logic is not unsafe, and you can find memory bugs easier i think
@@finnmonstar that's fair enough!
It magically became less readable as it became more rusty.
I think that's mainly down to the added support for any pin number rather than original's operation only on PIN 21. The arithmetic does get a little messy. I guess that is what encapsulation is for.. :-/
LLG.
LLG 5Life
Syntax of rust is horrible.
Why not they just take c grammar and added safety 😂
That's wonderful... it takes a "real programmer" to point at their own code and say "this stinks".
Rust: when you like C, but thought it is too readable.
Thanks!
*Chefs kiss*
:O Mark THANK YOU AGAIN my guy holy crap. Seriously this is so generous
@@LowLevelLearning This directly helps me. I'm working on a Time Clock for one of my customers. I've done it with a Raspberry Pi (In C) with Raspberry Pi OS and an RFID reader. Having to buy RFID keys has been come a pain so I'm going to do it with a PICO and a finger print reader next. At this point I might as well write it in Rust and I'd love to write it from the ground up. Plan is to have the code MIT licensed once I'm done with it as it's not a competitive advantage for me to keep the code a secret.
still bad tho
no u ha gottem
To make this Rust program perfect would be re-writing it in C!
C++. The simple stuff compiles just as small, but then it gets cool!
The audio is horribly out of sync with your video / mouth movement.
Watching all these videos I understand that I could never be a good programmer for at least two reasons: 1) I still can't type on my keyboard while watching to the screen; 2) I am absolutely unfamiliar with Linux and never even tried to learn it😑
And you just made code with worse performance for embedded. Same as arduino library do
UPD. My statement is wrong see godbolt link below
Rust's zero size struct semantics are not the same as an abstraction like C/C++ with AVR dude.
@@rallokkcaz but now he has to calculate a bunch of masks instead of pasting at the memory location directly. As this code seems to only target the 21 pin, it ends up wasting more CPU cycles (unless the compiler already precalculates those values before the function call, which I doubt it does).
@@softwarelivre2389 LLVM can easily inline simple calculations when all inputs are literals. It can even compute the result of a function at compile time and inline the result.
@@saadisave yeah, that I know, but as this is not a pure function, and it does memory allocations in its body, I don't know if that will be optimized beforehand or not in this context. If it is, then disregard my comment.
@@rallokkcaz It's not about struct. Is `register = match reg ` zero cost abstraction?
U wrote this code lol😂
Yeah rust is a no-go for me.
Rather not melt my brain
You are so handsome 😘
This is misleading. You just moved the unsafe code around, but it's still present. "No unsafe code" when you still have unsafe blocks. Call it an interface or encapsulation. What a joke. 😂
ooooor use C and stop wasting your time!
Since hundreds of libraries exist already for C it would've been even easier. Instead he's writing it from scratch in a language which treats him like a baby and loses most of its proclaimed advantages at that level.
@@anon_y_mousse not only that, even if you're in a system where no libraries exist or you cant use any libraries for whatever reason, C gives you no limitations and does not treat you like a baby, so as you said, all advantages that rustaceans claim are lost at that level.
@@AlFredo-sx2yy i'll bite. What advantages are lost at this level? The only difference from C that I can see is needing to actually say "unsafe" when the thing that you're doing is unsafe.
Also he doesn't actually use the rust features that would be used by a library author writing a hardware abstraction layer in rust. For example rust can prevent using nonexistent pin numbers or reading output pins/writing input pins at compile time with 0 runtime checks, haven't seen that in C.
He also gets a big chunk of libraries if he needs them, and all others if he writes a heap allocator.
@@d3line the "advantages" provided by rust are lost when you try to go this low level lmao..... i thought you had watched the video?
You havent seen C detect nonexistent pin numbers because you havent seen proper C code then. That's something that YOU have to program, the fact that Rust provides this out of the box for certain architectures doesnt mean shit, because good luck finding a build target for all of the architectures you can find lol....
Christ the shit i have to read i swear.
@@AlFredo-sx2yy 1) *which* advantages are lost? You keep exasperatedly saying that some nebulous advantages are lost without defining what, in fact, is lost.
2) I haven't seen stuff like compile time const functions in C because they don't exist in C, yes. C has no way to prevent you just using pin number 12345 except runtime "if" check. Rust can do this at compile time (not shown in video).
3) I'm not talking about using some magic from rust's platform support, you can code it yourself by using rust's type system, and provide your users with un-misuse-able API at no runtime cost. That's a rust advantage, and I don't see how it is in any way lost when programming for embedded devices.
Also please chill...
You may be able to move the linker stuff into a build.rs so it gets built automatically
Nothing prevents you from doing GPIO::set_output(any random u32), this is not that Rusty still.
Make. Invalid. State. Unrepresentable!!!
(that is, something wrong _logically_ should not even compile! Or be hard to make it compile such that you'd have to deliberately try to)
This was (with exclamation points hah) the greatest statement that Rust introduced me to and I replicate it in everything I write ever since.
So your 'safe interface' is actually not very safe
What you can do instead is this (or there are a few ways to do that, simplest that came to mind is a enum)
#[repr(u32)] // you can do enum_value as u32 where you need it now, totally safe
pub enum Pin {
PIN21 = 0x1234 // whatever it is
//.. and so on from the datasheet
}
impl Pin {
pub fn from_raw(raw: u32) -> Option {..}
pub unsafe fn from_raw_unchecked(raw: u32) -> Pin {..}
}
also unsafe can be an expression so you do `let mut val = unsafe { read_volatile }` - a bit shorter :)
also², please install rust-analyzer lsp extension in vscode please, watching you do cargo build in the terminal every time is painful :)
you make yourself sound so incredibly uneducated with the last paragraph that your (entirely valid) former paragraphs are out of the window.
@necauqua You posted some really helpful information. I have a lot of experience in Rust and C, have been lucky enough to work on very difficult problems throughout my career and have led a lot of engineering teams. I say this mainly because its given me exposure to engineers with all types of communication styles. Its obvious to me that you were trying to be helpful by posting a rusty approach and a clean interface that takes the reader into account as much as the runtime. Your approach was solid and I think you wrote it in good faith. Because of that I want to post some constructive criticism for you, also in good faith.
1. It appears you don't know how to use "lol". As it stands, your comments come off as extremely self-important and patronizing. If you remove the "lol", then your statements are just blunt but not necessarily malicious. You seemed to use "lol" to punctuate important points but, unless you're trying to alienate your reader, I recommend you abandon "lol" entirely. You can also try replacing them with exclamation points or clarifying questions.
2. Your classification of embedded is limiting and elitist. Also, you're categorically wrong about "proper embedded". Embedded systems are simply units, within larger electrical systems, that have a processor, memory, and Input/Output capabilities for peripheral devices/components. In this video and the last, he replaced the OS with some kernel code and fed it to a bootloader. All he used on the physical board was... the processor, memory, and I/O pins.
Maybe you'd rather he use an STM32 or some other MMU-less MCUs and spend half the video walking us through a circuit diagram. But there are already thousands of videos covering that for people who know where to look and what to look for.
Maybe a big reason this video focuses on raspberry pi's is because the boards are versatile and ubiquitous. You can have a desktop machine or just a processor, memory, and I/O. An embedded approach to raspberry pi is much more inviting than the same video with an STM32 or something.
Engineering, as a practice and discipline, is about trying to accomplish what you want with what you have. That's it. Everything about "proper" and "the right way" is just pedantic and frankly signals that the person has spent a lot of time in a narrow field, academia, or has little experience outside of their chosen discipline. If an engineer insists on a solution without bringing up trade-offs, alternatives, and cost benefit analysis, then 99% of the time they're just reciting dogma they read/heard or used to solve a problem in the past.
Like I said, it is obvious to me that you were trying to be helpful. I don't mean to be rude, only clear. You mentioning "Make. Invalid. State. Unrepresentable!!!!" up front made it obvious to me that you have experience in this field; that you care about attention to detail, correctness, and stability. All of these are great qualities that are really hard to find. If I were hiring an engineer, you'd be a desirable candidate. If I were looking to assign a mentor, you'd be on my list.
But your tone is very condescending and abrasive. You know so much that you assume the way you know how to do something is THE way to do it; You forget that much of what you've learned is just another engineer's opinion or ideology. An opinion that another engineer taught THEM and is either outdated or will likely become outdated. I could be wrong, but you sound like a student or a junior engineer that's very passionate about the subject but hasn't really been exposed to a variety of systems and problems.
Regardless, here's my parting advice:
The way you communicate just negates the value of the information you try to communicate. And people will opt for getting that information elsewhere. The hardest thing about engineering is having to collaborate with other humans and navigating the social nuance that emerges when solving difficult problems. Every tool you've mastered, or want to master, was built by a group of people that worked well together.
I believe you have a lot to offer as a teacher or collaborator. It seems like you want to help and share or at the very least contribute. If that matters to you at all, consider asking people more questions and making less assumptions before proposing a solution. Technological systems are built in the context of social systems. Communication skills will serve you well in social systems. I think practicing them will go a long way and you'll even enjoy it as you get better.
BUT
If you're just a troll and like to feel superior to others or self-important then... carry on and ignore my comment; it was meant for somebody else haha
@@minimalhostage Nothing but respect for the respectful way you phrased that; I don't have that in me but I commend it nonetheless Charles💯
@@minimalhostage wow this was very detailed, thanks
I mean I'm just used to be kind of rude/patronizing as you've said - because this is the internet and way more commonly you encounter obtuse people than good helpful people like you - and your approach also sounds kind of more 'formal' than I would've liked it to be - this was meant to be kind of a rant and I was annoyed (why? idk really actually, maybe it was elitism indeed, 'oh they learned some rust and sharing their incomplete knowledge') by some things in the video.
Also non-native english
I will edit some of my comment, everything you said is absolutely valid
It is funny how one can hate something in others yet express it themselves to such an extent, thanks for opening my eyes - I really don't like elitism and static unchanging ideologies and when someone thinks some one thing is 'proper', yet I said exactly that huh
Still hate that something that runs an OS is called embedded, but looks like my notion of 'embedded' was just invalid :)
@@bartpelle3460 while I removed the paragraph as it was really poorly worded anyway indeed - I did think (oh well maybe this was wrong the entire time) that embedded is when you run something on a 'bare metal', w/o an OS - and raspberry pi's being a full-blown arm computers with linux installed were out of this definition - yet every youtuber seems to do 'embedded' with raspis.
Although after the explanation from Charles it seems that if you run some code _in place_ of the OS, as it's done in this video - it is indeed embedded - I was under impression of some other youtubers doing like a blinking gpio led with like a python script running on that arm linux on raspi.