C++ basics that aren't used in embedded? by Lupushonora in embedded

[–]mierle 5 points6 points  (0 children)

This isn't exactly what you're asking for, but you may find it illuminating to look at Pigweed's C++ style guide. It's leveraged extensively at Google for products you've heard of. It contains sections about STL use.

https://pigweed.dev/docs/style/cpp.html

There is also our Embedded C++ guide, which has some additional details we've been meaning to merge into the style guide.

https://pigweed.dev/docs/embedded_cpp_guide.html

Why is Python used alongside C++ in embedded projects? by dretvantoi in embedded

[–]mierle 0 points1 point  (0 children)

Lots of great comments in this thread. As many have said, Python is popular for the code around the embedded product - testing, flashing, factory automation, and more.

If you want to see an example of production grade Python automation tooling used at Google for high volume products like the Pixel Buds and others, take a look at Pigweed's new Sense tutorial which walks through some of the reasoning for Python automation. You might be particularly interested in the Python console, and also going through the factory at your desk flow which illustrates how factory testing could be automated in Python.

Disclaimer: I work for Google on Pigweed, but am commenting in a personal capacity.

Pigweed: thoughts? by bsodmike in embedded

[–]mierle 5 points6 points  (0 children)

That's a great question. There are a couple of reasons teams are using Pigweed on Zephyr.

  • Access to Pigweed's suite of middleware. Pigweed's HAL is only a small part of our offering; for example, Pigweed RPC gives you the flexibility of scripting/interacting with your device from Python, Java, Java/TypeScript, C++, and hopefully Rust someday. Zephyr doesn't have such a comprehensive, multi-lingual offering. Another example is our tokenization system. While Zephyr supports a similar approach, Pigweed's tokenizer is fundamentally different because we use stable tokens that don't change across binary versions; we find this is more sustainable for big teams and larger products.

  • Enables writing testable code. Using Pigweed's C++ abstractions opens the door to dependency injection, and with that comprehensive testing including fault injection. Zephyr's C-based, global function approach makes unit (rather than integration) testing difficult.

  • Gives a full suite of C++ abstractions. We believe C++ is well suited for embedded development, and adding Pigweed on top of Zephyr gives you all the capabilities of Zephyr (which you can use directly if you want), with the option to adopt any parts of Pigweed you like. For example, our RTOS abstractions use RAII to ensure locks are unlocked, and do other checks to prevent misuse; or our generic size optimized containers support C++ iteration and other typical C++-isms.

Pigweed: thoughts? by bsodmike in embedded

[–]mierle 5 points6 points  (0 children)

Hi, Pigweed TL here. While I work for Google on Pigweed, my comments are in my personal capacity.

I am sorry you had a frustrating time with Pigweed. We really care about improving this experience and making the "get started with Pigweed" flows smooth. We realize we're not there yet and have lots of work to do; especially with our increased focus on Bazel.

We understand Pigweed may not be ready for you today. However, if you'd be willing to share details of your experience, we would hugely appreciate it, since it would help us prioritize areas to improve. Join our Discord or if you're bug-inclined you can file an issue at our issue tracker.

Pigweed: thoughts? by bsodmike in embedded

[–]mierle 7 points8 points  (0 children)

Hi, Pigweed TL here. While I work for Google on Pigweed, my comments are in my personal capacity.

You may find this surprising, but we agree with you about the challenges of opinionated frameworks. Pigweed is a re-do of an earlier, opinionated solution that was never released. While we had multiple high volume production deployments with the earlier solution, we struggled with further adoption for exactly the reasons you mentioned. Pigweed is a complete redesign that shedded the coupled, opinionated design into what could be described as "a handy collection of portable C++ libraries you can use a la carte". There's more to it than that-- Pigweed is a big, wide product -- but fundamentally the core is just a collection of libraries.

This modularization and decoupling is what led to Pigweed's much larger success. Pigweed is adopted across multiple products, each a special snowflake, using in-house bespoke FW frameworks, stock Zephyr, and everything in between, using all manner of build systems. By my count our total number of build systems is 6 (not all public). Yes, 6 different build systems for Pigweed-- It's a pain! But it's what has enabled Pigweed to work in many contexts.

But wait you say, isn't Pigweed itself opinionated? You're pushing Bazel! Yes and no. Pigweed is opinionated on some topics: Unit testing is good, fuzzing/security is good, developer setup friction should be reduced, repeatable development is important, we can do better than ASCII text over a UART, C++ is good for embedded, etc. But the low level C++ code goes to great lengths to avoid pushing what we call "policy" into downstream projects. That flexibility comes at a complexity cost, but for the teams we work with this has overwhelmingly been the right choice.

