Author Topic: C++ for the Embedded Programmer  (Read 8611 times)

0 Members and 2 Guests are viewing this topic.

Offline EEVblog

  • Administrator
  • *****
  • Posts: 27199
  • Country: au
    • EEVblog
C++ for the Embedded Programmer
« on: February 23, 2018, 02:27:10 pm »
David Ledger shows some advantages of using C++ in embedded microcontroller applications.
The use of template classes and meta programming to make code more platform independent and readable (and fun!) (David made me add that last bit).

 
The following users thanked this post: PuppyEngineer

Offline jeremy

  • Frequent Contributor
  • **
  • Posts: 796
  • Country: au
Re: C++ for the Embedded Programmer
« Reply #1 on: February 23, 2018, 03:08:42 pm »
Been doing this for a while now. I’ve heard it called “C+”, essentially meaning that you use only a chunk of the features available.

Features I do use:
- classes, abstract classes, singletons
- pass by reference
- single inheritance
- templates
- namespaces

Features I don’t use
- template metaprogramming (I don’t use this *ever*, anyway)
- new
- exceptions (sometimes)

An excellent library is ETL. It gives you statically allocated versions of the stuff in the STL.
 

Offline Ash

  • Regular Contributor
  • *
  • Posts: 143
  • Country: au
Re: C++ for the Embedded Programmer
« Reply #2 on: February 23, 2018, 06:24:06 pm »
+1 for ETL - its great. (https://www.etlcpp.com/:-+

I'm a big fan of using C++ features that prevent (or at least make it obvious) you are doing something wrong.

A good example of this is explicitly defining array types for buffers with specific sizes. I also prefer references over pointers where I can because you have to work hard to make them "null".

For instance:

Code: [Select]
#include <cstdint>

static constexpr int BUFFER_LENGTH = 200;
typedef uint8_t(&BufferReference)[BUFFER_LENGTH];

void DoSomething(BufferReference buffer)
{
    buffer[BUFFER_LENGTH-1] = 0; // safe, compiler errors on wrong size buffer
}

uint8_t badBuffer[100];
uint8_t goodBuffer[200];

int main()
{
    DoSomething(badBuffer); // ERROR
    DoSomething(goodBuffer); // OK

    return 0;
}

The other really good thing to get your head around is const - tell the compiler when something shouldn't be allowed to be modified and it will prevent you accidentally doing it (and it can often make really good optimisations).

I also like doing templates and typedefs for peripherals. When setup right, I can for instance have a GPIO Pin, timer or DMA channel and change instance being used in a piece of code by simply altering a single typedef. the actual template behind can be specialised on instance number and be completely static and basically optimises away into the appropriate register read/writes.. But that's a bit more tricky. However debugging templates is a bitch for the most part.. They can result in some horrific error messages, but the compilers are getting better..

The problem with C++ is that you need to have a relatively modern compiler on your platform to take advantages of the good stuff (C++11/14/17).

Ash.
« Last Edit: February 23, 2018, 06:25:37 pm by Ash »
 

Offline Fungus

  • Super Contributor
  • ***
  • Posts: 8771
  • Country: 00
Re: C++ for the Embedded Programmer
« Reply #3 on: February 23, 2018, 10:24:14 pm »
Oh, FFS...  :palm:



C++ is not Python
« Last Edit: February 23, 2018, 10:27:16 pm by Fungus »
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 1147
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #4 on: February 23, 2018, 11:09:38 pm »
The syntax is:
    while (expression) statement

A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.
 
The following users thanked this post: hans, thm_w, Jeroen3, GeorgeOfTheJungle, alexanderbrevig, nugglix

Offline gmb42

  • Regular Contributor
  • *
  • Posts: 158
  • Country: gb
Re: C++ for the Embedded Programmer
« Reply #5 on: February 24, 2018, 12:21:48 am »
The syntax is:
    while (expression) statement

A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.

And not adding braces will inevitably lead to a bug later on in the maintenance cycle.  Just add them from the start.
 
The following users thanked this post: kony, rs20, aandrew, Jacon

Offline NivagSwerdna

  • Super Contributor
  • ***
  • Posts: 1500
  • Country: gb
Re: C++ for the Embedded Programmer
« Reply #6 on: February 24, 2018, 01:03:08 am »
 

Offline crispus

  • Regular Contributor
  • *
  • Posts: 106
  • Country: ro
Re: C++ for the Embedded Programmer
« Reply #7 on: February 24, 2018, 01:33:43 am »
The title and the presentation might lead to a war between those who use C++ and those who don't.

Personally I think this is mistitled. C doesn't mean ST horrible HAL, so it is not fair to put equality between a poorly written library and a language.
As an example, you can look at the ChibiOS STM32 HAL which is absolutely amazing. Here is an example:
Code: [Select]

  while (true) {
    palSetPad(GPIOD, GPIOD_LED3);       /* Orange.  */
    osDelay(500);
    palClearPad(GPIOD, GPIOD_LED3);     /* Orange.  */
    osDelay(500);
}

And not adding braces will inevitably lead to a bug later on in the maintenance cycle.  Just add them from the start.
It is a good practice to add braces, but it doesn't lead inevitably to a bug. But it might.

DISCLAIMER: I use C++ in almost all of my embedded (as in Cortex-Mx) projects for more than 5 years.
I know I'm numskull, but I look around me and I feel better.
 
The following users thanked this post: Jacon

Offline Fungus

  • Super Contributor
  • ***
  • Posts: 8771
  • Country: 00
Re: C++ for the Embedded Programmer
« Reply #8 on: February 24, 2018, 03:44:53 am »
A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.

Yes, but only because it was correct C code back in the 1970s and breaking existing C code was deemed unacceptable when C++ was being developed.

« Last Edit: February 24, 2018, 03:47:36 am by Fungus »
 

Offline Craftplorer

  • Contributor
  • Posts: 8
  • Country: de
Re: C++ for the Embedded Programmer
« Reply #9 on: February 24, 2018, 04:07:49 am »
Personally I think this is mistitled. C doesn't mean ST horrible HAL, so it is not fair to put equality between a poorly written library and a language.

Exactly and how can he say that the code works on any platform without showing how much platform dependent code he has written for the library to work. This is only true if you use a already written library and apart from the Arduino stuff i dont know any library that works on many platforms. Not to say that Arduino definitly looses in the overhead discussion(not because of C++ of course).

So it really comes down on the project your working on and what your are familiar with. For example i would never use C++ on a 8bit microcontroller. Also most of the time i dont really have the time for writing a C++ library for a project atleat at not at work.
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 15434
  • Country: nl
    • NCT Developments
Re: C++ for the Embedded Programmer
« Reply #10 on: February 24, 2018, 04:10:02 am »
The syntax is:
    while (expression) statement

A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.

And not adding braces will inevitably lead to a bug later on in the maintenance cycle.  Just add them from the start.
Agreed. The fact C/C++ accepts code which is obfustigated doesn't mean the code has to be obfustigated. Have to watch the video later. Using C++ for embedded has been on my todo list for over a decade now.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline mart1n

  • Contributor
  • Posts: 17
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #11 on: February 24, 2018, 04:57:21 am »
An entire video comparing STM32 HAL libraries to a C++ library without linking to it or mentioning the libraries name?
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 1147
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #12 on: February 24, 2018, 05:45:33 am »
An entire video comparing STM32 HAL libraries to a C++ library without linking to it or mentioning the libraries name?

If you'd watched the video, or at least the last 3 minutes of it, you wouldn't say that.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 1706
  • Country: fi
  • Embedded SW/HW.
Re: C++ for the Embedded Programmer
« Reply #13 on: February 24, 2018, 06:38:58 am »
I can highly recommend the book "Real-Time C++ - Efficient Object-Oriented and Template Microcontroller Programming, 2nd. ed." by Christopher Kormanyos.

The following video is also a very good introduction for the template-based C++ embedded programming. The idea is to perform compile-time instantiation, polymorphism and optimization using templates instead of traditional run-time polymorphism, which allows the compiler to produce very optimized code. In the video Wouter van Ooijen compares the traditional C implementation to traditional C++ implementation and highly optimized C++ template based implementation.

goo.gl/6ttCZA

Edit: Changed the Youtube link with preview to this shorter one which will not hijack the thread.
« Last Edit: February 24, 2018, 06:47:29 am by Kalvin »
 

Online thm_w

  • Frequent Contributor
  • **
  • Posts: 837
  • Country: ca
Re: C++ for the Embedded Programmer
« Reply #14 on: February 24, 2018, 09:15:26 am »
If you'd watched the video, or at least the last 3 minutes of it, you wouldn't say that.

Can you clarify, I must have missed it as well. When do we expect this library to be available online?
 

Offline hans

  • Super Contributor
  • ***
  • Posts: 1002
  • Country: nl
Re: C++ for the Embedded Programmer
« Reply #15 on: February 25, 2018, 09:39:39 pm »
Been doing this for a while now. I’ve heard it called “C+”, essentially meaning that you use only a chunk of the features available.

Features I do use:
- classes, abstract classes, singletons
- pass by reference
- single inheritance
- templates
- namespaces

Features I don’t use
- template metaprogramming (I don’t use this *ever*, anyway)
- new
- exceptions (sometimes)

An excellent library is ETL. It gives you statically allocated versions of the stuff in the STL.

Yes, I think this is a nice summary how to use C++ effectively for embedded programming. I personally also use std::function quite as a local callback to the application. When paired with a template this can be rather efficient as well:
Quote
    template <typename T>
    static void RMW32(volatile void* addr, T operation)
    {
        volatile uint32_t* addr32 = reinterpret_cast<volatile uint32_t*>(addr);
        uint32_t rd, wr;

        do {
            rd = __LDREXW(addr32);
            wr = operation(rd);
        } while (__STREXW(wr, addr32));
    }
Which then used with type Tatomic:
Quote
Tatomic::RMW32(addr, [clr, set](uint32_t value) { return (value & ~clr) | set; });
This statement is then repackaged twice (first SetClear operation, then as GPIO SetPinMode) for application code. Don't notice any overhead in disassembly output with -O2:
Quote
8020342:   40a2         lsls   r2, r4
 8020344:   ea6f 0c05    mvn.w   ip, r5
 8020348:   e856 4f00    ldrex   r4, [r6]
 802034c:   ea0c 0404    and.w   r4, ip, r4
 8020350:   4314         orrs   r4, r2
 8020352:   e846 4700    strex   r7, r4, [r6]

 I think these videos are also a nice demonstration about negative cost C++ programming:



Also episodes 54 thru 56 show "zero cost" C++ embedded programming

I think the added safety of C++ type system, as well as added abstractions can speed up development massively.  For me also C++ code is much easier to unit test than C. It's easier to instantiate a class locally than it is to work with a C module that has uses some local storage, which you cannot reach to reset/instantiate for testing.

The piece of code I just demonstrated was from a small toy program playing around with these C++ definitions. I had created a Stm32Gpio object that can be used as in/out, write pins, etc. From that I created a bitbanged SPI driver using an abstract GPIO objects, not tied to the STM32 implementation.
Using that SPI driver, it's trivial to define a GPIO expander driver using a 74HC595 or a fancy SPI chip, which can then be used as GPIO over SPI. So basically we've gone full circle back to abstract GPIO objects again, but this time communicating over SPI, transparently. One danger ofcourse is that this detail is abstracted away, then any synchronous GPIO operation becomes very slow. Since most code is written synchronously to deal with GPIO, the application scope is rather small. You could ofcourse implement caching behaviour (e.g. accumulate R/W operations and then commit them all at once), but such caching and requiring flushing is not application agnostic, and thus falls flat down on it's face. I think there are other more higher-level applications that can make better use of abstractions though, e.g. memory devices or sensors drivers.

Nevertheless, it was still a funny exercise. Because the SPI GPIO's are "basic" GPIO's again, one could create a bitbanged SPI driver using GPIO that is already going over bitbanged SPI. I cascaded this with 5 chips. Since each GPIO write took 16 bits to transfer, it takes 16^5=1048576 clocks to write a single GPIO at the end of the cascaded chain (a few more actually because of latches or chip selects). With an average SPI clock of 10MHz on a STM32F4, that comes down to a blink rate of about 5Hz when it's running in a while(1) {} loop continuously. :-DD
« Last Edit: February 25, 2018, 09:41:35 pm by hans »
 

Offline Elandril

  • Contributor
  • Posts: 18
Re: C++ for the Embedded Programmer
« Reply #16 on: February 26, 2018, 05:11:47 am »
A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.

Yes, but only because it was correct C code back in the 1970s and breaking existing C code was deemed unacceptable when C++ was being developed.

Actually that is not really the reason. The C++ standard (as most programming languages by the way) defines the operational part of a loop as a statement. Such a statement can take several forms: labeled-statement, expression-statement, compound-statement, selection-statement, iteration-statement, jump-statement, declaration-statement or try-block. The form without the braces is an expression-statement, while the form with braces is a compound-statement. Both are perfectly valid. To be precise there is a small difference between the two: the braces do actually open up another scope.
 
The following users thanked this post: GeorgeOfTheJungle

Offline Auslander

  • Newbie
  • Posts: 1
  • Country: si
Re: C++ for the Embedded Programmer
« Reply #17 on: February 26, 2018, 07:39:44 pm »
Great video David,

Can you post source code you used in video. I'd really like to make comparison C vs C++ against speed, memory footprint, latency etc.
 

Online NexusKoolaid

  • Contributor
  • Posts: 23
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #18 on: February 27, 2018, 03:15:14 am »
A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.

Yes, but only because it was correct C code back in the 1970s and breaking existing C code was deemed unacceptable when C++ was being developed.

Actually that is not really the reason. The C++ standard (as most programming languages by the way) defines the operational part of a loop as a statement. Such a statement can take several forms: labeled-statement, expression-statement, compound-statement, selection-statement, iteration-statement, jump-statement, declaration-statement or try-block. The form without the braces is an expression-statement, while the form with braces is a compound-statement. Both are perfectly valid. To be precise there is a small difference between the two: the braces do actually open up another scope.
Isn't that just a yacc-ish grammatical breakdown of what he was talking about - the unacceptability of breaking from C grammar by the contextual disallowing of expression statements?
 

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • Posts: 1310
  • Country: pl
Re: C++ for the Embedded Programmer
« Reply #19 on: February 27, 2018, 08:00:48 pm »
A single statement without braces is perfectly correct C++ code, even if it offends your personal sense of style.

And one can also write:

Code: [Select]
while (what) something, something_else, and_even_moar();

Which is ~ as good as:

Code: [Select]
while (what) {
    something;
    something_else;
    and_even_moar();
}
« Last Edit: February 28, 2018, 08:08:53 am by GeorgeOfTheJungle »
 

Offline szechyjs

  • Supporter
  • ****
  • Posts: 4
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #20 on: March 07, 2018, 01:52:30 am »
Any chance you'll release your library David?

Thanks!
 

Offline rhb

  • Super Contributor
  • ***
  • Posts: 1858
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #21 on: March 07, 2018, 03:49:42 am »
The problem with conditionals without braces is you can't set a break point  on the condition being met.  You stop every time it is tested.  For conditionals inside loops that run for a long time that makes debugging *very* tedious.  I've worked on over 2.5 million lines of old code.  One of the first things I typically do is add braces to all conditionals.  If I want to stop on the Nth iteration of a loop for N large, I'll put in:

if( i  == N ){
    printf( "fubar" );
}

and set a breakpoint on the printf.  Yes, debuggers will let you set a breakpoint when a variable reaches some value.  But the value test gets made on every instruction which makes things run very slowly.  If you're doing a large 3D FFT and want to check the address of the last value written in each plane of the transform the code will run for a week before it halts.  I guess it does give an excuse for not doing anything useful.  "I'm waiting for the debugger to hit the breakpoint I set."

On processors which employ branch prediction there's no performance penalty at all.  That's probably not true for MCUs, but big machines get embedded when it's needed.

Personally, I do not and will not use C++ for *anything*.  I've spent 3-4 months on two occasions studying the language.  I finally concluded no one understands C++, they just pretend that they do.  I read obscure programming language manuals for fun, along with books on compiler optimization techniques.  So when I say "understand", I'm talking about register level behavior.

Object oriented programming has been a tremendous benefit to DRAM makers.  All those tables of pointers to functions that will never be applied to an object eat space like mad.  A text date and time display now consumes 80 MB of core.  Which is why it takes 4 GB of DRAM to run Firefox.

My real objection though is this:

int main( int argc ,char* argv[] ){

    new A a;
    new B b';
    new C c;

   c = a + b;
}

If multiple inheritance has been used it will be necessary to read all the class libraries, the relevant C++ standards document and the compiler implementation notes to determine what the single executable line does.  Furthermore, there is no guarantee that the next version of the compiler will produce the same result or even compile the code.  And changing the order of parent class declarations will change the behavior.


The only "benefit" I see to C++ is that it lets people who don't know what they are doing write things they don't understand.  I don't really have any issue with C++ for the sort of things that Stroustrop developed it for.  My issue is with proclaiming that everything is a nail and should be hit with a hammer.
 

Offline Fungus

  • Super Contributor
  • ***
  • Posts: 8771
  • Country: 00
Re: C++ for the Embedded Programmer
« Reply #22 on: March 07, 2018, 04:49:04 am »
Personally, I do not and will not use C++ for *anything*.  I've spent 3-4 months on two occasions studying the language.  I finally concluded no one understands C++, they just pretend that they do.  I read obscure programming language manuals for fun, along with books on compiler optimization techniques.  So when I say "understand", I'm talking about register level behavior.

Object oriented programming has been a tremendous benefit to DRAM makers.  All those tables of pointers to functions that will never be applied to an object eat space like mad.  A text date and time display now consumes 80 MB of core.  Which is why it takes 4 GB of DRAM to run Firefox.

My real objection though is this:

int main( int argc ,char* argv[] ){

    new A a;
    new B b';
    new C c;

   c = a + b;
}

If multiple inheritance has been used it will be necessary to read all the class libraries, the relevant C++ standards document and the compiler implementation notes to determine what the single executable line does.  Furthermore, there is no guarantee that the next version of the compiler will produce the same result or even compile the code.  And changing the order of parent class declarations will change the behavior.

The only "benefit" I see to C++ is that it lets people who don't know what they are doing write things they don't understand.  I don't really have any issue with C++ for the sort of things that Stroustrop developed it for.  My issue is with proclaiming that everything is a nail and should be hit with a hammer.

So much :palm:

Must not reply. EEVBLOG isn't the place. This flamewar was done and dusted decades ago.

<bites tongue>
« Last Edit: March 07, 2018, 04:51:06 am by Fungus »
 
The following users thanked this post: hans, janoc, jancumps, thm_w, Frank, Koen, NexusKoolaid, Jacon

Offline darrylp

  • Regular Contributor
  • *
  • Posts: 127
  • Country: gb
Re: C++ for the Embedded Programmer
« Reply #23 on: March 07, 2018, 05:27:55 am »
Why are people fixated on screen grabbing desktops running resolutions like 1920*1080 to show code ?

It's stopping people using mobiles and tablets being to usefully watching these videos.

Videos with source code showing line lengths longer than say ~132 characters total shows how bad you are at understanding your viewing audience needs as well as you poor use of desktop estate and if you need lines of code more than 132 characters then your not coding very well !


Sent from my HTC One using Tapatalk 2

 

Offline rhb

  • Super Contributor
  • ***
  • Posts: 1858
  • Country: us
Re: C++ for the Embedded Programmer
« Reply #24 on: March 07, 2018, 06:42:25 am »
Sorry.  I really was trying to be good and just comment on the curly brace issue.   Just because you can do something doesn't mean you should.

I got one of the Plan 9 diskettes at Usenix  in 1995.  It put an OS, editor, windowing system, Unicode support and  an assortment of command line utilities (e.g. ls)  in 1.44 MB with room to spare. IIRC it was written in Limbo, but I might be conflating things with Inferno, the other OS Bell Labs was  playing with at the time.

I recently had to retire my Internet access system, a dual core Atom with 2 GB of DRAM because it  no longer had room to run Firefox.  I spent 4 years in grad school working on a VAX 11/780 which didn't have 2 GB of disk.  And we had lots of disk for the day because we were processing seismic data.

All those pointers to pointers to pointers... consume a lot of memory and CPU time.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf