Embedded Rust on microcontrollers (Cortex M, Cortex A, Softcores etc.) - Page 1
Forum section: electronics / general

author: TopQuark
author_rank: Frequent Contributor
timestamp: November 07, 2022, 12:48:03 pm
content: Hi, the company I currently work for exclusively uses Rust for our product's embedded development, and I have been learning Rust and specifically embedded Rust lately. I thought I'd kickstart a thread discussing using embedded Rust, including learnings, successes and failures. I am still no expert in Rust, but I have gone through the "fighting the compiler" stage and am starting to see how Rust can be valuable in production. In fact, for a long time, I have been a Rust holdout and swore by C, but now I am starting to be a Rust convert.My company (M-Labs HK) happens to open source everything we develop, so I thought I'd share a few examples of usage of Rust in "real world" shipping, money making products.https://git.m-labs.hk/M-Labs/thermostat- Baremetal Rust on STM32F4, dual channel TEC controller capable of better than 1 milliKelvin control stability. Not quite stable release yet, but we have shipped systems to early beta participating customers.https://git.m-labs.hk/M-Labs/kirdy- Baremetal Rust on STM32F4, precision laser driver with TEC controller and photodiode monitor. Under (my) development, very early stage, hardware not finalised.https://github.com/m-labs/artiq- Baremetal Rust on softcore, Migen for FPGA fabric and softcore. Quantum physics control system. Very mature and production ready.https://git.m-labs.hk/M-Labs/artiq-zynq- Baremetal Rust on Zynq 7000, Migen for FPGA fabric. Quantum physics control system. Reasonably mature and production ready.This is by no means advertisement, but rather to demonstrate that "new-fangled" tools like Rust and Migen CAN be used in "real" products. I'd love to see more discussions and examples of Rust being used in products and projects! Show us your Rusty projects and discuss anything embedded Rust related!

author: voltsandjolts
author_rank: Unknown
timestamp: November 07, 2022, 01:16:48 pm
content: Interested to get your thoughts on this.Can you list the top five advantages of Rust over C, in an embedded environment like baremetal Cortex-M, as you see it?

author: TopQuark
author_rank: Frequent Contributor
timestamp: November 07, 2022, 02:39:44 pm
content: Just off my head, somethings I like about embedded rust1. Memory (and by extension memory mapped peripheral) safety. In baremetal C on systems without memory protection unit, there's nothing preventing you from dropping a HAL_GPIO_WritePin(port, pin) anywhere in your code, or changing a peripheral setting register anywhere in the code. There's no warning from the compiler nor any checks against this. This means if you have multiple processes (esp. when developed by multiple developers), you can't trust that the state of the memory (and memory mapped peripheral) is in the state you left it in, someone / some process could have changed it under the rug.In Rust, unless you specifically wrap your code in anunsafeblock, the compiler simply does not allow you to do that. Every bit of memory (and by extension memory mapped peripheral) has an owner, and only the owner of that bit of memory has write access to that bit of memory. Take for example a gpio pin, in Rust, the init code would take ownership of all the peripherals, break up the peripherals into individual objects (some SPI busses, some GPIO pins, some I2C busses etc), and pass the ownership these objects to various processes that now owns that bit of peripheral and has write access to it. The implication is your process can always trust that it has exclusive ownership of its memory objects, and can have confidence no other processes has altered its state. This is all done in COMPILE TIME, so there's no runtime overhead for having memory safety, even without a MPU.This alone is very significant imo.2. Modern tooling. In Rust there's Cargo, a build system + package manager that makes code building and reusing much nicer than C. If I want to add a library to my code, I just have to specify the name and version of the library I wish to use, and Cargo will integrate the library into my code properly and take care of all the dependencies and dependencies of dependencies. This is way better than C. Cross compiling is also a breeze, as Rustc uses LLVM, cross compiling means I just have to specify the architecture of the target and stuff just works. I don't need to maintain a version of GCC for linux, another version for windows, then arm-none-eabi-gcc for my cortex M stuff.3. I don't usually allocate heap when programming cortex M, but when I do, it is so much safer in Rust. The compiler makes sure there's no memory leaks, no double freeing, no dangling pointers etc. all at compile time with minimal runtime overhead. This also means no garbage collector is needed.4. Very strong, static, type system. Say you have a library function that implements sleep/delay. In Rust, properly written libraries will take a parameter of type time, instead of say a u32. In C, the programmer has to be cognizant of the physical meaning and unit of the number you pass to the sleep function. e.g. In stm32cube, HAL_Delay(x) takes a u32 and sleeps for x milliseconds. The programmer takes responsibility of making sure the number specified means milliseconds, not seconds, not microseconds, not ticks, not processor cycles. In Rust, the sleep function would take a generic parameter of time, and time can be a variable of type ms, or type us, or type second, or type ticks, and the sleep function would sleep according to the numeric value and type of the variable. So in Rust, your sleep function would look something like sleep(10_u32.millis()), or sleep(10000_u32.micros()), explicitly stating both the value and type, i.e.unit of the value. The compiler takes care of the part that translates the generic time type to the native type the sleep functions uses to count elapsed time, so no overhead again.5. General attitude and mindset. In Rust, the programmer is not to be trusted, and the compiler does what it can to force you not to write certain types of bugs (e.g. memory leaks, out of bound array indexing), unless you explicitly wrap your code withunsafe. In C, the programmer is assumed to know its sh*t and trusted to do whatever he/she wishes to do. This different attitude takes some getting used to, and rubs some people the wrong way. Many of us would like to think we are super smart and never writes bugs, but coding in Rust means you have to admit that you do write stupid and buggy code sometimes, and for certain types of coding errors, the compiler is capable of knowing better than you on what's buggy and what's not. This is particularly valuable in two situations imo,- You work solo with no one to review your code- You oversee a group of programmers with different levels of aptitude.In these situations, your code review process is much simpler and the resulting code is much less error prone, because- Illegal memory (and by extension memory mapped peripheral) access is prohibited by the compiler (point 1, 3)e.g.https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/- Strong type system reduces the chances of passing the wrong type of data to the wrong function (point 4)e.g.https://en.wikipedia.org/wiki/Mars_Climate_Orbiter- You can focus your review effort to the handful of lines of code markedunsafe, instead of scrutinising every single line of code.This is longer than I thought it would be, but I think it is good food for thought. I welcome counter arguments, but please don't turn this into a holy war between different languages.

author: AVI-crak
author_rank: Regular Contributor
timestamp: November 07, 2022, 02:52:09 pm
content: If you separate the bare metal, peripheral control, program level, and user level into different project files, with minimal connections, then 99.99% of the problems of the entire project will be solved.But the vast majority writes in the Arduino style, and this is not treated in any way. Even changing the programming language will not help.

author: TopQuark
author_rank: Frequent Contributor
timestamp: November 07, 2022, 03:06:34 pm
content: Quote from: AVI-crak on November 07, 2022, 02:52:09 pmSure, maybe you really know better than most people, and maybe 99.99% or you code is actually bug free, maybe. And maybe you are right that most people in the industry write crappy code. But what about your "arduino programming" colleagues? Wouldn't you want some kind of tooling (can be rust, can be something else) to force them to write better code?

author: JPortici
author_rank: Super Contributor
timestamp: November 07, 2022, 03:22:30 pm
content: My problem with rust is that i don't have an official compiler for it (let me know when C++ or Rust or whatever will be available for PIC24/dsPIC). And with official i mean something i can do production with, not some abandoned experiment on github that was started on a rainy saturday and then left there to rot (but enough for the random nagger to point the greasy finger and say "see it can be done? xxx is evil because they make you pay for it")Point 4, about type safety and polymorphism is already handled by C++ for which you have a production ready compiler. I could argue that newer C compilers or static analysis tool may nag you if you don't cast to the appropriate alias of the u32 type, but i won't.Point 2, i don't really care for nowPoint 3, i could argue that i tend not to use the heap either if i have another option and most of those bugs can be handled by runtime checks so it leads down to good practices, ect, ect, ect, but i won't.I am intrigued by 1 and 5 and wonder how big is the real performance penality

author: TopQuark
author_rank: Frequent Contributor
timestamp: November 07, 2022, 03:40:24 pm
content: Quote from: JPortici on November 07, 2022, 03:22:30 pmRe compilers and everything else. Yes, Rust is still in early days, and vendors still provide tooling mainly in C, rarely in C++, and almost never in Rust (besides espressif). My company actually spends quite some working hours (i.e. money) developing Rust drivers for different parts. If you want strong vendor support, Rust is not there yet.Re point 1,3,5. Rust handles all the memory safety guarantees incompile time, not run time. There's no Java like runtime in rust and there's no garbage collector at all. The penalty is next to nothing. Someone recently rewrote the Linux NVME driver in Rust, and it benchmarks practically just as fast as the native Linux one written in C (https://www.phoronix.com/news/LPC-2022-Rust-Linux). The memory safety and everything else causes the compile time to increase a bit, but not the execution time.

author: nctnico
author_rank: Super Contributor
timestamp: November 07, 2022, 04:09:48 pm
content: @TopQuark: First of all thanks for sharing this.My strong opinion is that C is not really suitable for writing complex software but so far it seems to be the best suitable for the job. What I'm tired of when writing C is adding all kinds of bounds checks just to make the software robust. I have been looking at Ada in the past but that doesn't seem to be gaining any traction at all. So I'm very interested to see where Rust is going. I have been looking at Lua and Micropython scripting as well which can be useful for implementing high level functionality but the low level still needs to be written in C.Now my question is: how is the debugging organised? Can you write software in Rust on a PC and single step through it? And how about doing debugging on a microcontroller?

author: T3sl4co1l
author_rank: Super Contributor
timestamp: November 07, 2022, 04:16:07 pm
content: Kind of tempted to look into this. But I mostly have AVRs handy; and, last I looked, there was actually an LLVM output for that, but veeery beta, so probably not too great to use. I mean, I wouldn't mind contributing improvements to such a project, honestly, but I suspect it's also going to fight me as much as learning the language in the first place, so that'd be a bit much. Especially if I expect to make real projects (read: $$$) at the same time. Perhaps I'll take a look soon [I last looked a few years ago], or in a few years again.Or maybe in a few years, a less...cryptic? dialect, or whole language, will come along?... Then more years of waiting for platform support...oh, right...Mind, not to say C isn't fucking cryptic, it just happens to be the crypt I've already learned.Tim

author: AVI-crak
author_rank: Regular Contributor
timestamp: November 07, 2022, 04:53:27 pm
content: Quote from: TopQuark on November 07, 2022, 03:06:34 pmMy code also has errors, like everyone else. Personal record - code work for five years, with a very difficult to detect error. The culprit was one missing letter in the macro. As a result, a very rare event performed a double-precision calculation, which created additional delay in the control of the manipulator mechanics. The steel gripper was lowered onto a plastic container with glass products - with an offset of several millimeters. A rare but extremely high-profile event!!!This is the price of inattention. This code has been reviewed and tested by many people, with no result. The error was found by accident when it was necessary to write a new one.Additional tools?Everything that could be invented has long been implemented in different variations.Everything that needs to be invented - breaks the old.For 50 years, overflow and saturation operators have not been added to the C language (there are functions). 10 years ago, GCC added tracking of array boundaries - the error is visible only during assembly !!!. Three years ago, a single IDE started using shadow compilation to track errors while writing code. The rate of progress is certainly impressive, but even a simple text editor develops many times faster.What is not, is not planned, and is not created from tools - intelligent assistants.For example, the source code view mode in the IDE is in overlay mode. This is when the source code is supplemented with types of variables or constants. For example:Code:/// 1)examplevoid setPixel_line_ram (int16_t x1,int16_t y1, int16_t x2, int16_t y2, uint8_t RGB);/// 2)usage example in codesetPixel_line_ram (lin.a, lin.b, 10, 25, g8.green);/// 3)overlay mode in code viewsetPixel_line_ram (<i16 x1> lin.a, <i16 y1> lin.b, <i16 y2> 10,<i16 y2> 25, <u8 RGB> g8.green);The first line is written somewhere very far away. In real code, I can find out about it - if I hold the mouse cursor for more than 5 seconds.When using a function, there are always hints, well, or almost always. While the fields are being filled in, the tooltip changes dynamically, and this is noma.With a quick view (2): the purpose of the function fields must either be known by heart, or variables consonant with the function field should be used - which is not always possible in the implementation.What you want to see in the view mode (3) - overlay with a separate color. Protecting overlays from copying in the IDE by the user - to protect against errors. A separate beautiful button for enabling this mode.Am I wanting too much?

author: TopQuark
author_rank: Frequent Contributor
timestamp: November 07, 2022, 05:21:16 pm
content: Quote from: nctnico on November 07, 2022, 04:09:48 pmDebugging is just as good as C. You use GDB with whatever debug probe you have, and the experience is just as good as C, at least with VS Code. Single stepping, call stack view, register view, memory view etc. everything is there. Even Segger RTT prints work flawlessly. See the attached screenshot.Quote from: AVI-crak on November 07, 2022, 04:53:27 pmI don't fully understand what it is you want, but what you describe (Good IDE/code editor hinting support) is available in Rust too. The hinting system integrates very well with the compiler, and is able to infer the complex types of the variables and show it, making it really easy to know what is what. See the attached screenshot.Quote from: T3sl4co1l on November 07, 2022, 04:16:07 pmI read you. I still very much love C. The language is dead simple with very few keywords, but you can do pretty much everything with it (not that you should do everything with it). I think it will take many years for Rust to be close to C in terms of vendor support.

author: westfw
author_rank: Super Contributor
timestamp: November 08, 2022, 03:27:20 am
content: QuoteSo ... let me ask a question about "bounds checking."When one talks about adding bounds checking to a C program, you usually end up with depressing code like:Code:int foo(a, b) { bounds_check(a); bounds_check(b); int result = bar(a, b, 123); bounds_check(result); return result;}int bar(a, b, c) { bounds_check(a); bounds_check(b); bounds_check(c);int result = baz(a, c, 567); bounds_check(result); return result;}ie redundant bounds checking at every level of a call tree. Even if you don't actually USE a parameter, but just pass it on. Because, after all, you don't know if the function that called you, or the function that you're calling, will do its own bounds checking.Do languages that inherently support bounds checking managed to optimize it so that a variable is only checked when it is about to be used? (and preferably, only if it hasn't been checked already since the last time it was changed?)

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 08, 2022, 04:08:26 am
content: Quote from: westfw on November 08, 2022, 03:27:20 amA reasonable C compiler will optimize redundant tests if all functions are in the same compilation unit. If not, of course, it can't. Although GCC's LTO might be able to do this as well, but I haven't used LTO much.

author: nctnico
author_rank: Super Contributor
timestamp: November 08, 2022, 05:09:46 pm
content: Quote from: westfw on November 08, 2022, 03:27:20 amSomething along that line. Typically with throwing a meaningful error somewhere in a log or debug output. Depressing but it has helped to diagnose and fix sporadic errors that would otherwise have been hard to catch. I'd be interested as well in how that works with Rust. In many cases compile time bounds checking isn't enough.

author: JuniorJack
author_rank: Contributor
timestamp: November 14, 2022, 04:54:02 pm
content: Hey TopQuark,Thanks for posting this detailed info about Rust.My personal reason to stick with C is that is very easy(unless i go crazy on optimizations) to just read out the Flash memory, drag the .bin file to IDA Proand decompile. It takes just seconds to locate functions i am interested in and usually it is pretty easy to see variables and execution paths.How readable would be a code generated in Rust from its binary form ? I have very bad experience with C++ in this regard. Thanks!

author: uliano
author_rank: Regular Contributor
timestamp: March 10, 2023, 10:15:31 am
content: Quote from: TopQuark on November 07, 2022, 05:21:16 pmCan you provide link/pointers to configure vscode+gdb+rust (also RTT, it would be really great!) I'm not finding much...Is it possible to view also peripheral register (by reading .SVD) or only cortex ones?

author: NorthGuy
author_rank: Super Contributor
timestamp: March 10, 2023, 05:05:12 pm
content: My be this is off topic, but I have these two rather philosophical points:1. Nowadays, programmers are obsessed with languages. But I believe the language doesn't matter, as long as it allows you to write what you have designed without typing too much.Imagine, a microbiologists writes a thesis about his microbes and then he decides that he needs to learn French and write the thesis in French. This is because French is safer. For example:Code:Je pense // I thinkTu penses // You thinkTherefore the spellchecker will be able to find errors if you mess things up. If you write "Je penses" then clearly you need to change something to make it correct. This makes writing in French safer and therefore it's a good idea to switch to French. Never mind the thesis is about microbes and what does matter is what he has to say about microbes, not the language he says it in.When a programmer dwells on languages instead of concentrating in the design it's equally silly.2. Everybody tries to achieve safety. They're convinced that the opposite of safety is recklessness. Like programming in assembler is reckless, while programming in Java is safe.In reality, the opposite of safety is freedom. The more safety you try to get, the more freedom you have to give up. Who on Earth lives in the conditions of greatest safety? Patients of mental institutions. They cannot hurt themselves even if they try very hard. How is this achieved? Very simple. Their freedom is taken away.Same in programming. Instead of giving up your freedom for imaginary safety, use your freedom to create a simpler design which has less operations, less special cases, less bloat. And then your design will be smaller, simpler, easier to work with, and surprisingly it also will be safer.

author: paf
author_rank: Regular Contributor
timestamp: March 10, 2023, 06:55:42 pm
content: Me, I have the intention of learning Rust one of these days.Rant:You have bad examples and bad metaphors. Your french english example is bad. French has more redundancy, so is more reliable in the presence of errors/cuts. If in english you hear "think" it may be "I think" or "you think" or "think". If you hear "pense" in french is "je pense" and "penses" is "tu penses".Different programming languages have different abstractions and data structures, that may offer different ways of thinking.In C (or assembly) I can cast anything to anything. In other languages I cannot unless I really want. The impression that I have from Rust ia that I will spend lots of time "fighting the compiler", but I think that is better to send more time "fighting the compiler" than to "fight bugs" after the compile phase.Learning a different language is always good because it gives you a "different way" of thinking. You only have learned a different language when you start to "think" in that language.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 10, 2023, 07:15:20 pm
content: I agree with NorthGuy here. I wouldn't quite go as far as saying that the programming language doesn't matter at all, but it's certainly not what matters most.Given the very steep learning curve of Rust, my opinion is that this time would be much better invested in learning how to improve your designs and how to make the most of the tools you already know.You might say that the two are not orthogonal, but our time is precious and limited.When one keeps looking for "better" tools rather than working on one's skills, this is pretty much akin to procrastination. Just my 2 cents.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 10, 2023, 07:47:19 pm
content: I agree with NorthGuy too. As a hobbyist there is no need to learn a lot of languages unless that is your hobby. Don't expect your projects to magically become better by switching to some more secure or higher level language.Programming is a skill and some will never learn it no matter what language they use. Sounds harsh but it is what it is.@uliano, in some other thread you mentioned the desire to go bare metal, and for that assembly is almost the barest of them all, but it is not necessary to go that low. With plain C you can achieve everything you want, as long as you really understand programming. And to learn programming my advise is to revisit the basics. Seek out the logic behind it. Forget about libraries, and really go bare metal.

author: artag
author_rank: Super Contributor
timestamp: March 10, 2023, 08:16:55 pm
content: I started to look at Rust, because although I'm against the concept of removing sharp edges to make things safe, I do appreciate that some things could be improved - though it will be worthless if I have to declare all the hard bits 'unsafe' to get them to compile.However what really puts me off - and this is probably why there's no official compiler - is that the language isn't properly defined yet. I see python, which is also changing constantly, and although I'm sure it's great for personal scripts it's just a portability disaster. I don't want to see another of those.Let someone think it right through and define it self-consistently. At the moment, it's an experiment.

author: tggzzz
author_rank: Super Contributor
timestamp: March 10, 2023, 08:58:37 pm
content: Quote from: SiliconWizard on March 10, 2023, 07:15:20 pmYes, repeat no.Language isn't the most important thing. But, and it is a big but, a language which enables you to accurately and succinctly express your solution is a big thing. The corollary is to choose a language that suits your problem and your solution.Thus there is little difference between Java and C#, or Delphi and Pascal, or C and assembler () If you grok one it takes very little time to grok the alternative.But there is a big difference between C, Smalltalk, xC, VHDL, Go, Rust, R, SQL, Prolog, LISP, Fortran, COBOL. When considering a career, it is vital to be able to distinguish "boring similar" languages from those that are worth grokking.Hence, understand your problem's constraints and then choose the language.If you are programming in a highly parallel environment then Rust or Go or xC have big advantages over C. Which is more or less applicable depends on the detailed nature of the parallelism.

author: Kjelt
author_rank: Super Contributor
timestamp: March 10, 2023, 10:10:07 pm
content: Quote from: NorthGuy on March 10, 2023, 05:05:12 pmMy personal opinion is that the whole development of new languages that are more safe etc. are the result of businesses that need so many programmers that they hire someone with some degree which is not root core programming.I rather have a record proven old language than a new language that might have issues.If there is a better new proven language than I am fine.But low and behold, new language features always introduce new issues.An example C# and java with its garbage collector were a goldmine for some epic hacks since the garbage collector was not real time.

author: tggzzz
author_rank: Super Contributor
timestamp: March 10, 2023, 10:29:47 pm
content: Quote from: Kjelt on March 10, 2023, 10:10:07 pmQue?C isn't "real time" (to repeat your misuse of the term) either!Start by considering the performance of, say, a cache implemented in C. Then consider the performance effects of all the hardware caches and superscalar operations in a modern processor.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 11, 2023, 01:00:06 am
content: You may be intrigued/interested to know that GCC 13 is going to include Modula-2 as an official front-end.Could be interesting for embedded development as well.Although again you should not focus too much on the language, at least for programming microcontrollers. Still interesting times.They are also working on a Rust front-end, although obviously it will take quite a while before becoming mature.

author: Marco
author_rank: Super Contributor
timestamp: March 11, 2023, 03:06:05 am
content: Quote from: Kjelt on March 10, 2023, 10:10:07 pmAFAICS breaking the sandbox with untrusted code mostly became a theoretical exercise after Java was banned from browsers, thus for C# too. At this point unless your code somehow allows an adversary to execute dynamic code, it's really unlikely that lifetime mismatches between native APIs and GC'd stuff is going to cause remote exploits.

author: gf
author_rank: Super Contributor
timestamp: March 11, 2023, 07:04:15 am
content: Quote from: tggzzz on March 10, 2023, 10:29:47 pmIn C you still have the choice how you manage memory yourself. In Java, C#, Python, etc. you don't.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 08:07:14 am
content: Quote from: Marco on March 11, 2023, 03:06:05 amJava the language+libraries is safe. Implementations of the JVM can have bugs, but the JVM is upgradeable without changing the application or its bytecode.C#, on the other hand,cannotbe safeby designsince it includes the unsafe keyword. Flaws in the C# compiler or libraries can require the application to be recompiled on each installed system. Without having bothered to investigate, my guess is that is a reason Windows updates take so much longer than Linux updates.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 08:33:17 am
content: Quote from: gf on March 11, 2023, 07:04:15 amThat's not the problem and therefore not the solution.Even on 486s with theirtinycaches, the peak-to-mean execution time for some simple sequences could be a factor of (IIRC) 8. It all depended on what was and was not in the caches when the sequence ran.With modern processor which haveenormousL1, L2, L3 caches, plus TLB caches and worse, when you exceed aninvisible and unknowable limitthe execution time drops increasesdramatically. Then add superscalar execution engines, multiple cores, NUMA, non-optimal data alignment, and execution time becomes even more unpredictable.Don't believe me?look at the processor data sheets, and try to determine how long it will take an instruction to execute. That used to be easy, decades agolook at simple array operationmicro-benchmarks for processors, and see how the execution time changes as data structure size in increases. Note especially the cliffs"Cache is the new DRAM, DRAM is the new disk".

author: westfw
author_rank: Super Contributor
timestamp: March 11, 2023, 09:16:47 am
content: So: "no processor that utilizes cache is realtime", and it has nothing to do with what language you pick?

author: Kjelt
author_rank: Super Contributor
timestamp: March 11, 2023, 09:25:36 am
content: Quote from: Marco on March 11, 2023, 03:06:05 amIt was part of a SANS hacking course on webapplications. 10 seconds after a user provided a password, the complete hash could still be found in the memory. Ofcourse a beteer practice would be as a programmer to wipe the arrays of memory with sensitive information.That is the difference between a security minded programmer and just a webdeveloper.But it goes so far that even on embedded security implementations for comparing for instance a hash of a password, a security programmer will not use a standard memcmp function. Nice quiz question , any idea why he should not use a standard libc memcmp ?

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 11, 2023, 09:27:59 am
content: Quote from: westfw on March 11, 2023, 09:16:47 amDefine "real time" I would say.One can argue that even interrupt driven system are not real time. When the interrupt is handled depends also on several factors, like the priority system and how and when the CPU switches to processing the interrupt instructions.

author: janoc
author_rank: Super Contributor
timestamp: March 11, 2023, 09:34:27 am
content: Quote from: westfw on March 11, 2023, 09:16:47 amRealtime has zero to do with programming language.There are no "realtime programming languages". You could write a hard real time system even in Python if you really really wanted to (and were sufficiently insane to undertake such project). Some languages merely make the job easier because they tend to be closer to the hardware.The same thing about processors and caches. Caches are a fact of life and have nothing to do whether or not your system can guarantee real time performance or not. What does is your system and software design, not whether or not the CPU has a cache.Yes, the caches (and other things) do make predicting the execution times harder. But the point is you don't design your system around carefully crafted cycle-counted routines that are neigh impossible to guarantee performance of on high end hw with varying data sizes and operating conditions. One uses things such as performance counters and hardware timers to ensure hard limits on task execution times instead.Basically the old personal computer and microcontroller techniques (cycle counting, disabling interrupts, etc.) don't really translate to these systems anymore. That doesn't mean you shouldn't optimize your code - but you can't rely only on that if your goal is real time performance. And at that point whether you have a cache or not becomes irrelevant - or rather, you do want the cache because it makes the machine perform much better than some obscure old junk without.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 09:57:38 am
content: Quote from: westfw on March 11, 2023, 09:16:47 amMy response must be interpreted in the context that you chose to snip, i.e. garbage collector => not realtime, but hand-coding C algorithms => (can be) realtime. That's false for many reasons I mentioned, not just caches. Don't ignore all the other problems!Anything written in any language that is executing on top of something with "unpredictable" timing cannot magically have predictable timing. No surprises there.Caches' principal function is to reduce theaverageexecution time. They do not (positively) change worst case execution time.For hard realtime systems where a missed deadline is fatal, average execution time is irrelevant - only worst case matters. In such cases the best option is to not have caches. That is true for caches implemented in hardware and software.For soft realtime systems it will come down to the probability of missing a deadline and the penalty when that happens. The tighter those are, the more caches can ensare the unware.But don't forget all the other issues that affect the predictability of timing, including but not limited to superscalar execution engines, multiple cores, NUMA, non-optimal data alignment.What was valid when C was in its infancy 40 years ago is no longer true; modern computers aren't "fast PDP-11s"!.Summary: a language is a tiny part of the overall behaviour of a system.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 10:05:50 am
content: Quote from: janoc on March 11, 2023, 09:34:27 amAgreed.QuoteNot quite. There is xC running on the xCORE multicore MCUs (up to 4000MIPS). The IDE tooling shows the exact number of clock cycles that a given instruction sequence will take to execute.Notably that is the combination of hardware and software, not software alone.QuoteIt may also matter what happens when such a hardware+software system suddenly and inexplicably performs much more slowly - and that can happen with caches, NUMA, superscalar execution, etc.Hardcoding a few data structures plus algorithms in a particular language isn't going to significantly affect that variability. Nor, in many useful circumstances, will having amoderngarbage collector.

author: janoc
author_rank: Super Contributor
timestamp: March 11, 2023, 10:34:05 am
content: Quote from: tggzzz on March 11, 2023, 10:05:50 amThat's what I meant when I said that some make it easier than others, especially when the vendor has engineered their own vendor specific tooling for their proprietary hardware.However there is not such thing as a "realtime language" as the "realtimeness" isn't some sort of an intrinsic language property where you could say "C is real time but no, Python is not!"There is fundamentally nothing preventing you from rewriting the Python interpreter/compiler + add stuff to the tooling to enable something like this too. Would you want to? Probably not. But the point is that it is possible to do, even though the result would probably differ from the standard Python in many places. Which would be the same like many other vendor-specific language dialects (e.g. C has many, BASIC was infamous for them, etc.)The programming languages are by design abstract tools to ultimately generate machine code. What you do with that code matters, not the tool you use to produce it.QuoteExactly. People have been harping on these things and specifically the garbage collectors ever since Lisp times - and it wasn't quite a valid argument even back then and is even less today. But it is a fairly good indicator that the person who pulls this out as an argument for or against use of some language or tool doesn't quite understand what they are talking about ...

