smaller firmware patch

Support forum for the mightyohm.com Geiger Counter.
http://mightyohm.com/geiger
Post Reply
nsd
Posts: 4
Joined: Mon Jun 30, 2014 2:40 pm

smaller firmware patch

Post by nsd »

I found I needed a little more code space than was available in the Atmel for my experiments, so I looked and found places where I could make the existing code smaller without changing its functionality. If you're interested, the patch attached, when applied to 1.00 code, results in 1450 bytes of flash + 85 bytes of ram, but acts the same as the 1.00 code (which is 1582+85 bytes).

-Nicolas Dade
Attachments
smaller_geiger_1.00_code.patch.txt
patch reduce code size of 1.00 geiger counter firmware
(5.93 KiB) Downloaded 832 times
User avatar
mightyohm
Site Admin
Posts: 1064
Joined: Fri Apr 03, 2009 10:29 pm
Location: Seattle, WA
Contact:

Re: smaller firmware patch

Post by mightyohm »

Nicolas,

Thanks for sharing this. I'm surprised that these changes result in 150 extra bytes. Is the compiler linking more efficiently with the "static" keyword on checkevent/sendreport?
nsd
Posts: 4
Joined: Mon Jun 30, 2014 2:40 pm

Re: smaller firmware patch

Post by nsd »

'static' helps a little bit in the case of send_report() because it is called only once. So since the function static the compiler knows no outside object file could reference it, and therefore the compiler can inline the function and eliminate the call and any setup/teardown which was needed.

However most of the savings come from changing the handling of the global volatiles. Some didn't need to be volatile. In the case of some others, when I could without causing trouble (in cases where the volatiles are written only by one function, for example), I changed the code so the volatile was read only once in each function which used it. That eliminated a lot of load and store instructions.

BTW after posting the 1st message I squeezed another 4 bytes out by changing accesses to a volatile into local var accesses in one more spot:

:~/src/geiger_counter/geiger$ svn diff -c10
Index: geiger.c
===================================================================
--- geiger.c (revision 9)
+++ geiger.c (revision 10)
@@ -111,8 +111,10 @@
// This interrupt is called on the falling edge of a GM pulse.
ISR(INT0_vect)
{
- if (count < UINT16_MAX) // check for overflow, if we do overflow just cap the counts at max possible
- count++; // increase event counter
+ uint16_t _count = count;
+ if (_count < UINT16_MAX) // check for overflow, if we do overflow just cap the counts at max possible
+ _count++; // increase event counter
+ count = _count;

// send a pulse to the PULSE connector
// a delay of 100us limits the max CPS to about 8000

-Nicolas Dade
Last edited by nsd on Wed Jul 02, 2014 2:33 pm, edited 1 time in total.
User avatar
mightyohm
Site Admin
Posts: 1064
Joined: Fri Apr 03, 2009 10:29 pm
Location: Seattle, WA
Contact:

Re: smaller firmware patch

Post by mightyohm »

Awesome! Thanks for the explanation and thanks again for posting the patch.
nsd
Posts: 4
Joined: Mon Jun 30, 2014 2:40 pm

Re: smaller firmware patch

Post by nsd »

BTW another 10 bytes of flash space are saved by changing the increment of count [already improved above] to avoid a direct comparison with UINT16_MAX. Instead you increment and skip storing the result if it is zero:

--- geiger.c (revision 16)
+++ geiger.c (working copy)
@@ -112,9 +112,8 @@
ISR(INT0_vect)
{
uint16_t _count = count;
- if (_count < UINT16_MAX) // check for overflow, if we do overflow just cap the counts at max possible
- _count++; // increase event counter
- count = _count;
+ if (++_count)
+ count = _count; // only update count if the increment doesn't overflow 16 bits

// send a pulse to the PULSE connector
// a delay of 100us limits the max CPS to about 8000

-Nicolas
User avatar
mightyohm
Site Admin
Posts: 1064
Joined: Fri Apr 03, 2009 10:29 pm
Location: Seattle, WA
Contact:

Re: smaller firmware patch

Post by mightyohm »

Very clever, thanks for sharing.
What are you doing with all of this extra code space? :D
nsd
Posts: 4
Joined: Mon Jun 30, 2014 2:40 pm

Re: smaller firmware patch

Post by nsd »

Random number generation. I run a jumper from TP1 (actually from the lower leg of R3 b/c that is even easier to grab) to the center pin on the PULSE connector (which I don't otherwise use). That feeds the GM pulse into the ICP pin, where I use it to capture the timestamp of the pulse accurately using the input capture feature of timer1. Comparing the time interval between two pairs of events generates one random bit (same method used by http://www.fourmilab.ch/hotbits/ RNG). The output using background radiation passes the rabbit test suite from TestU01, though it takes a day to accumulate enough bits to run it, and really a week+ is better.

I wanted to preserve the geiger counter functionality as-is, but in the end I had to change the CPM calculation from using the precise, 60 entry buffer[], method to a decaying average because I was out of room in the RAM.

The code is attached. It requires gcc <=2.7 to compile and fit. For some reason gcc 2.8 produces larger code (it seem the multiplication code got larger) and it no longer fits.

-Nicolas
Attachments
geiger.c
geiger + rng
(20.17 KiB) Downloaded 837 times
Post Reply