I've rewritten firmware from assembler to C and.. the binary size is actually smaller now :)
Interesting things I've found:
- PIC10F202 doesn't have multiplication, division, or modulo instructions. If they are used in C code, the compiler will generate assembly using what instructions are available - it will emulate the needed instructions. This creates huge code. Long story short: avoid at all cost in implementation. This was quite amusing for me; I didn't expect algorithmic challenges on such a small chip.
- Variables that are bigger than a byte generate huge binary size as well. All variables should be no bigger than a byte.
- MPLAB IDE already has stdint.h and stdbool.h - all types are there like uint8_t and bool. No need to create own types, very nice. Note that PIC chips don't use gcc/clang compiler, so this is not that obvious.
- The chip has a hardware call stack limited to only two levels deep. One has to carefully look at which functions call which ones - if the level is more than two, at runtime the app will crash. One trick to deal with that is to use function-like macros. Another is to set a flag instead of calling a function, and then in the top method call the function.
- A cool trick I've learned people do to save space is to declare all variables in one global structure. Is it God object antipattern? Probably yes :) This way all bool variables can be kept on a single byte, saving space. Bit fields.
- Although the chip doesn't have multiplication or division, the compiler is smart enough to compute things if they are constants, so multiplication is ok to use in #define constants.
- MPLAB IDE has C99 standard for those chips, but they have also implemented _Static_assert - very handy for static assertions.
PS; look on the new code I made while learning all this, would be great to get feedback:
Robert Gawron
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
The trick of putting bit flags to a set of bytes shared by many modules is a flags module pattern not a god object antipattern. For byte variables there is often no need to collect them to a common struct. The compiler/linker takes care of their optimal placement. However, there is an overlay pattern for static variables that are not used concurrently, using unions. That is quite common in embedded system even nowadays with large memories.
The PIC xc8 compiler does quite good job in reusing memory of automatic variables in the compiled call stack, but does not always seem to be able to reuse memory for static variables of limited life time, so an overlay for such static variables needs to be made by the programmer.
PIC10F20x, PIC16C5x and PIC16F5x share the same architecture and same limitations like 2-deep call stack (though the compiler may be able to extend the number of levels by compiled stack or other tricks), and differ mostly for the internal oscillator in PIC10F20x and comparator in some models. I find those fun devices for making something with absolutely simplest microcontroller, like VFD segment driver with two PIC16F57 running in tandem, one for segments and other for grids. I also keep a small supply of PIC10F222 and PIC10F322 microcontrollers for cases where a tiny microcontroller in some obscure hack is the choice of the day.
Are you sure? yes | no
OP was saving space by using 1-bit fields for booleans in the struct.
Are you sure? yes | no
>However, there is an overlay pattern for static variables that are not used concurrently, using unions.
I have heard this trick a couple of years ago, the guy was talking about some project done years ago on ancient chip, back then it sounded to me as super-cool but archaism. I wasn't that there were still then (and now and in future too IMHO) small chips and those tricks still are relevant.
Anyway thanks for pointing this out, might be useful!
>That is quite common in embedded system even nowadays with large memories.
Hmm, like chip that has to do processing a lot of data? But what would be such example? Can you give one?
Are you sure? yes | no
Yeah, I have a few ancient 16C55 and 16C57 PICs and the call stack depth of 2 is very limiting as it requires major rework of code I've already written. What were they thinking? I think the old PIC families were dragged from assembly development into C development. That C indicates an OTP PIC so I'm not confident that my code will work first time, and I'm not willing to buy NOS flash versions to test with. So they will stay in the junk box.
Cool trick putting all the globals into a single struct though.
Are you sure? yes | no
The fun thing is, I originally started this project to reuse an old PIC I bought long time ago (don't even remember the model now), just to clear out my junk box a bit.
But then I realized it was one-time programmable one... so I ended up buying PIC10F202s instead. They’re cheap, so it’s fine, but the whole 'clean out the junk box and reuse what I have' plan failed! :D
Are you sure? yes | no