author: hans
author_rank: Super Contributor
timestamp: March 11, 2023, 10:42:35 am
content: Quote from: westfw on November 08, 2022, 03:27:20 amI think a far greater problem is; what to do when a bounds check fails? Do you just return NULL? Do you try to best-effort execute some parts of the function call? Are there side effects that are persistent? What is the callee going to do with the failed result?Personally I only run assertion checks inside functions to check whether arguments are sane. If they are insane, then I know there is a problem in the callee. In release I remove these runtime checks, as I don't deem them as useful for non-debug images. I write unit tests that exercises as wide operating conditions of the code as possible. If the code has a clear fail-path, then I do implement a fail-safe return method.Modern programming languages fully embrace modern design patterns to deal with these kinds of issues, such as monads and pattern matching. You could implement a similar thing in C with structs and switch/case statements, but nobody is doing that because it's such as hassle to do. Typically C languages will push as pass/fail as return value, and output data via pointer/reference arguments.I disagree that programming languages do not play a role. Short hand notations do help here, otherwise I vote to go back to C89 and remove else and all loop statements, as these are all variants of the goto statement. I don't think it's about freedom: it's about putting the language to work for you. Some of the points listed by TopQuark are also available in modern C++, which is gaining plenty of traction under enthusiast embedded programmers for years. In particular it's capability for static_assert, constexpr, consteval, metaprogramming, etc. The more strict type system is also very welcome. You can still do crazy stuff in C++ if you really want to, but it will be surrounded by many reinterpret_cast and static_cast, which should warrant a programmer that he/she is dealing with something "unsafe" or potentially non-portable here.It's been years since I've been programming Rust, and I haven't touched it a ton, but it does itch to try it out one day. I think the memory ownership/borrowship is a very interesting concept, but I'm sure it will take some adjustment to learn the new design patterns to become fluent in writing code and implementing anything you want.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 10:54:26 am
content: Quote from: janoc on March 11, 2023, 10:34:05 amJust so.Often their experience is limited to a 30yo undergraduate course that, in passing, mentioned that some weird/niche languages use stop-the-world GCs that are either mark-collect or reference counting.That wasn't true 30 years ago, let alone now.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 11:04:36 am
content: Quote from: hans on March 11, 2023, 10:42:35 amI've not used Rust but it has been on my radar for years - because it is one of the few which directly addresses a modern challenge: multicore/processor applications. (Ditto Go, at a different level)How successful the own/borrow concept will be is still being determined, but it is a useful advance over languages whose designers explicitly stated that threading is a library issueMy bet is that it will be useful, and programmers will have to use higher level infelicities to screw things up. (Compare and contrast with a structured procedural language vs assembler)

author: Marco
author_rank: Super Contributor
timestamp: March 11, 2023, 12:27:06 pm
content: Quote from: Kjelt on March 11, 2023, 09:25:36 amIn process memory, but without running untrusted code it's rather unlikely you can remotely get the Java/C# program to escape the sandbox, get at the process memory and send it back to you.If you do want a sandbox for untrusted code you use JS/webassembly. Out of scope data hanging around in process memory? Who cares ... the sandbox evolved to the point that an escape is so valuable, it becomes almost unusable. Economically guaranteed security is the best security after mathematically guaranteed.

author: janoc
author_rank: Super Contributor
timestamp: March 11, 2023, 02:42:37 pm
content: Quote from: tggzzz on March 11, 2023, 11:04:36 amI have started to tinker with it on some toy projects of mine.Not sure about its specific usefulness on multicore/multiprocessor systems, there it doesn't really bring anything that others don't do or make anything significantly easier. The ownership/lifetime/borrowing doesn't really help you much if you have race conditions due to shared state between threads, etc. - you still need synchronization/mutexes/etc. in some form, the language doesn't handle this for you. The same for ease of parallelization/vectorization of algorithms - Rust is about the same as C (i.e. there are threads and coroutines - and the rest is up to you) here.However, what made me look at it in embedded context was the built-in support for the async/away style cooperative multitasking - that could make a lot of very common embedded problems simpler to deal with and without having to resort to an RTOS. Which is always a plus, especially in memory constrained situations.I have managed to get some code working even on ATMega328 (good old Arduino Uno board) and then, of course, ARM is fairly well supported. Where there are rough edges is the very immature ecosystem where there simply aren't as many packages ("crates") available and what is available are often one-man projects with little support and frequently abandoned. Hardware support often means you get the CPU core supported, code compiles and runs on the chip - but any peripherals beyond the basics like GPIO are up to you to implement drivers for.To a lesser degree this is true even for desktop programming with Rust - e.g. I needed 0MQ implementation, there are about 3 out there, one is abandoned, the other is an alpha version that doesn't support what I needed and the third is a buggy mess. But at least there was something out there - if you need something more demanding or more niche, tough luck. Rust has interop with C and it is possible to make even C++ code work with it with some effort but it is far from seamless. And if you are jumping through the hoops to talk to C++ - then why bother with Rust?So while there are plenty of "rustaceans" that will sing odes to the memory safety and similar things, the reality is that if your use case doesn't fit into the (fairly small) niche where there is good library support already, the language and ecosystem aren't going to be of much use to you. I don't see it replacing C or C++ any time soon, exactly for these reasons. Even the best programming language is of no use when you can't solve your problem with it.Concerning the language itself, I am a bit on the fence with the syntax - I am a Python/C/C++/C# guy, so I am used to some pretty weird and "noisy" syntax. However, Rust feels a bit like the language syntax hasn't been designed but "grown" - "Oh, crap, we didn't think about this, let's make the programmer write an apostrophe here and there to indicate this!" And that despite that there is no formal standard out yet and the language is still pretty new (~10 years) and still in flux.Worse, a lot of this "noise" comes from very low-level implementation detail boilerplate that "leaks" out and the user is forced to deal with it explicitly - like annotating the variable lifetimes. In some cases the compiler can infer it but in many it can't, which kinda sucks and leads to "line noise" statements like:Code:fn f<'a, 'b>(s: &'a str, t: &'b str) -> &'str {...}(that's a function taking two string arguments by reference with different lifetimes annotated by those 'a and 'b annotations and returns a reference to another string)It is certainly not the worst stuff I have seen and I get why it is necessary for the compiler to know this - ever shot yourself in the foot by operating on a pointer/reference to a temporary that has been destroyed in the meantime? This is what the lifetimes are trying to address in Rust. However, the way it is done is really ... meh. A bit of wasted opportunity to design a language that isn't "write only" here, IMO. Of course, C++ is much worse in this regard - but C++ is also 40 years old and carries a lot of historical baggage with it.

author: coppice
author_rank: Super Contributor
timestamp: March 11, 2023, 02:49:31 pm
content: Quote from: tggzzz on March 10, 2023, 10:29:47 pmC is as real time as any language specifically known as real time. It doesn't enforce any of the road blocks, like garbage collection, that make real time systems hard or impractical to implement.

author: janoc
author_rank: Super Contributor
timestamp: March 11, 2023, 02:59:26 pm
content: Quote from: coppice on March 11, 2023, 02:49:31 pmThat just means you are doing/thinking about the real time wrong, that's all.Pretty much every garbage collected language has means to both disable/delay/control the garbage collector, so that it isn't running during the critical portions of your code and you can often also replace it with your completely custom one too. Or even disable it altogether if you want. Or even replace the entire runtime with your custom one - even for Java. Just like Google did with Android - there Java code doesn't run on JVM but their own custom runtime - first Dalvik, later ART. OK, that is obviously not a real time system but the point stands that one can do that.Heck, there is even a real time specification for Java being developed, with several implementations already:https://en.wikipedia.org/wiki/Real_time_JavaFor example Erlang is both garbage collected and widely used for real time work, such as in telecom industry.Whether or not something can be described as real time is really not a function of the programming language used.

author: coppice
author_rank: Super Contributor
timestamp: March 11, 2023, 03:09:01 pm
content: Quote from: janoc on March 11, 2023, 02:59:26 pmThe vast majority of telecoms code is soft real time, and many things can work well for that. Hard real time with decent throughput is another matter. None of the "get out of the way" collectors I've seen are 100% lock free, and just don't get in the way when a real time input, requiring a short hard deadline response, occurs.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 03:11:45 pm
content: Quote from: coppice on March 11, 2023, 02:49:31 pmRealtime language: xC on xCORE has a toolchain that guarantees code execution time to the clock cycle. That is hard realtime!GC: I have successfully designed and implemented a commercial soft realtime application in Java. The performance amazed those that were used to the equivalent C application, to the extent that another company unexpectedly bought rights to the core part. Application domain: telecoms billing, where some of the customers started throwing chairs around if the calls weren't terminated the second the credit expired.Reason for the Java application's performance: language primitives that allow for multithread/multicore operation, plus not having to be excessively defensive about ensuring next year's team members won't have used the language or a data structure improperly.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 03:17:30 pm
content: Quote from: coppice on March 11, 2023, 03:09:01 pmPlease state which language plus hardware guarantees hard realtime performance. N.B. measuring and hoping you bumbled across the worst case performance isn't a guarantee.C applications running on (most) modern processors are also soft realtime, for the reasons I've given. Too many people are in denial or blissful ignorance about that.

author: janoc
author_rank: Super Contributor
timestamp: March 11, 2023, 03:21:39 pm
content: Quote from: coppice on March 11, 2023, 03:09:01 pmThen write a lockfree garbage collector if that is a requirement? Or disable garbage collection for that critical part? Again, this has zero to do with the language used, that's a matter of the runtime/architecture/etc.And re soft/hard real time - if one wants to have a meaningful discussion then one should say what are we talking about instead of making blanket statements that "X is not suitable because garbage collector/Y". Soft real time is still real time processing.And yes, even hard real time can be done in a garbage collected environment. with a formal proof that it will achieve the timing requirements. It isn't common but it is certainly possible and work is being done on it, see e.g. these papers researching the subject:https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=911647500f989fae31051993e9fe99769ff65b27https://www.cs.purdue.edu/homes/hosking/papers/rtss09.pdf

author: coppice
author_rank: Super Contributor
timestamp: March 11, 2023, 03:52:59 pm
content: Quote from: tggzzz on March 11, 2023, 03:17:30 pmNo modern combination of language and hardware will get you to hard real time performance on their own.I've implemented DSP solutions where the core clock was PLLed to the incoming data clock; the core, like most DSP cores, was always cycle accurate; the code was crafted so every path through it was exactly the same length; and that length was tuned to be the exact interval between incoming data samples. Once synced up code didn't even have to spend time waiting for the next input sample to be ready. Being cycle accurate, it just took the next input sample on the right clock cycle. Few people want to implement solutions like that, but it was very hardware efficient at the time.There isn't much around today that you can do something like that with. Even if you turn off the caches, almost everything is pipelined and pipelines are chaotic. However, without the cache in your way, the pipelines do have an absolute worse case. Its a while since I used one, but there are tools which will take your code and figure out true worst case cycles through any path in the code. You can still build hard real time solutions. The language and hardware issues are not whether the make for a hard real time solution. The issue is whether they get in your way or totally block you.

author: coppice
author_rank: Super Contributor
timestamp: March 11, 2023, 03:59:06 pm
content: Quote from: janoc on March 11, 2023, 03:21:39 pmThose papers are quite old. I'd have to re-read them to remember all they said. However, I so remember them as are very hand wavy about aspects of the problem, only attempting a formal proof of a part of it.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 04:39:53 pm
content: Quote from: coppice on March 11, 2023, 03:52:59 pmxC + xCORE gives you hard realtime guarantees. It helps (more than a little!) that there are no caches, no interrupts, no pipelines. Just 32 cores 4000MIPS. IDE+tools examines the object code to show execution clock cycles of all paths betweenhereandthere, including for optimised code.But apart from that, I agree.GC and caches/NUMA/multicore/etc all screw up hard realtime guarantees. Hence - back to my point(!) - there's little validity to this contention: .....Quote from: gf on March 11, 2023, 07:04:15 am

author: coppice
author_rank: Super Contributor
timestamp: March 11, 2023, 06:14:45 pm
content: Quote from: tggzzz on March 11, 2023, 04:39:53 pmMost hard real time solutions do manage their memory, but do it statically. That is, they check the configuration requirements, allocate memory as appropriate, and stick with it until operation might be paused for a reconfiguration.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 07:41:35 pm
content: Quote from: coppice on March 11, 2023, 06:14:45 pmAgreed.Even that isn't sufficient to be able to predict performance on a modern processor and computer.Except in special circumstances it is impossible to predict the time taken to read (or worse write) an array element, because the time depends on thevaluesthat variables had arbitrarily far in the past. (And the sequence of instructions executed, of course)People really ought to be disabused of the false idea that C performance is predictable and other languages aren't predictable.

author: coppice
author_rank: Super Contributor
timestamp: March 11, 2023, 08:44:45 pm
content: Quote from: tggzzz on March 11, 2023, 07:41:35 pmIts amazing how clueless even quite senior engineers can be about the strengths and weaknesses of modern tools. Like taking code that runs in a loop, putting it on an ultra low power MCU, and being shocked that the current consumption is not anything like the minuscule figures the vendors have indicated.

author: tggzzz
author_rank: Super Contributor
timestamp: March 11, 2023, 09:29:16 pm
content: Quote from: coppice on March 11, 2023, 08:44:45 pmThere seem to be a few boundaries in thinking, possibly derived from how Things Are Taught.Chemistry vs biology. That meant biochemistry had to be "invented" in the 60s/70s.Analogue vs digitial vs RF electronics. OK, RF used to be completely distinct, but the rise of DSP/SDR and clock speeds has made the boundaries very porous. Digital vs analogue: too many people don't understand that (almost) all electronics are analogue, with some analogue circuits interpreting voltages as digital signals.Software vs hardware vs electronics vs physics. To me they are a continuum, all interacting with one another (your example is software<->physics).I see no easy-to-define boundary between (digital) hardware and software. But many people's experience is so insular and limited that they have difficulty comprehending the similarities and can't understand why there is no solid boundary.

author: Kjelt
author_rank: Super Contributor
timestamp: March 11, 2023, 09:51:58 pm
content: Quote from: tggzzz on March 11, 2023, 09:29:16 pmThat has IMO less to do with people than with the college/university system artificially seperating both.But this goes for all studies all sciences, the artificial boundaries are so people can graduate in four years and have a limited scope. Everything from the universe to the sub molecule level are linked but comprehending everything is too big for a single human being to comprehend. Then you have to split it up in smaller parts and we get specialists.But what I don't get is that if you have mastered one part you are not interested in the part next to it with what you interact. Personally I have a broad interest and also have all the hobbies, electronics, software, me hanics, mechatronics, pneumatics.

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 12:27:39 am
content: Quote from: tggzzz on March 11, 2023, 09:29:16 pmPeople haven't really been hired for their ability to write software since the early 70s. Sure, there are lots of ads for software people, but when you get down to what they are really looking for its not the ability to write software. That's like the ability to write English. It a requirement so basic it barely registers in an interview. What people are really hired for at some level is application expertise. That might be business practices, or database design, or human interaction, or knowing enough about electronics to write the software to control some.There used to be things called :software houses" that did really well in the early 70s as pure software plays, but crashed at the end of the 70s. They had to rapidly adapt to become some form of systems house, which was pretty hard to do, as there was a massive economic downturn at just the time they were restructuring.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 08:50:21 am
content: Quote from: Kjelt on March 11, 2023, 09:51:58 pmCreating models is the way the complexity is contained. But you have to understand the source of the model and the model's boundaries. As someone once put it, "the best result of advanced mathematics is that you don't have to understand the detailed derivation".QuoteJust so.That principle also applies in business....In order to understand the value your product/service has to your customer, you have to understand how your product/service helps/hinders giving value to your customer's customers. Similarly, in order to have a good relationship with your supplier so they want to help you, you have to understand how they do/don't make their money.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 12, 2023, 09:36:37 am
content: Realtime-ness in itself is a continuum. From most control and guarantees, to least,1 Custom ASICs2 FPGA's3 The XMOS things4 High end microcontrollers with application features (caches, external flash memories) disabled (minus point if RTOS is used)5 Low end microcontrollers6 High end microcontrollers with said application features enabled and used for all code (minus point if RTOS is used)7 Application CPUs with general purpose OS tailored for real-time tasks8 General purpose PC with general purpose OS not optimized for real-time tasks1-3 can prove timing to one clock cycle, but with decreasing amount of resources (custom ASIC can do sub-ns stuff; FPGA is limited to maybe 500MHz tops clock and digital synchronous logic; XMOS is yet a step slower, and hard-limited by number of cores). 4-5 can besometimesproved down to a clock cycle, but that is usually too much work; practically they are accurate down to "a few" cycles. Additionally, parallelism with many tasks whichallare highly timing-critical becomes impossible. 6-8 become progressively more difficult to try to prove anything regarding timing.A wise man learns to use the available tools; for example, while a high-end microcontroller with caches appear slower and more jittery if programmed lazily, it could be equipped with core-coupled instruction RAM which can be used for all timing-critical routines, leaving only user interfaces and such behind slower interfaces (and caches).