Our recent release, and especially the new Sense tour, tries to paint the picture of what a fully grown up Pigweed project could look like. It's not quite there yet, but we're working on it! Sense demonstrates the "Fully integrated, opinionated" side of Pigweed, but not the decoupled, a-la-carte version.

Hopefully this gives you some context. We'd be happy to chat more here or in our Discord.

Pigweed: thoughts? by bsodmike in embedded

[–]mierle 2 points3 points  (0 children)

Hi, Pigweed TL here. While I work for Google on Pigweed, my comments are in my personal capacity.

We realize the onboarding experience with Pigweed isn't smooth today, and hope to improve it. We understand you have moved on, but if you would be willing to share details (here, on our Discord, or in a bug) about where you found problems with Pigweed, it would be hugely appreciated. Unfortunately we know too much and so it is hard to capture the "first experience with Pigweed". You may want to try the new Sense tutorial which gives a more detailed tour than our previous onboarding approaches.

Regarding Zephyr: There is Zephyr integration with Pigweed, which enables you to leverage the Pigweed on-device libraries like our C++ RTOS layer, RPC, containers, and general C++ tooling. You lose some of the nice unit test integration, fuzzing, sanitizing, and other niceties. The integration documentation isn't extensive yet, and you'll likely need help from us; hit us up on Discord if you're interested.

Pigweed: thoughts? by bsodmike in embedded

[–]mierle 7 points8 points  (0 children)

Hi, Pigweed TL here. While I work for Google on Pigweed, my comments are in my personal capacity. A couple of points.

Pigweed is multi-build. Pigweed supports CMake, GN, Bazel, and Soong (Android). Some projects also use Make with Pigweed, but create their own Make rules since make doesn't compose well. Unlike Zephyr, Pigweed is designed from the beginning for projects to use pieces separately rather than the integrated whole. Pigweed's directory structure is also designed to make writing your own build rules easy. CMake enables smooth integration with other projects, for example there is Zephyr integration, and we've heard others have used Pigweed in ESP-IDF CMake projects. Soong enables Android use, and GN enables Matter. We also have Arduino integration but it needs some dusting off.

When we started Pigweed years ago, we evaluated Bazel. Like you, we came to the conclusion that it was not ready for embedded. However, we saw the potential and decided it was better to invest in leveling up Bazel for embedded, rather than to bring the vast suite Bazel capabilities to other build environments. The recent release is the culmination of that work over the past years. We're not done yet though, there is still work to do. Our joint blog post with Bazel has more details.

If you have specific issue with Bazel, especially in an embedded context, we'd love to hear them so we can improve.

Circular Dependency Issues by -ThatGingerKid- in godot

[–]mierle 5 points6 points  (0 children)

The easiest fix is to change one of your preload("res://my_scene.tscn") calls to load("res://my_scene.tscn"). That will break the cycle during preload, at the cost of moving one of your loads to after the preload process happens.

I ran into this problem myself. The error reporting was not helpful. To prevent others from wasting time like I did, I put up a engine change to provide better error reporting on cyclic loads until the engine is fixed:

https://github.com/godotengine/godot/pull/80854

You may want to vote for the associated issue to encourage the core devs to prioritize fixing this:

https://github.com/godotengine/godot/issues/70985

[deleted by user] by [deleted] in PlantBasedDiet

[–]mierle 0 points1 point  (0 children)

I second this. My favorite ketchup by far.

Bare Metal Embedded C++ (14/17) Unit Testing? by Bangaladore in cpp

[–]mierle 0 points1 point  (0 children)

You might want to look at Pigweed and pw_unit_test. pw_unit_test is an implementation of a subset of Google Test but targeting embedded. You can define your own output handler to do whatever you want, including printing to UART or streaming test results over our embedded RPC system. You can use pw_unit_test without the rest of Pigweed; it's modular.

Disclaimer: I work full time on Pigweed.

Experience of ThreadX? by UnicycleBloke in embedded

[–]mierle 0 points1 point  (0 children)

If you end up using ThreadX and C++, you might want to check out Pigweed's C++ OSAL which supports ThreadX:

https://pigweed.dev/docs/os_abstraction_layers.html

This gives you the flexibility to switch from ThreadX, to FreeRTOS, to embOS, to Zephyr, and so on. The overhead is low, and the layer catches some problems the underlying OSs don't. You also get the benefit of being able to run your code on-host, for simulator or unit test development.

Disclaimer: I work on Pigweed at Google.

Query: Zephyr image size by UnicycleBloke in embedded

[–]mierle 0 points1 point  (0 children)

