Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
user:embedded_c_code_doesn_t_have_to_be_ugly [2020/05/11 16:36] – [3. #define vs. enum] Igor Yefmov | user:embedded_c_code_doesn_t_have_to_be_ugly [2020/05/11 17:15] – [4. Bit manipulations vs. structured data] Igor Yefmov | ||
---|---|---|---|
Line 18: | Line 18: | ||
Even if unit tests are not something that pop to mind when working on firmware (embedded) code, one must always make sure to fully understand the code before modifying it. | Even if unit tests are not something that pop to mind when working on firmware (embedded) code, one must always make sure to fully understand the code before modifying it. | ||
- | ==== 1. IDE setup ==== | + | ==== 1. Use *YOUR* favorite |
- | The default SDK provided an IDE based around [[https:// | + | The default SDK provided an IDE based around [[https:// |
* My favorite keyboard shortcuts (A mouse? It often just slows me down when I'm working with text!) | * My favorite keyboard shortcuts (A mouse? It often just slows me down when I'm working with text!) | ||
* Code browsing database | * Code browsing database | ||
+ | * Mouse-over function/ | ||
+ | * Datatype information (especially useful for '' | ||
* "Find all references" | * "Find all references" | ||
+ | * Search text in: block, file, all open files, all files for the project/ | ||
* Jump to declaration/ | * Jump to declaration/ | ||
* View call hierarchy (both " | * View call hierarchy (both " | ||
Line 95: | Line 98: | ||
==== 4. Bit manipulations vs. structured data ==== | ==== 4. Bit manipulations vs. structured data ==== | ||
+ | Working with the low-level code((which is, basically, pretty much all the embedded code)) quite often requires direct bit manipulation. And as much as every '' | ||
+ | |||
+ | Here's a more concrete example: working with 16/32 bit integers, where depending on the context it is either a CPU-addressable word, or a stream of bytes on the wire (be it USB or I²C). Traditionally that would result in the 1970's style code like this: | ||
+ | <code C> | ||
+ | uint8_t location[4]; | ||
+ | location[1] = (byteAddress >> 16) & 0xFF; /* MS byte */ | ||
+ | location[2] = (byteAddress >> 8) & 0xFF; | ||
+ | location[3] = byteAddress & 0xFF; /* LS byte */ | ||
+ | </ | ||
+ | |||
+ | Do you see an **obvious bug** in that code((yes, this is what was in the code! An uninitialized first byte of the '' | ||
+ | |||
+ | Here's a much more modernized version of this, which also (automagically!!!) takes care of that idiotic bug: | ||
+ | <code C> | ||
+ | uint16_t v; | ||
+ | struct{ uint8_t l, h; }; | ||
+ | uint8_t a[2]; | ||
+ | } PackedUint16; | ||
+ | typedef union PackedInt16{ | ||
+ | int16_t v; | ||
+ | struct{ uint8_t l, h; }; | ||
+ | uint8_t a[2]; | ||
+ | } PackedInt16; | ||
+ | typedef union PackedUint32{ | ||
+ | uint32_t v; | ||
+ | struct{ PackedUint16 l, h; }; | ||
+ | uint8_t a[4]; | ||
+ | } PackedUint32; | ||
+ | |||
+ | /////////////////////////////////// | ||
+ | |||
+ | PackedUint16 pageAddress = {12356}; | ||
+ | uint8_t location[4] = {}; /* uninitialized memory is evil */ | ||
+ | location[1] = byteAddress.h.l; | ||
+ | location[2] = byteAddress.l.h; | ||
+ | location[3] = byteAddress.l.l; | ||
+ | |||
+ | /* alternatively the code above can be written even more compactly and more to-the-point, | ||
+ | const uint8_t * const location = pageAddress.a; | ||
+ | */ | ||
+ | </ | ||
+ | |||
==== 5. Globals ==== | ==== 5. Globals ==== |