author: Marco
author_rank: Super Contributor
timestamp: March 12, 2023, 10:32:01 am
content: I'm pretty sure Kjelt was talking about GC not working real time in the sense of not immediately calling the destructor the moment an object goes out of scope BTW.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 10:59:31 am
content: Quote from: Siwastaja on March 12, 2023, 09:36:37 amA sensible summary, especially "A wise man learns to use the available tools"I'd nit-pick:point 1 Custom ASICs and discrete logicpoint 1-2 to sub-clock predictability, since they will be estimating gate and wire delayspoint 3-7 minus point if any algorithm which isn't O(1) used, e.g. a dictionary where performance degenerates when too fullThe last of those is ignored by people that think programs written in C (and other languages of course!) have predictable performance.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 12, 2023, 01:00:09 pm
content: In FPGA you have full control of timing, so you can time events very precisely, such as 50-100 ps resolution.In MCUs, if you have cycle accurate CPU, the best you can do is a clock cycle, say 10 ns on 100 MHz CPU. As CPUs get faster they tend to lose their cycle-accuracy, so you cannot get anywhere close to FPGAs.However, many MCUs have means to time things more precisely, such as PWM modules which may produce sub-ns resolution regardless of the CPU clock.All of these have nothing to do with languages however. In FPGA to get the highest resolution you have to use vendor-specific primitives (no matter if you use VHDL, Verilog, or whatever). To get precision on cycle-accurate MCU you must use assembler. To use timing features of MCU hardware modules, you write to MCU registers (or use vendor-specific librarians which do that for you).

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 01:48:01 pm
content: Quote from: Siwastaja on March 12, 2023, 09:36:37 amNothing confuses people like temporal issues. You seem to be confusing speed with real time. Hard real time is about meeting strict deadlines 100% of the time. Sometimes those deadlines are really short and only a few techniques can meet the goal. Sometimes those deadlines are quite long and a wide range of approaches can be shown to reliable. In almost every case you need to clock at the input and output interfaces, get the response to an input ready ahead of or exactly on the output deadline, and let the output clock feed it through at the right moment. If your deadlines are really critical the purity of the clocks at the input and output become your actual real time performance limit, not the solution you use in between.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 02:36:02 pm
content: Quote from: NorthGuy on March 12, 2023, 01:00:09 pmNot true.The object code timing will be the same whether it is created directly by a human or indirectly via a compiler.The algorithms, data structures, data values, and hardware will determine howrepeatable/predictablethe algorithm and instruction timings turn out to be. The language is irrelevant.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 12, 2023, 02:48:07 pm
content: Quote from: tggzzz on March 12, 2023, 02:36:02 pmOk. Write a code which toggles one pin and then toggles the other pin exactly 4 cycles later without using assembler.

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 02:50:29 pm
content: Quote from: tggzzz on March 12, 2023, 02:36:02 pmIn a sense he was right. In a core so simple that the timing is predictable (which is getting rare) assembly language code will always do what you expect. For any high level language you need to check the version of every software tool you use, and ensure they never change during the life of the software. Any minor update might change the generated code.

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 02:54:30 pm
content: Quote from: NorthGuy on March 12, 2023, 02:48:07 pmFor things that basic the code produced by a compiler is so predictable that people frequently write C code for it. Looking up the cycles produced by simple C patterns is really no different from looking up the cycles each line of assembly language takes. As predictable cores fade away that will end.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 03:07:32 pm
content: Quote from: NorthGuy on March 12, 2023, 02:48:07 pmPlease don't snip the reasons in order to make a strawman argument.Or maybe you didn't understand the reasons?

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 03:08:35 pm
content: Quote from: coppice on March 12, 2023, 02:50:29 pmThere's truth in that, but it isn't clear cut.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 03:21:11 pm
content: Quote from: NorthGuy on March 12, 2023, 02:48:07 pmOr perhaps I should enlighten people to one example of programming in a hard realtime environment. From the relevant programming guide, an example of generating a clock with a 40% duty cycle...6.8 Performing I/O on specific clock edgesIt is often necessary to perform an I/O operation on a port at a specific time with respect to its clock. The program below drives a pin high on the third clock period and low on the fifth:Code:void do_toggle ( out port p) {int count ;p <: 0 @ count ; // timestamped outputwhile (1) {count += 3;p count <: 1; // timed outputcount += 2;p count <: 0; // timed output}}The statementp <: 0 count;performs atimestamped output, outputting the value 0 to the port p and reading into the variable count the value of the port counter when the output data is driven on the pins. The program then increments count by a value of 3 and performs atimed outputstatementp count <: 1;This statement causes the port to wait until its counter equals the value count+3 (advancing three clock periods) and to then drive its pin high. The last two statements delay the next output by two clock periods.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 12, 2023, 03:35:30 pm
content: Quote from: tggzzz on March 12, 2023, 03:21:11 pmWhat cycle-accurate MCU is this written for?

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 04:18:08 pm
content: Quote from: NorthGuy on March 12, 2023, 03:35:30 pmxCORE, of course.The i/o ports' clock is settable independently of the processor clock. FPGA equivalent: clock tiles.There are no library functions invoked by that code; each output instruction translates directly into two assembly instructions, one to set the timer in the relevant port, one to set the data value.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 12, 2023, 04:36:48 pm
content: Quote from: coppice on March 12, 2023, 01:48:01 pmI'm not confusing anything. "Realtime-ness" was a fluffy term on purpose, it has no definite, correct meaning.In real world realtime applications, both performance (speed) AND predictability are important, which is why I grouped first by predictability, but within the group of similar predictability, sorted by performance.People often confuse their importance, for example thinking that extreme predictability is way more important than performance, or vice versa. Typical example would be thinking that a 8MHz AVR is somehow "better" than a 400MHz Cortex-M7 only because in the latter, branch prediction and ISR stacking tail-chaining, gives a few clock cycles of jitter. In reality however, meeting deadlines (worst case behavior) is usually more important than small amount of jitter, raw performance is in favor of this.

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 06:07:12 pm
content: Quote from: Siwastaja on March 12, 2023, 04:36:48 pmIs this M7 on a chip with so much RAM it can run at 400MHz with the caches of? If not you'll get a lot more than a few cycles of jitter. The effects of branch predictors are minor compared to cache. Its a real killer for predictability in most modern devices.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 12, 2023, 06:37:42 pm
content: Quote from: tggzzz on March 12, 2023, 04:18:08 pmSo, it's a programmable periphery like PIO in RP2040.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 12, 2023, 06:47:17 pm
content: Quote from: coppice on March 12, 2023, 06:07:12 pmOf course it depends on a project. I have never needed external flash or external RAM and thus caches on any of my STM32H7 projects, which have been quite complex in my own opinion. Quite frankly, I don't see the use case for the caches at all, but maybe there are some I don't see. Clearly caches are available for the same reason you have JPEG codec or two CAN peripherals available: some users might want it.For example, H743/H750 has 64KB of core-coupled instruction RAM which does not need to go through bus arbitration, and 128KB of core-coupled data RAM, same thing. Anything even remotely timing critical tends to fit in some dozen KB, in my experience. Put interrupt vectors and all ISRs on the ITCM, it could not be easier.

author: JPortici
author_rank: Super Contributor
timestamp: March 12, 2023, 07:08:03 pm
content: So, GCC is coming up with a Rust frond end, huh?That would be interesting as the architecture i use the most (dsPIC) only has a GCC based compiler. Not that i expect a Rust compiler from microchip appearing any time soon

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 12, 2023, 07:11:28 pm
content: Quote from: Siwastaja on March 12, 2023, 06:47:17 pmIt will depend on your type of application and the hardware. When I did the new firmware for the FNIRSI-1013D running on the Allwinner F1C100s, turning on the cache made quite the difference in the performance of the display code. Even though the chip has 32MB of internal DDR it is not fast enough to keep up with the ~600MHz core.Would I choose the chip for some specific "real time" task. Most likely not. And that is what count does it not? When designing something, you search for the best suiting components to get the job done. Same applies for the programming language. When I have to write up something that has to run in a browser, I choose the language(s) best suited for the job, and in that case it ain't C or Rust.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 07:58:08 pm
content: Quote from: NorthGuy on March 12, 2023, 06:37:42 pmWho cares.What matters is the capabilities - or rather the system level guarantees given by the hardware and software. Does the RP2040 give similar system level guarantees?

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 08:25:57 pm
content: Quote from: Siwastaja on March 12, 2023, 06:47:17 pmOK, those do have quite a bit of closely coupled memory for your timing critical code. However, I'm puzzled by you not seeing the use of the caches. Have you see how slow code runs from flash with them turned off? Even running from that AXI SRAM things take quite a hit.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 12, 2023, 10:08:46 pm
content: Quote from: tggzzz on March 12, 2023, 07:58:08 pmYes, PIO is sort of a small state machine (or a very small specialized CPU if you will)

author: nctnico
author_rank: Super Contributor
timestamp: March 12, 2023, 10:37:49 pm
content: Quote from: coppice on March 12, 2023, 06:07:12 pmWhy would you want to have predictability in the first case? Product functionality isn't fixed nowadays so a far better solution is a design that doesn't need predictable execution time. Nowadays products see upgrades and modifications to the software all the time and these are easy to implement because the predictable execution time requirements have been taken out of the design equation. Everything is OK for as long as the CPU has cycles to spare between working on processing data.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 12, 2023, 10:42:43 pm
content: A very recurring discussion.Don't rely on predictable timings in the first place for as much of the code as possible, and use dedicated peripherals/hardware otherwise.This covers a very wide range of use cases.Only in a few cases do you absolutely need strict, hard real-time on a *software* level, in which case you usually won't be using an off-the-shelf MCU anyway, and probably neither C nor Rust either.Note that one point is not just the physical *possibility* of meeting hard real-time requirements, but making it provable. In which case you can refer to what tggzzz has been saying.

author: coppice
author_rank: Super Contributor
timestamp: March 12, 2023, 10:46:20 pm
content: Quote from: nctnico on March 12, 2023, 10:37:49 pmWe were talking about real time applications.

author: tggzzz
author_rank: Super Contributor
timestamp: March 12, 2023, 10:59:52 pm
content: Quote from: nctnico on March 12, 2023, 10:37:49 pmAt some level and to some degree, predictability isalwaysrequired. You state as much when you writeQuoteHowcanyou prove that if there is no predictability? Random unpredictable behaviour is a killer for realtime guarantees.Take some rough figures...Suppose L1 latency is 1ns and DRAM latency is 100ns. The mean latency may well be 5ns, but what latency do you use when evaluating whether there are spare cycles? What then happens when the wind is against you and latencies are pessimal this time?If you want to keep real-time guarantees, then you either have to disable the cache or ensure that everything is in the cache.BTW 10:1 worst:mean latencies are easily visible; and if TLBs are involved then the ratio will bemuchworse.

author: westfw
author_rank: Super Contributor
timestamp: March 13, 2023, 12:54:25 am
content: QuoteI think the most compelling argument against "higher level languages" (C++, in particular) at a previous employer was that it was substantially difficult to keep track of whichthingswere likely to be performance, real-time, or concurrency "problems." You could be innocently going along make good use of enhanced features and protections, and suddenly use a particular signature of an overloaded function or operator that happened to invoke bad behavior, and it would be really hard to notice.(It's significantly difficult to keep track of internally created low-level functions, too, but they can get big fat warning documentation attached to them.)I suppose the obvious example is Strings. I mean, I really hate trying to do any significant string/text processing in C, compared to the more reasonable functionality available in C++, Python, even BASIC. But at least in C your code is very explicit in what is has to do, whereas I have very little visibility into the absolute performance characteristics of those other languages...

author: uliano
author_rank: Regular Contributor
timestamp: March 13, 2023, 07:58:33 am
content: Wow! I didn't mean to resuscitate such a rabbit hole.And yes, I know very well that a new language won't help solving concrete problems and won't save but make me waste time but, as a hobbyist, I can sometimes afford some procrastination.Also I was (partly) aware of rust's limitations such as lack of standardization but, in this specific case my digression has been motivated by limitations of well standardized languages.When I was younger we had only K&R C and one of its "feature" most aggravating to me was automatic promotion of function parameters (e.g. the infamous float to double). I thought that this crap was gone with the advent of function prototypes in the early stages of the standardization process but, alas only to discover (now that MCU learned/forced me to look into assembly code) that automatic type promotion is still there even if only in variadic functions. Ok, sure, nothing that you can't live without but WHY??? ( The other topic emerged in the thread against rust is portability, yes C is very portable but only thanks to is UGLY preprocessor and macro language)The other trigger has to do with partial template class specialization not doing what I had liked, but this case is still under investigation and I may be wrong. I'm confident however that even if C++ is fully defined and standardized, its standard is a complete mess! Sure born from the competing exigences of innovation and compatibility with old codebase but, boys, even FORTRAN has done better job in evolving its standard!Anyway I'm digressing, I'm writing this to thank you all from preventing me waste my time. I still hope that somewhere lies a better language that, even if not solving problems for me, can make my programming experience less frustrating but again, (to use Mario's words) our princess is in another castle...A particular thank to janoc for having been explicit on many relevant aspects.Quote from: janoc on March 11, 2023, 02:42:37 pm

author: tggzzz
author_rank: Super Contributor
timestamp: March 13, 2023, 08:08:03 am
content: Quote from: NorthGuy on March 12, 2023, 10:08:46 pmIn that case they arevery different.xCORE ports can be configured (very easily and cleanly) to be SERDES, strobed, clocked, timestamped, conditional, buffered. They are more like FPGA i/o blocks.The code example I gave is running onfully-fledged MCU level cores, running C/C++/xC. Another example might beCode:# include < print .h ># include < xs1 .h >timer t ;select my_case ( chanend c , unsigned timeout ) {case c : > int x:printintln ( factorial(x) );break ;case t when timerafter ( timeout ) : > void :printstrln ( "Ouch, panic" ) ;break ;}Notice:arbitrary functions, factorial() and printf() in this caseselect statement, which halts the core until any one of the case clauses is validwaiting for an inputora timer's timeout to occuroften you would wrap that lot in the traditional init(); while(1) { ... }often inputs would be messages from other cores, and outputs would be messages to other coresSo,nothing whatsoever like the very limited PIO state machines.

author: nctnico
author_rank: Super Contributor
timestamp: March 13, 2023, 10:58:49 am
content: Quote from: coppice on March 12, 2023, 10:46:20 pmYes. And as long as processing is done in time, everything is fine. Working with excess performance (which is what most modern microcontrollers offer) is much easier where it comes to predictable behaviour and upgrading a product. What I mean is that you basically decouple the actual execution time from the realtime requirements.One of my former employers made an absolute killing by replacing DSP based telecom equipment that took years to develop (hand crafted assembly) by PC based software (all written using C / C++) that took months to develop. The PC based solution also scaled better due to the ever increasing performance of processors used in PCs. Both solutions catered to the same realtime signal processing application but the PC based solution was like 20 times cheaper to buy while performing equally.

author: tggzzz
author_rank: Super Contributor
timestamp: March 13, 2023, 01:04:08 pm
content: Quote from: nctnico on March 13, 2023, 10:58:49 amGrossly overprovisioning a system is possible insomecircumstances.Frequently it isn't possible, either due to cost constraints or because the application is pushing the bounds of the possible. I've normally been doing the latter."An engineer is someone who can do for $1 what any fool can do for $10".QuoteTelecom stuff has seriously wierd pricing constraints - or ratherlackof constraints. I well remember finding the price HP charged for 64kb/s SS7 interfaces, compared to the cost of the whole box.

author: JPortici
author_rank: Super Contributor
timestamp: March 13, 2023, 01:50:49 pm
content: To all: This is the same old argument that comes up every 10 thread or so, with the same comments from the same people, so please can we keep this thread on topic regarding Embedded Rust?Thanks

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 13, 2023, 02:03:33 pm
content: Quote from: JPortici on March 13, 2023, 01:50:49 pmTrue, but the thread already died last year to only be resurrected by uliano who is now scared of of RustLet them have their arena to beat the real time issue to death

author: uliano
author_rank: Regular Contributor
timestamp: March 13, 2023, 02:58:59 pm
content: Quote from: pcprogrammer on March 13, 2023, 02:03:33 pmI'm not scared, I would say disenchanted.I lowered the priority, didn't trashed it away... yet.I still would have liked an answer from TopQuark(never underestimate hobbyists' capability to waste their own time!)

author: NorthGuy
author_rank: Super Contributor
timestamp: March 13, 2023, 03:36:59 pm
content: Quote from: uliano on March 13, 2023, 07:58:33 amThere's no type promotion in C. There's integer promotion, which converts everything shorther than the int size to the int size. The reason for this is because a CPU may not have shorter operation. For example, in ARM everything is 32-bit (no 8-bit or 16-bit operations), hence to add two numbers you need to promote them to int.Quote from: uliano on March 13, 2023, 07:58:33 amThe pre-processor is designed for the specific purposes and it serves them well. Certainly could have been better. If you're interested in this, you can extend the pre-processor, for example create pre-processor variables and operations. Then you can use it for code generation which will save you time if you will indeed use it.If you're interested in languages, you're not alone. People love to create new languages, such as Algol 68 (over 50 years back) which is the first example of systemic language (as opposed to practical). You can even create your own language. I would say it's even very interesting and worth doing as a hobby. However, it's unlikely that a new language will dramatically simplify your life.If you're centred on your project, the important thing is to have a design first, then implement it using a language of your choice. As opposed to expecting that the language will create a design for you.

author: uliano
author_rank: Regular Contributor
timestamp: March 13, 2023, 04:33:25 pm
content: Quote from: NorthGuy on March 13, 2023, 03:36:59 pmOh there really is!https://stackoverflow.com/questions/58178731/override-gccs-varargs-argument-promotionQuoteThe preprocessor is 50 (and counting) years old crap, source of both side effects and unreadable code.Once upon a time a guy processed the c source (actually after the pre-processor step) before sending it to cc and C++ was created. It was good, for the times...QuoteI'm more interested in evaluating existing ones when some euristics suggest me that they could be worth.QuoteThis is yet a completely different story.

author: cv007
author_rank: Frequent Contributor
timestamp: March 13, 2023, 04:52:32 pm
content: my rusty 2 cents-I think there is too much required syntax in Rust and becomes unreadable-https://github.com/stm32-rs/stm32g0xx-hal/blob/main/src/gpio.rs(kind of a forth problem- a week after its written you cannot read/understand it)That is a gpio 'hal' for a stm32g0 series, the 'pac' (register access) is somewhere else and they seem to have a source file for each register (treating each port separately also, it appears)-https://github.com/stm32-rs/stm32-rs-nightlies/blob/master/stm32g0/src/stm32g031/gpioa/bsrr.rsI haven't given it a fair shake, and have only attempted to learn it a few times. Each time I end up wondering what I am gaining over what I already have. Maybe the examples typically seen could be better and there is something simpler lurking underneath that could be brought out, but I doubt it (examples in any language are not necessarily a good indication of what is possible).In contrast, c++ is not syntax heavy for most uses and you can express what you want in minimal code-https://godbolt.org/z/6ffeohj8zI think it remains readable even if you are not familiar with C++, and in this case the gpio 'hal' source code is about 10x less than the rust equivalent above (this example excluded exti use but is not much more code). The example given also has no dependencies (online compiler has no knowledge of a stm32), although the pieces inside would normally live in their own header.I'm sure I have made this comment before, but I think C++ is perfectly suited for mcu use. You get C which you already know, and can add additional features from C++ that make sense for the limited resources of the mcu. You also get a toolchain, and everything that surrounds it, that has been around a long time. I think in many cases those that promote or want rust on embedded have simply skipped over C++, and are always looking for the next 'best' language. Nothing wrong with that, but it may rob you of time better spent polishing your skills in an existing language. C++ seems to be a well kept secret for the mcu.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 13, 2023, 05:34:37 pm
content: Quote from: uliano on March 13, 2023, 04:33:25 pmThis is only when you pass argument to the function and the type of the argument being expected by the function is unknown. Is that somewhat important to you? Why?Quote from: uliano on March 13, 2023, 07:58:33 amQuote from: uliano on March 13, 2023, 04:33:25 pmWorks for me. It actually makes code more readable, as it lets you replace cryptic things with macros. A la:Code:GREEN_LED = 1;It's up to you. You can use it to your advantage, or you can use it to create problems.Same, as you can use a hummer to drive nails, or you can use it to flatten your fingers. But when you hit your finger, you wouldn't call the hummer is a 3000-year old crap, would you?I, personally, do not like C syntax very much. Something pascal-like looks better to me. But I don't think it's important. What's important that Icando what I want. I don't want to spend hours to find a way to convey the compiler to do what I want it to do.

author: nctnico
author_rank: Super Contributor
timestamp: March 13, 2023, 11:08:33 pm
content: Quote from: uliano on March 13, 2023, 07:58:33 amRecently I have been looking at Lua and Micropython to implement higher level logic in embedded projects. A project I'm currently working on will very likely have the high level logic / functionality implemented in Micropython. Besides having code run inside a VM, one of the other advantages is that the code can be compiled on the target itself (as part of the initialisation) so it is easier to replace the logic that implements the functionality of the device without needing to recompile the entire source.

author: uliano
author_rank: Regular Contributor
timestamp: March 14, 2023, 11:01:11 am
content: Quote from: NorthGuy on March 13, 2023, 05:34:37 pmI'm not saying that this is dealbreaker but it is there if, for example, you want to implement some kind of printf loggingthe point here is "yes we have a standard", yay! that prevents "correct" beahaviour, admittedly on a marginal problem.QuoteIn the context of MCU firmware, despite some marginal ugliness, C is a robust and proven tool, possibly even the best, but it's not THE definitive tool, there is always space for some kind of progress. I'm not saying that Rust will necessarily be a progress but, having time to waste (my definition of hobby), why not keep an open mind and give it a look?

author: uliano
author_rank: Regular Contributor
timestamp: March 14, 2023, 11:04:13 am
content: Quote from: nctnico on March 13, 2023, 11:08:33 pmThat would be a *completely* different story. Good only when the ratio between computational resources (therefore cost?) to problem complexity is high.

author: tggzzz
author_rank: Super Contributor
timestamp: March 14, 2023, 01:18:33 pm
content: Quote from: uliano on March 14, 2023, 11:01:11 amPrecisely. Looking for relative strengths and weaknesses is good and professional.My doing that as a hobby enabled me to make some professional choices that turned out to be very advantageous, and to avoid some really bad choices.

author: coppice
author_rank: Super Contributor
timestamp: March 14, 2023, 01:26:58 pm
content: Quote from: nctnico on March 13, 2023, 11:08:33 pmLua doesn't seem to get the coverage it deserves. I haven't done much with it, but I've seen people who do. Once they start using it they don't usually go back. It seems to work well for them.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 14, 2023, 04:48:30 pm
content: Quote from: uliano on March 14, 2023, 11:01:11 amThere's progress. Newer MCUs are getting better periphery, the peripheral modules get interconnected in various ways, more and more tasks can be off-loaded to peripheral, you get more memory so you can create better algorithms, you get faster and more reliable communications. That's where the progress is, not in languages.Let me ask you a question. If you want to create a software program, you need to design data structures, algorithms, processes. When you do that, do you ever need to know what language you're going to use to implement it?

author: tggzzz
author_rank: Super Contributor
timestamp: March 14, 2023, 06:49:45 pm
content: Quote from: NorthGuy on March 14, 2023, 04:48:30 pmSuch parallelism implies concepts and thinking that don't come naturally to most people coming from a pure software background. Parallelism and distributed systems are not as well taught as they should be. People coming from a digital hardware background don't have much trouble with those concepts.That progress in hardware needs to be matched by progress in languages. Sticking plasters aren't sufficient.QuoteYes, you do, since the language affects what you can and cannot express. There are similar issues with human languages.Having said that, many languages are more or less equivalentin the sense that if you grok one then switching to another is not a big hurdle, e.g.C/C++/Delphi, or Smalltalk/Java/C#, or VHDL/Verilog, or Erlang/xC/Occam, or SQL, or Matlab/Mathematica, or Prolog.Example: you wouldn't suggest using SQL to send messages from one Unix box to another, would you.

author: coppice
author_rank: Super Contributor
timestamp: March 14, 2023, 06:57:11 pm
content: Quote from: tggzzz on March 14, 2023, 06:49:45 pmThe problem with temporal issues in systems is most people are very bad at getting their heads around them. I don't see how any kind of tool less than a machine which can totally replace a human will ever do much about that.

author: tggzzz
author_rank: Super Contributor
timestamp: March 14, 2023, 07:28:06 pm
content: Quote from: coppice on March 14, 2023, 06:57:11 pmIthinkhope that is a bit strong!Most of the current tools contain features that actively sabotage being able to reliably express parallelism. That has to stop.It will stop, but only over the course of a generation and with adherents of the current tools kicking and screaming all the way. That is the same way that scientific dogma atrophies.

author: coppice
author_rank: Super Contributor
timestamp: March 14, 2023, 07:31:12 pm
content: Quote from: tggzzz on March 14, 2023, 07:28:06 pmI'm not sure its the tools that really make things hard. A lot of it is poor documentation. When you see the potential gotchas, and look up exactly what is going on behind the scenes, too often you can't find the answer without massive effort.If this will stop over a generation, why is the problem still here? We've been faffing around with this since the late 70s.

author: nctnico
author_rank: Super Contributor
timestamp: March 14, 2023, 08:03:56 pm
content: Quote from: uliano on March 14, 2023, 11:04:13 amNo. You can run embedded versions of Lua (not specifically eLua) on a standard microcontrollers. You'd need about 128kB of flash and 32kB of RAM to run a Lua based application. Last year I've been working on a Lua 'fork' that can be used without an OS as part of a round-robin scheduler, non-blocking process. I have not got round to finishing it yet. Maybe this summer holiday...

author: tggzzz
author_rank: Super Contributor
timestamp: March 14, 2023, 08:42:50 pm
content: Quote from: coppice on March 14, 2023, 07:31:12 pmYou need the right conceptual primitives and concepts. Sticking plasters added later don't count!You need simplicity and economy of concepts. Complexity is the enemy of comprehension and prediction.QuoteIt is the usual two steps forward one step backward. Meanwhile semiconductor process scaling was making ten steps forward. That's ceased, so people are having to become more imaginative and inventive. Plus the new generation starts with parallel distributed system.I

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 14, 2023, 09:02:03 pm
content: I like Lua as a scripting language, but any "embedded" version I've seen is non-official, usually doesn't support the whole Lua language (for obvious reasons), and most are not well or actively maintained.Happy to be proven wrong though.One variant I've mentioned at some point was nelua. Heavily inspired by Lua, but with a whole lot more, with things more adapted to embedded software.It compiles to C, so should be usable with pretty much any target with some minimal preliminary work.https://nelua.io/Of course it's a compiled language, not an interpreted one, so it doesn't quite fit the same purpose or use case. But as a replacement for C for those who are curious and willing to experiment, why not.

author: coppice
author_rank: Super Contributor
timestamp: March 14, 2023, 09:03:07 pm
content: Quote from: SiliconWizard on March 14, 2023, 09:02:03 pmA key thing about embedded stuff is it doesn't have to be portable. Being "official" has few benefits.

author: nctnico
author_rank: Super Contributor
timestamp: March 14, 2023, 09:08:17 pm
content: Quote from: SiliconWizard on March 14, 2023, 09:02:03 pmLua is mature; it doesn't need to be maintained. It ain't broken, so it doesn't need fixing / adding more bugs. For my own fork, I started with this:https://github.com/szieke/embLua.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 14, 2023, 10:19:45 pm
content: Quote from: nctnico on March 14, 2023, 09:08:17 pmYes, sure. That's exactly what I said to my grandma the other day.

author: uliano
author_rank: Regular Contributor
timestamp: March 15, 2023, 05:58:22 am
content: Quote from: NorthGuy on March 14, 2023, 04:48:30 pmYou can't be serious

author: uliano
author_rank: Regular Contributor
timestamp: March 15, 2023, 06:04:43 am
content: Quote from: nctnico on March 14, 2023, 08:03:56 pmThe "ratio" thing is nice because it also has a denominator. I'm sure eLua is really nice and well fit for many applications, but it won't go on par with compiled code in terms of resources (flash, ram and also time).

author: nctnico
author_rank: Super Contributor
timestamp: March 15, 2023, 10:48:27 am
content: Quote from: uliano on March 15, 2023, 06:04:43 amYou should also think about things like reliability, robustness and focussing on implementing a solution. As I wrote earlier in this thread, writing robust C code is rather tedious because you'll need to prevent range & buffer overflows. This draws attention away from dealing with the actual programming problem at hand. With languages like Python and Lua you can't have problems with buffer overflows and pointers going wrong. And if something bad happens, you can use exceptions to recover gracefully. On top of that, Python and Lua are way more suitable for dealing with data sets and text / strings which reduces development time while producing a higher quality result (as in easy to read, to the point code).

author: Siwastaja
author_rank: Super Contributor
timestamp: March 15, 2023, 10:54:22 am
content: Quote from: nctnico on March 15, 2023, 10:48:27 amI don't agree, at all. The problem with C is not that youhaveto do input validation, it's that the consequences of not doing it are more dire than it needs to be.Writing in a language which does not corrupt memory and trusting the language instead of validating inputs results in code that does notcrashin the most strict meaning of word, but stilldoes not workand fails in almost as badly. Very typical example is some unhandled exception propagate gazillion levels and then just get good old crash (from user's viewpoint) with ten pages of cryptic exception stack trace (and in case of embedded, no way to propagate any of this to the user or developer).Instead, if one checks the inputs and returns -1, and the caller handles this error condition, then it can (a) report the issue, (b) use some fail-safe logic.This is a textbook example offalse sense of security. Input validation is always required and there is no silver bullet; it's hard work, because it involvesdesign; designing how errors arefunctionallyhandled. Not corrupting memory is not enough.

author: tggzzz
author_rank: Super Contributor
timestamp: March 15, 2023, 10:57:49 am
content: Quote from: nctnico on March 15, 2023, 10:48:27 amPrecisely, but plus more practical pitfalls and distractions, of course. Anything that reduces the distractions is to be welcomed, provided it doesn't bring other problems.Based on the practical evidence, I'd change "rather tedious" to "rather tedious and error prone".

author: nctnico
author_rank: Super Contributor
timestamp: March 15, 2023, 10:58:41 am
content: @Siwastaja: You are missing the point. For example: in Python and Lua you can have dynamically sized arrays / data sets out of the box. In C you either need to know the maximum size at design time OR use some kind of library that implements that for you. Both are extra work and sources for errors (for example: getting the maximum size wrong or being different at various places in software). Writing robust software is not just about input validation but also about minimizing the potential for programming errors.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 15, 2023, 11:10:59 am
content: Quote from: nctnico on March 15, 2023, 10:58:41 amI don't disagree with that, so yeah, I probably missed your point. Yes, with C you need to do more, which means more surface area for bugs, too.Languages which already solve problems for you still don't free you from the same type of input validation and range checking you do in C; just you don't need to do that for things that already work out of box, of course. You can use foreach to iterate a table, but if you need X elements for your algorithm to operate correctly, you still need to check you have those.

author: uliano
author_rank: Regular Contributor
timestamp: March 15, 2023, 01:36:37 pm
content: Quote from: nctnico on March 15, 2023, 10:48:27 amYou don't have to tell me this, as a matter of fact in my real job I'm using Python since maybe 20 years [I also paid (as maybe other 20-25 people in the world) for the documentation of numpy when it was not free as the code itself :-D ]. In those times the huge library that makes Python so useful today wasn't there and I had to write some function in C to speed up my image processing application. So I KNOW that there ARE overheads. The huge python library itself it is not even written in Python and probably neither or mostly-not available for micropython so you are just moving your "ghosts" to the people who wrote the code for you.This double language problem is well known and attempts were made to overcome it as e.g. in Julia, alas not a very successful attempt in my opinion.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 15, 2023, 05:46:14 pm
content: Quote from: nctnico on March 15, 2023, 10:58:41 amYou can use dynamic allocation in C too. malloc() is, sort of, built-in. Whether or not you should use dynamic memory allocations is another question. It depends on the project. This is totally different story.If you don't like malloc(), you can write your own allocator in C, even in assembler. This is actually very easy to do. Can you write your own allocator in Python?Of course, allocation may fail if you're running out of memory. Have you tested what happens to your Python programs if Python itself runs out of memory? How would it affect your customers?

author: nctnico
author_rank: Super Contributor
timestamp: March 15, 2023, 06:19:57 pm
content: Quote from: NorthGuy on March 15, 2023, 05:46:14 pmYou are also missing the point. You really shouldn't need or want to be messing with dynamic memory allocation at all! Let well tested & proven libraries deal with that deep under the hood somewhere. When I need dynamically allocated structures in C, I will use C++ and STL templates that do this for me so the room for mistakes is next to non-existent. I've had my fair share of debugging time with valgrind to find other people's memory allocation mistakes. I don't want to add to that mess.Recently I put solar panels on my roof. If you look at the 'professional' installers, 99% of them walk on sloped roofs without any safety measures. I, however, used a certified safety harness and attachements while working on the roof. Bottom line: just because something is possible or seems to be the standard way of doing something, it doesn't mean it is a wise thing to do. Safety first.

author: nctnico
author_rank: Super Contributor
timestamp: March 15, 2023, 06:21:42 pm
content: Quote from: uliano on March 15, 2023, 01:36:37 pmIt is not about moving ghosts, but using well tested & proven libraries / existing code in a way that makes it hard to add mistakes. Python and Lua (for example, not saying you should limit yourself to Python or Lua) allow that.

author: westfw
author_rank: Super Contributor
timestamp: March 15, 2023, 11:42:14 pm
content: QuoteJust out of curiosity, what happens to the average Python or Lua embedded program that has used "out of the box dynamically sized arrays" if those arrays exceed available memory?I guess it probably throws some sort of exception that the programmer probably didn't plan for, causing ... something... (Shades of Ariane ?) (Not that carefully checking the return value of every malloc() in C (or any other language) means that you have a obvious and effective course of action, either.)

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 12:12:08 am
content: Quote from: westfw on March 15, 2023, 11:42:14 pmThe 'C side' can catch that because the Python / Lua VM exits and then can decide a reset or some other form of recovery. This is contained within a few lines of C code. It doesn't require to propagate an out-of-memory error many layers up to some application layer which may not even have a way to deal with such an error. Ofcourse the error can also be handled inside the Lua / Python program using an exception handler.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 16, 2023, 02:07:35 am
content: Quote from: nctnico on March 15, 2023, 06:19:57 pmI think you confuse fear with safety. There's no reason to be afraid of mistakes. People learn from their mistakes. The more mistakes you make, the more opportunities to learn. Mistakes will not harm you. You'll find them and correct them. Moreover the more time you spend correcting your mistakes the easier it will become - you will see reasons why the mistakes appear, you will learn new ways to deal with them. Being indiscriminately afraid of mistakes is a really bad idea.Working on the roof is different because if you fall down you will die.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 16, 2023, 06:24:13 am
content: Quote from: NorthGuy on March 16, 2023, 02:07:35 amMistakes in embedded software can also cause someone to die - but this just emphasizes your point. If I had to hire someone to write firmware for a pacemaker or brake ECU, I would pick a team of extremely experienced professionals - those who have done gazillion of mistakes - not someone who says "hey, Python hides these memory allocations for you so it can't fail".Yeah - the earlier you start doing all the mistakes, the better.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 07:41:45 am
content: Quote from: nctnico on March 15, 2023, 06:21:42 pmThen, if you limit yourself to base Python (I never used micro- but I suppose it's a subset, possibly not proven as much as cpython), you are sailing calm waters and, I agree, if you are goin' on the heap you don't need Python but even modern C++ or, surprise, Rust, among others, can do the same.Other libraries not part of Python core itself have varying degrees of provedness so, yes there could be some ghost.However, generally speaking the heap is not my first choice for memory management on MCUs.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 08:07:45 am
content: Quote from: karpouzi9 on March 15, 2023, 08:55:05 pmSo maybe you can help in my originalquestion(before the thread got derailed and went guerrilla)I'm mostly there, given I don't understand the mechanics/jargon that governs rust dependency management, I was able to set up a stupid blinker and debug it in vscode with cortex-debug with st-link. Then I got lost trying to move that to Jlink to useRTT. An hell made of duplicated crates (with different second version digit), linker errors and stuff that mostly I don't understand has appeared.Yes, i know, I'm just doing the wrong way around but I have been surprised by the limited number of silly functional examples out there and the difficulty/impossibility to combine them grabbin' one piece here and another there (yeah, bad practice, but before entering the rust world it mostly served me well).BottomlineI'm lookin' for a working example ofVSCode + cortex-debug + JLink + RTT.After that, I swear, I'll go back and start a systematic study.

author: tggzzz
author_rank: Super Contributor
timestamp: March 16, 2023, 09:15:59 am
content: Quote from: NorthGuy on March 16, 2023, 02:07:35 amComplacent nonsense.There are many ways a mistake can harm you. The obvious way is a mistake could cause you to lose your job or career. (Yes, there are other ways for that to happen, but they are irrelevant to your point)As an extreme example, one product I implemented could kill people - even if it worked as designed.

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 01:10:01 pm
content: Quote from: Siwastaja on March 16, 2023, 06:24:13 amThose professionals will use Lua, Python, Ada, Rust (?), etc. Anything that has a managed environment that doesn't allow to shoot yourself in the foot like you can with C.

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 01:12:33 pm
content: Quote from: NorthGuy on March 16, 2023, 02:07:35 amI've made enough mistakes and I'm simply tired of using tools that need extra bandaids/work because they allow mistakes. Maybe you are not at that point yet or are just not aware of your own 'mortality'. As some point you learn to point & push sharp objects away from you.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 16, 2023, 01:21:39 pm
content: Quote from: nctnico on March 16, 2023, 01:12:33 pmHigher level languages on microcontrollers tend to allow larger-scale mistakes, such as failure to assign resources (such as RAM), because it is difficult or even impossible to do so. The consequence of these mistakes is the same as the small C mistakes: complete failure of the product. The difference is, a memory leak in C implementation can be found and fixed. A python implementation using a library with too high memory requirements requires a complete rewrite on a project. I have seen numerous of such cases. Product is designed, high-level software team thinks they can do it, project is engineered - until finally it is found out no one has idea how to do embedded. Then people like me are called in and write the firmware in a lower-level language.On a PC, this is not as much an issue because software engineering can choose to ignore availability of resources because they are so plentiful.

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 01:33:16 pm
content: Quote from: Siwastaja on March 16, 2023, 01:21:39 pmNo. Having enough resources is part of the design process. But even when resources run out due to some unforeseen circumstance, you can make the software fail & recover in a much more predictable way because there is a layer to deal with that situation. Both embedded Lua and Micropython allow to set heap sizes which are dedicated areas of RAM. So the underlying software will not be affected by a memory shortage and still be fully operational (and able to do an orderly shutdown / recovery).

author: Siwastaja
author_rank: Super Contributor
timestamp: March 16, 2023, 01:40:44 pm
content: Quote from: nctnico on March 16, 2023, 01:33:16 pmAnd that "underlying software" is some handler which dumps "out of memory" error message to... nowhere. Or maybe, in best case, some debug interface.If the part running out of memory was not important, it could have been removed to begin with.But that's fine, we clearly just mean completely different things with "embedded".

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 01:42:13 pm
content: Quote from: nctnico on March 16, 2023, 01:12:33 pmmistakes were and are being made in python and lua despite the security in memory mangment...

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 02:01:31 pm
content: Quote from: Siwastaja on March 16, 2023, 01:40:44 pmDumping the error somewhere is one, but recovery is the other. In what way the device should recover is part of the design requirements but there is nothing that stands in the way of clearing the heap and restarting the program. And there really is no need to have a different definition of embedded. The bottom line is that C is far from ideal in order to make robust software because it allows mistakes that are beyond functional errors in software.For example: you have a dataset you want to process. In C you can make several mistakes: use the wrong range (buffer overflow), use the wrong type and have an error in the formula. In Python or Lua you can only have an error in the formula.Moving towards managed languages is a natural evolution of embedded programming. But we'll have the C versus assembly argument allover again.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 02:06:19 pm
content: Quote from: nctnico on March 16, 2023, 02:01:31 pmPython doesn't check types...

author: Siwastaja
author_rank: Super Contributor
timestamp: March 16, 2023, 02:12:13 pm
content: Quote from: nctnico on March 16, 2023, 02:01:31 pmC: Can't have wrong type (as easily), as language is manually and semi-strongly typed. Compiler erroring out on incompatible types is forced by standard.Python: Type errors cause silently wrong results or more implicit conversions which affect memory footprint.Wrong range:C: CrashPython: Crash(with different definition of "crash", but same result for end user, as explained above)Formula:C: Need to be extra careful with integer promotions, casts, and other such rules that seem weird especially to mathematiciansPython: Arguably easier and matches better with expectations coming from Matlab/etc.But nctnico is just nctnicoing, as usual. This is my last off-topic comment in this thread.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 02:13:18 pm
content: Quote from: nctnico on March 16, 2023, 02:01:31 pmyou mean in the IoT kind of stuff?

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 02:32:41 pm
content: Quote from: uliano on March 16, 2023, 02:13:18 pmNo, in general. Microcontrollers with large memories keep getting cheaper so a small memory footprint becomes less important. In general the functionality also increases in size; it just doesn't make sense to wanting to program everything in C 'just because'. The controller to be used in the project I'm currently working on has about 1MB or RAM and several MB of flash while it costs somewhere around US $4 in small quantities. Someone else will be implementing the logic for this product; it is very helpfull & economic if that person doesn't need to be a C expert.Also the modern day junior software engineers are more geared towards the 'higher level' languages anyway. How much time do you want to spend on training them & fixing their errors while they learn how to program C? And how worthwhile (=economic sensible) is that given the alternatives?

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 02:45:47 pm
content: Quote from: uliano on March 16, 2023, 02:06:19 pmIt does but the type for a variable is determined by what you assign to it initially. You'll need to convert between types if you want to assign variables with different types. If there is a mismatch, you'll get a runtime error.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 02:47:57 pm
content: Quote from: nctnico on March 16, 2023, 02:01:31 pmand also runs ta a few dozen GHz? as the constraints were (and are): flash, ram AND time and Python is not fast... Unless you write a low level library in... guess what? C or similar...

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 02:51:40 pm
content: Quote from: nctnico on March 16, 2023, 02:45:47 pmI strongly advise you to revise your Python...

author: tggzzz
author_rank: Super Contributor
timestamp: March 16, 2023, 03:18:54 pm
content: When people start comparing types in languages, I like to annoy them by pointing out that Smalltalk (and Python) isstronglytyped whereas C isuntyped.When they start huffing and puffing, I refine that to:in C, variables are typed but data untyped. That's why you can cast a Person into Concretein Smalltalk, variables are untyped but the data is strongly typed. There's no way you can coerce the program into treating a Person as a DogJava has the best of both worlds: both variables and data are strongly typed.The advantage of strongly typed data is obvious. Having strongly typed variables is the starting point for that wonder of decent IDEs: cntl-space for autocompletion

author: nctnico
author_rank: Super Contributor
timestamp: March 16, 2023, 03:24:24 pm
content: Quote from: uliano on March 16, 2023, 02:51:40 pmI've been using Python (version 3) quite a bit lately and adding a variable which has a number to one that has a string doesn't work.Quote from: uliano on March 16, 2023, 02:47:57 pmNo. Somewhere around 130MHz. IIRC the controller maxes out at 250MHz. Typically I don't worry about execution speed until it is a problem. Optimising for speed takes an exponential amount of time (=money) so the least you have to optimise, the lower the NRE costs. Worrying about speed upfront is like wanting to buy a vehicle without knowing what you need to transport. A definition for a solution can only come from a definition of a problem.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 16, 2023, 03:25:16 pm
content: Quote from: nctnico on March 16, 2023, 02:32:41 pmWe live in different worlds. I just went to DigiKey and selected all the MCUs with at least 1MB RAM and 4MB flash, and the cheapest for quantity of 1000 came at US $13 ($15 if you count only those that they have 1000 in stock).

author: coppice
author_rank: Super Contributor
timestamp: March 16, 2023, 03:25:56 pm
content: Quote from: tggzzz on March 16, 2023, 03:18:54 pmHave you been developing any bridging software? Your comment seems foundational for that market.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 03:31:35 pm
content: Python OBJECTS are typed, variables are just names referring to them and DON'T carry ANY type along, they just adapt to what they are referring to, moment by moment.Python (recent versions) has type annotations AKA type hintsIDE need to know function/method prototypes to make their wonders and Pythondoesn't enforcethat.Various approach have been taken either by libraries or IDE to document their content: generating stubs, reading all code...

author: tggzzz
author_rank: Super Contributor
timestamp: March 16, 2023, 03:32:54 pm
content: Quote from: coppice on March 16, 2023, 03:25:56 pmNah. While I might think some of the people I've worked with/for areamob, I've never worked withthemob. There are some people that I've encountered that made me wish I was a crow, though, so I could use "mob" as a verb.

author: tggzzz
author_rank: Super Contributor
timestamp: March 16, 2023, 03:38:14 pm
content: Quote from: uliano on March 16, 2023, 03:31:35 pmJust like SmalltalkQuoteThe worst of both worlds, where you state something that may or may not be true. Just like preparing to deal with an HonestPerson, only to find out you been given a Politician.

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 03:38:31 pm
content: Quote from: nctnico on March 16, 2023, 03:24:24 pmyou are confusing Python Objects with Python variables, your error is associated with the operator + which is not defined for string and numbers (you can define it if you like and can give it a meaning...)Code:uliano@huey ~% ipythonPython 3.11.0 | packaged by conda-forge | (main, Jan 15 2023, 05:44:48) [Clang 14.0.6 ]Type 'copyright', 'credits' or 'license' for more informationIPython 8.11.0 -- An enhanced Interactive Python. Type '?' for help.In : i=1In : type(i)Out: intIn : i='cat'In : type(i)Out: strIn : 1+'cat'---------------------------------------------------------------------------TypeError Traceback (most recent call last)Cell In, line 1----> 1 1+'cat'TypeError: unsupported operand type(s) for +: 'int' and 'str'In :Do you really want to exit (/n)? yuliano@huey ~%Quote from: nctnico on March 16, 2023, 02:01:31 pmand that's why you are using python

author: MarginallyStable
author_rank: Regular Contributor
timestamp: March 16, 2023, 03:54:39 pm
content: QuoteSorry!

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 04:02:40 pm
content: Quote from: tggzzz on March 16, 2023, 03:38:14 pmI think that compile time type checking is overvalued, especially with compound complex types which may remain partially unspecified or lead to a couple-lines-specification per parameter.Being sure that type is correct does not guarantee that data is correct, ok protection against silly errors is better than nothing...

author: uliano
author_rank: Regular Contributor
timestamp: March 16, 2023, 06:53:01 pm
content: Quote from: karpouzi9 on March 16, 2023, 06:02:05 pmnevermind, somehow I did it!Now I'll dig deeper in Rust (starting from the beginning) and possibly understand what I did.(I combined stuff from here and there but the quite rigid build/package system was challenging me in the mixup operation)

author: tggzzz
author_rank: Super Contributor
timestamp: March 16, 2023, 10:01:40 pm
content: Quote from: uliano on March 16, 2023, 04:02:40 pmCompile time type.checking is an extremely valuable technique because it removes whole classes of errors.It is not a panacea, and cannot be - for deep fundamental theoretical reasons.IThat does notremovethe benefits, but it does a them.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 16, 2023, 10:51:50 pm
content: Quote from: tggzzz on March 16, 2023, 10:01:40 pmYes. And with static typing comes the possibility of checking value ranges to some extent (at least with decent languages). You can also implement statically-checked contracts.All this is just almost completely impossible with anything dynamically typed.But hey, how dare we anyway. We should just let software developers throw stuff at the wall until it sticks. This method is clearly undervalued!

author: tggzzz
author_rank: Super Contributor
timestamp: March 16, 2023, 10:59:13 pm
content: Quote from: SiliconWizard on March 16, 2023, 10:51:50 pmThat's unnecessarily complicated. All you need to do is ensure the unit tests are passed and the green light is showing. That means the software is working,by definition.Wadda you mean "you can't test quality into a product"? That'ssolast millennium.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 16, 2023, 11:00:45 pm
content: Quote from: tggzzz on March 16, 2023, 10:59:13 pm

author: Siwastaja
author_rank: Super Contributor
timestamp: March 17, 2023, 01:31:14 pm
content: Quote from: SiliconWizard on March 16, 2023, 10:51:50 pmAnd this is my pet peeve: people complain that C does too little for type safety (arguably true), but then suggest alternatives which do even worse.C at least has a typing system which requires active decisions to bypass. *((Concrete*)&person) does not happen by accident. (Some implicit conversions like integer promotion are footguns, though.)

author: alexanderbrevig
author_rank: Frequent Contributor
timestamp: March 17, 2023, 01:48:41 pm
content: Glad to see someone mentioning and liking Rust and surviving long enough to tell the tale!Rust is the future, Rust is now

author: tggzzz
author_rank: Super Contributor
timestamp: March 17, 2023, 03:15:40 pm
content: Quote from: Siwastaja on March 17, 2023, 01:31:14 pmUnfortunately not. Ever had to trawl through a core dump or single step in order to find what that 0xdeadbabe "is" and where it came from?It is trivial tointerpretthat 0xdeadbabe in many many ways, but which is the correct interpretation? It is a damn sight easier when the 0xdeadbabe also specifies that itmustbe interpreted as a stack frame.

author: nctnico
author_rank: Super Contributor
timestamp: March 17, 2023, 03:37:07 pm
content: Quote from: Siwastaja on March 17, 2023, 01:31:14 pmActually it does because C allows the use of void pointers and casting at will. Some software is riddled with void pointers which are then cast to a type that is expected. There is no check at all whether the data that is pointed to, is actually the data that is being expected. There is a large burden on the shoulders of the programmer here to not make a mistake. APIs that allow to convey user data in the form of a void pointer are a clear & common example of the abuse of void pointers. The Linux kernel is another bad example.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 17, 2023, 07:14:54 pm
content: Quote from: nctnico on March 17, 2023, 03:37:07 pmThat's not what they do. Avoiding mistakes is not their plan. They design and create somethings and focus on what they're designing.A knife is made sharp because it is made to cut. The ability to cut is its purpose. If you make it dull to avoid cutting yourself the knife will become useless. Of course, you can use a dull knife all you want, but there must be sharp knifes somewhere and there must be people who use sharp knifes. You depend on them. Somebody had to write a Linux kernel for you, or lwIP, or whatnot. You would not be able to do anything without these people.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 17, 2023, 07:20:59 pm
content: Also the linux kernel, while not perfect style, and while not totally bug-free, is one of the most successful and one of the most reliable and robustlarge(non-trivial) software projects known to human kind. Suggesting that linux kernel is the bad example, and some random work in Python in embedded without any idea of resource use "because it will just fail gracefully if out of memory" is pretty... interesting.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 17, 2023, 07:32:39 pm
content: Quote from: Siwastaja on March 17, 2023, 07:20:59 pmYes.The language is not the problem.Bad developers are the problem.That's not to say that some languages are not more elegant than others. I personally think that if Modula-3 (which was based on Modula-2 but devised with many "modern" features, all by a group of industry experts but with the blessing of Wirth, rather than only academics or only one random guy with the sudden urge to design a new one) had taken off rather than C++ and Java, the overall software quality would probably much higher than it currently is. It would have been good as a C replacement as well.And while it was much too "heavy" for a long time, Ada would now be (with the current tools and available processing power) a great alternative to many other current languages.But even so, give a crap developer the best tools, only crap will come out.As a side and related note, any developer not capable of writing robust C is probably not fit for teaching anyone how to develop and what kind of language they should use.

author: nctnico
author_rank: Super Contributor
timestamp: March 17, 2023, 08:02:16 pm
content: Quote from: SiliconWizard on March 17, 2023, 07:32:39 pmThe fact is people make mistakes. It doesn't matter whether you have good or bad programmers; both will make mistakes in equal amounts. Human nature and so on.Take a car analogy for example. Modern cars are fitted with seatbelts, ABS, anti-skid, collission avoidance systems, airbags, etc to make car safer to use and prevent mistakes from becoming a problem.Are the people claiming that C is a 'safe programming language' seriously going to argue that having all these safety features in cars, that are statistically proven to save lifes / prevent injuries, are nonsense as well?

author: Siwastaja
author_rank: Super Contributor
timestamp: March 17, 2023, 08:06:20 pm
content: Quote from: karpouzi9 on March 17, 2023, 07:53:59 pmFor someone who "hates" to engage in "these threads", you sure seem quite ill-minded and are twisting the whole thing around pretty bad.We are being lectured how linux kernel is crap, our working methods are crap, C is crap, by some self-proclaimed "experts" who think Python is a silver bullet. I'm surprised The Excellency of ChatGPT hasn't been mentioned yet.We are doing nothing else but simply say the truth out loud. It is your choice to get offended by it. I'm 99.999% sure SiliconWizard never meant any offence.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 17, 2023, 08:31:19 pm
content: Quote from: nctnico on March 17, 2023, 08:02:16 pmThat is a bold statement (no pun intended). Sure everybody makes mistakes, but to say in equal amounts is utter bullshit. Some hardly make mistakes, while others fuck up constantly.Quote from: nctnico on March 17, 2023, 08:02:16 pmSure the car has become safer with these features, but also makes some people become more reckless, because of these safety features. "Oh, nothing can happen to me because I'm wearing my seat belt and I have airbags, so doing 100 in a 50 zone is safe for me"The same can apply to these high level, filled with safety features, programming languages. "Oh, I don't have to check on this, because the language does it for me".Like SiliconWizard and Siwastaja also state, the language is not the problem, but bad and lazy developers are the problem. It is a mindset that counts in these cases.Quote from: nctnico on March 17, 2023, 08:02:16 pmAnd I don't believe they are claiming C is a safe programming language. It is a language that allows you to have full control, which sometimes is needed, but it can also backfire. I'm not saying that the features in other languages are nonsense, but they can bite you in the ass just as well.

author: nctnico
author_rank: Super Contributor
timestamp: March 17, 2023, 08:35:31 pm
content: Quote from: pcprogrammer on March 17, 2023, 08:31:19 pmThat is exactly where the problem is: only a few outliers make few mistakes. The rest are just normal humans. What I'm seeing from the workfloor is that common programmers do make mistakes. What do you want to do about that? Fire them and hire programmers that don't exist? Or choose a different programming language that makes those programmers more productive? Cost wise, the choice is pretty clear to me.QuoteIn the end you can't fix stupid but catching (common) mistakes is very possible. And that is precisely the goal of those safety features. BTW: I was thinking about adding this text in my original posting but I choose not to. Maybe I should have to avoid people bringing up this nonsense argument. Next thing you know some will come up with stories how seatbelts makes things worse despite the statistics (that paint the big picture) telling otherwise.

author: elagergren
author_rank: Unknown
timestamp: March 17, 2023, 08:58:53 pm
content: Do you have any advice (like things to avoid, etc.) for embedded Rust?

author: tggzzz
author_rank: Super Contributor
timestamp: March 17, 2023, 09:08:40 pm
content: Quote from: NorthGuy on March 17, 2023, 07:14:54 pmThe knife analogy always was facile, ignorant, and generated heat rather than illumination.Where people have to use sharp knives in food processing industries, they wear chain mail gloves, and even chains to keep them distant from the cutters.

author: Muessigb
author_rank: Contributor
timestamp: March 17, 2023, 09:24:17 pm
content: Quote from: nctnico on March 17, 2023, 08:02:16 pmIndeed. For (embedded) Linux programs, I have started moving away from C towards Go, since I much prefer the built-in safety, as well as compatibility with C.Doing something similar on microcontrollers is something I have been thinking about for a while, but I consider giving Rust a try now when the opportunity arises.

author: tggzzz
author_rank: Super Contributor
timestamp: March 17, 2023, 09:33:11 pm
content: Quote from: nctnico on March 17, 2023, 08:02:16 pmProbably, yesIt does them no credit.Too often the "I am good enough to use knives safely" chain ofreasoningthought is merely an excuse for not learning how to use new tools to best advantage.

author: Muessigb
author_rank: Contributor
timestamp: March 17, 2023, 09:37:29 pm
content: Quote from: tggzzz on March 17, 2023, 09:33:11 pmIt's an excuse if you are comfortable enough with your current technology to not have to move onwards and step on new and unknown grounds.I can see how this happens, but when something much better presents itself without many trade-offs, I would still make the jump.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 17, 2023, 11:08:05 pm
content: Quote from: nctnico on March 17, 2023, 08:02:16 pmWhat you need from the language is functionality, not safety. If your car doesn't run, you can wear a seat belt all day long and it won't do you any good.The amount of problems you encounter during development will depend first and foremost on your design. If you design complicated contrived data structures, use over-complicated algorithms which involve lots lots of special processing and bloat, then the probability of making mistakes increases manifold. In contrast, if you come up with simple data structures and elegant algorithms, you will write less, you will make less bugs, and, more importantly your bugs will be easier to find and fix.When it comes to choosing a language, you must chose a language which allows you to implement your beautiful elegant design. If you chose otherwise, you will have to abandon your design, make new design, write more code, make your code needlessly complex, prone to bugs. Moreover, the final product will not work as well as it would've if you could implement your original design.When you write your code, you will make mistakes, like you may write "==" instead of "=" or vice versa, or you can type a wrong variable name, who knows. Some of them may make it through a compiler and cause strange behaviour. I don't see a big deal in correcting these or similar. This is really nothing compared to the fact that youcanimplement your design, because if you can't then this is a much bigger problem.If I can do my design in either C or in Rust, then there's really no much difference. I certainly would choose C, but if I had more experience in Rust I could've chosen Rust. As long as Icanimplement the design. But if I can implement something in C, but cannot implement the same in Python, I wouldn't want to complicate my life just because someone on the Internet has an irrational belief that using Python would make your program safer, would I?

author: tggzzz
author_rank: Super Contributor
timestamp: March 17, 2023, 11:18:22 pm
content: Quote from: Muessigb on March 17, 2023, 09:37:29 pmThe trick is to spot when a new language really does offer something new and beneficial. Too many languages are new without offering significant new benefits. There will always be penalties with jumping ship to a new language; the benefits must exceed the prenalties.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 18, 2023, 05:49:51 am
content: Quote from: nctnico on March 17, 2023, 08:35:31 pmOnly if the language is suited for the job, and not creating other problems instead. To quote our famous soccer player Johan Cruijf, "every advantage has its disadvantage". A good example of cost wise backfiring is outsourcing to cheap labor countries. Managers think they save lots of money that way, but in the end have to pay more to get a proper working product. Same can happen here.How about educating your programmers to become better at the job, instead of having them learn another languages with its own set of problems. Put more focus on testing, instead of trying to avoid making the mistakes, have them learn from these mistakes.Quote from: nctnico on March 17, 2023, 08:35:31 pmYou can call it a nonsense argument but it is still valid for a certain percentage of the population. If everybody on the planet was wise and responsible we would not need those safety features in the first place. But unfortunately that is not the case. Probably part of the reason why the seemingly safer programming languages are invented. To allow more people into programming. Is it a real improvement, I don't know. There is also a lot of shit being produced with all these languages. And don't forget that these languages have their own bugs too. Sure they will be ironed out over time, but can make live miserable for a while.

author: pcprogrammer
author_rank: Super Contributor
timestamp: March 18, 2023, 06:47:46 am
content: Quote from: karpouzi9 on March 17, 2023, 09:32:21 pmWho says we are afraid of learning new languages. I'm not, but will do so only when I feel the need for it and it solves problems I might have with some project that can't be solved with what I'm using normally.And yes it is very wise to advice against listening to >30-40 years of experience. Nothing can be learned from that for sure.The thing is that I have not ran into the need of learning a new programming language for a long time until now. The new programming language I'm learning at the moment is a graphical one called robopro to make fischertechnik models work. Not very spectacular or capable to use for big complex projects but something new just the same.My bet is that most of the what you call fossils are glad and willing to learn something new every day because that is in their nature.

author: peter-h
author_rank: Super Contributor
timestamp: March 18, 2023, 07:32:52 pm
content: Had a quick scan of this thread.I think there is too much polarisation. It's not black and white.I go back to ~1978 when Coral and later Ada were used in the military business. The problem with that business is that the contractor gets a contract to develop say a new torpedo, and 300 programmers are recruited for the contract. When this is done, say 2 years later, they all get laid off (fired). Then it repeats. So you need a language which can be used to write code which isn't total crap, in that scenario, and that is really difficult.Same in a big company where you might have 20 coders working on one product. Out of those 20, maybe 5 will be good. But if you want the finished thing to work, you probably can't use C.Then throw in the lack of code comments which is a fashion among coders (except those writing asm) and lack of documentation (unless absolutely enforced) done to make laying off as unpleasant as possible for the company.Then throw in the need to pick up the product 5-10 years later. By that time the original coders have moved on. Especially if they were contractors; I'd say 90% are gone after 5 years (usually got a full time job, for less money but much better security).For server-side stuff I always specify PHP. Other stuff, and most of the trendy frameworks, will be old hat at 5-10 years. Look at Ruby. Java produces a vast amount of just-working code, low performance, impossible to maintain.C will be around for ever. But you need to get somebody good, and you need to make them test and document stuff.Some other language just means your choice of coders will be really narrow. It takes years to become productive in a new language. And it looks terrible on a CVI am not saying C is good; I am being practical.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 18, 2023, 07:42:08 pm
content: Quote from: Siwastaja on March 17, 2023, 08:06:20 pmYep. If I had a YT channel and I had said that in a video, I'm pretty sure I would have received death threats.

author: coppice
author_rank: Super Contributor
timestamp: March 18, 2023, 07:48:33 pm
content: Quote from: peter-h on March 18, 2023, 07:32:52 pmOh, that old chestnut. I've spent long periods taking projects that went astray, and getting them back in good order. The first thing to do with most code is strip out all the comments. They rarely illuminate anything. They are usually sufficiently out of date they just confuse you, and they bulk up the code making it harder to scan through. Next step is to reformat everything to a consistent layout to improve readability. Next comes identifying what symbols like asdoigildub actual mean, and globally editing them to something more meaningful. That's not an easy task is the average program which reused the same name for a whole bunch of things in different parts of the code. Good practice is to make the code readable, not the comments. The compiler will check the code is up to date. It won't check that the comments haven't been meaningful for the past 2 years. Comments should be for things like "this bit might seem completely stupid, but it deals with this obscure issue it took ages for us to flush out".

author: peter-h
author_rank: Super Contributor
timestamp: March 18, 2023, 09:43:10 pm
content: Sure, but if people write crap code, they will write crap code in any language.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 19, 2023, 06:40:28 am
content: Quote from: nctnico on March 17, 2023, 08:02:16 pmBut no one ever claimed that. This is a totally ridiculous strawman argument. You are picking fight for no apparent reason. All that was questioned was that safer languages (than C) are silver bullets thatsignificantlyreduce number of dangerous bugs. This is not true. Most bugs arenotcaused by lack of automated memory range checking, zero terminated strings and other classic similar C issues (which we all agree are dangerous); but logical thinking errors in higher level design, implementation of algorithms, failure to sanitize inputs and doing the wrong thing as a result, and so on.There is also an impression that languages which do not allow overindexing a table or casting a type to other, do not require nearly as much input validation. This is also wrong. Projects that depend on automatic escalation of exceptions to a top level handler (or worse, no handling at all), because developers were lazy and/or thought "the language takes care of it", are notoriously fragile. On a PC, they just crash with a massive wall of text. On embedded, you don't even get that; the thing just dies.Failing less dramatically is still failing, and especially in embedded, the difference is surprisingly small.

author: peter-h
author_rank: Super Contributor
timestamp: March 19, 2023, 06:49:04 am
content: I agree.Look at Pascal. All the rage when I was at univ. IAR and others had a go at getting it into embedded. What did it do? Reduce productivityI used it quite a lot, back then and since.

author: tggzzz
author_rank: Super Contributor
timestamp: March 19, 2023, 09:29:41 am
content: Quote from: Siwastaja on March 19, 2023, 06:40:28 amNot "caused by...", but certainly "enabled by...", especially in conjunction with commercial pressures and human frailties.QuoteAgreed. Input validation is always a requirement, to contain errors and to assign [legal,technical] liability.I hate the modern trend towards having "unchecked exceptions" silently passed up the stack.A major benefit of "checked exceptions" is that the different ways in which a subsystem can fail areforcedin your face andcannotbe ignored. Either you deal with them or force somebody else to deal with them. There's nothing preventing silently swallowing exceptions, but that is an explicit visible decision, and the version control system will show who committed the sin. (Yes, I have seen a project where NullPointerExceptions were routinely swallowed)

author: Siwastaja
author_rank: Super Contributor
timestamp: March 19, 2023, 09:36:33 am
content: The "power" of exception system in general is, it supposedly saves developer time: one does not need to checkeverywherebecause they propagate. But this power is also the danger of the system.C does not come with such power built-in (let's forget setjmp/longjmp stuff), forcing the developers to do good old if(check) return ERR; stuff. Most of us complain about this being a lot of work; but later accept that as a necessary fact of life.The flawed argument we see is: "because C is low level, C has power, and with power, comes danger and responsibilities". The next argument is, "high level languages are very powerful and save time". For some illogical reason, people thinkthatkind of power is free from danger and responsibilities. It isn't. Exception system is a perfect example. It's an advanced goto on steroids. And it's 1000 times more dangerous than goto, exactlybecauseit saves one from repetitive work. That repetitive work was important.

author: tggzzz
author_rank: Super Contributor
timestamp: March 19, 2023, 09:54:40 am
content: Quote from: Siwastaja on March 19, 2023, 09:36:33 amI disagree.The power of an exception system is that the user of a module is forcibly confronted with the ways in which it can fail. They then have to explicitly deal with the failure or explicitly punt the responsibility somewhere else.Unchecked exceptions subvert that benefit, just as "unsafe" keywords subvert the benefits of managed environments.The interesting boundary is things like division by zero. If a module invokes tan(x), then there is the possibility of a division by zero inside the tan() function. In my opinion a /0 exception should be caught near the tan(x) operation, and mutated into another exception that is specific to the module's function and operation. That new exception can then be passed upwards if appropriate.Of course, if it doesn't matter whether the software works reliably and predictably, then any discussion of exceptions is moot ;} even an "oh shit wake up the lawyer" exception is acceptable

author: nctnico
author_rank: Super Contributor
timestamp: March 19, 2023, 11:08:08 am
content: Quote from: Siwastaja on March 19, 2023, 06:40:28 amI'm not picking a fight at all. It is you who is getting utterly defensive over a very narrow range of issues and losing track of the big picture.QuoteSuch bugs are easy to find, easy to test for and easy to fix; the program does not behave as it should given a certain input / condition. If software gets released in such a state, management is to blame for not allowing enough development & testing time.However, in my experience the pitfalls of C are the cause of the bugs that are the hardest to find (and thus take a lot of time). Avoiding those pitfalls is rather tedious as well. On top of that I see less experienced programmers step into those pitfalls quite often leading to code that is not as robust as it should be. So to me it makes a lot of sense to look at different programming languages that lead to better (=more robust) code with less effort. That takes care of at least one source of bugs; I'm making a clear distinction between 'language induced bugs' and 'programming error' here. I'm not saying such a language exists or a particular language is best but I'm certainly interested in alternatives for C for use on microcontrollers. In all my previous postings in this thread I listed Python and Lua as examples of possibilities. Not to be silver bullets; I have used the word 'example' a couple of times.After programming in C and working with other people on C software for several decades, I simply noticed several drawbacks of using C which are technical, human resource and human nature related. Some of these drawbacks can be addressed effectively by using a different language (either as part of the mix or as a replacement). Personally I can't ignore that outside of embedded programming world, the C programming language is used very little so other languages must have at least some merit.

author: tggzzz
author_rank: Super Contributor
timestamp: March 19, 2023, 11:40:05 am
content: Quote from: nctnico on March 19, 2023, 11:08:08 amPerhaps- the code you or your organisation write. But most projects include code from other people organisations.Your comments below indicate you realise that, but it is worth emphasisingQuoteJust so.My "report card" summary of C: "Adequate, but could do better. Improvement required".

author: peter-h
author_rank: Super Contributor
timestamp: March 19, 2023, 07:39:33 pm
content: The context here is "embedded" and there you usually have a huge problem when compared to other uses: no user interface capable of reporting errors.So all the stuff which Language X might have to prevent say buffer overflow is of no use, because the product will just crash, or maybe reboot, perhaps with a watchdog reset.AFAICT the only benefit some other language might have is better static analysis. Like avoiding this kind of time wasting messhttps://www.eevblog.com/forum/microcontrollers/a-question-on-gcc-ld-linker-script-syntax/msg4764548/#msg4764548And yes that mess was caused by idiotic programming, using weak functions which enable a project to build but not work. Idiotic programming is language independent

author: nctnico
author_rank: Super Contributor
timestamp: March 19, 2023, 07:56:25 pm
content: Quote from: peter-h on March 19, 2023, 07:39:33 pmThe same goes for tons of software running on servers and background processes running on desktop PCs; there is no error reporting UI either.QuoteNo. If you use a language that can iterate through an array without the programmer needing to know the actual array bounds, you already prevent 99% of the mistakes made when using array sizes in C. From what I have seen is that having an array with 10 elements numbered from 0 to 9 is very counter intuitive to many. Even seasoned C programmers slip up every now and then. Or take the extra 0 at the end of a string in C. Not many answer that question correctly during a job interview. All the more reason to use a language that doesn't need attention to such details.

author: uliano
author_rank: Regular Contributor
timestamp: March 19, 2023, 08:04:59 pm
content: Fun fact: most post in this thread are about C.

author: peter-h
author_rank: Super Contributor
timestamp: March 19, 2023, 08:18:39 pm
content: QuoteWell, depends. Take Windows 3.1. You'd be doing well if you got more than a few hours out of it before a GPF error. And M$ got "telemetry" from these; in the old days via bug reports and in later versions via actual telemetry. So the bugs could be fixed. In embedded you rarely get the option to do telemetry.

author: nctnico
author_rank: Super Contributor
timestamp: March 19, 2023, 10:17:34 pm
content: Quote from: peter-h on March 19, 2023, 08:18:39 pmAll the more reason to minimise the chance on making mistakes. However, it also helps a lot to make an embedded device as debuggable as possible. Typically I have a status LED, a command line interface and serial debug output that provides status changes and data. This has been proven to be super helpful to diagnose problems from systems that are in-situ and solve bugs without needing to go to the customer's location.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 19, 2023, 11:02:47 pm
content: Quote from: uliano on March 19, 2023, 08:04:59 pmThey try to make it into a "C vs Rust" discussion. People will take sides. The funny thing is that by taking a side, regardless of what side you're taking, you silently agree that software engineering is about languages. It is not. The practical difference between "bad" and "good" designs is such that it simply dwarfs the difference between languages.It would be easy to demonstrate if you actually gave the same project to 1000 different software designers using different languages and compared the results. But there's no such studies. And there never will beBut you can do it in micro-scale by yourself. Get a small project. Implement it in Rust. Implement it in C for comparison. Post the results.

author: peter-h
author_rank: Super Contributor
timestamp: March 19, 2023, 11:04:56 pm
content: I would still say that if I was contracting out something which needs to work and be "workable on" by others well into the future, I would not allow the use of some "wonderful new language" because I know full well that it will bite me in the bumOutside of embedded, and particularly server-side, we see a new "paradigm" every month, with fashionable new "frameworks" all the time.That's why most people over about 40 are sick of that work. But we've seen all kinds of these initiatives even in embedded. I recall somebody pushing Forth some years ago. You just know that when that guy retires, disappears, or dies, your product will be dead as far as any maintenance goes.C is reasonably future-proof. You still have to get a coder who is careful, but that's true for any language. Well, except Java, where the application of unlimited money, say $100 per line, will eventually deliver something which isn't complete crap

author: nctnico
author_rank: Super Contributor
timestamp: March 19, 2023, 11:25:59 pm
content: There is another facet to this discussion. One recurring question I have gotten from various customers is that they want to be able to make changes to the software themselves in an easy way. I noticed that as soon as I pointed them to a fully fledged IDE with libraries they have to install and deal with programming hardware, they become awfully quiet and let go of the idea. So I went looking for an alternative. For a couple of embedded Linux projects I have implemented the logic for an application using Lua. The Lua script is a seperate file that can be uploaded onto the device using a USB stick. Before deployment, the code can be tested using a testbench that can run on a PC. For most this is way more accessible compared messing around in C directly.Where it comes microcontroller based projects I had to dissapoint my customers so far. And truth to be told, I have created several projects that implement complicated logic; this would have been easier to implement in Lua for me as well. So I have set a goal for myself to have an off-the-shelve Lua implementation that I can use on (OS-less) microcontroller projects. Still, when I mention Lua the reception is luke warm. I always get the question: can't you use Python instead of Lua? I know I'm back at Lua and Python right now but this is because I know Lua better than Python while my customers are asking for Python.

author: peter-h
author_rank: Super Contributor
timestamp: March 20, 2023, 10:00:00 am
content: Python is certainly very much in vogue right now.It's not easy to work out how long this will last. Also while those writing code, in most companies, are relatively young, the decisionmakers (the successful ones) tend to be a lot older. Also those writing code are generally happy to do anything that puts bread on the table at home (regardless of their company's success), those who own the companies need to think much more long-term.Andembeddedis just a very different world to everything else (not least due to the extreme difficulties of fixing bugs in the field, and the commercial risk of delivering 10k boxes which turn out to have a bug - stuff which is regarded as both normal and commercially acceptable in other sectors) yet I think many (not you) conflate embedded with the more trendy stuff like server-side tools.There is a similarity between C for embedded, and PHP for server-side. Both are slagged off by many as crap, insecure, blah blah, but both represent by far the most long term maintainable approaches.

author: nctnico
author_rank: Super Contributor
timestamp: March 20, 2023, 11:52:13 am
content: Offtopic: I strongly doubt PHP will remain for (web) server side programming. I have been involved in various projects at several clients that collect data on a server and all use Python. The Python libraries that help implement web / data services pack a serious punch. It takes surprisingly little programming effort (*) to make -for example- a database driven online inventory system using Python. The strong point of Python is that it is a programming language that universally useable so knowledge can be re-used more effectively. Or to be more precise: the ecosystem around Python is way more universal compared to PHP. But this is based on my own observations that may not be representative for the entire world.* Early this millenium I have done quite a bit of PHP programming myself for web applications so I do know the basics and what is involved.

author: peter-h
author_rank: Super Contributor
timestamp: March 20, 2023, 12:36:58 pm
content: One could have written the same about Ruby on Rails. Totally superior to everything. Today, a dead language, unless you want to pay COBOL66 daily ratesI know, since I "run" a server done in Ruby, 15-20 years ago. Thankfully, it needs no maintenance but if it did I would have to abandon itOr quite a few other languages.There is a lot of understanding of PHP, acquired over past 20-25 years, which means finding somebody who can get into it is a lot easier, hence I continue to specify it. It was all the rage 20-25 years ago, but got a bad name due to so many hackers using it badly. A bit like C reallyThe experts I know think that Ruby is more secure than PHP (there is no dispute there btw) simply because the "IQ barrier" to entry is so much higher, so only really smart people know Ruby. A bit like C reallyOften an overriding factor is the availability of ready-written modules. I think for embedded nearly everything is in C. Let's say you need ETH USB TCP TLS. Zero chance of writing it yourself. Even if you are brilliant, it would take 10 years of your life.That is also true server-side. But fashions move. A few years ago, Laravel was all the rage. Now it is fading. Well, it could have been predicted, with the BS on their website:The PHP Frameworkfor Web Artisans

author: coppice
author_rank: Super Contributor
timestamp: March 20, 2023, 04:50:24 pm
content: Quote from: peter-h on March 20, 2023, 12:36:58 pmThe rise and fall of Ruby off the Rails was quite spectacular. If you vacationed at the right moment it might have been hot when you started and obscure when you got home.

author: tggzzz
author_rank: Super Contributor
timestamp: March 20, 2023, 05:06:15 pm
content: Quote from: coppice on March 20, 2023, 04:50:24 pmWhen Ruby appeared, I pegged it as the triumphant reinvention of Smalltalk (which I like), but as single-thread executable it was far less interesting than Java. I ignored it, as I do all "me too" languages.

author: peter-h
author_rank: Super Contributor
timestamp: March 20, 2023, 05:21:10 pm
content: Ruby is still significant in the corporate sphere, but the daily rates for coders are ~ 1.5k GBP / day.If you talk about long term mod-ability, in reality one rarely needs a large mod done. With PHP, anybody who knows PHP can dive in and do it. With a language which is off the beaten track, like Ruby, the people who can makeanysense of it are very rare. I have a rather sad example: I wanted someone to add a graphical captcha for user signups on the ruby written application (server is Centos+NGINX). I found a guy who had done some Ruby. By the time he got it going, he died of a brain tumour. You just had to be a real expert.So I think any off the beaten track language will just bite you in the bum.Obviously (cynicism++) if you are a contractor then you don't need to care.I think there is potential for Python for embedded but struggle to convince myself, versus the cost of implementation on the target.

author: tggzzz
author_rank: Super Contributor
timestamp: March 20, 2023, 05:54:43 pm
content: Quote from: peter-h on March 20, 2023, 05:21:10 pmThe trick is to spot the new language thatwill becomewidely used, and ignore those that won't.

author: coppice
author_rank: Super Contributor
timestamp: March 20, 2023, 05:59:41 pm
content: Quote from: peter-h on March 20, 2023, 05:21:10 pmYou mean contractors benefit from a contracting market? How strange?

author: ejeffrey
author_rank: Super Contributor
timestamp: March 20, 2023, 06:44:19 pm
content: Quote from: peter-h on March 19, 2023, 07:39:33 pmOnly if you don't build an error reporting mechanism. Sometimes that isn't desirable to do, but many many embedded systems do have ways to report or log errors -- whether a display, a network connection, a serial port, or just logging crash data to extra flash.So all the stuff which Language X might have to prevent say buffer overflow is of no use, because the product will just crash, or maybe reboot, perhaps with a watchdog reset.This is completely wrong. Detecting memory errors while avoiding memory corruption caused by buffer overflow is fantastically useful in any situation. Even if all you do is trigger the hard fault handler. It is much more likely to isolate the bug to the time when it occurs, avoids corrupting the stack trace so that you can actually analyze the bug when you have a debug environment. It makes runtime error recovery at least possible in some situations. One particular advantage to an embedded system is that it avoids spreading memory errors to more critical (and better tested) parts of a program. With array bounds checking a buffer overflow in a UI event loop is much less likely to corrupt the the data structures used by a PWM motor driver causing it to do something bad. This is not something you should rely on for safety, but it could avoid equipment putting itself in an undamaged state.Nobody is arguing that using automated checking tools will fix all bugs. That is a strawman argument and pointless to consider. But good tools can make us likely to make certain classes of mistakes, limit the scope of damage when they occur, and make them easier to find and fix.QuoteOf course static analysis is even more effective when it works. Which is what rust does: static memory usage analysis of both stack and heap variables. I haven't used it enough to know how well it works, but the that is definitely part of the goal.

author: peter-h
author_rank: Super Contributor
timestamp: March 20, 2023, 07:18:58 pm
content: QuoteYes, if you have the box in front of you. Not after you have shipped 10k of themBut with a PC or similar you can get away with it.In most embedded applications you either have no way for telemetry, or the customer would not authorise it.QuoteHeap in embedded is a disaster, usually.QuoteYes; in the short term. The incentives are just different.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 20, 2023, 07:52:38 pm
content: Quote from: ejeffrey on March 20, 2023, 06:44:19 pmDo you suggest always using range checks?How about algorithms where range check cannot be performed? Do you suggest banning them completely?

author: tggzzz
author_rank: Super Contributor
timestamp: March 20, 2023, 08:23:38 pm
content: Quote from: NorthGuy on March 20, 2023, 07:52:38 pmDo you suggest deliberately writing code that doesn't detect errors and failsafe?Strawman arguments are annoying, and generate heat rather than light. Hint: don't introduce false dichotomies into a discussion.

author: coppice
author_rank: Super Contributor
timestamp: March 20, 2023, 08:38:36 pm
content: Quote from: peter-h on March 20, 2023, 07:18:58 pmNot necessarily so short. It saw many a COBOL programmer through to comfortable retirement.

author: peter-h
author_rank: Super Contributor
timestamp: March 20, 2023, 10:58:08 pm
content: We don't disagree

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 01:15:15 am
content: Quote from: tggzzz on March 20, 2023, 08:23:38 pmThese are not arguments, but questions. Addressed to @ejeffrey.

author: profdc9
author_rank: Frequent Contributor
timestamp: March 21, 2023, 03:41:41 am
content: I am an electrical engineer and almost 50 years old and I have been writing code since 1982, so my entire adult life and most of my childhood on 80s micros.Here's what I've had to learn: C, C++, Pascal, COBOL, Fortran 77, dBase III/IV/FoxPro, 6502 assembly, 8086 assembly, 80386 assembly, Matlab, Python 1/2/3, Perl, Lua, Forth, Java, various flavors of SQL, and probably tons of stuff I am forgetting. It got so bad that I could write an entire page of code before I realized I was writing it in the wrong language.I started to dislike programming during the 90s with the battle between Microsoft and Sun. It was clear that the whole Java vs. .NET was not about making life better for the programmer, but forcing the programmer to commit to learning an extensive system of idiosyncratic libraries to be able to do their work, thus taking time away from learning a competitor's idiosyncratic language and libraries. Things have not improved much since then, except for perhaps the presence of open source being an alternative that motivates the commercial software vendors not to engage in excessively deleterious behavior.Generally the more fanatical the support of a language is, the less practical the language. While I can see some value to the design choices made in Rust, in particular the aspect of forcing the programmer to "prove" to the compiler that certain aspects of their program likely work as intended, it seems that there is an idea that Rust code makes code which is inherently bug-free and self-documenting, and that this is the revolutionary part of Rust. Rust forces certain design patterns on the programmer that can be proved by the compiler to work in a particular way (but not necessarily the way that is desired), and any deviation from these patterns requires unsafe code for which the proofs are not required. This could be helpful to ensure certain guarantees about code quality, for example, the prevention of memory or resource leaks. Perhaps in some cases that may be a reason to adopt Rust vs. another computer language that has much wider adoption and support. Other aspects, for example, ensuring that worst case dynamic memory allocation and fragmentation doesn't result in unavailable memory, or that worst-case latencies are not excessive, seem harder to prove.I think the only real proof will be to see the astounding productivity that embedded Rust programmers have, with millions of dollars saved from not having to roll out emergency bug fixes or firmware updates. But creating a language that makes programming harder is going to be a non-starter for most people, because of the effort paid up front for only prospective future gains. One of the craziest things I find about most Rust documentation is that it tends to spend more time explaining what one should not do, rather than how to do something. This already takes a language that is manifestly unfriendly and makes it downright unapproachable.

author: peter-h
author_rank: Super Contributor
timestamp: March 21, 2023, 09:30:33 am
content: QuoteIt won't achieve that, because the marketplace usually moves too fast to fix bugs before version++ happens

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 09:51:24 am
content: Quote from: profdc9 on March 21, 2023, 03:41:41 amJava was fine; even on first release it enabled programmers to easily do basic simple things that C++ had failed to manage in a decade. The pleasure of not having tore-invent yetagaina dictionary or set or growable array or String was delightful - it enabled me to concentrate on my task not on a deficient tool. That's the benefits ofstandardlibraries.OTOH, C# was deliberately pitched as a me-too Java killer - Anders Hejlsberg said as much when he gave a talk at my workplace (HPLabs) a few months before C# was launched. At least 50 people attended; I never saw anyone bothering to use the language.OTOH learning theframeworkof the month (cf the standardlibrary) is something you only do when necessary.QuoteAh. Those old chestnuts. They were trotted out against using "structured programming" and avoiding goto.QuoteCreating something correct isalwaysgoing to be more difficult than creating something almost, sort-of, when-the-wind-is-blowing-in-the-right-direction correct. Deal with it.If I'm allowed to create something that is incorrect, I can very quickly create something that is very fast and uses very few resources. Is thatreallythe objective?

author: nctnico
author_rank: Super Contributor
timestamp: March 21, 2023, 10:23:42 am
content: Quote from: peter-h on March 20, 2023, 07:18:58 pmI think there is a slight disconnect here. If you can detect problems in runtime, you can let the device fail in a controlled manner which is better compared to letting it go on with bad values and do something random. If a device fails in a controlled manner, it is likely that you get sensible feedback from the customer as well because there may be a clear cause & effect (I do this, and that happens) so fixing the bug will be easier. So yes, even without telemetry, debug output or whatever, having a device fail in a controlled manner is way better compared to letting it run and crash 'randomly'.And ofcourse having runtime detection of problems helps during the test phase of the product to find lingering problems.

author: gmb42
author_rank: Frequent Contributor
timestamp: March 21, 2023, 10:43:23 am
content: Quote from: peter-h on March 20, 2023, 05:21:10 pmAnd this, in my elitist opinion, is why most PHP "applications" are piles of steaming shit.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 02:05:12 pm
content: Quote from: nctnico on March 21, 2023, 10:23:42 amConsider a different scenario. There's a bug which doesn't have any effect on the functionality. But you detect it and fail in a controlled manner at the time when the customer needs your device the most. The cure may be worse than the disease..Effects of bugs are unpredictable, therefore it is silly to make assumptions about the nature and magnitude of the effects, let alone try to mitigate these unknown effects.A software engineer should try to minimize the number of bugs. The best way to do this is by simplifying the design, because nothing breads bugs more than unneeded complexity. Unfortunately too many people believe they can cure bugs by using "safe" languages (or whatnot), as savages believe that their amulets protect them from nastiness of the outside world.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 02:37:56 pm
content: Quote from: NorthGuy on March 21, 2023, 02:05:12 pmThat's why battleships short out the fuses just before going into action.Fuses are still a good idea in most circumstances.QuoteAndoneexcellent way to do that is to use a language that prevents whole classes of bugs being created,not spotted, and deployed.You go on to mentionone otherway...QuoteThe counterpoint is also true: using an "unsafe" language doesn't protect you.There are no panaceas.We should usealltools at our disposal to reduce defects in deployed systems.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 02:46:25 pm
content: Quote from: tggzzz on March 21, 2023, 02:37:56 pmAbsolutely! You finally got my point. The language doesn't matter.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 03:02:23 pm
content: Quote from: NorthGuy on March 21, 2023, 02:46:25 pmYoudeliberatelymissed the important point to concentrate on a minor point. Why?The important point that you chose to snip is "There are no panaceas. We should usealltools at our disposal to reduce defects in deployed systems.""Safe" languages are an important tool in reducing defects.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 03:02:45 pm
content: Quote from: tggzzz on March 21, 2023, 02:37:56 pmThat's true too. You need to evaluate different solutions and make decisions based on your evaluation. Which, BTW, you cannot do until you know what is that you're supposed to build.Believing that using a certain language would solve problems is like believing that choosing a certain hammer would let you build a better house. There are other things to consider first - blueprints, materials, construction methods ...

author: Siwastaja
author_rank: Super Contributor
timestamp: March 21, 2023, 03:11:40 pm
content: Quote from: tggzzz on March 21, 2023, 03:02:23 pmWhile that is true, it's a qualitative statement, not quantitative. Observing my own recent history, 95% of bugs have been something not avoidable by a different language; sad, because itwould be niceto have such a silver bullet language.Software has always been buggy, and still is, despite the fact gazillions of new languages and tools are being introduced all the time. If some of themtrulyhelped tosignificantlyreduce the number of bugs, why wouldn't such a language get embraced by developers?The answer is dire: people expect the new languages to be immensely helpful so they try, but the end result is the same each time; a few upsides, maybe a few avoided bugs, but then again, most of the bugs sneak in just like they always did, and there are always some unexpected downsides to any new language which isn't instantly obvious.Before nctnico starts building another strawman, I mention explicitly: this is not to say adding safety in languages and tooling is a bad idea, or totally useless. Just trying to put things in perspective, for thebig picture.Finally, I can see a semantic trick lurking here. In certain fields, especially regulated ones, say aviation, there is stricter separation between design (not in the final programming language) and implementation. If you don't count design errors as "bugs" at all, then surely your number of bugs goes down significantly, and from what remains, larger part are those that could be prevented by using a more "safe" programming language.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 03:34:20 pm
content: Quote from: Siwastaja on March 21, 2023, 03:11:40 pmThere are no silver bullet languages, and never will be.Reducing 5% (to use your figure) can be very important; it depends on when the latent bug would have been found and the consequences. No surprises there.QuoteThere are many reasons, some good some bad, why better mousetraps aren't embraced. People are complex.QuoteIt is worth embracing a new tool that aids avoiding avoidable defects.While aviation (etc)enforcesseparation between validation (do the right thing) and verification (do the thing right), I've used modelling and/or designverificationin almost all my activities before implementing andverifyingin the final language.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 03:36:49 pm
content: Quote from: NorthGuy on March 21, 2023, 03:02:45 pmYou are committing an elementary error: conflating verification (do the right thing) and verification (do the thing right) in order to make an argument. That is a strawman argument since other people are not conflating the two.

author: profdc9
author_rank: Frequent Contributor
timestamp: March 21, 2023, 04:06:37 pm
content: I would really sincerely like to see a better solution for programming, and if Rust is that, I would be more in favor of it. Nothing on this thread is going to result in a better solution, or convince anyone to try or adopt anything. There is no one trying to reach out to someone halfway, and if I have one complaint about Rust, it's that those who advocate it are especially unwilling to reach out to others. They almost wear the difficulty of their language as a badge of honor, so that only the best and most qualified will use it. No one has to use anything, and this thread is doing very little to convince anyone that Rust is an approachable, useful solution for anything.It would be great if even one person on this thread said, "well golly, I didn't realize Rust is a good tool, I'll try it," but the rhetoric here is polarizing and offers no solutions. This is one of my greatest beefs with Rust in general, in that it seems to be more about how not to program than it is how to program, which isn't very helpful. I can't see a language with this philosophy being widely adopted.There are good ideas in Rust, but I am going to guess that someone other group of people that are more accommodating will likely use them in a more approachable language, and that will be adopted instead of Rust.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 04:31:23 pm
content: Quote from: tggzzz on March 21, 2023, 03:36:49 pmVerification and verification? That's a major conflating.There's no right or wrong. There are requirements. The design either meets them or it doesn't. There are gazillion ways to fulfill requirements, hence there are gazillion ways to design the same thing. Each design has associated parameters - cost, time, reliability, maintenability. You need to somehow optimize these when designing.In my experience, if you can use a simpler design, it decreases cost and time (because you write less) , it increases reliability (because there's less room for mistakes), it is easier to maintain (because it is easier to understand how it works). Therefore, the simpler your design, the better, in practically any way. So, that's what I'm trying to do.The language is simply a way to implement the design. Le langage est simplement un moyen d'implémenter la conception. El lenguaje es simplemente una forma de implementar el diseño.If a language forces you out of your design because it doesn't have enough capabilities to implement it what do I do? I use a different language. As simple as that. And by preserving my original design, you make the project safer.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 05:02:47 pm
content: Quote from: NorthGuy on March 21, 2023, 04:31:23 pm(Context is important. Please use the "quote" button and do not remove part of the quoted message. This is not stackechange nor edaboard etc.)Apart from that, clearly you do not understand the difference between validation and verification, nor why they should be kept separate, nor why different tools are used for each.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 05:42:35 pm
content: Quote from: tggzzz on March 21, 2023, 05:02:47 pmWhat a bullshit. If you quote the entire text, the long quotes become unreadable. Not to mention that it makes unclear what exactly the comment is about. You always can click on the quote and read the entire post.Quote from: tggzzz on March 21, 2023, 05:02:47 pmWow. Personal attacks. I like that. I don't understand. This automatically makes you right. Undeniable.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 05:50:43 pm
content: Quote from: NorthGuy on March 21, 2023, 05:42:35 pmNo, it doesn't make them unreadable - unless you have dyslexia or a dysfunctionally small viewing device.Nobody bothers to go back and look at previous messages - and it shouldn't be necessary to.As for "too long". Good taste can and should be employed to ensure that the conversation remains comprehensible.QuoteNo, pointing out what you don't comprehend doesn'tautomaticallymake me right.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 06:20:36 pm
content: Quote from: tggzzz on March 21, 2023, 05:50:43 pmSure it does. Even when I pointed exactly to the sentence where you spelled "verification" instead of "validation", you still couldn't read it. That's a definition of unreadable.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 21, 2023, 06:43:10 pm
content: Quote from: NorthGuy on March 21, 2023, 04:31:23 pmThis is just so completely impossible to deny. It is too simple, anyone can understand it, there are zero buzzwords in it, no computer scientist research to prove it - and yet everyone knows it is true. Therefore, it triggers people; it drives people mad, as they want but can't argue back. All that is left is ridiculing.Yet this simplicity of design viewpoint is hugely underestimated. It should be #1 priority in design, always.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 06:58:46 pm
content: Quote from: Siwastaja on March 21, 2023, 06:43:10 pmAs simple as possible, but no simplerI know my implementations are going well when the number of lines of code is reducing. Drives LoC-metric managers to distraction, heh heh.

author: nctnico
author_rank: Super Contributor
timestamp: March 21, 2023, 07:03:19 pm
content: Quote from: Siwastaja on March 21, 2023, 06:43:10 pmThis reasoning falls apart for any practical system. A simple example is the case you need to run 2 parallel processes. Are you going to use a pre-emptive multi-tasking OS or run a round-robin scheduler and implement 2 non-blocking tasks (using statemachines)? Both options have pros and cons where it comes to simplicity.When using an OS you shove all the complexity of running 2 tasks in parallel into an existing framework and what is left to implement becomes incredibly simple (with a lower chance of bugs). Alternatively you can argue setting up the OS is complicated and having a simple round-robin scheduler is simple but you'll likely need to turn a process that needs to wait for input, into a more complicated statemachine than the problem actually requires.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 07:15:13 pm
content: Quote from: nctnico on March 21, 2023, 07:03:19 pmMy preference is to choose the implementation technique that maps simply to the specification. If the spec is written in terms of states and events, use an FSM. If it is written in the form of a "story with waitUntils", then cooperating tasks or coroutines may be better. Etc, etc.That simplifies a vital task: ensuring the implementation is complete and matches the specification.When Hatley and Pirbhai were defining the methodology used for 777s, they had two parallel hierarchies, one for the specification and one for the implementation. The only design tool they automated was a database which recorded the N:M mapping between specification artefacts and implementation artefacts.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 21, 2023, 07:20:58 pm
content: Quote from: Siwastaja on March 21, 2023, 06:43:10 pmThis has been Wirth's point for most of his career. Definitely a big yes.And thing is, it applies both to the design itself as it does to the tools you use. Which has been his point as well all along.As to precisely Rust, which was the topic, I *have* taken a close look at it. I *have* watched numerous conferences about it, and tutoring videos. My *personal* view on it doesn't matter (I do think it's a near-schizophrenic language, as I said in another thread, but that's just my opinion.) What I would really like is to actually *see* running projects and the related source code.What strikes me is that there seems to be a lot more people talking about Rust than people actually using it.The OP said that they use Rust *exclusively* at his company, which is nice to hear. I haven't looked at the projects he posted yet, I probably will. But at least he gave concrete examples, which is rare enough to be mentioned.

author: nctnico
author_rank: Super Contributor
timestamp: March 21, 2023, 07:42:30 pm
content: Quote from: tggzzz on March 21, 2023, 07:15:13 pmThat leads me to the following questions: But what if you can simplify the specification if it is written in a different way? Should the specification push a certain implementation method?QuoteThat is a good point but I'm not sure it always works out the way you want in terms of maintainability and so on. From my own experience: very early on in my career I have implemented an ISDN protocol stack in C. The implementation I created matches the state machines as outlined in the specification but I can't say the resulting code is pretty or easy to maintain / follow. I have not found anyone else able/willing to maintain this particular piece of code. If I would have to take on a similar project again, I'm not sure whether I would follow the specification but more likely I'd deviate from it to get to an implementation that is easier to understand / maintain.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 21, 2023, 07:43:01 pm
content: Quote from: nctnico on March 21, 2023, 07:03:19 pmUsually you need to run much more than two, and many of these will have time requirements - like something must be done at certain time (or by certain time). Moreover, you may need to split some of the processes - for example, you may collect something to the buffer, and then process it separately, with totally different timing. Aside of preemptive OS and round robin state machines there are many other choices - periphery, DMA, interrupts of various priorities, piggy-backs. Each case is individual. You need to come up with data structures, data flows, operations etc. which work well together. In the end, you need to design something which is reliable, meets the timing requirements of all processes, share resources in a way that you never run out of them, and so on.If you simply start writing the code, it is very easy to create something incredibly complex and nearly unmanageable. Then you may spend months making it all work (ever heard someone telling you that he spent a month or so fixing a bug?). Or, you can spend some time upfront organizing things, making them simpler, so that you write less and it is well-segregated, meaning that parts of the code do not depend on each other and do not interfere with each other. Then it'll be easier to maintain, to find bugs, to fix them, to make changes.

author: DiTBho
author_rank: Super Contributor
timestamp: March 21, 2023, 07:49:49 pm
content: Quote from: SiliconWizard on March 21, 2023, 07:20:58 pmQuote from: SiliconWizard on March 21, 2023, 07:20:58 pmyup, precisely. I am looking at the AppleSilicon Linux port with interest.Especially for the Rust-kernel-module.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 07:56:07 pm
content: Quote from: nctnico on March 21, 2023, 07:42:30 pmThat's a different but interesting question, which is key in making many scientific and engineering advances.It is rare that a domain expert can completely change the way in which they envisage their problem. If they can change, fine. When not, then the implementation technology has to be the variable that changes.QuoteArguably that unprettiness is not important.What is important is that when the specification changes abit, it can be accurately determined whichbitof the implementation must be changed andwhich sections do not have to be andmust notbe changed. I've seen that latter problem sink a company division.The specifications will, as sure as eggs are eggs, be changed "a little bit" by the client. If the implementation doesn't reflect the specification, the client won't understand why their "little change" requires a major re-implementation.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 21, 2023, 08:03:05 pm
content: In regulated industries, one has to be a bit more strict about all this, and the "state of the art" approach is to have lists of detailed specifications, and for each, which part(s) of the code implement(s) it.It's extremely tedious.Expect the coding part to be only a very small fraction of all the work.Actually, as soon as the *coding* part takes any significant fraction of the development time, you know you're going to have problems.

author: tggzzz
author_rank: Super Contributor
timestamp: March 21, 2023, 08:10:23 pm
content: Quote from: SiliconWizard on March 21, 2023, 08:03:05 pmMy experience is that - even in unregulated industries - it takes longer to work out what to do than it does to do it. Validation takes a long time too

author: baldurn
author_rank: Regular Contributor
timestamp: March 22, 2023, 12:04:41 am
content: I am using embedded Rust with the Raspberry PI Pico (RP2040). I may apologize for being on topic but let me tell you my experience with it.First, the reason I went for Rust is that I wanted a better C. I wanted a system programming languagehttps://en.wikipedia.org/wiki/System_programming_languageas that seems to make sense for embedded programming. I know we have options like embedded Python but I will admit to be preconceived that this is for beginners :-).For a system language I expect it to have no (mandatory) garbage collection nor need for any environment (C++ exceptions requires this). Not for the usual reasons which I disagree with: garbage collection can be real time and people forget that malloc also has issues like memory fragmentation and varying runtime. But it should be lean. Do nothing except what I programmed and have little extra bagage in the binary.Why a better C? I am working in a different project where the client specified C. Therefore it will be C. It has to interface to some rarely used Linux kernel network system calls. I spent a week chasing a mistake where nothing made any sense. The program did not crash, it just did not work as it should. I was convinced the Linux call, which is very poorly documented, was not working and that I must be using it wrong. Turns out to be an off by one error on a buffer allocation. The size of the buffer is decided by equally poorly documented macros from some Linux kernel header files. The buffer size needed to be +1. This made the kernel call override some random variable on my stack and from there on the program behavior was fucked in a way you could never tell from reading the code. Maybe other people are just better than me, but I want a language with bounds checking please.There are of course a ton of other improvements by using Rust. Safe memory allocation, safe multithreading etc. Modern tools.So for my RP2040 project I decided to go Rust. I haven't given up but it sadly it has been a very steep learning curve. The documentation stinks. It is easy enough if you just want to make a blinking LED demo project. But I need to program the PIO, use DMA transfers and interrupts. All the fancy stuff. And there simply is _no_ documentation! No blog posts that aren't outdated. There is some autogenerated documentation, with half the links broken and the other half only understandable by someone who knows Rust and the embedded libraries very well. Oh and everyone points you to the outdated "embedded rust book" that skips over all the juicy bits and only gets you to the "blinking LED" stage.I ended up with something half working but I found my Cargo.toml with a huge list of dependencies, half of which I am unsure if are really needed. And then the PIO assembly macros for Rust advertised that it would compile the PIO instructions at compile time. Which fails because suddenly the whole thing expects my Pico to depend on std so it can make colorful error messages on the non existing console?Apologies for the rant. I _will_ make it work. But I fully understand if someone just skips this nonsense and gets the job done using C instead.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 22, 2023, 02:13:31 am
content: Quote from: baldurn on March 22, 2023, 12:04:41 amHow would the language with bound checking know that the kernel needs "size+1" buffer?

author: Marco
author_rank: Super Contributor
timestamp: March 22, 2023, 02:17:12 am
content: If the kernel was written in the same language it would know because it's part of the type system, the compiler would throw an error.

author: wek
author_rank: Frequent Contributor
timestamp: March 22, 2023, 05:48:21 am
content: Quote from: Marco on March 22, 2023, 02:17:12 amStop right just there. That is what characterizes this thread the best.JW

author: Siwastaja
author_rank: Super Contributor
timestamp: March 22, 2023, 07:49:25 am
content: Quote from: Marco on March 22, 2023, 02:17:12 amThat's a pretty big if indeed. And there might be reasons why the linux kernel is not written completely in Rust, which are not instantly obvious (i.e., other than legacy). You only see them when you start porting the whole project.The story is as usual: existing way shows a nasty bug, but the alternative that could be free of that bug, cannot be used at all. There are zero bugs, because there is nothing to run.That "cannot do anything because of colorful logging" part of the story reminds me of nRF52 SDK which proves you can totally fuck this shit up in C, too: their Hello World example compiled, IIRC, over 100 000 lines of code from over 200 files, one of which was a massive configuration header which hadthousandsof lines just to define colors of different logging levels. Unsurprisingly, it was never able to print the Hello World in any color. Something was wrong within that 100 000 LoC.

author: tggzzz
author_rank: Super Contributor
timestamp: March 22, 2023, 08:20:03 am
content: Quote from: baldurn on March 22, 2023, 12:04:41 amYes. Too many people don't understand the subtleties of using C and its libraries.QuoteYes, those are characteristics of working on the bleeding edge.I applaud your perserverence and agree with that conclusion. Perhaps you will be able to put your experiences to good use, either by helping the language creators shape the language/environment, or by helping people use the language/environment. Either would also be good for you, in unpredictable ways.Thanks for those notes, and have fun.

author: baldurn
author_rank: Regular Contributor
timestamp: March 22, 2023, 09:55:31 am
content: Quote from: NorthGuy on March 22, 2023, 02:13:31 amYou would write a wrapper that did the bound checking before executing the unsafe keyword. In this case I expect there already is a wrapper because the actual system call is just "recvmsg". But just take a look at the man page for that system call and it becomes immediately obvious how easy it is to fuck up that mess of structs, pointers and lengths you have to pass.It has been extensively documented how the C language is especially prune to certain types of errors compared to other languages. My problem here was one of the classics. But it is just not that the language allows the problem, but also how hard it can be to debug when it happens. That it was a system call is not the point, because this type of stuff is also common in many large C code bases.I did not want to bash on C but just tell why I thought the idea of a "better C" is appealing. That is what I want from Rust for my embedded projects.

author: uliano
author_rank: Regular Contributor
timestamp: March 22, 2023, 12:01:49 pm
content: Quote from: baldurn on March 22, 2023, 12:04:41 amI dedicated only a few hours to Rust and already I can relate with most of the above. Also I don't like some level of fanaticism I perceive in the evangelists (although not different to other emerging languages). My motivation is also similar to yours: I'd like an higher level C while I dislike the C++ take. I should spend much more time on it before deciding if that can be the solution for my quest but, aside high levels of frustration, I perceive that there could be something here, at least for a common MCU as STM32 the toolset is very usable from within VSCode.The language has its quirks but until i dig into it deeper I can't say whether they are unmotivated or not, at this stage my worries are more on the fragmentation of the crate system (I would have said library but no, they just felt the need to rename everything!): for a blinking led + RTT log I have a total of 25 crates.Even if community seems more concerned with the high level abstraction HAL I'll probably dig into the lower layer PAC before. I'm always afraid of thing done by opaque layer of software, brings my mind to Arduino...May I ask which one (HAL or PAC) you decided to use and why?

author: gmb42
author_rank: Frequent Contributor
timestamp: March 22, 2023, 02:51:24 pm
content: Infineon jumping on the Rust train:https://www.electronicproducts.com/infineon-mcus-support-rust-programming-language/

author: wek
author_rank: Frequent Contributor
timestamp: March 22, 2023, 02:56:39 pm
content: Quote from: uliano on March 22, 2023, 12:01:49 pmTo be fair, this shouldn't be chalked up as *Rust's* (i.e. the language's) shortcoming.JW

author: coppice
author_rank: Super Contributor
timestamp: March 22, 2023, 04:06:49 pm
content: Quote from: wek on March 22, 2023, 02:56:39 pmIts the whole package that matters. Great ideas are far more common than great execution. If a language can't muster what it takes to be appealing, that is one of its shortcomings.

author: Marco
author_rank: Super Contributor
timestamp: March 22, 2023, 05:35:12 pm
content: Quote from: gmb42 on March 22, 2023, 02:51:24 pmHow useful is this for low level automotive systems as long as there's no certified ISO 26262 Rust development environment?

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 22, 2023, 08:03:28 pm
content: Quote from: Marco on March 22, 2023, 05:35:12 pmIt isn't.They're probably pushing it 1/ to get some marketing benefits (as it appears trendy to jump on the Rust bandwagon), and 2/ hoping this move will contribute to getting it certified at some point (which can be thought of as fair, it all has to start somewhere).The first hurdle will of course be to get a standard for the Rust language.

author: coppice
author_rank: Super Contributor
timestamp: March 22, 2023, 08:53:56 pm
content: Quote from: Marco on March 22, 2023, 05:35:12 pmChicken meets egg.

author: nctnico
author_rank: Super Contributor
timestamp: March 22, 2023, 09:45:47 pm
content: Quote from: Marco on March 22, 2023, 05:35:12 pmAfter some Googling it seems quite a few car makers are using Rust already for low risk stuff and a commercial party is working on getting (lets call it) a Rust fork qualified:https://ferrous-systems.com/blog/the-ferrocene-language-specification-is-here/

author: NorthGuy
author_rank: Super Contributor
timestamp: March 23, 2023, 02:26:07 pm
content: Quote from: baldurn on March 22, 2023, 09:55:31 amBy your description, it looks like you got in troubles because of thecomplexityof this function. If you used a simpler function, such as recv(), you wouldn't have any problems. There's no reason to blame this on C or on Linux.<edit>This is a good example how extra complexity may cause bugs.

author: baldurn
author_rank: Regular Contributor
timestamp: March 23, 2023, 06:36:15 pm
content: Quote from: NorthGuy on March 23, 2023, 02:26:07 pmHmm maybe you know something nobody else does? How exactly do you communicate with the Linux Kernel using Netlink without using recvmsg? You have to pass a struct sockaddr_nl with nl_family and nl_groups set to magic values. Last I checked there was no way to pass that to recv(). You will get multiple values back that has to parsed using undocumented macros NLMSG_OK and NLMSG_NEXT then cast to nlmsghdr* and switch based on nlmsg_type (RTM_NEWLINK, RTM_NEWADDR, etc). If you had all that in your head I am impressed. You should write some documentation because nobody else bothered. You have to find out about half of that by looking at source code.If you can in fact use vanilla recv() I can say I am not the only one who missed that. All code I found is using recvmsg() for Netlink.Now to get back on track: would a Rust kernel have an insane API like that? I mean the man page just list the first parameter of struct msghdr as void* but it is really struct sockaddr_nl* with nothing in the man page tell you that?! Yes, I do blame C for making people use void* instead of actual types.

author: JPortici
author_rank: Super Contributor
timestamp: March 23, 2023, 07:31:13 pm
content: Quote from: baldurn on March 23, 2023, 06:36:15 pmwhy can't you use the actual type again? the only place i use (void*) is in the library functions that expect it (basically only memcpy)

author: tggzzz
author_rank: Super Contributor
timestamp: March 23, 2023, 08:13:39 pm
content: Quote from: baldurn on March 23, 2023, 06:36:15 pmHopefully it wouldn't start with such an insane API - but over time such things always become cancerous. Whether Rust would make such cancers easier to deal with is an interesting and important question.Yes, void* is a clear admission of defeat; even class Object plus checked downcasting is better!

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 23, 2023, 08:32:26 pm
content: Quote from: nctnico on March 22, 2023, 09:45:47 pmYep, so this is the first step I was talking about. They are writing a *language report*. Something without which it's impossible to do anything serious with a language.So, "Ferrocene" it will be.And, yes, I've seen Adacore recently jumping on the Rust bandwagon themselves. Probably in hopes that Adacore will not end up dying.I'm not completely sure yet what I think about their move here.

author: tggzzz
author_rank: Super Contributor
timestamp: March 23, 2023, 08:50:03 pm
content: Quote from: SiliconWizard on March 23, 2023, 08:32:26 pmBased on reading that for all of 90s, I'll note the use of the phrase "It is undefined behavior..."

author: NorthGuy
author_rank: Super Contributor
timestamp: March 23, 2023, 11:18:31 pm
content: Quote from: baldurn on March 23, 2023, 06:36:15 pmAll I said is that recvmsg() happened to be too complex for you (actually that what you said yourself), which caused bugs in your code. You attributed the bug to C being unsafe language. But this is not the case, as there are many other C functions which you used without problems. The only difference is that these other functions were simpler.

author: westfw
author_rank: Super Contributor
timestamp: March 23, 2023, 11:40:01 pm
content: QuoteAre you complaining about the documentation of the rp2040 in general, or the documentation of the Rust SDK toolkit provided for it ? The rp2040 docs (all C-oriented) usually get a pretty good rating; I don't know whether they can be easily translated into Rust (about which I know nothing), or whether the C SDK needed to be completely re-thought to fit into Rust.If you can't take the usual hardware data sheet (with examples in assembly language or C) and easily come up with counterparts in the language of your choice (ie Rust), then I claim that that IS a problem with the language. (And one that I've encountered with Smalltalk, Java, and Python - some simple concept like "Hello World" (embedded) blows up because (for example) because that raw ascii characters I want to deal with have been generalized into charsets and encodings and ... and ... Grr.(OTOH, higher level libraries are nice. I was astonished how easy it was to deal with XML or JSON in python.)

author: ve7xen
author_rank: Super Contributor
timestamp: March 23, 2023, 11:51:24 pm
content: Quote from: NorthGuy on March 23, 2023, 11:18:31 pmThe difference is that C has little better than this insane mess to offer, and if you need to create an API for such a feature, that is what you get. Yes, with documentation, it should be somewhat usable, but it will still be rife with footguns. Such a horrible API is...difficult...to create in Rust, the sane path is far easier. That you don't think a language with a strong type system and things like discriminated unions help both in terms of ease of use and ease of correct use is crazy.Can people write good software in C? Sure, they've been doing it for 50 years. Does that mean that all software problems are the programmer's fault, and that languages can't, by their design, reduce errors and aid in doing the right thing? Absolutely not. We still see regular serious stupid security bugs in openssl that would have been prevented just by using a language like Rust, and that is old C code that has been done by professionals, audited by professionals, and used by more programmers than most other code.As far as use in embedded, I'm excited for it. The ergonomics of the language vs C or C++, plus the ease of finding and using 3rd party code are justsomuch nicer, it's not even a contest which I'd rather use. But the ecosystem isn't really there yet.

author: baldurn
author_rank: Regular Contributor
timestamp: March 24, 2023, 12:21:30 am
content: Quote from: westfw on March 23, 2023, 11:40:01 pmThe RP2040 documentation is indeed quite good. That is not the problem at all. On the contrary I come from having read the RP2040 documentation and made a plan for what I want to do. I figured I need to program the PIO just so and then I can do some DMA transfers like this and finally with an interrupt handler I should be able to make everything fit together. Next step would be to code it.I actually do not know how hard it would be to program the hardware directly without using any Rust libraries. Not too hard I suspect since everything is memory mapped, so it should just be some wrappers using a few pointers in an unsafe section.But that is not how I want to do it. I want to use the ecosystem that is part of the language. They have an hardware abstraction layer both generic and specific. It is supposedly all very nice and it appears it really is. The problem is the documentation. I believe it is probably not too hard to parse the documentation if you are well versed in Rust but not for newbies like me. Second it also appears a lot of refactoring has been done, which is why half of what you find on the net is no longer correct. Even ChatGPT gives you wrong code because it is coding to old standards that has been deprecated :-)As someone said this is all expected from being on the bleeding edge. Makes it no less painful... With time it will become much better.

author: westfw
author_rank: Super Contributor
timestamp: March 24, 2023, 07:16:12 am
content: Quote"They" as in official Rust specs, or some particular published example?I found this:https://www.fullstacklabs.co/blog/rust-raspberry-pi-pico-blink- is that the way it's supposed to look?

author: ve7xen
author_rank: Super Contributor
timestamp: March 24, 2023, 10:02:30 am
content: Quote from: westfw on March 24, 2023, 07:16:12 amembedded_halas a generic HAL comes from the 'official'Rust Embedded Working Groupthat is at least endorsed by the Rust main team (not sure on the history/politics), but operates as its own entity.rp2040-halimplements this HAL + extensions for the RP2040.STM32F3Discovery is kind of the demo platform for embedded rust, there's a tutorial-style book on the basics on that platform herehttps://docs.rust-embedded.org/discovery/f3discovery/index.html. Most of it should apply to other embedded_hal implementations, but YMMV. That RP2040 demo looks pretty reasonable to me.

author: nctnico
author_rank: Super Contributor
timestamp: March 24, 2023, 11:38:10 am
content: I just can't help noticing various Rust related sites are referring to books. In my experience (in general) it is a good start to buy a book and go from there. In the past I bought books to get started with WxWidgets, Linux kernel drivers, OpenCV, etc and those books where money well spend. IOW: don't expect to find all answers or a coherent write-up online.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 24, 2023, 12:29:15 pm
content: Quote from: baldurn on March 24, 2023, 12:21:30 amI can sense some irony in your posts.Have undocumented C API which is so difficult to use -> C forced to make it complex; with Rust one could make it simple!Have undocumented Rust API which is so difficult to use -> not fault of Rust, just poor documentation. It will get better once someone writes the documentation!(And I'm not trying to be mean to you. It's just the same old pattern I'm seeing - despite high expectations, new tools not being to able to solve the problem.)

author: baldurn
author_rank: Regular Contributor
timestamp: March 24, 2023, 12:38:35 pm
content: Quote from: Siwastaja on March 24, 2023, 12:29:15 pmTo be fair, the recvmsg system call may be older than me :-) They have had some time to write documentation.Another difference is that the Rust code refuses to compile when I do it wrong. I am still stuck mind you. But not with a program that compiles and crashes for reasons I do not understand.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 24, 2023, 12:51:52 pm
content: Quote from: baldurn on March 24, 2023, 12:38:35 pmAnd that's the key. Existing ecosystem, existing ABIs and library interfaces are the real enemy. This is also why we see very few C++ libraries; no standardized ABI, so library calls have to be in C. Unless one writes complete operating systems and libraries from scratch, Rust will face all the same issues; it will have to interact with recvmsg().Now one could (and has to) write a sane wrapper for recvmsg() in Rust, but on the other hand one could do the wrapper in C as well! If nothing else, replace those void pointers with actual types. If you have more than one possible type, you can use a union to limit the choices in much more sustainable way than casting void pointers to anything.The problem is, no one has bothered to write those wrappers, or if they have, they are lost in the noise of the Internet. I also hate the fact every project on POSIX starts with writing a wrapper for write() and read() which gives the desired blocking/nonblocking behavior and always return exact count or error. That is what users want. Yet you have to do it yourself every time.For completely self-contained embedded projects (with no dependencies on libraries at all), one can easily use any language they wish. On the other hand, in such case, one can also write modern and decent C, then, so advantages are smaller as the worst pain points are always in existing libraries and their interfaces, as shown by your recvmsg() example. (I also had a first stack corruption casein yearsbecause I used DNS code written by WIZnet, where they strcpy() a hostname to a fixed 24-length buffer. Go ****ing figure.)

author: wek
author_rank: Frequent Contributor
timestamp: March 24, 2023, 12:53:54 pm
content: Quote from: baldurn on March 24, 2023, 12:38:35 pmOh, They. Cousin of If.IMO Abstraction means Least Common Denominator, and as such is perpendicular to everything Controller in microControllers. In other words, if you want to use microcontrollers with Rust, you must learn how to write those pesky hardware-relatedlibrariescrates. Or just do the Arduino thing - there's nothing wrong with that, the world is not black and white.JW

author: tggzzz
author_rank: Super Contributor
timestamp: March 24, 2023, 12:59:56 pm
content: Quote from: wek on March 24, 2023, 12:53:54 pmI've seen many international standards where the abstraction is the highest common multiple. That enables all manufacturer's equipment to conform to the standard. (Or at least the parts of the standard that they have implemented, cough).That can still have advantages for clients of the various manufacturers' equipment, but it still allows manufacturer lockin.

author: coppice
author_rank: Super Contributor
timestamp: March 24, 2023, 01:07:16 pm
content: Quote from: wek on March 24, 2023, 12:53:54 pmThere is a weird trend in MCUs. People have unique features in their peripherals that put them head and shoulders above the competition for specific applications, but in 2023 all they want to do is dumb things down by pushing abstraction libraries that only expose the most basic generic features. For an MCU, abstraction is great for things like ethernet and USB interfaces. It loses most of the interesting qualities of most other peripherals.

author: nctnico
author_rank: Super Contributor
timestamp: March 24, 2023, 01:43:15 pm
content: Quote from: coppice on March 24, 2023, 01:07:16 pmI depends a bit on how the HAL is implemented. Recently I have been working on some STM32 projects and I find ST's HAL absolutely horrific and inconsistent. Where I can, I am replacing the HAL parts with bare metal code that just works better and is easier to use.OTOH I find the way Linux deals with low level interfaces much better while it doesn't incur much overhead. You have open, read, write, close and ioctl that work on what is basically a file on the file system. Only ioctl deals with peripheral specific stuff. You can implement something similar for a microcontroller with a much thinner interface.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 24, 2023, 02:58:04 pm
content: Quote from: baldurn on March 24, 2023, 12:38:35 pmWhat's wrong with understanding reasons? It's not a rocket science you know. You did well with recvmsg() in the end. A few dozens of such cases and seeing reasons won't be that hard any more.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 24, 2023, 03:54:16 pm
content: Quote from: NorthGuy on March 24, 2023, 02:58:04 pmLearning from mistakes is not just how to avoid those exact mistakes by learning higher level of self-control, but how toimprovethings so that whole classes of mistakes just disappear. This mindset has been highly successful in aviation safety, for example.That being said, one needs to be careful so they understand the root causes properly, to do the right decisions. One should also look at the aviation safety here. No recommendations are made until the root causes andsignificantcontributing factors are well understood.Some of the weirdest POSIX interfaces need good usability wrappers, or at very least good documentation with examples covering most usual use cases. It's a pity they are not widely/commonly available.

author: coppice
author_rank: Super Contributor
timestamp: March 24, 2023, 05:18:49 pm
content: Quote from: Siwastaja on March 24, 2023, 03:54:16 pmWhere POSIX differs from straight up traditional Unix its supposed to be to overcome shortcomings that experience has shown in the original. However, in many cases they just seem to have achieved an even quirkier API.

author: nctnico
author_rank: Super Contributor
timestamp: March 24, 2023, 05:27:19 pm
content: Quote from: coppice on March 24, 2023, 05:18:49 pmOn systems with an OS you are way better of using at least C++ and one of the many frameworks (like Boost, Qt, Wxwidgets, etc) to turn the OS calls into sensible interfaces.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 24, 2023, 05:29:26 pm
content: Quote from: Siwastaja on March 24, 2023, 03:54:16 pmBefore you can improve on something you need to understand what is the root cause.Whether you use your own means or external tools to solve a problem, the understanding is a must. Without understanding, everything would look like a magic to you - a la "my program crashes, I need a better language which will fix this", or "I changed an unrelated line of code and look - my bug is fixed and MCU doesn't crash any more".

author: uliano
author_rank: Regular Contributor
timestamp: March 25, 2023, 08:25:21 pm
content: I had some time to spend and finally I'm starting to grok a little.Quote from: uliano on March 22, 2023, 12:01:49 pmI was SO WRONG!To the point that I could go further the silly examples only after discoveringrtic.rswhich sits above the HALA software task (driven through the unused SPI1 interrupt by systick) every 10ms generates a pulse on PB1 which is electrically connected to PB0 where an higher priority, EXTI0 driven, task generates a pulse on PB2 while the led is blinking at 1Hz and log messages are sent through RTT in about 100 lines of code. It is not even Rust, rather a kind of application specific language implemented in macro but, once in the known, the code is rather clear and even elegant.Also I gave up to generic tools such as cortex-debug, openOCD, gdb... and adopted the native probe-rs (with its VSCode extension), cargo-flash cargo-embed...Finally, I was rather skeptical about the thaumaturgical powers of static analysis but I should say that thedesign contractsimplemented by the HAL are quite effective in preventing lots of silly distraction mistakes. In my short (one day) experience I can say that once it compiles it runs, maybe it does not do what it was meant for, but it doesn't hang or crash, to the point that I never felt the need to reach for the debugger.Next step will be to try some simple peripherals like I2C or SPI.Code:#![deny(unsafe_code)]#![deny(warnings)]#!#!use panic_rtt_target as _;use rtic::app;use rtt_target::{rprintln, rtt_init_print};use systick_monotonic::{fugit::Duration, Systick};use systick_monotonic::fugit::Instant as Instant;#[app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = )]mod app {use super::*;use stm32f4xx_hal::{gpio::{Input, Output, PushPull, Edge, PC13, PB0, PB1, PB2},prelude::*};// use stm32f4xx_hal::prelude::*;#struct Shared {}#struct Local {input: PB0<Input>,signal: PB1<Output<PushPull>>,output: PB2<Output<PushPull>>,led: PC13<Output<PushPull>>,count: u32,start_time: Instant<u64, 1, 1000>}#[monotonic(binds = SysTick, default = true)]type MonoTimer = Systick<1000>;#fn init(mut cx: init::Context) -> (Shared, Local, init::Monotonics) {rtt_init_print!();rprintln!("init");// Setup clockslet rcc = cx.device.RCC.constrain();let mono = Systick::new(cx.core.SYST, 96_000_000);let _clocks = rcc.cfgr.use_hse(25.MHz()).sysclk(96.MHz()).hclk(96.MHz()).pclk1(48.MHz()).pclk2(96.MHz()).freeze();// Setup Pinslet gpioc = cx.device.GPIOC.split();let mut led = gpioc.pc13.into_push_pull_output();led.set_high();let mut syscfg = cx.device.SYSCFG.constrain();let gpiob = cx.device.GPIOB.split();let mut input = gpiob.pb0.into_pull_down_input();input.make_interrupt_source(&mut syscfg);input.trigger_on_edge(&mut cx.device.EXTI, Edge::Rising);input.enable_interrupt(&mut cx.device.EXTI);let mut signal = gpiob.pb1.into_push_pull_output();signal.set_low();let mut output = gpiob.pb2.into_push_pull_output();output.set_low();// Schedule the blinking task 10 ticks = 10 ms from nowlet first_time = monotonics::MonoTimer::now() + Duration::<u64, 1, 1000>::from_ticks(10);blink::spawn_at(first_time).unwrap();(Shared {},Local { input, signal, output, led, count: 0, start_time: first_time },init::Monotonics(mono),)}#[task(local = [led, signal, count, start_time], priority = 1)]fn blink(cx: blink::Context) {cx.local.signal.set_high();cx.local.signal.set_low();if *cx.local.count == 100 {cx.local.led.set_high();rprintln!("blink");}if *cx.local.count == 200 {cx.local.led.set_low();*cx.local.count = 0;rprintln!("blonk");}*cx.local.count += 1;// Schedule the next blinking task 10 ticks later*cx.local.start_time += Duration::<u64, 1, 1000>::from_ticks(10);blink::spawn_at(*cx.local.start_time).unwrap();}#[task(binds = EXTI0, local = [input, output], priority = 2)]fn on_exti0(cx: on_exti0::Context){cx.local.output.set_high();cx.local.output.set_low();cx.local.input.clear_interrupt_pending_bit();}}

author: tggzzz
author_rank: Super Contributor
timestamp: March 25, 2023, 09:14:01 pm
content: Quote from: uliano on March 25, 2023, 08:25:21 pmThank you for those comments.It is always a pleasant surprise to find someone that looks, thinks, tries,understands the subtleties, and even changes their mind. That is all too rare - and useful for other people

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 25, 2023, 11:41:28 pm
content: I dig this kind of stuff:Code:blink::spawn_at(*cx.local.start_time).unwrap();

author: coppice
author_rank: Super Contributor
timestamp: March 26, 2023, 02:34:15 pm
content: Quote from: karpouzi9 on March 26, 2023, 10:03:16 amIn a universe with abundant oxygen the existence of rust is beyond question. It will always be with us. As the great philosopher Neil Young noted - Rust Never Sleeps.

author: uliano
author_rank: Regular Contributor
timestamp: March 26, 2023, 04:05:19 pm
content: sorry, my bad!I will amend myself by showing this grotesque type annotation (and yes I needed to write this)Code:lcd: Ili9341<SPIInterface<Spi<pac::SPI1, (Pin<'A', 5>, NoPin, Pin<'A', 7, Alternate<5>>), false>, Pin<'A', 4, Output>, Pin<'A', 2, Output>>, Pin<'A', 3, Output>>

author: NorthGuy
author_rank: Super Contributor
timestamp: March 26, 2023, 04:07:06 pm
content: Quote from: karpouzi9 on March 26, 2023, 10:03:16 amToo late. I have already noticed it. 113 lines for LED blinker - that's really amazing productivity. And the warm feeling that your LED blinker will never crash. Priceless.

author: ve7xen
author_rank: Super Contributor
timestamp: March 27, 2023, 07:52:49 am
content: Quote from: NorthGuy on March 26, 2023, 04:07:06 pmA minimal LED blinker for stm32f103 using embedded_hal is 30 lines, it's all the same initialization stuff you need to do with C...Code:#!#!use cortex_m_rt::entry;use nb::block;use panic_halt as _;use stm32f1xx_hal::{pac, prelude::*, timer::Timer};#fn main() -> ! {let cp = cortex_m::Peripherals::take().unwrap();let dp = pac::Peripherals::take().unwrap();let mut flash = dp.FLASH.constrain();let rcc = dp.RCC.constrain();let clocks = rcc.cfgr.freeze(&mut flash.acr);let mut gpioc = dp.GPIOC.split();let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();timer.start(2.Hz()).unwrap();loop {led.toggle();block!(timer.wait()).unwrap();}}QuoteYou can usually avoid this mess in function signatures by using traits instead, but it can be unavoidable in your shared state, but really should only exist in one place. This is a wart for sure, but the complex strong types are also the strength. I suspect as embedded Rust matures, there will be some 'standard' macros that emerge to make dealing with this a bit more ergonomic.async in no-std is pretty exciting for embedded, IMO. Still pretty experimental, but Embassy looks fairly mature.

author: uliano
author_rank: Regular Contributor
timestamp: March 27, 2023, 10:18:02 am
content: Quote from: ve7xen on March 27, 2023, 07:52:49 amyeah, in effect it was advertised asQuotemaybe someone can't or won't read...QuoteI wasn't really complaining, rather sticking to the "social protocol" for this thread.QuoteMy plan is to stick with rtic, at least initially, I feel much more at home having to deal with interrupt tasks, also my Rust proficiency is, at the moment, quite low and it's probably better to await alittle till it grows to an acceptable state.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 27, 2023, 05:44:28 pm
content: Quote from: ve7xen on March 27, 2023, 07:52:49 amSame stuff ... Who would've thought.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 27, 2023, 06:34:13 pm
content: This is cute.

author: wek
author_rank: Frequent Contributor
timestamp: March 27, 2023, 08:19:11 pm
content: Hi ve7xen,Quote from: ve7xen on March 27, 2023, 07:52:49 amThanks for the example.Could you please perhaps comment it, explaining what element does what in that example, for us, uninitiated?Thanks,JW

author: ve7xen
author_rank: Super Contributor
timestamp: March 27, 2023, 09:17:31 pm
content: Quote from: wek on March 27, 2023, 08:19:11 pmSure. Keep in mind I'm by no means a Rust expert (though I have spent some time with it making small CLI tools and web APIs), and have only spent some hours here and there tinkering with embedded rust over the last couple years.A 'crate' is sort of a source library. It can include runtime code, compile time macros, and so on. Using them is integrated into the cargo build tool that is the normal way to build anything with Rust.Code:// Tell the tools not to build or link to the Rust standard library. std requires a heap allocator, which you can bring in if you want (for example from the embedded-alloc crate)#!// Likewise, we don't want any of the normal setup code for a hosted binary, so don't set up an entry point#!// `use` instructs the compiler to import modules from external crates// This is the setup code (interrupt vectors, static init etc.) for cortex m, and will create our entry point. This crate also contains similar macros for ISRs.use cortex_m_rt::entry;// A macro to busy wait on a predicateuse nb::block;// A panic handler is required.// 'panic_halt' just halts the CPU. Other options might be `panic_semihosting` to print the panic message to the semihosting environment, or your own implementation.// We just need to import it into the build, we won't reference it anywhere, so it imports as _ which in Rust usually means 'I don't need this'use panic_halt as _;// Here we bring in the device support module.// pac is the 'peripheral access crate', basically register maps// prelude in rust modules is usually a convenience module that lets you import 'all the typically useful stuff' in one use statement// timer::Timer lets us use a timer peripheral to create the delay we needuse stm32f1xx_hal::{pac, prelude::*, timer::Timer};// This is the cortex_m_rt::entry macro and flags the function as the entry point#// Function signature, -> sets the return type, ! means 'returns nothing', which is distinct from returning Nonefn main() -> ! {// Generally there are 'core peripherals' from a processor support crate, and 'device peripherals' from a device support crate.// In this case we need the core peripherals for the SysTick timer, and device peripherals for RCC, GPIO and Flash controllers// So we reference the module and 'take()' to transfer ownership to our context, as these are singletons.// This operation can fail (if for example they are already owned), so returns a Result that can be an error or contain a value// we unwrap() it to get the inner value, and panic if it's an error instead.let cp = cortex_m::Peripherals::take().unwrap();let dp = pac::Peripherals::take().unwrap();// Our specific device has 'specialized' peripherals from the PAC, but we need them as standard HAL objects to use the traits from HAL// so we take the device peripheral and 'constrain' it to the HAL specification, which gives us an owned HAL-type objectlet mut flash = dp.FLASH.constrain();let rcc = dp.RCC.constrain();// We will need a Clocks object later to set up the timer. This describes the clock configuration in the system. To get it,// we must 'freeze' the clock configuration register. This 'consumes' the reference to the register and makes the borrow// checker guarantee for us that we can't reference it anywhere else. In other words, it guarantees that as long as the Clocks// object we create here exists, it will reflect the running clock configuration. Trying to reference rcc.cfgr after this will result in a compile error.let clocks = rcc.cfgr.freeze(&mut flash.acr);// split() is similar to constrain() above and basically lets us take ownership of a reference to a standard HAL representation of a peripherallet mut gpioc = dp.GPIOC.split();// Configure the pin and take ownership of it (we borrow crh mutably from the port to make the change)let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);// Here we take cp.SYST (reference to the SysTick timer) and create a usable timer with 1Hz resolution from it, based on the clock setup we fixed earlierlet mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();// Start the timer with a 2Hz period. Consuming Results is mandatory in Rust, so we have to unwrap() here.timer.start(2.Hz()).unwrap();loop {led.toggle();// our predicate here is timer.wait() which returns an Err until the timer fires, when it will return an Ok, which unblocks the block macroblock!(timer.wait()).unwrap();}}

author: wek
author_rank: Frequent Contributor
timestamp: March 27, 2023, 09:39:15 pm
content: Thanks. This will take some time to digest... :-)JW

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 01:39:56 am
content: Quote from: ve7xen on March 27, 2023, 09:17:31 pmQuote from: ve7xen on March 27, 2023, 09:17:31 pmIf taking ownership could fail there, can it also fail here (as if the pin already has an owner)? If it cannot then why? If it can then why don't you use unwrap() here?

author: ve7xen
author_rank: Super Contributor
timestamp: March 28, 2023, 06:31:54 am
content: Quote from: NorthGuy on March 28, 2023, 01:39:56 amNot at runtime, the static analysis of the borrow checker will guarantee it for us. That's not the case with take(), since it's not bound to an instance. What is happening with the GPIO pin pc13 is a 'singleton type' - the type system is used to store the details of the pin, and all its internals are private so it can't be constructed outside of the library. Since it can't be constructed, only one instance exists. into_push_pull_output is bound to the instance in the library, and calling it transfers ownership of that instance into into_push_pull_output, which then returns it to main where it is bound to led - main now owns the pin.Exactly why take() is needed on the PAC is in the weeds and I'm not sure I fully understand it. I believe that it is because the borrow checker works on function calls, and you can't 'steal' variables. So ultimately we need a singleton gated by a function that transfers ownership of the protected state to make the whole thing work. If it were just a pub static variable, the borrow checker wouldn't protect us from multiple access. Once we've done it once as a function call, then that instance contains all the other singleton types like pc13 (exactly one), which we can borrow as we own the parent struct.

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 08:21:08 am
content: But what if you want to share a GPIO pin because it has two functions depending on the mode of operation? Think about using a pin to configure and FPGA which after configuration gets a different function.

author: uliano
author_rank: Regular Contributor
timestamp: March 28, 2023, 09:49:26 am
content: Quote from: nctnico on March 28, 2023, 08:21:08 amusingrticyou can instantiate shared resources in the init, those resources can be accessed by different tasks. if the task run on the same priority no special care is required; otherwise you have to provide some kind of resouce contention mechanism, mutex or the like (I still have to test the resource sharing part... so take this with a grain of salt)

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 10:14:14 am
content: Quote from: uliano on March 28, 2023, 09:49:26 amBut that looks like you can do different things with the pin at the same time which is potentially unsafe. But I think I'll need to do more reading first on how you can transfer control over a resource from one task to the other while doing the check at compile time. Or there has to be some runtime mechanism other than writing the code by yourself. Earlier on I already commented about how Linux deal with peripherals; a peripheral (which can also be a single device on an I2C bus) gets locked by a process for as long as it has an open file descriptor for the device. However, such a mechanism also implies the need for some kind of recovery mechanism in case something goes wrong and a process keep locking a device.

author: uliano
author_rank: Regular Contributor
timestamp: March 28, 2023, 10:51:17 am
content: Quote from: nctnico on March 28, 2023, 10:14:14 amrtic is not preemptive, just interrupts and priority levels, so at the same priority it is impossible that the pin is accessed -at the same time-.At the same priority you get executed after the other interrupt has finished.

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 12:15:06 pm
content: Quote from: uliano on March 28, 2023, 10:51:17 amBut I assume there are two concurrent parallel processes that have access to the same pin where each process can do what it wants given the chance. If that is the case, that it is something you might want to avoid. So only process A or process B can access a pin while the process is alive (=an active task whether it gets execution time or not).

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 01:39:04 pm
content: Quote from: uliano on March 28, 2023, 09:49:26 amMutex and ownership seem to perform the same function.You acquire ownership to get access to the object then you relinquish it so that the other IRQL could get access to it.Traditional mutex would do the same thing except that the object is imaginary - nobody knows what is the resource being protected by mutex. But that shouldn't be possible in Rust as it must block the access to the resource protected by the mutex to enforce its no-crash guarantees. Otherwise, you can access the pin even if you forgot to acquire the mutex.You need to give us more details.

author: uliano
author_rank: Regular Contributor
timestamp: March 28, 2023, 01:47:42 pm
content: Quote from: nctnico on March 28, 2023, 12:15:06 pmIf you don't share the pin between tasks nobody is given simultaneous access. I was answering toQuoteIt's your choiceWhat rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.You need to protect your pin from "simultaenous" access only by higher priority tasks

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 02:59:12 pm
content: Quote from: uliano on March 28, 2023, 01:47:42 pmImagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 03:49:44 pm
content: Quote from: NorthGuy on March 28, 2023, 02:59:12 pmYou've got this the wrong way around. In your example you can easely have a race condition in which the fet is turned on again after it has been turned off.The actual use case is when you have 2 processes: the production process and a self-test process. You don't want to be able to run both these processes at the same time. And if they do for some reason, it is -at the minimum- very nice to be able to deny access to the hardware if a process isn't supposed to run.And this is not some far fetched example. I have systems in the field that deal with a crap load of energy. Before running a self-test on these systems, the modules need to be set to a self-test mode specifically which allows certain conditions which otherwise are strictly forbidden.That is the reason why I asked about per-process resource locking. It is a handy feature for a language / framework to support.

author: JPortici
author_rank: Super Contributor
timestamp: March 28, 2023, 03:49:58 pm
content: Quote from: NorthGuy on March 28, 2023, 02:59:12 pmcan't the pin be part of the task that does both the setting and the monitoring? Since you're doing it in software anyway (I'm of course not discussing the obvious "use the hardware" as in Output Compare with fault inputs, or directly a comparator)It seems to me it would be a programming error rather than a deficiency in the language (which i know, is the whole point of the discussion, that believing that new languange = no bugs is delusional)I honestly don't think i ever wrote a firmware in which a pin is controlled by two processes at the same time. Communication peripherals, yes, and that's why we use mutexes. And it's actually a mutex to a task, only one task control the peripheral

author: uliano
author_rank: Regular Contributor
timestamp: March 28, 2023, 04:00:21 pm
content: I'm just speculating because, as I said, the contention of shared resources (the link posted a few posts above) is in my (crowded) next thing to read list, but I suppose that the contention between your tasks can be managed by giving the default to the highest priority and just in few instants here and there the lowest priority can gain access to change something, OR the highest priority just sets a flag that is continuously monitored by the lowest priority (not so elegant). In any case, I'm not an EE however I would implement the safety behind the comparator in hardware gaining in speed and therefore safety.I see that there are difficulties, before finding rtic even initializing stuff in my mind (with very little knowledge of rust) would have required static globals and other horrible things to be able to share. But then there may be other solutions out there, when I finish my tour in rtic I will probably turn to give an eye to Embassy, which, afaik, implements cooperative multitasking (and may not be suited for your usecase).My point isnt that Rust is perfect for every application, far from that! (for example the rtic API are changing furiously release after release as it is expected for new things in rapid evolution, this has the effect of obsoleting most material and, you know, documentation sucks). My point is that after some (euphemism) effort I've been really impressed by the effectiveness of static analysis and that I will go on digging for a while.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 28, 2023, 04:08:56 pm
content: How do you define "race condition" here? Such details matter. It is impossible to "simultaneously" write a pin in a single-core microcontroller from two places. Writing a pin is always a correct and allowed operation. The only question is, is it functionally correct?Maybe expanding on NorthGuy's example: there is a self-test code that acquires ownership to the pin. This code does not normally run, but due to a bug, this process is accidentally triggered. It does not actually actively drive the pin to '1' (or maybe does it just once), but just acquires the ownership. Now the high-priority overcurrent ISR fails to get the ownership. If the ISR run bypassing any ownership checking, it would drive the pin '0' and there would still be no race condition as the self-test code running accidentally is not writing the pin back to '1' even if it has the ownership. A small bug turned into a larger bug. Neither type of bug causes memory corruption or some similar undefined behavior - just the "safe" version is functionally incorrect, while the "less safe" is functionally correct, albeit by luck.I see both ways having issues; the only real solution is to fix the bug of that self-test code accidentally triggering. The "safe language" fix is therefore not a silver bullet.I'm all for failing gracefully with out-of-bounds accesses instead of stack corruption, etc., This is something a languagecanhelp with. Those true C deficiencies I mean: zero-terminated strings, out-of-bounds array accesses, arrays decaying into pointers, we all know the drill.But failing in a supposedly "more safe" way in a simple logical error which does not cause a total corruption of program state - one needs toprovethe way actually is safer.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 04:47:47 pm
content: Quote from: JPortici on March 28, 2023, 03:49:58 pmOf course this is a programming error. The situation is totally symmetrical:In C, you can write out of the bounds of array, or dereference NULL pointer (or do other "unsafe" things). So we need a different language where such errors are impossible. Rust perhaps?In Rust, you can mess up with ownership in a wrong way (or do other things we haven't discovered yet). So we need a different language where such errors are impossible. C perhaps?Or, you may take full responsibility for your bugs, and use common sense and rational thinking. IMHO, that will take you much further towards your goals than expecting miracles from languages, libraries, or whatnot.

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 04:54:04 pm
content: Quote from: Siwastaja on March 28, 2023, 04:08:56 pmSimple: you don't know when and where in the execution path the protection interrupt fires. If the protection interrupt fires just before the normal interrupt sets the pin to turn the fet on, then the protection interrupt has no effect. There is no way you can prove correct operation of this particular system. As Jportici already noticed: there shouldn't be 2 processes controlling the same pin (resource) to begin with. But let's not dig too deep into this.QuoteThe thing is that the self-test code should not be able to acquire ownership because the regular task is already running.What I'm after is resource locking (by process). Not resource sharing!

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 06:33:07 pm
content: Quote from: nctnico on March 28, 2023, 04:54:04 pmYou can do something about it. For example, after the "main" process turns the FET on, it can check if there was a fault condition and turn it back off if needed. This is enough to solve the problem in C, but not in Rust.Or, you can eliminate the race condition by disabling interrupts in the "main" making (fault check)+(FET setting) an atomic operation. This will work in C. This will work in Rust too (if you are given an ability to disable interrupts).

author: ve7xen
author_rank: Super Contributor
timestamp: March 28, 2023, 06:49:51 pm
content: Quote from: nctnico on March 28, 2023, 08:21:08 amThe way embedded-hal is structured is to use typestate programming to ensure that there is always a maximum of one owner of each peripheral / register. The language itself then guarantees that each peripheral/register can only be (mutably) held by one execution flow at the same time, through the borrow checker. It doesn't directly speak to how you then use these singletons in your own code. If you need to 'share' pins among tasks there are a few ways you can accomplish it. You can use a barrier mechanism like a Mutex<RefCell>, though this should generally only be necessary if you need them in interrupt context. You can continue in the spirit of standard Rust programming and the borrow checker, for example in a main loop, each sub-task can borrow the peripherals from main, and implicitly return them when it is done. This pattern is very common in standard Rust as well, as you also need to contend with the borrow checker for your shared state on desktop too (though you can make use of 'heavy' std library solutions like Arc there).Or, as others have mentioned, you can use a lightweight framework to help with handling shared state, such as rtic, which for most embedded work satisfies the common requirements - but we are stacking more on top of Rust itself to get there.QuoteMutexes are runtime guards. Locking them is blocking and they consume resources and can lead to deadlocks. Ownership is guaranteed by static analysis at compile-time, so it's free at runtime. So yeah, you could build a Rust embedded project that encapsulates all the peripherals in Mutex guards and it'd accomplish roughly the same thing, but it would be quite inefficient. Really in any program, embedded or not, if you're using mutexes when you don't have concurrency, you're doing it wrong. Without the borrow checker you wouldn't really want to force access through Mutexes, due to their cost and risks, but if you don't force it, it means unsafe access is possible. Borrow checker guarantees zero-cost safety for the normal case, and you can still use a mutex (or other concurrent primitives like atomic operations) where you need concurrent access to state.QuoteThis is not generally true, at least with the abstraction we are using here. Some microcontrollers do have atomic access at the pin level, but many others do not and require read-modify-write semantics that can be interrupted. It is also not always clear/guaranteed that even if it is a single instruction to write to GPIO, that it is in fact an *atomic* instruction. Without a guarantee, you can guess but can't prove who wins if an interrupt fires in the middle of a GPIO write and performs a conflicting write; most modern cores are pipelined at least if not superscalar, and peripherals are connected via a bus that may need arbitration etc. etc..QuoteExtra care is definitely required when you need preemptive access to peripherals. This is a special case though, and generally the exact sort of thing you *want* to fail (preferably at compile time) and require extra consideration, because even in C this design is fraught with concurrency pitfalls. I think you could accomplish this with critical sections to guard access. In Rust though this idea of a higher priority access to the peripheral 'working by default' just isn't a thing, and you can't bypass the borrow checker. So you wouldn't be able to compile the implementation you describe in the first place. It is safe by default because it just won't let you assume that it works. You'd need to explicitly create some mechanism to share access to this peripheral between the two threads, and that means taking care of concurrency. This does require a different way of thinking about this kind of situation, but it forces you to be aware of it and consider the details, which I don't think is a bad thing.QuoteThere is not much that borrow checker can prove about concurrent tasks, so this is a lot to ask of it. In general, for runtime locking you'll need to use runtime primitives like Mutexes to guard access to multiple references to the same resource. It might be an option to pass ownership when the task is first spawned, but this depends on how your task concurrency is working, I don't *think* this is possible in rtic but I haven't looked into it.

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 06:56:08 pm
content: Quote from: NorthGuy on March 28, 2023, 06:33:07 pmI don't care about the technical implementation at this point. What I'm looking for is if there is some way Rust (or another language) can prevent the problem existing in the first place. A problem that can't exist is much better than a fix.

author: tggzzz
author_rank: Super Contributor
timestamp: March 28, 2023, 07:47:47 pm
content: Quote from: NorthGuy on March 28, 2023, 02:59:12 pmThe real error there is attempting to guarantee all that in software running on a conventional processor.Either do it in hardware, or use a processor plus software that states the hard real-time guarantees at compile time. Both are practical.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 28, 2023, 08:09:50 pm
content: Quote from: tggzzz on March 28, 2023, 07:47:47 pmI have to agree with this. Now of course we can use methods to decrease the probability of an error with common hardware, but we still can't *guarantee* much, and attempts at doing so are, for the most part, going to be vain.One of the things I think is "wrong" (or at least vain) with Rust or other similar languages is that they focus on trying to guarantee stuff using conventional hardware and software architectures, which are notoriously bad for certain things.Hard real-time and resource sharing are two such things.As to a gigantic source of exploits - arbitrary execution of code by overwriting the "stack"'s content - return addresses should never have been stored on the common data stack anyway. This has been one of the most dreadful mistakes in software history and should be banned.Regarding sharing hardware resources, such as peripherals, I'm personally in favor of architectures in which one peripheral is only accessed from one task. You avoid a large number of problems this way.

author: nctnico
author_rank: Super Contributor
timestamp: March 28, 2023, 08:16:54 pm
content: Quote from: SiliconWizard on March 28, 2023, 08:09:50 pmYou are both digging too deep into the given (poor) example.You have to look at it on a higher level where a software solution is appropriate.Where safety/reliability is at stake, it can help to add protective layers in both hardware and software where it is sensible to do so. Again, if a certain programming language is more suitable than another, it could help to reduce engineering costs and create a better product in one go.

author: tggzzz
author_rank: Super Contributor
timestamp: March 28, 2023, 08:48:19 pm
content: Quote from: SiliconWizard on March 28, 2023, 08:09:50 pmThe guarantees given by Rust seem to me to be valuable, and a useful advance over C.Nobody in their right mind imagines they extend to real time properties. That's why the example being discussed is so inappropriate.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 08:49:26 pm
content: Quote from: ve7xen on March 28, 2023, 06:49:51 pmWhat kind of mechanism and how would I create it?

author: tggzzz
author_rank: Super Contributor
timestamp: March 28, 2023, 08:52:20 pm
content: Quote from: nctnico on March 28, 2023, 08:16:54 pmStrictly speaking I'm arguingagainstdiscussing NorthGuy's example, because it is about something that is outside the scope of any (or ratheralmostany) language and processor.

author: tggzzz
author_rank: Super Contributor
timestamp: March 28, 2023, 08:58:44 pm
content: Quote from: NorthGuy on March 28, 2023, 08:49:26 pmEither pure hardware or xC running on xCORE. The IDE will inspect the compiled and optimised code and show you the exact number of clock cycles on any of the paths between here and there. No interrupts and no caches to cause jitter, and you dedicate one of many cores to dealing with each "peripheral". In this case the peripheral would be the FET drive output and the comparator input.Or use a few logic gates, of course.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 28, 2023, 09:13:01 pm
content: Quote from: tggzzz on March 28, 2023, 08:48:19 pmI was extending the ideas a bit here - hence maybe nctnico's reply - but here it is: I do think those are band-aids on flawed approaches.Sure band-aids can be useful if you have wounds that need fixing.Quote from: tggzzz on March 28, 2023, 08:48:19 pmI don't know what people have on their mind or not.But I wasn't even only talking about real-time, if you take my whole post.I included resource sharing into the mix.So I'll quote myself:QuoteThis one doesn't require any specific hardware. It's just a software approach that can even be taken in pretty much any language.

author: ve7xen
author_rank: Super Contributor
timestamp: March 28, 2023, 09:24:24 pm
content: Quote from: NorthGuy on March 28, 2023, 08:49:26 pmYou'd use a different architecture for this, and avoid accessing peripherals in interrupt context. Probably you should just monitor the action inside the task that is doing the switching and already owns the pin. You could also use an AtomicBool (which is Sync and Send, so can have and access references to it in multiple threads) to set a flag that you monitor for this condition in another task. Or better yet, since your contrived example is mostly in hardware anyway, just satisfy it in hardware by having the comparator output force the FET off with a hard pulldown or something rather than relying on the software to do it.If you really wanted to do it your way anyway, or had a better reason for it, you'd do it with Mutex<RefCell> of some form, probably enforcing that you're in a critical section (interrupts disabled) to access the inner (a normal mutex is not safe in interrupt context since you will deadlock if the lock is held when the interrupt arrives). This pattern is described in the Embedded Rust bookhttps://docs.rust-embedded.org/book/concurrency/

author: NorthGuy
author_rank: Super Contributor
timestamp: March 28, 2023, 11:19:43 pm
content: Quote from: ve7xen on March 28, 2023, 09:24:24 pmI see. So, the ownership is static and never changes. You can access any periphery from only a single IRQL, and there's no way to circumvent this. I've never, not once, had a problem with accesses to certain periphery, and I do access the same periphery from different IRQLs for various reasons. May be there are people who routinely have those problems, but I really doubt so. Thus this ownership feature solves the problem which doesn't exist. On the other hand, it imposes restrictions on what you can do. So, such feature is both useless and harmful.Your vision of a CPU is very strange. You say: "monitor the action inside the task", "set a flag that you monitor for this condition in another task". But how can you monitor flags or actions? CPU consecutively executing instructions from memory. To notice the change of a flag, the CPU needs to encounter an instruction that polls for that flag. If CPU executes a different task which doesn't want to yield, such task must be pre-empted first. This is done through a timer interrupt (which is typically 1ms in RTOSes). 1 ms is a very long time by MCU standards. And then the scheduler may give execution to a different task which it thinks needs execution faster. Here goes another 1 ms, and another, and another ...For example, you want to drive a pin high, then start a timer, get an interrupt from this timer 100 us later and, in the ISR, drive the pin low. Thus you hope to produce a 100 us pulse. Although this is not a good mechanism for producing pulses, this is a good example to demonstrate the time scale. If you relay the processing of the interrupt to the task-switching mechanism (because the ownership doesn't let you use the same pin from the ISR directly), the length of the pulse will be very far from 100 us. May be several ms instead. That's not you want.Then you need to get creative and think how do you circumvent the static ownership. For example, you may give the ownership of the pin to the interrupt code, then immediately invoke the interrupt (say with 100 ns timer) to drive the pin high and then start the real timer to drive it low. See what happened: the language forced you to change things a bit to satisfy its internal hunger, but didn't provide any benefits in return. You spent time fighting the language instead of concentrating on your direct tasks. Does that make you more productive. I doubt so.Or, am I misunderstanding the mechanism of the ownership?

author: ve7xen
author_rank: Super Contributor
timestamp: March 29, 2023, 12:55:52 am
content: Quote from: NorthGuy on March 28, 2023, 11:19:43 pmNo, you don't see. Ownership can change, but it must be possible for the compiler to analyze it statically and it must satisfy some constraints. In other words the compiler needs to be able to infer a chain of (mutable) ownership. That is not possible when you introduce arbitrary concurrency, such as interrupts or (usually) threads/tasks. It's no problem to pass around a peripheral reference to wherever it's needed in your code within the same thread, either returning it implicitly (borrowing), even from a shared static, or with explicit ownership transfers. The problem here is trying to transfer it across thread boundaries.Your view on what is 'harmless' seems...confused. It is definitely not harmless to let you do whatever you want in a concurrent context, there are countless ways this can go wrong. Concurrency is pretty difficult to get right in all but the most trivial of cases. In fact, it is usually difficult to show you aren't doing something stupid. It might 'work', but I think in a great many cases these things 'work' almost by accident and ignore many edge cases, for example the common read-modify-write semantics of GPIOs. What is useful about how Rust handles concurrency and ownership is that you can trust that if it compiles, you aren't doing something broken with concurrency, which is far more than most languages that can target microcontrollers can say about safe concurrency.If you really want you can just stuff the peripheral in a UnsafeCell and wrap your access in unsafe {} but this is kind of defeating the purpose of the conversation. It might be necessary and safe sometimes, but it's not really what we're talking about here, and if you're littering your code with this, you're holding it wrong and should rethink your design.QuoteWhether that task is the main loop, a green thread being run in an async exectuor, or a full-fledged RTOS task isn't really relevant, the point is that you safely 'send a message' out of interrupt context to where you can handle it more appropriately rather than try to do it in interrupt context itself. If you want to access it in the interrupt anyway, you can do so fairly easily with the pattern I showed above, which will be generally included in the processor support package, or use the built-in support in rtic or similar embedded runtime for this.QuoteNo it's not, you should improve the design.QuoteMore productive? Once you embrace and learn how to use it, I don't think these concepts make you *less* productive. But they certainly provide far stronger guarantees about the correctness of what you are doing, which is, at least to me, of a lot of value and removes one huge source of both errors and 'problem solving' for lack of a better word. The learning curve is pretty steep though, and I am coming to this opinion from my experience using it for traditional programming. I haven't explored it much in embedded space yet, but I absolutely see the benefits.QuoteThere are actually two concepts at play here. Ownership / borrow checker is one of them, the other is Sync/Send and concurrency. If peripherals were Sync+Send ('thread safe' basically), then they could be borrowed in interrupt context, but they aren't, so they need to somehow be wrapped in something that *is* Sync+Send. This is not difficult.

author: JPortici
author_rank: Super Contributor
timestamp: March 29, 2023, 05:27:00 am
content: Quote from: NorthGuy on March 28, 2023, 11:19:43 pmIf your system is multitasking, and the scheduler has enough resolution, use a delay in the task/raise the task priority/make it a critical section and wait.. there are always alternatives. When i'm using freestanding C i'm taking all the liberties i want, i have to do all the choices after all. Instead in a freeRTOS project, for example, i try to use whatever the OS gives me for the best, even if i have to start again with a new approach at some point. Your case would be an exception because i would reserve a peripheral to do the work, or write a tiny, tiny section of firmware that live outside of he framework. It is an exception.I always try not to share peripehrals between processes, but have a peripheral controlled by one process, then everything is between processes so the problem of sharing hardware never arises in the first place

author: Siwastaja
author_rank: Super Contributor
timestamp: March 29, 2023, 05:47:17 am
content: Quote from: ve7xen on March 29, 2023, 12:55:52 amOK, I think I have seen enough. As a summary, Rust is completely unusable for most microcontroller projects because the whole paradigm is designed around problems that are not relevant at all, and the solutions to these nonexistent problems limits what you can do with it greatly; clearly the importance of interrupt-driven programming was not considered during language design, but instead OS-type scheduling multitasking.There probably are workarounds that basically bypass the whole ownership system, but then the question is, is it sensible to use Rust, then?I can see Rust being used in a general computing type, non-realtime system which does not need the event-response type programming written on top of the peripherals and their interrupt requests.I still want to see a "better C" which fixes actual problems, those that cause real-life issues, whicharepossible to deal with language level; return addresses in stack, stack corruption, zero terminated strings, type system which is nearly OK but a bit too lacking resulting people to cast void* pointers.But this whole ownership system seems like a total disaster of complexity. If the issue is atomic access to peripheral registers, it can be dealt with much easier.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 29, 2023, 07:14:35 am
content: Quote from: karpouzi9 on March 29, 2023, 06:50:33 amHow would Hello World help me dispel the concerns I have about the Rust's ownership system being useful ininterrupt-driven real-time microcontroller development?QuoteYour post in particular simply shouts absolute non-technical stupidness to me.But now it's clear. This thread is polluted with the classical fanboyism, as always. Thanks for the "discussion".

author: uliano
author_rank: Regular Contributor
timestamp: March 29, 2023, 07:34:48 am
content: Quote from: Siwastaja on March 29, 2023, 07:14:35 amI found a feasible answer inrticwith the caveat that it is immature (API is changing fast) and that it is just a solution for distributing ownership across interrupt tasks which is kinda an artificial problem introduced by rust, therefore you need to be already curious/motivated to check out rust.QuoteAs always, it is everybody's choice to contribute to the content or to the noise...

author: wek
author_rank: Frequent Contributor
timestamp: March 29, 2023, 08:02:27 am
content: Quote from: Siwastaja on March 29, 2023, 05:47:17 amThe touted ownership feature may solve a problem which we don't have, and maybe there's no real solution in Rust for the real atomicity/concurrency/whaeveryoucallit problem; but that problem is hard, may have no good solution generally, and the language as such still may solve other problems which we do have (you've listed quite a couple of them above).So, it still may be the "better C", although not for the reasons its proponents put forth; and it may drag unwanted baggage in, but which language doesn't.JW

author: Marco
author_rank: Super Contributor
timestamp: March 29, 2023, 08:44:17 am
content: You can use unsafe global variables to your c programmer hearts content, objecting to rust for not having an idiomatic way to do it better is a bit silly. Finding the best way to do it better is an open problem, but doing it just as bad is always an option (with a slightly more headache inducing syntax).https://github.com/rust-embedded/not-yet-awesome-embedded-rust#sharing-data-with-interrupts

author: wek
author_rank: Frequent Contributor
timestamp: March 29, 2023, 09:09:14 am
content: > objecting to rust for not having an idiomatic way to do it better is a bit sillyRust is touted as the ultimate "safe" language, and the most pressing problem in mcu programming is atomicity/concurrency/whatevrryoucallit of variables/registers in main/interrupts. So, without knowing up front what exactly is meant by "safety", IMO it's a reasonable expectation that it encompasses this characteristic problem.Turns out, it doesn't. Let's move on.JW

author: tggzzz
author_rank: Super Contributor
timestamp: March 29, 2023, 09:56:04 am
content: I'll highlight a few comments I think important. The full context in ve7xen's post justifies them.Quote from: ve7xen on March 29, 2023, 12:55:52 amHaving noted those, if your market is such that getting to market fast is more important and having unreproduceable failures is less important, then I can understand that the existing tools may be preferable.

author: nctnico
author_rank: Super Contributor
timestamp: March 29, 2023, 10:08:08 am
content: Quote from: karpouzi9 on March 29, 2023, 06:50:33 amMore like lack of understanding which is also where I am at. I'm thankfull for the insights that people who actually use Rust provide in this thread. IMHO it takes a far deeper study to understand how to use Rust effectively on embedded targets like microcontrollers while leveraging the advantages Rust is supposed to give. I assume that will be completely different compared to C and shoehorning the 'C way' into Rust will just result in pain & poor code.One particular example of shoehorning one language into another is how VHDL and Verilog examples are typically put side to side where Verilog is translated into VHDL 1:1. In many cases VHDL provides a much better way of implementing the example due to the more extensive language constructs but the creator of the examples didn't know or didn't care.

author: baldurn
author_rank: Regular Contributor
timestamp: March 29, 2023, 01:19:44 pm
content: Quote from: NorthGuy on March 28, 2023, 06:33:07 pmI feel there is a big misunderstanding here. Nothing prevents you from writing an unsafe {} block in rust, casting a pointer to the GPIO block and just write to the damn IO pin. Bypassing the ownership model and everyting. Anything you can do in C you can also do in Rust in the exact same way, more or less. It is just unsafe code.In doing so you are _probably_ shooting yourself in the foot, but if you really think it is warranted, you just do it.In fact many fuctions in the Rust standard library are using unsafe blocks to implement stuff that can not be implemented in "pure" Rust. There are things where unsafe is the solution. If you isolate that to a few places and make sure that part of the program is well analyzed and understood, there is no problem. You can still use the safety of the language in the rest of the program.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 29, 2023, 03:29:28 pm
content: Quote from: baldurn on March 29, 2023, 01:19:44 pmI don't think there is any misunderstanding. Obviously you can bypass the "safety".How is that different from casting and storing typed pointers into void* in C, then back into typed pointers, something nctnico brings up? It's the same thing, language has the more "safe" feature available which is the recommended way to work with, but because it is possible to circumvent, people do exactly that - and then others complain that it's the language problem.What I realistically see is Rust programmer writing peripheral access functions (abstractions) and just wrap the implementation of said functions into unsafe{}, with parameter checking. It's exactly what I would do. But how is that different from the usual C counterpart, writing similar access functions and again doing parameter checks? Such C function is safe to call, too. The only difference I can see is the C's arrays decaying into pointers and not coupled with size; an error-prone process. Which is why I concentrate on that array bounds checking thing being a truly useful feature, but the ownership thing not so much.

author: baldurn
author_rank: Regular Contributor
timestamp: March 29, 2023, 04:00:03 pm
content: Quote from: Siwastaja on March 29, 2023, 03:29:28 pmI would suggest that most people will use the premade PACs where available. But you can of course easily make your own version and you could make your PACs more C-like than Rust-like if that is to your likening. Having not done so much Rust code myself yet, I can not be sure, but I believe that Rust-style is actually not so bad to work with as some here thinks.For simple programs I might agree that mixing up access to simple GPIO pins is probably not a huge deal. The available Rust PACs just implement pin ownership because they can and it is easy. It is better, at least in theory. And very easy to escape from if you find it a problem. You just put the "pin" into one of the available shareable container classes made for this purpose. Now it is the container that owns the pin and this container can be used from both your interrupt handler and main loop. You can choose a container that is a Mutex, or one that checks that there is no conflict at runtime or even one that is just "unsafe". No problem at all.But even if you chose unsafe IO there is still a lot to be gained from memory safety and concurrency safety etc. It has been claimed by big players such as Microsoft and Google that 70% of all security bugs are memory related. Why not use the language if it fixes just that one thing?

author: NorthGuy
author_rank: Super Contributor
timestamp: March 29, 2023, 04:04:36 pm
content: Quote from: baldurn on March 29, 2023, 01:19:44 pmBut I was thinking of a planTo dye one's whiskers green,And always use so large a fanThat it could not be seen.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 29, 2023, 04:29:34 pm
content: Quote from: ve7xen on March 29, 2023, 12:55:52 amThis about explains everything.You adopted the philosophy of a servant. In your mind, there must be a master who guides you through everything. And you have chosen Rust to be your master. You perceive "not being allowed" as a good thing. This gives you a feeling of safety. You're told that there many problems. You have chosen to be afraid of them. You have chosen to trust your master to guide you around them in the safest way possible, whatever that means.I however, adopted the philosophy of a free man. In my design, I can do whatever I want, nobody needs to allow me to do things. I perceive "not being allowed" as an assault to my freedom. I realize that there are problems out there. I have chosen not to be afraid of them. I have chosen to understand them and I I have chosen to learn to deal with them. As time goes by, I understand things better and better, and I will continue to learn until my brain stops working.So, happy rusting

author: ve7xen
author_rank: Super Contributor
timestamp: March 29, 2023, 05:13:19 pm
content: This discussion has focused on how Rust is not C, and doing things differently is bad.Let's shift the focus to some things that are useful and convenient, and not just about safety guarantees that like anything safety-related are often less 'convenient', just like using your fall protection when working at height is less 'convenient' and a lot of people will be opposed to it, despite it saving many lives.1. 'Enum Types' (aka. algebraic data types, sum types, tagged unions) and the match operator:Code:enum Message {One(u32),Two(String)}fn main() {let foo: Message = Message::One(10);let num = match foo {Message::One(uint) => uint,Message::Two(s) => s.len() as u32,};}There is no equivalent of this in C or C++, and it is so useful and ergonomic. Match is also much more powerful than suggested here, it can include predicate conditions in addition to the demonstrated type matching, and of course classic 'switch/case' type conditions, etc. This is also used throughout core and std, for example the useful Result (returns an Ok type that wraps a result, or an Err type that wraps an error result) and Option patterns (return a wrapped type or None). Since this leverages the static type system, there is no storage cost.2. 'Traits' (aka. interfaces, mixins)Code:// Adding to the aboveimpl ToString for Message {fn to_string(&self) -> String {match self {Message::One(uint) => uint.to_string(),Message::Two(s) => s.to_owned(),}}}// Then we can pass anything that implements ToString as a parameter as a virtual call:fn stringable(foo: &impl ToString) {println!("{}", foo.to_string());}// Or statically (generate new code for each T)fn stringable2<T: ToString> (foo: T) {println!("{}", foo.to_string());}There are a host of standard traits in the library, and they can be used for things like automatically parsing strings to other types, converting/coercing between types, operator overrides, comparisons, and many other common tasks.You can do this in C++ with multiple inheritance, but it's a lot less clean and avoiding dynamic calls is a lot more difficult (maybe impossible? not a template expert).3. First-class closures and good iterators/functional primitivesCode:let pred = |x: &&u32| x < &&10; // Yes this looks a bit ugly, it's not as silly for non-primitive typeslet data: [u32; 5] = [1,11,2,12,15];let sum: u32 = data.iter().filter(pred).sum();println!("{}", sum);3C++11 has closures, but they aren't as ergonomic and it's lacking a lot of functional methods. C++20 can do the above (I think), but it's not nearly as clean.4. The 'question mark operator' / error handlingCode:fn foo() -> Result<u32, MyError> {let number = something_that_returns_a_result()?;}This is shorthand to unwrap the result if it's Ok, otherwise coerce to the error type of our result and return that. When you actually need to handle the error, you can use `match` or the similar `if let`. Not exceptions, and far more ergonmic than constantly wrapping calls in if() and returning sentinel values or whatever. C and C++ both suck at this and most programmers seem to prefer to not do any error handling at all.And general observations: Type inference is awesome, and I haven't tried a language that is better than Rust at it (though I haven't ever ventured into things like Haskell). Rust's compiler errors are the most useful I have ever seen. The language seems to minimize boilerplate, while not generally feeling like it's constraining my style or forcing a particular approach. Learning how to contend with the borrow checker and lifetimes is challenging, but once you grok it, it doesn't really get in the way.QuoteWow, just...wow. What an absurd take. Rather, it is the opposite. I have taken the view that I'd rather let my tools do the hard work of figuring out if what I'm doing makes sense. I'm going to stop wasting my time responding to you.

author: nctnico
author_rank: Super Contributor
timestamp: March 29, 2023, 05:24:37 pm
content: I have to say I find the syntax of Rust very cryptic. The meaning of the examples above is not clear at all to me. I get that the creators of Rust wanted to avoid getting slapped for creating a too verbose language like Ada/Pascal/VHDL but IMHO they went a bit overboard. It makes it hard to do a code review unless you are really intimate with the language.

author: baldurn
author_rank: Regular Contributor
timestamp: March 29, 2023, 05:43:56 pm
content: Quote from: nctnico on March 29, 2023, 05:24:37 pmI come from a background in computer science. I know Haskel and several other functional languages. I have worked a fair amount Scala (a functional language on the JVM / alternative to Java). I have worked with libraries that do a lot of type system magic. Many of the concepts in Rust translate very well. I do however fear the learning curve is going to be steep for someone who has only done C or has not previously been exposed to much functional programming paradigm.In the Scala community they have the same problem. So they made "levels" that represent reduced set of the language. The idea that the beginner is guided to learn the most useful parts of the language before getting confused by advanced concepts.For me the problem with Rust has been mostly the documentation and specifically the auto generated API documentation. Nothing wrong with generating documentation from source code, but even the standard library seems to have a lot of methods that have just one line, actually only a shortened sentence, as a description. You are apparently supposed to recognize what this is about just from the name of the function and the function signature. This part is really subpar :-( The thing is for a learner you don't know how things fit together, plus parsing the signatures can be very hard. Double so if you are not used to read signatures with a lot of type variance, which might be concepts you do not really understand that well.

author: tggzzz
author_rank: Super Contributor
timestamp: March 29, 2023, 06:15:38 pm
content: Quote from: NorthGuy on March 29, 2023, 04:29:34 pmNow you are just being a twat.Yes, that is an ad hominem attact, one that is justified IMNHSO.

author: nctnico
author_rank: Super Contributor
timestamp: March 29, 2023, 06:34:42 pm
content: Quote from: baldurn on March 29, 2023, 05:43:56 pmNot sure whether the spoon fed approach is a good one. Many will stick with the simple concepts and never be willing to use more efficient constructs. When I started with VHDL I always looked how I could get the most done with as little code as possible. It is not very productive in the beginning but it pays back later.QuoteThat is a big fail. Automatically generated documentation is outright useless because the coherency between the parts gets lost. How the parts fit together and how they are to be used is the most important information a user for a library needs. Someone should add ChatGPT to Doxygen as a code analysis tool and produce documentation. It will be an improvement for sure... But maybe (hopefully) there is a book about it.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 29, 2023, 06:40:21 pm
content: Quote from: tggzzz on March 29, 2023, 06:15:38 pmThat's true - but after all the snake oil selling and the utter "you are not just open to new things" bullshit* that comment made me chuckle out loud.*) it's weird how some people always assume asking for data, andshowingthat something is not suitable for a specified task,basedon data, is some kind of irrational "not liking change" reaction. Maybe, just maybe, we are not old bitter greybeards, butengineerswho would not buy a capacitor if it has no voltage rating listed, and once found out that the voltage rating is 50V and our DC bus is 80V, then not buy the capacitor. But this is actually totally unsurprising - people project their own values into others. If one chooses to be interested in a programming language out of pure interest, then it's logical to assume others who don't reach the same conclusion do that out ofdisinterest. This is not necessarily the case. For example, I have commented multiple times which features I find useful (array bounds, more powerful type system) and which are the pain points (difficult to understand ownership system that does not seem to actually solve concurrency in interrupt-driven microcontroller designs at all). Yet, any of this does not matter - I'm being labeled a greybeard who is not open to the new things. So let it be that way, then; thumbs-up to NorthGuy's comment.

author: tggzzz
author_rank: Super Contributor
timestamp: March 29, 2023, 07:43:11 pm
content: We have all seen new mousetraps that are merely incremental variations on existing mousetraps. Boring.I am always looking for a better mousetrap, where "better" "different" and "worse" all need to be specfied. TINSTAAFL.Rust appears on the surface to be significantly better in some ways, but I do not yet understand the significant "different" and "worse" aspects. They will be more widely understood when many people have kicked the tyres.And that's why I've stayed in this thread. or nutcrackers or, judging by the number and variety of Victorian patents, Apple corers.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 29, 2023, 08:50:40 pm
content: Quote from: ve7xen on March 29, 2023, 05:13:19 pmThat's not what most of the posts I've read or written here are about. If that's what you read, read again. IMHO.Quote from: ve7xen on March 29, 2023, 05:13:19 pmThat's not at all what most posts here are about either.I have actually not seen any real comparison of Rust with C in this thread, but more general considerations about programming languages and how Rust may not be as useful as it's hyped to be, at least for embedded software. It's more about how Rust *may* not actually address the issues that are mainly encountered for embedded dev rather than about how C would be better. You keep mentioning C, while very few other people have actually mentioned it except to reply to bluntly false assertions.But maybe trying to make it all look like a Rust vs. C battle, you are cornering Rust proponents into some victim position, shutting down all discussion after that.Actually most people here have said that C was ridden with its own issues and that something "better" would be nice, but have argued that Rust may not be the answer.If you don't like that idea, sorry to hear that.I have appreciated that the OP has posted links to actual projects in Rust that we can all have a look at. That's better than blind promotion.Unfortunately, we are failing to see any real-world metric that would prove it yields undoubtedly "safer" products while keeping productivity at a reasonable level, so it's often a lot of talk and some whining as soon as some people dare question its benefits.

author: coppice
author_rank: Super Contributor
timestamp: March 29, 2023, 09:48:40 pm
content: Quote from: tggzzz on March 29, 2023, 07:43:11 pmWell we all know its a waste of time creating a new Nutcracker, when people love the Tchaikovsky one so much.

author: tggzzz
author_rank: Super Contributor
timestamp: March 29, 2023, 11:26:22 pm
content: Quote from: coppice on March 29, 2023, 09:48:40 pmI dislike Tchaikovsky with a vengence. Put me off classical music for years.I have found exactly one nutcracker that I like using; I've been using it for more than half a century. Even so, it isn't wonderful with brazil "nuts". Memo to self: find a tool that is better for that use case.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 30, 2023, 04:20:28 am
content: Quote from: tggzzz on March 29, 2023, 11:26:22 pmTo each their own.Quote from: tggzzz on March 29, 2023, 11:26:22 pmMaybe something involving XMOS?

author: wek
author_rank: Frequent Contributor
timestamp: March 30, 2023, 07:47:32 am
content: Quote from: ve7xen on March 29, 2023, 05:13:19 pmThanks for the overview.However I am not sure whether all these - and other advanced techniques/features - are that much applicable to microcontrollers programming.I understand that with increasing chip density(*) the perception of mcus among developers is shifting towards "general-purpose computer with some annoying peripherals" (see HAL, multitasking, etc.); thus principles applying to general-purpose computers increasingly apply to mcus too.However, I am coming from the "annoying peripherals" side, seeing C as a "better asm", feeling uneasy when the "oh there's surely enough memory" argument comes and being overwhelmed by the levels of abstraction in modern languages. I am afraid it would take me too much time to see clearly the connection between those constructs and the generated and run binary - and I need that understanding to be able to judge the impact of using any such construct to the actual workings of the mcu.Also, I personally enjoy more reading a couple dozens of pages of manuals and poking the hardware using primitive methods, rather than observing how a few lines of highly abstract code translates into a complex yet perfectly functional product.Quote from: ve7xen on March 29, 2023, 05:13:19 pmI don't find the work of spelling out explicitly what I intend to do that hard.JW(*) R.I.P., Gordon Moore.

author: tggzzz
author_rank: Super Contributor
timestamp: March 30, 2023, 08:02:27 am
content: Quote from: SiliconWizard on March 30, 2023, 04:20:28 amNah.IhavegoodtasteI came across the received wisdom embodied in Peter Ustinov's anecdote thattheanswer to "name a Russian composer" is "Tchaikovsky" (Rachmaninov was an incorrect answer!)Similarly I never thought Beethoven was "the best composer". I always preferred JS Bach, Scarlatti, and others.QuoteCertainly not. The plastic is too soft.

author: coppice
author_rank: Super Contributor
timestamp: March 30, 2023, 12:30:11 pm
content: Quote from: tggzzz on March 30, 2023, 08:02:27 amThe correct answer to "name a Russian composer" is Rimsky Korsakov. Have you heard how they play the flight of the bumble bee?The Nutcracker really is a great work for introducing your children to the classics. Taking our daughter, and later our son, at about 4 years of age to see the Nutcracker performed with a live orchestra by a really good ballet founded their appreciation of great music and theatre.

author: Marco
author_rank: Super Contributor
timestamp: March 30, 2023, 04:32:18 pm
content: Quote from: SiliconWizard on March 29, 2023, 08:50:40 pmTime is running out to be a contender. Billions of dollars are going to cement the winner of the memory safe system programming language race soon, Rust and ADA Spark seem the only contenders.Unless the C++ standards committee pulls a rabbit out of a hat and stops writing more guidelines and and instead creates a machine verifiable safe C++ subset, while also replacing exceptions with something more sane (and thus the standard library).

author: Siwastaja
author_rank: Super Contributor
timestamp: March 30, 2023, 05:06:05 pm
content: Quote from: Marco on March 30, 2023, 04:32:18 pmExcept this is just a buzzword. Everything relates to memory, every variable and data structure is in memory, and if you can do anything at all with data, you can also do mistakes. You can remove some types of errors like accessing array Y through overindexed array X, but this is just the tip of an iceberg; you can still accidentally access Y when you wanted Y and so on. The rest is just nontechnical brand work, like defining a term like "memory safe" in a way which allows you to call your product "memory safe".For something that doesn't even have a standard, I don't know. <New language X> fanboys always place their bets on safety critical industries such as aviation because it "sounds cool" and they themselves think it's convincing, but safety critical industries specifically require a long legacy to the level or being boring and just barely functional due to actual greybeardism way above people like NorthGuy who is, I'm sure, totally open to any solution he finds useful.

author: tggzzz
author_rank: Super Contributor
timestamp: March 30, 2023, 05:15:20 pm
content: Quote from: Marco on March 30, 2023, 04:32:18 pmFat chance!In the early-mid 90s the committeeflatly denied that the STL was a Turing complete programming language - until Erwin Unruh forcibly rubbed their noses in it by causing thecompilerto generate the prime numbersduring compilationspent years discussing whether or not to require/forbid "casting away constness"; there are good reasons for either decisionand even this millennium it was necessary for Hans Boehm to produce his famous paperhttps://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf"Threads Cannot be Implemented as a Library"That convinced me that C++ was a castle built on sand, and nothing has caused me to change my mind since.

author: coppice
author_rank: Super Contributor
timestamp: March 30, 2023, 05:17:50 pm
content: Quote from: Marco on March 30, 2023, 04:32:18 pmTime ran out for anything in the ADA sphere a long time ago. If you build a new language on one that was only ever used when the customer said it must be used, you are probably only trying to appeal to the same niche's updated thinking.

author: Marco
author_rank: Super Contributor
timestamp: March 30, 2023, 06:25:37 pm
content: Quote from: Siwastaja on March 30, 2023, 05:06:05 pmNah, it's justimprecisely defined. The minimum definition is just that the program isn't allowed to access un/deallocated memory.QuoteUS government Billions can get things moving quickly. NSA and congress talking about memory safety is the reason Bjarne has been talking up C++'s ability to be memory safe (convincing absolutely no one, they lack the will to do what is truly necessary).

author: Marco
author_rank: Super Contributor
timestamp: March 30, 2023, 06:27:47 pm
content: Quote from: coppice on March 30, 2023, 05:17:50 pmBecause US government allowed alternatives ... money talks.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 30, 2023, 07:50:34 pm
content: Quote from: Marco on March 30, 2023, 04:32:18 pmNot only "memory safe" is largely a buzzword, possibly focusing on the wrong problem, as some of us have said, but that aside, your statement above has the benefit of making clear what it's all about: marketing and money. It's a political and commercial affair, not an engineering or scientific one. And the buzzwords have all their place.

author: ve7xen
author_rank: Super Contributor
timestamp: March 30, 2023, 08:06:05 pm
content: Quote from: nctnico on March 29, 2023, 06:34:42 pmThis is absolutely my biggest sticking point with it too. The Rust Book is a pretty good introduction to a lot of the language concepts, but it has nocontext. When I'm learning a new language I tend to spend most of my time in the library/API documentation sections poking around the bits I think will be useful to the problem I'm solving. Usually these docs will include context-aware usage examples which are idiomatic, and help with understanding how to compose useful things out of the language concepts. To me this is what is lacking most. Once you understand that so much behaviour is driven by Traits, you learn to follow the trail of Trait implementations to find some documentation on how they're meant to be used, but again, these docs & examples lack the context of the struct implementing them, which doesn't help much with idiomatic usage of a given library. Not to even get into how difficult it is to make sense of what the type generics are being used to do. Huge room for improvement here, especially (obviously) with embedded that is much newer in the ecosystem.QuoteThe thread at large, no, but the chain of posts I was referring to was a lot of 'I want to do <thing I can do in C> in Rust and it sounds like I can't'. In general, any comparison or 'subjective' evaluation may not explicitly be with respect to C, but it's a pretty darn safe assumption in this space. Whether or not that's the case in the thread, the point was to bring some things folks might/probably not know about if they haven't looked at Rust past the surface, which I haven't seen a lot of discussion about.QuoteIf I'm mischaracterizing the conversation, I think this is doing the same. My main point is not even about safety, despite that people seem to think this is all Rust has to offer. Whether or not this leads to fundamentally safer products in the end is not really an answerable question. There's a) far more to it than thread/memory safety and b) other ways to prove/test/guarantee the system is working properly (though these are generally a lot more expensive than a few seconds of compile time). But when I'm wearing my developer hat, I certainly appreciate having two fewer things that can be fraught with hidden pitfalls to think about, and which I will certainly get wrong eventually, no matter how good I think I understand what I'm doing. Outside of embedded, which is still averyopen question for me, I have found it's just a pleasant and capable tool to use. It offers all the performance of other low-level languages, but far more modern niceties, most of which are 'free' at runtime, which for me makes it nearly as usable as something like Python.Does that transfer to embedded without creating undue friction? Still trying to figure that out, but I don't think there is a way to know without getting your hands dirty and actually learning the language, because it is fundamentally so different. From what I've done so far, I think it is not ready yet, the HAL APIs aren't stable enough/have some warts, too much type ugliness shows through to the application, and as mentioned the documentation - but these are notlanguageissues and it seems things are improving rapidly. If you just want to bang on the registers via PAC and manage concurrency yourself, I think it's quite usable, but the learning curve is quite steep.

author: tggzzz
author_rank: Super Contributor
timestamp: March 30, 2023, 08:09:13 pm
content: Quote from: SiliconWizard on March 30, 2023, 07:50:34 pm"Memory safety" is not largely a buzzword."Memory safety" is not the whole solution, by any means."Memory safety" is an important and useful mechanism of reducing common and widespread defects.Defects introduced by suboptimum tools waste valuable engineering attention, time (and money).Much more profitable to focus engineering attention where it belongs: on understanding the task at hand and creating a solution to the problems inherent in the task. Not problems in the tools.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 31, 2023, 04:51:18 am
content: Memory errors are symptoms of other problems - they can be caused by many things - typos, miscalculations, misunderstandings, design failures, etc. etc. In each particular case, the cause must be found and fixed. Curing symptoms, even if possible, will not cure problems.For example, people cough, which is a bad thing and may be a symptom of various diseases. If everyone would be required to wear a special collar which makes coughing physically impossible, this would hardly cure anyone.

author: Siwastaja
author_rank: Super Contributor
timestamp: March 31, 2023, 06:47:13 am
content: Quote from: NorthGuy on March 31, 2023, 04:51:18 amOn the other hand, if coughing becomes impossible, that will reduce the spread of the disease to others. Disease still needs to be cured, but consequences are less serious. That's the whole point of mechanisms such as preventing access to other unrelated memory through overindexing an array, and some of them are relatively easy to implement, so called low hanging fruits.

author: tggzzz
author_rank: Super Contributor
timestamp: March 31, 2023, 11:32:34 am
content: Quote from: NorthGuy on March 31, 2023, 04:51:18 amYou "forgot" to add that they can be caused by choosing a poor tool for the job.Avoidance is better than cure.QuoteThat's a revealing analogy. More analogies like that will help all readers of this thread.

author: coppice
author_rank: Super Contributor
timestamp: March 31, 2023, 12:06:31 pm
content: Quote from: tggzzz on March 31, 2023, 11:32:34 amJust because they aren't very good programmers, you shouldn't call them a tool. I assume that's what you meant. By far the biggest factor in the success of any software development is the quality of the people, not the quality of what they use. The average slob can make a disaster out of anything.

author: tggzzz
author_rank: Super Contributor
timestamp: March 31, 2023, 01:05:39 pm
content: Quote from: coppice on March 31, 2023, 12:06:31 pmNeat misinterpretationI wonder how well the joke is understood by those for whom English is a second language (and that includes left-pondians).

author: uliano
author_rank: Regular Contributor
timestamp: March 31, 2023, 01:55:33 pm
content: Quote from: tggzzz on March 31, 2023, 01:05:39 pmAs a non native english reader I fell into a huge rabbit hole.

author: baldurn
author_rank: Regular Contributor
timestamp: March 31, 2023, 09:55:10 pm
content: So I was thinking of the poor documentation and why don't they just use ChatGPT to improve the documentation? Then I thought why don't _I_ use ChatGPT to get better documentation? And so I tried this prompt:"I need documentation with examples for embedded rust HAL and PAC for use with RP2040"And what do you know? It started giving me much better documentation on exactly that :-)Funny enough it made an example for the timer using unsafe:TimersThe RP2040 features timers that can be used for timekeeping, delays, and generating periodic events.Example: Timer InterruptCode:#!#!use cortex_m_rt::{entry, exception};use hal::clocks::{init_clocks_and_plls, Clock};use hal::gpio::{GpioExt, Input, Output, PullDown, PullNone};use hal::sio::Sio;use hal::timer::Timer;use pac::{interrupt, Peripherals, TIMER};use cortex_m::peripheral::NVIC;static mut LED_TOGGLE: bool = false;#fn main() -> ! {let pac_peripherals = Peripherals::take().unwrap();let sio = Sio::new(pac_peripherals.SIO);let pins = hal::gpio::Pins::new(pac_peripherals.IO_BANK0, pac_peripherals.PADS_BANK0, sio.gpio_bank0, &sio);let mut led = pins.gpio25.into_push_pull_output();let mut timer = Timer::new(pac_peripherals.TIMER);timer.init_interrupt(1_000_000.hz());// Enable the TIMER_IRQ_0 interruptunsafe {let mut nvic = NVIC::new();nvic.enable(interrupt::TIMER_IRQ_0);}loop {if unsafe { LED_TOGGLE } {led.set_high().unwrap();} else {led.set_low().unwrap();}cortex_m::asm::wfi();}}#fn TIMER_IRQ_0() {let mut peripherals = unsafe { Peripherals::steal() };peripherals.TIMER.ints.modify(|_, w| w.timerr().set_bit());unsafe { LED_TOGGLE = !LED_TOGGLE; }}In this example, we configure a timer to generate an interrupt every second. The TIMER_IRQ_0 interrupt handler toggles the LED state and clears the interrupt flag.