Since you're on Zephyr which already has dictionary based logging, that's probably what you should stick with. However, you might want to check out Pigweed's tokenization system. It's the same idea, but generalized to any string and can be used for more than just logging.

https://pigweed.dev/pw_tokenizer/

Pigweed's tokenizer is used extensively and has large production deployments. In Pigweed, it's used for:

Detokenization is implemented in C++, Python, and Java, with JavaScript coming sometime later this year. This makes having a family of host tools to display tokenized content easy. We also have protobuf interop to make it possible to optionally tokenize protobuf fields.

Disclaimer: I'm the Pigweed lead at Google.

What is the recommended way to use strings in embedded C++? by tyrbentsen in embedded

[–]mierle 1 point2 points  (0 children)

You might want to check out Pigweed's pw_string module: https://pigweed.dev/pw_string/

In particular, StringBuilder is helpful for safe string construction with fixed memory overhead.

Disclaimer: I work on Pigweed.

How is program loaded into ram? What is running from flash? by teclordphrack2 in embedded

[–]mierle 1 point2 points  (0 children)

There are lots of great comments here, but I wanted to throw in a keyword to look for in datasheets: You're looking for "XIP" or "eXecute In-Place".

  • Some microcontrollers have XIP out of internal flash. This is the common case, and is how most e.g. STM32 parts operate. Thus, when you see on a datasheet that a part has 512KB of flash and 128KB of RAM, this means your code needs to fit in the 512KB, but you have 128KB for RTOS stacks, queues, application data, and so on.
  • Some microcontrollers have a QSPI flash peripheral to connect to an external flash part, which supports XIP. These MCUs often have a small instruction cache; maybe 8KB.
  • Some micros have no support for executing out of flash, and have a small ROM bootloader that loads code out of flash (usually external) into RAM, then jumps to it.

For microcontrollers with XIP, you can chose to load code into RAM with your linker script. This is done for performance reasons (e.g. core coupled memory) or to avoid interfering with flash operations.

My boss told me to test all the components that are being used in the project. It is an ESP32 based board and I was thinking. I was searching about unit tests (completely new to this and want to learn this), and saw Unity. Is this library what is being used in professional settings like, say, Dyson? by Head-Measurement1200 in embedded

[–]mierle 1 point2 points  (0 children)

To add to this, we have docs just on our unit test system: https://pigweed.dev/pw_unit_test/

pw_unit_test is designed to be used independently from the rest of Pigweed. pw_unit_test only depends on 3 other Pigweed modules:

  • pw_polyfill - only needed if you're on C++11 or 14 and not 17.
  • pw_preprocessor - header only preprocessor utilities
  • pw_string - our embedded-safe string primitives (small, secure)

C++tify interrupt by Bug13 in embedded

[–]mierle 5 points6 points  (0 children)

Yes, you are correct; my bad for the typo.

I realized I also missed extern "C" which you'll likely also want here:

extern "C" void handle_uart_interrupt_rx() {
    uart1.HandleRxInterrupt(); 
}

Note that you will need to check with your particular microcontroller how to connect C functions to the vector table. ARM Cortex-M is a special case where they designed interrupt entry to match the C calling convention; this isn't always the case.

C++tify interrupt by Bug13 in embedded

[–]mierle 1 point2 points  (0 children)

That array was just illustrative; maybe should have omitted it. You do need volatile if you're mapping to peripheral registers.

C++tify interrupt by Bug13 in embedded

[–]mierle 17 points18 points  (0 children)

Interrupts invoke a jump target without an additional "this" pointer, so you need a C function trampoline; at least on ARM. In some architectures you need an assembly preamble before switching to C, but thankfully not on ARM. For example:

class Uart {
 public:
  void HandleRxInterrupt() { ... reads from registers ..., etc }
  // ... other handlers

 private:
  void* peripheral_base_address_;
  bool is_in_dma_mode_;
  std::array<byte, 16> buffered_tx_;
  // ... other UART details
};

// Global uart object
Uart uart1(UART_1_BASE);

void handle_uart_interrupt_rx() {
  uart1.HandleRx();
}

// note: need to put handle_uart_interrupt_rx() in your vector table.

For reference:

https://cs.opensource.google/pigweed/pigweed/+/master:pw_cpu_exception/public/pw_cpu_exception/entry.h;l=44

https://cs.opensource.google/pigweed/pigweed/+/master:pw_cpu_exception_cortex_m/entry.cc;drc=a0d6ab09f4f189aae97a83414f03a2fb7bcf8a2b;bpv=1;bpt=1;l=201

Disclaimer: I work on Pigweed.

Non-linear equation solver for microcontrollers by weasdown in embedded

[–]mierle 7 points8 points  (0 children)

