Close

Reducing code size

A project log for Circadian - Radio control your internal clock!

A radio controlled melatonin saving lamp

matthias-kampaMatthias Kampa 01/05/2017 at 13:380 Comments

Using assembler can reduce code size a lot already. These are the techniques I used to implement a RTC including date, DST, leap days, DCF decoding and synchronization in less than 420 bytes.

Binary is your friend

How do you calculate if a year is dividable by 4? In C probably using " Year % 4 ". In assembler, this would have been a lot of lines to code. Try to use shifting and other binary operations for calculations.

Know the SREG

Another technique you can see in the snippet above is that a comparison doesn't have to be followed by the conditional jump it is executed for. A jump doesn't change the SREG. By jumping to the conditional jump and not coding it twice I could save another line.

Here is a more elaborate example of SREG trickery. This snippet switches the LEDs PWM and timer off if it isn't between 10 and 11 p.m. and if override isn't activated. Override forces the light to go to day mode. BRLO (branch if lower) is the same as BRCS (branch if carry set), so I just set the carry bit and jump behind the comparison, where the PWM and timer is deactivated. The jump to tLedDay is then performed because the carry is still set. If the comparison comparison against 22 is performed because override is not set, the comparison result will still be persistent after deactivating the PWM and timer and is used for the brlo.

Use tables and ijumps

The snippet below reads the length of a month from a table and uses it to wrap the day properly. I saw C code grouping equally long month in comparisons instead, ending up with way more lines of compiled code. Pay attention to the wrapping of the table. In this case, I aligned it with the address 0x0200.

I did not use any ijumps in this code, but they should be mentioned here too. I would have used an ijump if multiple month would have needed their own function like February does.

Let your µC's hardware do the work

Microcontrollers have a lot of built in functions and using it (right) can save you lots of lines. Because the PWMs frequency is not very critical, I just set it to 3600 (the amount of seconds in an hour) so the device has a great resolution with little computational (and coding) effort.

Don't move data around

The easiest way to reduce code size is to leave data in working registers to reduce push, pop, lds and sts instructions. Just by not using the SREG in my main loop I saved another 16 to 32 bytes because I didn't have to save its content in every interrupt routine.

Think out of the box

Well, there's no recipe for this. Just be brave and don't follow the handbook all the time. Maybe my code can give you some inspiration. Check out how the DCF interrupt doesn't distinguish between high or low levels, why I use the RTC timer with a smaller divider and how the DCFs CRC is calculated on the way.

Be lazy

Makros can save time and make code look clean, but if you want to save code space, don't use them. Your laziness will motivate you to code smarter and more efficient.

Discussions