6 ms·
Almost nobody in their right mind would do this. (To be fair, many people working with hardware are not in their right mind anymore. Try it, you'll see.) 1: Do
by 95014_refugee 8y ago
Almost nobody in their right mind would do this. (To be fair, many people working with hardware are not in their right mind anymore. Try it, you'll see.)
1: Don't use bitfields when interacting with registers. The language does not guarantee the behavior you want. Or even the behaviour you think you want.
2: 'volatile' is the contract that we (language users) have hammered out with the compiler industry over the last 20 years; it means "don't get smart with this memory location". Use it.
3: For any SoC of more than trivial complexity, the vendor will supply headers that describe the hardware (register names and addresses, field names, sizes, offsets, enumerations, etc.). You will hate their naming convention. You will hate the way they encode field sizes, offsets, masks, etc. Deal. Because the alternative is you, or your intern, making dozens of mistakes attempting to transcribe from the documentation. Here's a hint - the better vendors auto-generate these headers from the VHDL. They are often right even when the documentation isn't.
4: It's trivial to template most interactions with registers. See, for example: https://github.com/steffanw/laks https://github.com/steffanw/laks
5: A little investment in your abstractions, even if the lower levels look a bit more complex or verbose, helps make your application logic easier to follow.
The discussion here about re-ordering is largely moot; if you're having issues with the core re-ordering your transactions, either your core is børked or you haven't mapped your peripheral space correctly. The former is pleasantly rare, the latter common enough that your compiler vendor is going to ask you about it before they give you a bug number.
- minipci1321 8y ago> Here's a hint - the better vendors auto-generate these headers from the VHDL. Yes! And the hateful naming might come straight from the RTL where digital designers have their own notions about what is a pretty name ;-) > They are often right even when the documentation isn't. More so -- if you decide for changing these names, one day debugging a complex issue will require talking to RTL people and everybody will be instantly lost -- your names won't be meaning much to them.
- stevenhuang 8y agoChoosing between bitfields and masks for register twiddling was something I looked into deeply. Like the article, I wanted the readability of bitfields, but after reading about all the pitfalls and how loosely bitfields specs were defined in the C89 standard, I decided to go with masks instead. Here was a great summary I found from a comment explaining the dangers of bitfields. Seeing it spelled out like this made it clear which to choose, lest you're a fan of nasal demons :). "The royal mistake is to use bit fields in the first place. The following is not specified by the standard: – whether bit field int is treated as signed or unsigned int – the bit order (lsb is where?) – whether the bit field can reach past the memory alignment of the CPU or not – the alignment of non-bit field members of the struct – the memory alignment of bit fields (to the left or to the right?) – the endianess of bit fields larger than one byte – whether plain int values assigned to them are interpreted as signed or unsigned – how bit fields are promoted implicitly by the integer promotions – whether signed bit fields are one’s compliment or two’s compliment – padding bytes – padding bits – values of padding bits. – and so on." Source: https://embeddedgurus.com/stack-overflow/2009/10/effective-c-tip-6-creating-a-flags-variable/#comment-2390 https://embeddedgurus.com/stack-overflow/2009/10/effective-c...
- stinos 8y agoSo do I understand it correctly that you are saying the OP's code (or e.g. the one like in AceJohnny2) is not guaranteed to work correctly according to C89? Any idea about C99?
- Gibbon1 8y agoMy thoughts Probably will work with a specific compiler. If it fails it'll likely fall on it's face fail. Which with embedded is the best type of failure. Also you probably can force the behavior you need with pragma's (not portable) Portability is usually completely unimportant in embedded. C89 just don't. C++ in embedded. Lord god no, if you want to do that use rust instead. Or embedded python or lua, anything but C++.
- pjmlp 8y ago> C++ in embedded. Lord god no, if you want to do that use rust instead. Or embedded python or lua, anything but C++. First Rust needs to reach C++'s tooling maturity on embedded space. When there is High Integrity Rust certification, compiler backends for all major CPUs, SDK support on OSes like INTEGRITY or Mbed, UI embedded tooling for IoT displays, maybe we can start seeing production code there.
- Gibbon1 8y ago> First Rust needs to reach C++'s tooling maturity on embedded space. Yeah and that's soon. Anyone starting an embedded project in C++ is making a grave mistake. > Mbed Those guys make a bad mistake and will pay for it.
- pjmlp 8y agoTouching C is an even bigger one. It took C++ about 20 years to reach maturity in this space, with help of several OS and compiler vendors. You might be willing to bet the house on Rust, most business aren't, not in the current state of its toolchain. In 10 years from now, yeah I can clearly see it.
- speedplane 8y agoout of curiosity, do people now use exceptions when programming on embedded? It's been 10 years years since I've really programmed embedded systems, but at the time exceptions were a big no-no. It was often unclear how an exception would mess with the stack, how far up things would go, and what information was (and its size) being passed up. Instead, we just checked return values of everything.
- proverbialbunny 8y agoExceptions are still a no-no for code that needs to be real time due to it's non-deterministic nature. The feature can be disabled with the -fno-exceptions flag. However, this might change in C++23. Herb Sutter just proposed C++ switch to deterministic exceptions. The paper is quite good: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p070... It looks popular, so there is a high chance it will become a thing allowing stl to work in the embedded world.
- nitrogen 8y ago1: Don't use bitfields when interacting with registers. The language does not guarantee the behavior you want. Or even the behaviour you think you want. To back this up: it's important to remember that reads and writes to memory-mapped registers have meaning independent from simple memory access. I once was writing an interrupt handler for an MCU. There was a bitfield register that indicated which interrupts had fired on read, and acknowledged/cleared an interrupt on write (IIRC). I was reading the register, clearing the interrupt I'd just handled, then writing it again. So I might read 0x84, mask out 0x80, then write 0x04. Or so I thought. Turns out what the processor actually wanted was a direct write. You'd just write 0x80 to acknowledge that interrupt, not read/mask/write. And reading had a different effect on the MCU too, as I recall. So I was only getting interrupts sporadically and my code didn't work. Now add compiler bitfields. You have to be 100% certain that the implementation behaves the way the CPU wants (no extra reads/writes, expected bits set/cleared), and that it won't change from version to version. Instead it's common to use macros to deal with registers. Not quite as pretty as bitfields, but much more predictable.
- orbifold 8y agoThe example in point 4. does almost no bit level manipulation and when it does, it does so with locally hard coded constants and shifts, which is probably one of the worst ways of dealing with this.
- JoeAltmaier 8y agoRemember that embedded programming is often deployed on a particular machine using particular tools. So even with all the uncertainty, a little testing (looking at generated code) and you can get it to work. And it should stay working, since the code isn't going anywhere (different machine/tools). There's still the downside of course - looking at the code to 'prove' it is troublesome. And often the code generated for bitfields is ugly. You can likely generate better code by hand. So the single remaining advantage is, the C looks pretty clear. There's the register; there are its bits by name; assuming that's all been checked to work right, the coding (and code reading) can proceed without any more concern over bits.