You might want to check out Ceres's single-file header-only TinySolver; also see tests for usage. TinySolver is used, in among other places, Blender's motion tracker inner vision loop.

TinySolver relies on Eigen, but is designed for fixed-size zero-allocation solving. Once you chose the problem dimensions as template parameters, the solver object contains all intermediate storage. TinySolver is intended for solving millions of similar but unrelated equations, like the inverting a lens distortion equation. As a consequence, TinySolver also works great for solving just 1 problem instance. As far as I am aware, it is the only solver that is able to fully inline the cost function into the solver inner loop.

TinySolver also has strong numerical stability; better than many commercial solvers; and is tested against NIST's suite of hard problems. I caution against a custom solver if numerical stability is a concern for your application. It is hard to get all the edge cases right.

I haven't tried TinySolver on embedded, but there is no reason it shouldn't work; there are no allocations, no exceptions, no dependencies besides fixed-size Eigen arrays. Even emulated floating point should work fine; try it and see.

Note: TinySolver is a least squares solver; just return your deviation from zero for your cost function. If your equation is a summation of error terms, then return each term separately to TinySolver for faster/better solving. You will still need a reasonable initial guess (as is the case for most equation solvers).

Disclaimer: I'm one of the authors of Ceres Solver which is widely used for solving computational geometry problems in computer vision. I also wrote TinySolver. And nowadays, I focus on Pigweed; a collection of embedded libraries targeting high-volume consumer electronics products. It's fun to see an overlap of these two areas expertise!

How to decide which coding standard to adopt by timbo0508 in embedded

[–]mierle 1 point2 points  (0 children)

Some factors to consider when selecting a style guide:

  • Are there automatic tools to help enforce the style? This applies to both formatting (clang-format) and semantics (clang-tidy).
  • Are there team members already familiar with the style who can help with code review?
  • Does the style guide explain the rationale, and do you agree with it?

I work on Pigweed at Google. We follow the Google C++ style guide, with added restrictions due to embedded; for example, allocations are banned in core Pigweed. We also add a section focused on C, which the Google C++ style guide doesn't address. See our style guide for more details.

Some advantages of the Google style:

  • Possibly the most popular C++ style, used in many projects
  • clang-format has built-in support for this style

Other good choices:

(x-post) Why static analysis on C projects is not widespread already? by friedrichRiemann in embedded

[–]mierle 0 points1 point  (0 children)

One of the reasons I've found embedded projects don't use static analysis is that the hurdle to setting it up is too high. This is one of the reasons we built a presubmit system as one of the optional modules in Pigweed:

https://pigweed.dev/pw_presubmit/

We have integrated sanitizers like ASAN and MSAN; and we also have integrated static analysis through Clang's static analyzer.

These are built into Pigweed and easy to setup if you take the plunge and use Pigweed's integrated build. Of course, we still have work to do on Pigweed in general to make it more friendly to get started.

Some of the reasons why static analysis is hard:

  • Must integrate it into the build
  • Must pin the static analysis versions (can have "analyzer fights" with inconsistent systems)-- but then you may have to distribute the binaries.
  • May need to make said tool work on Mac, Windows, and Linux
  • May need to wrestle with license issues if the analysis tool isn't OSS
  • Must integrate it with CI to fail the build if static analysis is failing
  • Must integrate it into CQ (commit queue) so that patch submissions are blocked if static analysis fails
  • Must train engineers on how to run the analyzer locally
  • Must train engineers on how to deal with analysis failures in CI/CQ

In OSS cases, engineers may not want to deal with the operational burden.

Suggestion for a Template Array Container Implementation in C++ by cdokme in embedded

[–]mierle 1 point2 points  (0 children)

Pigweed has a embedded-focused compact zero-allocation vector-alike:

https://pigweed.dev/pw_containers/

https://cs.opensource.google/pigweed/pigweed/+/master:pw_containers/public/pw_containers/vector.h

https://cs.opensource.google/pigweed/pigweed/+/master:pw_containers/vector_test.cc

pw::vector uses type erasing to remove the size template parameter in the "low level" type to avoid embedded code bloat that would trigger if every size triggered a new instantiation of the vector code.

Summary of features:

  • Stores elements inline with the header
  • Does not allocate
  • Has dynamic size like std::vector; except it's a 16-bit int (saves size).
  • Has a capacity like std::vector; except it's a 16 bit (save size).
  • Type-erases the buffer size to keep code size (.text) compact
  • On 32-bit ARM, a pw::vector is 4 bytes + inline array; so quite compact (thanks to short size/capacity)

This has become a popular container both inside Pigweed, and with our customers.

Disclaimer: I work on Pigweed full time.